diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css index c28f2fa32e70..645ab3d384ac 100644 --- a/b2g/chrome/content/content.css +++ b/b2g/chrome/content/content.css @@ -178,8 +178,6 @@ button { input[type="radio"], input[type="checkbox"] { - max-width: 14px; - max-height: 14px; border: 1px solid #a7a7a7 !important; padding: 2px 1px 2px 1px; } diff --git a/browser/base/content/test/general/browser_notification_tab_switching.js b/browser/base/content/test/general/browser_notification_tab_switching.js index f1f568daad33..75af0f4e6f70 100644 --- a/browser/base/content/test/general/browser_notification_tab_switching.js +++ b/browser/base/content/test/general/browser_notification_tab_switching.js @@ -1,58 +1,95 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -"use strict"; - -let tab; -let notification; -let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; - -function test () { - waitForExplicitFinish(); - - let pm = Services.perms; - registerCleanupFunction(function() { - pm.remove(notificationURL, "desktop-notification"); - gBrowser.removeTab(tab); - window.restore(); - }); - - pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); - - tab = gBrowser.addTab(notificationURL); - tab.linkedBrowser.addEventListener("load", onLoad, true); -} - -function onLoad() { - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - tab.linkedBrowser.removeEventListener("load", onLoad, true); - let win = tab.linkedBrowser.contentWindow.wrappedJSObject; - notification = win.showNotification(); - notification.addEventListener("show", onAlertShowing); -} - -function onAlertShowing() { - info("Notification alert showing"); - notification.removeEventListener("show", onAlertShowing); - - let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); - if (!alertWindow) { - todo(false, "Notifications don't use XUL windows on all platforms."); - notification.close(); - finish(); - return; - } - gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); - EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); - info("Clicked on notification"); - alertWindow.close(); -} - -function onTabSelect() { - gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); - is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, - "Notification tab should be selected."); - - finish(); -} +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +let tab; +let notification; +let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; +let newWindowOpenedFromTab; + +function test () { + waitForExplicitFinish(); + + let pm = Services.perms; + registerCleanupFunction(function() { + pm.remove(notificationURL, "desktop-notification"); + gBrowser.removeTab(tab); + window.restore(); + }); + + pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); + + tab = gBrowser.addTab(notificationURL); + tab.linkedBrowser.addEventListener("load", onLoad, true); +} + +function onLoad() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + tab.linkedBrowser.removeEventListener("load", onLoad, true); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + win.newWindow = win.open("about:blank", "", "height=100,width=100"); + newWindowOpenedFromTab = win.newWindow; + win.newWindow.addEventListener("load", function() { + info("new window loaded"); + win.newWindow.addEventListener("blur", function b() { + info("new window got blur"); + win.newWindow.removeEventListener("blur", b); + notification = win.showNotification1(); + win.newWindow.addEventListener("focus", onNewWindowFocused); + notification.addEventListener("show", onAlertShowing); + }); + + function waitUntilNewWindowHasFocus() { + if (!win.newWindow.document.hasFocus()) { + setTimeout(waitUntilNewWindowHasFocus, 50); + } else { + // Focus another window so that new window gets blur event. + gBrowser.selectedTab.linkedBrowser.contentWindow.focus(); + } + } + win.newWindow.focus(); + waitUntilNewWindowHasFocus(); + }); +} + +function onAlertShowing() { + info("Notification alert showing"); + notification.removeEventListener("show", onAlertShowing); + + let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); + if (!alertWindow) { + todo(false, "Notifications don't use XUL windows on all platforms."); + notification.close(); + newWindowOpenedFromTab.close(); + finish(); + return; + } + gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); + EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); + info("Clicked on notification"); + alertWindow.close(); +} + +function onNewWindowFocused(event) { + event.target.close(); + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + // Using timeout to test that something do *not* happen! + setTimeout(openSecondNotification, 50); +} + +function openSecondNotification() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + notification = win.showNotification2(); + notification.addEventListener("show", onAlertShowing); +} + +function onTabSelect() { + gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); + is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, + "Notification tab should be selected."); + + finish(); +} diff --git a/browser/base/content/test/general/file_dom_notifications.html b/browser/base/content/test/general/file_dom_notifications.html index 8791d5a1a5be..078c94a42d18 100644 --- a/browser/base/content/test/general/file_dom_notifications.html +++ b/browser/base/content/test/general/file_dom_notifications.html @@ -1,23 +1,40 @@ - - - - - -
- -
- - + + + + + +
+ +
+ + diff --git a/config/external/nss/nss.def b/config/external/nss/nss.def index c15831cc89bd..9480229e9f62 100644 --- a/config/external/nss/nss.def +++ b/config/external/nss/nss.def @@ -87,6 +87,7 @@ CERT_FilterCertListByUsage CERT_FilterCertListForUserCerts CERT_FindCertByDERCert CERT_FindCertByIssuerAndSN +CERT_FindCertByName CERT_FindCertByNickname CERT_FindCertByNicknameOrEmailAddr CERT_FindCertExtension @@ -159,6 +160,8 @@ DER_GetInteger_Util DER_Lengths DER_SetUInteger DER_UTCTimeToTime_Util +DSAU_DecodeDerSigToLen +DSAU_EncodeDerSigWithLen DTLS_GetHandshakeTimeout DTLS_ImportFD HASH_Begin @@ -307,6 +310,7 @@ PK11_DeriveWithTemplate PK11_DestroyContext PK11_DestroyGenericObject PK11_DestroyMergeLog +PK11_DestroyObject PK11_DestroyTokenObject PK11_DigestBegin PK11_DigestFinal @@ -368,6 +372,7 @@ PK11_ImportCert PK11_ImportCertForKey PK11_ImportCRL PK11_ImportDERPrivateKeyInfoAndReturnKey +PK11_ImportPublicKey PK11_ImportSymKey PK11_InitPin PK11_IsDisabled @@ -632,6 +637,7 @@ SSL_CipherPrefSet SSL_CipherPrefSetDefault SSL_ClearSessionCache SSL_ConfigSecureServer +SSL_ConfigSecureServerWithCertChain SSL_ConfigServerSessionIDCache SSL_ExportKeyingMaterial SSL_ForceHandshake @@ -670,6 +676,7 @@ VFY_CreateContext VFY_DestroyContext VFY_End VFY_Update +VFY_VerifyData VFY_VerifyDataDirect VFY_VerifyDataWithAlgorithmID _SGN_VerifyPKCS1DigestInfo diff --git a/configure.in b/configure.in index 7390c685a24c..007885b74b4c 100644 --- a/configure.in +++ b/configure.in @@ -7241,9 +7241,6 @@ dnl our own linker. if test "$OS_TARGET" = Android; then WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue" WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv" - if test -z "$gonkdir"; then - WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm" - fi if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill" fi diff --git a/content/base/src/DOMMatrix.cpp b/content/base/src/DOMMatrix.cpp index 4c98f6dec536..462b8225cfc3 100644 --- a/content/base/src/DOMMatrix.cpp +++ b/content/base/src/DOMMatrix.cpp @@ -435,7 +435,7 @@ DOMMatrix::TranslateSelf(double aTx, if (mMatrix3D || aTz != 0) { Ensure3DMatrix(); - mMatrix3D->Translate(aTx, aTy, aTz); + mMatrix3D->PreTranslate(aTx, aTy, aTz); } else { mMatrix2D->PreTranslate(aTx, aTy); } diff --git a/content/base/src/EventSource.cpp b/content/base/src/EventSource.cpp index 47be79f75366..610b29be2780 100644 --- a/content/base/src/EventSource.cpp +++ b/content/base/src/EventSource.cpp @@ -27,7 +27,6 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIScriptError.h" #include "mozilla/dom/EncodingUtils.h" -#include "nsIChannelPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsContentUtils.h" #include "mozilla/Preferences.h" @@ -737,17 +736,7 @@ EventSource::InitChannelAndRequestEventSource() nsLoadFlags loadFlags; loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE; - // get Content Security Policy from principal to pass into channel - nsCOMPtr channelPolicy; - nsCOMPtr csp; - nsresult rv = mPrincipal->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_DATAREQUEST); - } - + nsresult rv; nsIScriptContext* sc = GetContextForEventHandlers(&rv); nsCOMPtr doc = nsContentUtils::GetDocumentFromScriptContext(sc); @@ -760,7 +749,6 @@ EventSource::InitChannelAndRequestEventSource() doc, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_DATAREQUEST, - channelPolicy, // aChannelPolicy mLoadGroup, // loadGroup nullptr, // aCallbacks loadFlags); // aLoadFlags @@ -771,7 +759,6 @@ EventSource::InitChannelAndRequestEventSource() mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_DATAREQUEST, - channelPolicy, // aChannelPolicy mLoadGroup, // loadGroup nullptr, // aCallbacks loadFlags); // aLoadFlags diff --git a/content/base/src/ImportManager.cpp b/content/base/src/ImportManager.cpp index da7645d538cf..918bae5184a9 100644 --- a/content/base/src/ImportManager.cpp +++ b/content/base/src/ImportManager.cpp @@ -12,7 +12,6 @@ #include "nsContentUtils.h" #include "nsCrossSiteListenerProxy.h" #include "nsIChannel.h" -#include "nsIChannelPolicy.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsIDocument.h" @@ -485,23 +484,12 @@ ImportLoader::Open() NS_ENSURE_SUCCESS_VOID(rv); nsCOMPtr loadGroup = master->GetDocumentLoadGroup(); - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = principal->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS_VOID(rv); - - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT); - } nsCOMPtr channel; rv = NS_NewChannel(getter_AddRefs(channel), mURI, mImportParent, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_SUBDOCUMENT, - channelPolicy, loadGroup, nullptr, // aCallbacks nsIRequest::LOAD_BACKGROUND); diff --git a/content/base/src/moz.build b/content/base/src/moz.build index 7090ecf7b4da..849e9448b328 100644 --- a/content/base/src/moz.build +++ b/content/base/src/moz.build @@ -112,7 +112,6 @@ UNIFIED_SOURCES += [ 'nsAttrValue.cpp', 'nsAttrValueOrString.cpp', 'nsCCUncollectableMarker.cpp', - 'nsChannelPolicy.cpp', 'nsContentAreaDragDrop.cpp', 'nsContentIterator.cpp', 'nsContentList.cpp', diff --git a/content/base/src/nsCSPContext.cpp b/content/base/src/nsCSPContext.cpp index ccbb2fdd8464..657fe992012f 100644 --- a/content/base/src/nsCSPContext.cpp +++ b/content/base/src/nsCSPContext.cpp @@ -11,7 +11,6 @@ #include "nsCSPService.h" #include "nsError.h" #include "nsIAsyncVerifyRedirectCallback.h" -#include "nsIChannelPolicy.h" #include "nsIClassInfoImpl.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" @@ -25,12 +24,10 @@ #include "nsIObjectOutputStream.h" #include "nsIObserver.h" #include "nsIObserverService.h" -#include "nsIPropertyBag2.h" #include "nsIStringStream.h" #include "nsIUploadChannel.h" #include "nsIScriptError.h" #include "nsIWebNavigation.h" -#include "nsIWritablePropertyBag2.h" #include "nsNetUtil.h" #include "nsNullPrincipal.h" #include "nsIContentPolicy.h" diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp index d872851c23df..0683e78db0d0 100644 --- a/content/base/src/nsCSPService.cpp +++ b/content/base/src/nsCSPService.cpp @@ -12,17 +12,13 @@ #include "nsIContent.h" #include "nsCSPService.h" #include "nsIContentSecurityPolicy.h" -#include "nsIChannelPolicy.h" -#include "nsIChannelEventSink.h" -#include "nsIPropertyBag2.h" -#include "nsIWritablePropertyBag2.h" #include "nsError.h" -#include "nsChannelProperties.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsAsyncRedirectVerifyHelper.h" #include "mozilla/Preferences.h" #include "nsIScriptError.h" #include "nsContentUtils.h" +#include "nsContentPolicyUtils.h" #include "nsPrincipal.h" using namespace mozilla; @@ -236,53 +232,56 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel, { nsAsyncRedirectAutoCallback autoCallback(callback); - // get the Content Security Policy and load type from the property bag - nsCOMPtr policyContainer; - nsCOMPtr props(do_QueryInterface(oldChannel)); - if (!props) + nsCOMPtr loadInfo; + nsresult rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo)); + + // if no loadInfo on the channel, nothing for us to do + if (!loadInfo) { return NS_OK; + } - props->GetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY, - NS_GET_IID(nsISupports), - getter_AddRefs(policyContainer)); + // The loadInfo must not necessarily contain a Node, hence we try to query + // the CSP in the following order: + // a) Get the Node, the Principal of that Node, and the CSP of that Principal + // b) Get the Principal and the CSP of that Principal - // see if we have a valid nsIChannelPolicy containing CSP and load type - nsCOMPtr channelPolicy(do_QueryInterface(policyContainer)); - if (!channelPolicy) - return NS_OK; - - nsCOMPtr supports; + nsCOMPtr loadingNode = loadInfo->LoadingNode(); + nsCOMPtr principal = loadingNode ? + loadingNode->NodePrincipal() : + loadInfo->LoadingPrincipal(); + NS_ASSERTION(principal, "Can not evaluate CSP without a principal"); nsCOMPtr csp; - channelPolicy->GetContentSecurityPolicy(getter_AddRefs(supports)); - csp = do_QueryInterface(supports); - uint32_t loadType; - channelPolicy->GetLoadType(&loadType); + rv = principal->GetCsp(getter_AddRefs(csp)); + NS_ENSURE_SUCCESS(rv, rv); - // if no CSP in the channelPolicy, nothing for us to add to the channel - if (!csp) + // if there is no CSP, nothing for us to do + if (!csp) { return NS_OK; + } /* Since redirecting channels don't call into nsIContentPolicy, we call our - * Content Policy implementation directly when redirects occur. When channels - * are created using NS_NewChannel(), callers can optionally pass in a - * nsIChannelPolicy containing a CSP object and load type, which is placed in - * the new channel's property bag. This container is propagated forward when - * channels redirect. + * Content Policy implementation directly when redirects occur using the + * information set in the LoadInfo when channels are created. + * + * We check if the CSP permits this host for this type of load, if not, + * we cancel the load now. */ - // Does the CSP permit this host for this type of load? - // If not, cancel the load now. nsCOMPtr newUri; - newChannel->GetURI(getter_AddRefs(newUri)); + rv = newChannel->GetURI(getter_AddRefs(newUri)); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr originalUri; - oldChannel->GetOriginalURI(getter_AddRefs(originalUri)); + rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri)); + NS_ENSURE_SUCCESS(rv, rv); + nsContentPolicyType policyType = loadInfo->GetContentPolicyType(); + int16_t aDecision = nsIContentPolicy::ACCEPT; - csp->ShouldLoad(loadType, // load type per nsIContentPolicy (uint32_t) - newUri, // nsIURI - nullptr, // nsIURI - nullptr, // nsISupports - EmptyCString(), // ACString - MIME guess - originalUri, // nsISupports - extra + csp->ShouldLoad(policyType, // load type per nsIContentPolicy (uint32_t) + newUri, // nsIURI + nullptr, // nsIURI + nullptr, // nsISupports + EmptyCString(), // ACString - MIME guess + originalUri, // aMimeTypeGuess &aDecision); #ifdef PR_LOGGING @@ -302,36 +301,9 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel, #endif // if ShouldLoad doesn't accept the load, cancel the request - if (aDecision != 1) { + if (!NS_CP_ACCEPTED(aDecision)) { autoCallback.DontCallback(); return NS_BINDING_FAILED; } - - // the redirect is permitted, so propagate the Content Security Policy - // and load type to the redirecting channel - nsresult rv; - nsCOMPtr props2 = do_QueryInterface(newChannel); - if (props2) { - rv = props2->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY, - channelPolicy); - if (NS_SUCCEEDED(rv)) { - return NS_OK; - } - } - - // The redirecting channel isn't a writable property bag, we won't be able - // to enforce the load policy if it redirects again, so we stop it now. - nsAutoCString newUriSpec; - rv = newUri->GetSpec(newUriSpec); - NS_ConvertUTF8toUTF16 unicodeSpec(newUriSpec); - const char16_t *formatParams[] = { unicodeSpec.get() }; - if (NS_SUCCEEDED(rv)) { - nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, - NS_LITERAL_CSTRING("Redirect Error"), nullptr, - nsContentUtils::eDOM_PROPERTIES, - "InvalidRedirectChannelWarning", - formatParams, 1); - } - - return NS_BINDING_FAILED; + return NS_OK; } diff --git a/content/base/src/nsChannelPolicy.cpp b/content/base/src/nsChannelPolicy.cpp deleted file mode 100644 index 7d647695bbe6..000000000000 --- a/content/base/src/nsChannelPolicy.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsChannelPolicy.h" - -nsChannelPolicy::nsChannelPolicy() - : mLoadType(0) -{ -} - -nsChannelPolicy::~nsChannelPolicy() -{ -} - -NS_IMPL_ISUPPORTS(nsChannelPolicy, nsIChannelPolicy) - -NS_IMETHODIMP -nsChannelPolicy::GetLoadType(uint32_t *aLoadType) -{ - *aLoadType = mLoadType; - return NS_OK; -} - -NS_IMETHODIMP -nsChannelPolicy::SetLoadType(uint32_t aLoadType) -{ - mLoadType = aLoadType; - return NS_OK; -} - -NS_IMETHODIMP -nsChannelPolicy::GetContentSecurityPolicy(nsISupports **aCSP) -{ - *aCSP = mCSP; - NS_IF_ADDREF(*aCSP); - return NS_OK; -} - -NS_IMETHODIMP -nsChannelPolicy::SetContentSecurityPolicy(nsISupports *aCSP) -{ - mCSP = aCSP; - return NS_OK; -} diff --git a/content/base/src/nsChannelPolicy.h b/content/base/src/nsChannelPolicy.h deleted file mode 100644 index f5a0ba29f0e0..000000000000 --- a/content/base/src/nsChannelPolicy.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsChannelPolicy_h___ -#define nsChannelPolicy_h___ - -#include "nsCOMPtr.h" -#include "nsIChannelPolicy.h" - -#define NSCHANNELPOLICY_CONTRACTID "@mozilla.org/nschannelpolicy;1" -#define NSCHANNELPOLICY_CID \ -{ 0xd396b3cd, 0xf164, 0x4ce8, \ - { 0x93, 0xa7, 0xe3, 0x85, 0xe1, 0x46, 0x56, 0x3c } } - -class nsChannelPolicy : public nsIChannelPolicy -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICHANNELPOLICY - - nsChannelPolicy(); - -protected: - virtual ~nsChannelPolicy(); - - /* Represents the type of content being loaded in the channel per - * nsIContentPolicy, e.g. TYPE_IMAGE, TYPE_SCRIPT - */ - unsigned long mLoadType; - - /* pointer to a Content Security Policy object if available */ - nsCOMPtr mCSP; -}; - -#endif /* nsChannelPolicy_h___ */ diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 63f541df96c4..38ec950eccf2 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -59,7 +59,6 @@ #include "nsAttrValueInlines.h" #include "nsBindingManager.h" #include "nsCCUncollectableMarker.h" -#include "nsChannelPolicy.h" #include "nsCharSeparatedTokenizer.h" #include "nsCOMPtr.h" #include "nsContentCreatorFunctions.h" @@ -88,7 +87,6 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "nsICategoryManager.h" #include "nsIChannelEventSink.h" -#include "nsIChannelPolicy.h" #include "nsICharsetDetectionObserver.h" #include "nsIChromeRegistry.h" #include "nsIConsoleService.h" @@ -3007,20 +3005,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, NS_ASSERTION(loadGroup || IsFontTableURI(documentURI), "Could not get loadgroup; onload may fire too early"); - // check for a Content Security Policy to pass down to the channel that - // will get created to load the image - nsCOMPtr channelPolicy; - nsCOMPtr csp; - if (aLoadingPrincipal) { - nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE); - } - } - // Make the URI immutable so people won't change it under us NS_TryToSetImmutable(aURI); @@ -3035,7 +3019,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, aLoadingDocument, /* uniquification key */ aLoadFlags, /* load flags */ nullptr, /* cache key */ - channelPolicy, /* CSP info */ initiatorType, /* the load initiator */ aRequest); } diff --git a/content/base/src/nsCrossSiteListenerProxy.cpp b/content/base/src/nsCrossSiteListenerProxy.cpp index 6a2ea5122a4c..582b6336c82d 100644 --- a/content/base/src/nsCrossSiteListenerProxy.cpp +++ b/content/base/src/nsCrossSiteListenerProxy.cpp @@ -1122,7 +1122,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel, rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel), uri, loadInfo, - nullptr, // aChannelPolicy loadGroup, nullptr, // aCallbacks loadFlags); @@ -1134,7 +1133,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel, nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy loadGroup, nullptr, // aCallbacks loadFlags); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 7962fc23da08..9d06af8500b4 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1330,7 +1330,6 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI, aRequestingNode, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy loadGroup, req); // aCallbacks diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index 967592658350..781f53efe32f 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -65,8 +65,6 @@ #include "nsObjectLoadingContent.h" #include "mozAutoDocUpdate.h" #include "nsIContentSecurityPolicy.h" -#include "nsIChannelPolicy.h" -#include "nsChannelPolicy.h" #include "GeckoProfiler.h" #include "nsPluginFrame.h" #include "nsDOMClassInfo.h" @@ -2492,15 +2490,6 @@ nsObjectLoadingContent::OpenChannel() nsCOMPtr group = doc->GetDocumentLoadGroup(); nsCOMPtr chan; - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT); - } nsRefPtr shim = new ObjectInterfaceRequestorShim(this); @@ -2522,7 +2511,6 @@ nsObjectLoadingContent::OpenChannel() thisContent, securityFlags, nsIContentPolicy::TYPE_OBJECT, - channelPolicy, group, // aLoadGroup shim, // aCallbacks nsIChannel::LOAD_CALL_CONTENT_SNIFFERS | diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp index 53cbbef24e22..7b730948be76 100644 --- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -41,8 +41,6 @@ #include "nsDocShellCID.h" #include "nsIContentSecurityPolicy.h" #include "prlog.h" -#include "nsIChannelPolicy.h" -#include "nsChannelPolicy.h" #include "nsCRT.h" #include "nsContentCreatorFunctions.h" #include "nsCrossSiteListenerProxy.h" @@ -307,25 +305,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, return NS_OK; } - // check for a Content Security Policy to pass down to the channel - // that will be created to load the script - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT); - } - nsCOMPtr channel; rv = NS_NewChannel(getter_AddRefs(channel), aRequest->mURI, mDocument, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_SCRIPT, - channelPolicy, loadGroup, prompter, nsIRequest::LOAD_NORMAL | diff --git a/content/base/src/nsSyncLoadService.cpp b/content/base/src/nsSyncLoadService.cpp index 3a675e1a8d6e..6805aca44df9 100644 --- a/content/base/src/nsSyncLoadService.cpp +++ b/content/base/src/nsSyncLoadService.cpp @@ -315,7 +315,6 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal, aLoaderPrincipal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy aLoadGroup); NS_ENSURE_SUCCESS(rv, rv); diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 108d8fa75b60..6d1aa993538f 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -52,8 +52,6 @@ #include "nsIPromptFactory.h" #include "nsIWindowWatcher.h" #include "nsIConsoleService.h" -#include "nsIChannelPolicy.h" -#include "nsChannelPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsAsyncRedirectVerifyHelper.h" #include "nsStringBuffer.h" @@ -474,6 +472,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest, NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink) @@ -492,6 +494,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest, NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink) @@ -1724,17 +1730,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, // will be automatically aborted if the user leaves the page. nsCOMPtr loadGroup = GetLoadGroup(); - // get Content Security Policy from principal to pass into channel - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = mPrincipal->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_XMLHTTPREQUEST); - } - nsSecurityFlags secFlags = nsILoadInfo::SEC_NORMAL; if (IsSystemXHR()) { // Don't give this document the system principal. We need to keep track of @@ -1754,7 +1749,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, doc, secFlags, nsIContentPolicy::TYPE_XMLHTTPREQUEST, - channelPolicy, loadGroup, nullptr, // aCallbacks nsIRequest::LOAD_BACKGROUND); @@ -1765,7 +1759,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, mPrincipal, secFlags, nsIContentPolicy::TYPE_XMLHTTPREQUEST, - channelPolicy, loadGroup, nullptr, // aCallbacks nsIRequest::LOAD_BACKGROUND); diff --git a/content/base/test/mochitest.ini b/content/base/test/mochitest.ini index 9c6c1ea5a9b7..659c8757ea63 100644 --- a/content/base/test/mochitest.ini +++ b/content/base/test/mochitest.ini @@ -291,6 +291,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug [test_bug340571.html] [test_bug343596.html] [test_bug345339.html] +skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File [test_bug346485.html] [test_bug352728.html] [test_bug352728.xhtml] diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 9b916fbc202d..171861002c66 100755 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -99,8 +99,6 @@ static PRLogModuleInfo* gMediaElementEventsLog; #endif #include "nsIContentSecurityPolicy.h" -#include "nsIChannelPolicy.h" -#include "nsChannelPolicy.h" #include "mozilla/Preferences.h" @@ -1170,25 +1168,12 @@ nsresult HTMLMediaElement::LoadResource() } nsCOMPtr loadGroup = GetDocumentLoadGroup(); - - // check for a Content Security Policy to pass down to the channel - // created to load the media content - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv,rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA); - } nsCOMPtr channel; rv = NS_NewChannel(getter_AddRefs(channel), mLoadingSrc, static_cast(this), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_MEDIA, - channelPolicy, loadGroup, nullptr, // aCallbacks nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY | diff --git a/content/html/content/src/HTMLTrackElement.cpp b/content/html/content/src/HTMLTrackElement.cpp index 5c21c4cc6f59..db01a4d5608c 100644 --- a/content/html/content/src/HTMLTrackElement.cpp +++ b/content/html/content/src/HTMLTrackElement.cpp @@ -21,7 +21,6 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "nsICachingChannel.h" #include "nsIChannelEventSink.h" -#include "nsIChannelPolicy.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsIDocument.h" @@ -237,20 +236,6 @@ HTMLTrackElement::LoadResource() CreateTextTrack(); } - // Check for a Content Security Policy to pass down to the channel - // created to load the media content. - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - if (!channelPolicy) { - return; - } - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA); - } nsCOMPtr channel; nsCOMPtr loadGroup = OwnerDoc()->GetDocumentLoadGroup(); rv = NS_NewChannel(getter_AddRefs(channel), @@ -258,7 +243,6 @@ HTMLTrackElement::LoadResource() static_cast(this), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_MEDIA, - channelPolicy, loadGroup); NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 8580903b4f9b..065f691625b0 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -291,16 +291,11 @@ static const nsAttrValue::EnumTable kDirTable[] = { void nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel) { - //XXXsmaug We shouldn't need PresContext for this. - nsPresContext *presContext = GetPresContext(eForComposedDoc); - - if (presContext) { - nsAutoString suffix; - GetAccessKey(suffix); - if (!suffix.IsEmpty() && - presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) { - aLabel.Append(suffix); - } + nsAutoString suffix; + GetAccessKey(suffix); + if (!suffix.IsEmpty()) { + EventStateManager::GetAccessKeyLabelPrefix(this, aLabel); + aLabel.Append(suffix); } } diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index d03ca06535f2..72d890366858 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1516,7 +1516,6 @@ nsHTMLDocument::Open(JSContext* cx, callerDoc, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy group); if (rv.Failed()) { diff --git a/content/media/GraphDriver.cpp b/content/media/GraphDriver.cpp index 1c87f168bf91..8a1490eedc37 100644 --- a/content/media/GraphDriver.cpp +++ b/content/media/GraphDriver.cpp @@ -464,7 +464,7 @@ AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation mOperation(aOperation), mShutdownGrip(aDriver->GraphImpl()) { - MOZ_ASSERT(mDriver->mAudioStream || aOperation == INIT, "No audio stream !"); + NS_WARN_IF_FALSE(mDriver->mAudioStream || aOperation == INIT, "No audio stream !"); } AsyncCubebTask::~AsyncCubebTask() diff --git a/content/media/MediaResource.cpp b/content/media/MediaResource.cpp index 194734fc68fa..b73fbddc4899 100644 --- a/content/media/MediaResource.cpp +++ b/content/media/MediaResource.cpp @@ -924,7 +924,6 @@ ChannelMediaResource::RecreateChannel() element, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_MEDIA, - nullptr, // aChannelPolicy loadGroup, nullptr, // aCallbacks loadFlags); @@ -1442,7 +1441,6 @@ already_AddRefed FileMediaResource::CloneData(MediaDecoder* aDeco element, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_MEDIA, - nullptr, // aChannelPolicy loadGroup); if (NS_FAILED(rv)) diff --git a/content/media/mediasource/MediaSourceReader.cpp b/content/media/mediasource/MediaSourceReader.cpp index ab014ef91e6e..126ded6f7f42 100644 --- a/content/media/mediasource/MediaSourceReader.cpp +++ b/content/media/mediasource/MediaSourceReader.cpp @@ -202,24 +202,26 @@ void MediaSourceReader::Shutdown() { MediaDecoderReader::Shutdown(); + for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { + mTrackBuffers[i]->Shutdown(); + } mAudioTrack = nullptr; mAudioReader = nullptr; mVideoTrack = nullptr; mVideoReader = nullptr; - for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { - mTrackBuffers[i]->Shutdown(); - } - mTrackBuffers.Clear(); } void MediaSourceReader::BreakCycles() { MediaDecoderReader::BreakCycles(); - mAudioTrack = nullptr; - mAudioReader = nullptr; - mVideoTrack = nullptr; - mVideoReader = nullptr; + + // These were cleared in Shutdown(). + MOZ_ASSERT(!mAudioTrack); + MOZ_ASSERT(!mAudioReader); + MOZ_ASSERT(!mVideoTrack); + MOZ_ASSERT(!mVideoReader); + for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { mTrackBuffers[i]->BreakCycles(); } diff --git a/content/media/mediasource/SourceBuffer.cpp b/content/media/mediasource/SourceBuffer.cpp index 57fe1f586470..320e2a6559e1 100644 --- a/content/media/mediasource/SourceBuffer.cpp +++ b/content/media/mediasource/SourceBuffer.cpp @@ -416,8 +416,21 @@ SourceBuffer::Dump(const char* aPath) } #endif -NS_IMPL_CYCLE_COLLECTION_INHERITED(SourceBuffer, DOMEventTargetHelper, - mMediaSource) +NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer) + // Tell the TrackBuffer to end its current SourceBufferResource. + TrackBuffer* track = tmp->mTrackBuffer; + if (track) { + track->Detach(); + } + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SourceBuffer, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_ADDREF_INHERITED(SourceBuffer, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(SourceBuffer, DOMEventTargetHelper) diff --git a/content/media/mediasource/TrackBuffer.cpp b/content/media/mediasource/TrackBuffer.cpp index 6f9bc6fcb0c0..98f8b4c84a67 100644 --- a/content/media/mediasource/TrackBuffer.cpp +++ b/content/media/mediasource/TrackBuffer.cpp @@ -54,31 +54,22 @@ TrackBuffer::~TrackBuffer() class ReleaseDecoderTask : public nsRunnable { public: explicit ReleaseDecoderTask(SourceBufferDecoder* aDecoder) + : mDecoder(aDecoder) { - mDecoders.AppendElement(aDecoder); - } - - explicit ReleaseDecoderTask(nsTArray>& aDecoders) - { - mDecoders.SwapElements(aDecoders); } NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL { - mDecoders.Clear(); + mDecoder = nullptr; return NS_OK; } private: - nsTArray> mDecoders; + nsRefPtr mDecoder; }; void TrackBuffer::Shutdown() { - // End the SourceBufferResource associated with mCurrentDecoder, which will - // unblock any decoder initialization in ReadMetadata(). - DiscardDecoder(); - // Finish any decoder initialization, which may add to mInitializedDecoders. // Shutdown waits for any pending events, which may require the monitor, // so we must not hold the monitor during this call. @@ -91,8 +82,6 @@ TrackBuffer::Shutdown() mDecoders[i]->GetReader()->Shutdown(); } mInitializedDecoders.Clear(); - NS_DispatchToMainThread(new ReleaseDecoderTask(mDecoders)); - MOZ_ASSERT(mDecoders.IsEmpty()); mParentDecoder = nullptr; } @@ -399,13 +388,16 @@ TrackBuffer::ContainsTime(int64_t aTime) void TrackBuffer::BreakCycles() { + MOZ_ASSERT(NS_IsMainThread()); + for (uint32_t i = 0; i < mDecoders.Length(); ++i) { mDecoders[i]->GetReader()->BreakCycles(); } - mInitializedDecoders.Clear(); - NS_DispatchToMainThread(new ReleaseDecoderTask(mDecoders)); - MOZ_ASSERT(mDecoders.IsEmpty()); - mParentDecoder = nullptr; + mDecoders.Clear(); + + // These are cleared in Shutdown() + MOZ_ASSERT(mInitializedDecoders.IsEmpty()); + MOZ_ASSERT(!mParentDecoder); } void diff --git a/content/media/test/mochitest.ini b/content/media/test/mochitest.ini index 94787bd9120e..139a859f6923 100644 --- a/content/media/test/mochitest.ini +++ b/content/media/test/mochitest.ini @@ -460,7 +460,6 @@ skip-if = true # bug 1021673 [test_standalone.html] [test_streams_autoplay.html] [test_streams_element_capture.html] -skip-if = e10s && os == 'win' # Bug 1065881 - Crash on child process shutdown in ShadowLayerForwarder::InWorkerThread [test_streams_element_capture_createObjectURL.html] [test_streams_element_capture_playback.html] [test_streams_element_capture_reset.html] diff --git a/content/media/test/test_mediarecorder_record_immediate_stop.html b/content/media/test/test_mediarecorder_record_immediate_stop.html index 1327f1acd73c..0f51fe300ed0 100644 --- a/content/media/test/test_mediarecorder_record_immediate_stop.html +++ b/content/media/test/test_mediarecorder_record_immediate_stop.html @@ -97,9 +97,9 @@ function startTest(test, token) { // This handler completes a start and stop of recording and verifies // respective media recorder state. - var canPlayThrough = function() { - element.removeEventListener('canplaythrough', canPlayThrough, false); - + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + element.play(); mediaRecorder.start(); is(mediaRecorder.state, 'recording', 'Media recorder should be recording'); is(mediaRecorder.stream, element.stream, @@ -112,8 +112,7 @@ function startTest(test, token) { 'Media recorder stream = element stream post recording'); }; - element.addEventListener('canplaythrough', canPlayThrough, false); - element.play(); + element.preload = "metadata"; } manager.runTests(gMediaRecorderTests, startTest); diff --git a/content/media/test/test_mediarecorder_record_no_timeslice.html b/content/media/test/test_mediarecorder_record_no_timeslice.html index 5d0270e013de..67321ceb4efc 100644 --- a/content/media/test/test_mediarecorder_record_no_timeslice.html +++ b/content/media/test/test_mediarecorder_record_no_timeslice.html @@ -84,24 +84,18 @@ function startTest(test, token) { } }; - element.oncanplaythrough = function () { - element.oncanplaythrough = null; - // If content has ended, skip the test - if (element.ended) { - ok(true, 'ended fired before canplaythrough, skipping test'); - manager.finished(token); - } else { - // If content hasn't ended, start recording - mediaRecorder.start(); - is(mediaRecorder.state, 'recording', - 'Media recorder should be recording'); - is(mediaRecorder.stream, element.stream, - 'Media recorder stream = element stream at the start of recording'); - // Recording will automatically stop when the stream ends. - } - } + element.preload = "metadata"; - element.play(); + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + mediaRecorder.start(); + is(mediaRecorder.state, 'recording', + 'Media recorder should be recording'); + is(mediaRecorder.stream, element.stream, + 'Media recorder stream = element stream at the start of recording'); + + element.play(); + } } manager.runTests(gMediaRecorderTests, startTest); diff --git a/content/media/test/test_mediarecorder_record_session.html b/content/media/test/test_mediarecorder_record_session.html index a4b4a4b7a8ed..3c179ced020e 100644 --- a/content/media/test/test_mediarecorder_record_session.html +++ b/content/media/test/test_mediarecorder_record_session.html @@ -54,15 +54,17 @@ function startTest(test, token) { ok(false, 'Unexpected warning fired'); } - element.oncanplaythrough = function () { - element.oncanplaythrough = null; + element.preload = "metadata"; + + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + element.play(); for (var i = 0; i < mExpectStopCount; i++) { mediaRecorder.start(1000); mediaRecorder.stop(); } } - element.play(); } manager.runTests(gMediaRecorderTests, startTest); diff --git a/content/media/test/test_timeupdate_small_files.html b/content/media/test/test_timeupdate_small_files.html index b6d51800bdbe..9eac499e2536 100644 --- a/content/media/test/test_timeupdate_small_files.html +++ b/content/media/test/test_timeupdate_small_files.html @@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495319 var manager = new MediaTestManager; -function timeupdate(e) { - var v = e.target; - v._timeupdateCount++; - ok(v.gotEnded == 0, v._name + " - shouldn't get timeupdate after ended"); -} - function ended(e) { var v = e.target; - ++v.gotEnded; - ok(v._timeupdateCount > 0, v._name + " - should see at least one timeupdate: " + v.currentTime); - v._finished = true; + ++v.counter["ended"]; + is(v.counter["ended"], 1, v._name + " should see ended only once"); + ok(v.counter["timeupdate"] > 0, v._name + " should see at least one timeupdate: " + v.currentTime); + + // Rest event counters for we don't allow events after ended. + eventsToLog.forEach(function(e) { + v.counter[e] = 0; + }); + // Finish the test after 500ms. We shouldn't receive any timeupdate events // after the ended event, so this gives time for any pending timeupdate events // to fire so we can ensure we don't regress behaviour. @@ -39,10 +39,9 @@ function ended(e) { // invoked when it's removed from a document), and we don't want those // confusing the test results. v.removeEventListener("ended", ended, false); - v.removeEventListener("timeupdate", timeupdate, false); - for (var i = 0; i < eventsToLog.length; ++i) { - v.removeEventListener(eventsToLog[i], logEvent, false); - } + eventsToLog.forEach(function(e) { + v.removeEventListener(e, logEvent, false); + }); removeNodeAndSource(v); manager.finished(v.token); }, @@ -50,17 +49,14 @@ function ended(e) { } var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmetadata", - "loadeddata", "playing", "progress", "timeupdate", "ended", "suspend", "error", "stalled", "emptied", "abort", + "loadeddata", "playing", "timeupdate", "error", "stalled", "emptied", "abort", "waiting", "pause"]; + function logEvent(event) { - if (event.target.gotEnded > (event.type == "ended" ? 1 : 0)) { - if (event.target.currentSrc.slice(-9) == "seek.webm" && event.type == "stalled") { - todo(false, event.target.currentSrc + " got unexpected stalled after ended (bug 760770)"); - } else { - ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended"); - } - } else { - info(event.target.currentSrc + " got " + event.type); + var v = event.target; + ++v.counter[event.type]; + if (v.counter["ended"] > 0) { + is(v.counter[event.type], 0, v._name + " got unexpected " + event.type + " after ended"); } } @@ -71,14 +67,15 @@ function startTest(test, token) { manager.started(token); v.src = test.name; v._name = test.name; - v._timeupdateCount = 0; - v._finished = false; - v.gotEnded = 0; + + // Keep how many events received for each event type. + v.counter = {}; + eventsToLog.forEach(function(e) { + v.addEventListener(e, logEvent, false); + v.counter[e] = 0; + }); v.addEventListener("ended", ended, false); - v.addEventListener("timeupdate", timeupdate, false); - for (var i = 0; i < eventsToLog.length; ++i) { - v.addEventListener(eventsToLog[i], logEvent, false); - } + v.counter["ended"] = 0; document.body.appendChild(v); v.play(); } diff --git a/content/media/webspeech/synth/pico/nsPicoService.cpp b/content/media/webspeech/synth/pico/nsPicoService.cpp index 5d436dcdb060..908272696c51 100644 --- a/content/media/webspeech/synth/pico/nsPicoService.cpp +++ b/content/media/webspeech/synth/pico/nsPicoService.cpp @@ -411,7 +411,8 @@ PicoCallbackRunnable::OnCancel() NS_INTERFACE_MAP_BEGIN(nsPicoService) NS_INTERFACE_MAP_ENTRY(nsISpeechService) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsPicoService) @@ -427,10 +428,6 @@ nsPicoService::nsPicoService() , mTaResource(nullptr) , mPicoMemArea(nullptr) { - DebugOnly rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread)); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - rv = mThread->Dispatch(NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL); - MOZ_ASSERT(NS_SUCCEEDED(rv)); } nsPicoService::~nsPicoService() @@ -447,6 +444,20 @@ nsPicoService::~nsPicoService() UnloadEngine(); } +// nsIObserver + +NS_IMETHODIMP +nsPicoService::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED); + + DebugOnly rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return mThread->Dispatch( + NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL); +} // nsISpeechService NS_IMETHODIMP diff --git a/content/media/webspeech/synth/pico/nsPicoService.h b/content/media/webspeech/synth/pico/nsPicoService.h index bebadbe3ec4a..a22568ec3c02 100644 --- a/content/media/webspeech/synth/pico/nsPicoService.h +++ b/content/media/webspeech/synth/pico/nsPicoService.h @@ -10,6 +10,7 @@ #include "mozilla/Mutex.h" #include "nsAutoPtr.h" #include "nsTArray.h" +#include "nsIObserver.h" #include "nsIThread.h" #include "nsISpeechService.h" #include "nsRefPtrHashtable.h" @@ -26,7 +27,8 @@ typedef void* pico_System; typedef void* pico_Resource; typedef void* pico_Engine; -class nsPicoService : public nsISpeechService +class nsPicoService : public nsIObserver, + public nsISpeechService { friend class PicoCallbackRunnable; friend class PicoInitRunnable; @@ -34,6 +36,7 @@ class nsPicoService : public nsISpeechService public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISPEECHSERVICE + NS_DECL_NSIOBSERVER nsPicoService(); diff --git a/content/xul/document/src/XULDocument.cpp b/content/xul/document/src/XULDocument.cpp index 1c873a4c9f85..a31a93385c0d 100644 --- a/content/xul/document/src/XULDocument.cpp +++ b/content/xul/document/src/XULDocument.cpp @@ -2702,7 +2702,6 @@ XULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic, NodePrincipal(), nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy group); if (NS_SUCCEEDED(rv)) { diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index bc62441bf5b7..5e6fbeb1090a 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -67,7 +67,7 @@ static RedirEntry kRedirMap[] = { nsIAboutModule::ALLOW_SCRIPT }, { "networking", "chrome://global/content/aboutNetworking.xhtml", nsIAboutModule::ALLOW_SCRIPT }, - { "webrtc", "chrome://global/content/aboutWebrtc.xhtml", + { "webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.xhtml", nsIAboutModule::ALLOW_SCRIPT }, // about:srcdoc is unresolvable by specification. It is included here // because the security manager would disallow srcdoc iframes otherwise. diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 7cae031b1824..d218f4810825 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -168,7 +168,6 @@ #endif #include "nsContentUtils.h" -#include "nsIChannelPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsILoadInfo.h" #include "nsSandboxFlags.h" @@ -10158,27 +10157,7 @@ nsDocShell::DoURILoad(nsIURI * aURI, loadFlags |= nsIChannel::LOAD_BACKGROUND; } - // check for Content Security Policy to pass along with the - // new channel we are creating - nsCOMPtr channelPolicy; if (IsFrame()) { - // check the parent docshell for a CSP - nsCOMPtr csp; - nsCOMPtr parentItem; - GetSameTypeParent(getter_AddRefs(parentItem)); - if (parentItem) { - nsCOMPtr doc = parentItem->GetDocument(); - if (doc) { - rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT); - } - } - } - // Only allow view-source scheme in top-level docshells. view-source is // the only scheme to which this applies at the moment due to potential // timing attacks to read data from cross-origin iframes. If this widens @@ -10247,7 +10226,6 @@ nsDocShell::DoURILoad(nsIURI * aURI, requestingPrincipal, securityFlags, aContentPolicyType, - channelPolicy, nullptr, // loadGroup static_cast(this), loadFlags); diff --git a/dom/apps/AppsServiceChild.jsm b/dom/apps/AppsServiceChild.jsm index 0c3bbe6a59b2..8d5663607d24 100644 --- a/dom/apps/AppsServiceChild.jsm +++ b/dom/apps/AppsServiceChild.jsm @@ -131,9 +131,6 @@ this.DOMApplicationRegistry = { APPS_IPC_MSG_NAMES.forEach((aMsgName) => { this.cpmm.removeMessageListener(aMsgName, this); }); - - this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", - APPS_IPC_MSG_NAMES) }, receiveMessage: function receiveMessage(aMessage) { diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 1e1cfe7fedb6..3ef0cc9dc98b 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -67,7 +67,6 @@ #include "mozIApplication.h" #include "WidgetUtils.h" #include "mozIThirdPartyUtil.h" -#include "nsChannelPolicy.h" #ifdef MOZ_MEDIA_NAVIGATOR #include "MediaManager.h" @@ -1056,26 +1055,11 @@ Navigator::SendBeacon(const nsAString& aUrl, } nsCOMPtr channel; - nsCOMPtr channelPolicy; - nsCOMPtr csp; - rv = principal->GetCsp(getter_AddRefs(csp)); - if (NS_FAILED(rv)) { - aRv.Throw(NS_ERROR_FAILURE); - return false; - } - - if (csp) { - channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON); - } - rv = NS_NewChannel(getter_AddRefs(channel), uri, doc, nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_BEACON, - channelPolicy); + nsIContentPolicy::TYPE_BEACON); if (NS_FAILED(rv)) { aRv.Throw(rv); diff --git a/dom/base/URLSearchParams.h b/dom/base/URLSearchParams.h index 1fab838b4790..ec1afad5505d 100644 --- a/dom/base/URLSearchParams.h +++ b/dom/base/URLSearchParams.h @@ -75,7 +75,7 @@ public: void Delete(const nsAString& aName); - void Stringify(nsString& aRetval) + void Stringify(nsString& aRetval) const { Serialize(aRetval); } diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 333a435513d4..8b8048d5d404 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -62,3 +62,4 @@ MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-o MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, "Missing required {0}.") MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, "Invalid request method {0}.") MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, "Request body has already been consumed.") +MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, "Response statusText may not contain newline or carriage return.") diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 9b1ee279b9ff..ee1d2a4762d8 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -83,6 +83,7 @@ let SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12); let MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE; let MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = (MOZILLA_PKIX_ERROR_BASE + 1); +let MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = (MOZILLA_PKIX_ERROR_BASE + 3); function getErrorClass(errorCode) { let NSPRCode = -1 * NS_ERROR_GET_CODE(errorCode); @@ -96,6 +97,7 @@ function getErrorClass(errorCode) { case SEC_ERROR_EXPIRED_CERTIFICATE: case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: case MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: + case MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: return Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT; default: return Ci.nsINSSErrorsService.ERROR_CLASS_SSL_PROTOCOL; diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 80352a8fe470..50793d5771c0 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1022,8 +1022,10 @@ CanvasRenderingContext2D::Redraw(const mgfx::Rect &r) void CanvasRenderingContext2D::DidRefresh() { - SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); - if (glue) { + if (IsTargetValid() && SkiaGLTex()) { + SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); + MOZ_ASSERT(glue); + auto gl = glue->GetGLContext(); gl->FlushIfHeavyGLCallsSinceLastFlush(); } @@ -4823,6 +4825,14 @@ CanvasRenderingContext2D::CreateImageData(JSContext* cx, static uint8_t g2DContextLayerUserData; + +uint32_t +CanvasRenderingContext2D::SkiaGLTex() const +{ + MOZ_ASSERT(IsTargetValid()); + return (uint32_t)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE); +} + already_AddRefed CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, @@ -4854,9 +4864,11 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer::Data data; - SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); - GLuint skiaGLTex = (GLuint)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE); - if (glue && skiaGLTex) { + GLuint skiaGLTex = SkiaGLTex(); + if (skiaGLTex) { + SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); + MOZ_ASSERT(glue); + data.mGLContext = glue->GetGLContext(); data.mFrontbufferGLTex = skiaGLTex; } else { @@ -4898,11 +4910,14 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, data.mSize = nsIntSize(mWidth, mHeight); data.mHasAlpha = !mOpaque; - SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); - GLuint skiaGLTex = (GLuint)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE); - if (glue && skiaGLTex) { + GLuint skiaGLTex = SkiaGLTex(); + if (skiaGLTex) { canvasLayer->SetPreTransactionCallback( CanvasRenderingContext2DUserData::PreTransactionCallback, userData); + + SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue(); + MOZ_ASSERT(glue); + data.mGLContext = glue->GetGLContext(); data.mFrontbufferGLTex = skiaGLTex; } else { diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index ab14dc8081f3..bfe8d83fd326 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -698,7 +698,9 @@ protected: /** * Check if the target is valid after calling EnsureTarget. */ - bool IsTargetValid() { return mTarget != sErrorTarget && mTarget != nullptr; } + bool IsTargetValid() const { + return mTarget != sErrorTarget && mTarget != nullptr; + } /** * Returns the surface format this canvas should be allocated using. Takes @@ -764,6 +766,8 @@ protected: // sErrorTarget. mozilla::RefPtr mTarget; + uint32_t SkiaGLTex() const; + /** * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever * Redraw is called, reset to false when Render is called. diff --git a/dom/canvas/WebGL2ContextTextures.cpp b/dom/canvas/WebGL2ContextTextures.cpp index e134ed100c28..21028d09e5b6 100644 --- a/dom/canvas/WebGL2ContextTextures.cpp +++ b/dom/canvas/WebGL2ContextTextures.cpp @@ -351,6 +351,8 @@ WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname) { switch (pname) { case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT: + case LOCAL_GL_TEXTURE_BASE_LEVEL: + case LOCAL_GL_TEXTURE_MAX_LEVEL: { GLint i = 0; gl->fGetTexParameteriv(target.get(), pname, &i); diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index cf8be3fed833..74e67e38a489 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -922,7 +922,7 @@ WebGLContext::GenerateMipmap(GLenum rawTarget) const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; - if (!tex->HasImageInfoAt(imageTarget, 0)) + if (!tex->HasImageInfoAt(imageTarget, tex->GetBaseMipmapLevel())) { return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined."); } @@ -1510,6 +1510,19 @@ void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname, bool paramValueInvalid = false; switch (pname) { + case LOCAL_GL_TEXTURE_BASE_LEVEL: + case LOCAL_GL_TEXTURE_MAX_LEVEL: + if (!IsWebGL2()) + return ErrorInvalidEnumInfo("texParameter: pname", pname); + if (intParam < 0) { + paramValueInvalid = true; + break; + } + if (pname == LOCAL_GL_TEXTURE_BASE_LEVEL) + tex->SetBaseMipmapLevel(intParam); + else + tex->SetMaxMipmapLevel(intParam); + break; case LOCAL_GL_TEXTURE_MIN_FILTER: switch (intParam) { case LOCAL_GL_NEAREST: diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index 768742d4161b..474734bbfac7 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -186,6 +186,10 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) gl->fGetIntegerv(pname, &val); return JS::NumberValue(uint32_t(val)); } + + case LOCAL_GL_TEXTURE_BINDING_3D: { + return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv); + } } } diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 16df08f9a1a7..265358a8a550 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -219,6 +219,13 @@ bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info) case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP: return true; + case LOCAL_GL_TEXTURE_3D: { + const bool isValid = IsWebGL2(); + if (!isValid) { + ErrorInvalidEnumInfo(info, target); + } + return isValid; + } default: ErrorInvalidEnumInfo(info, target); return false; diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 45914f8e9794..e14bbc4d7c7a 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -33,6 +33,8 @@ WebGLTexture::WebGLTexture(WebGLContext *context) , mMaxLevelWithCustomImages(0) , mHaveGeneratedMipmap(false) , mImmutable(false) + , mBaseMipmapLevel(0) + , mMaxMipmapLevel(1000) , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture) { mContext->MakeContextCurrent(); @@ -62,22 +64,8 @@ WebGLTexture::MemoryUsage() const { return 0; size_t result = 0; for(size_t face = 0; face < mFacesCount; face++) { - if (mHaveGeneratedMipmap) { - size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage(); - // Each mipmap level is 1/(2^d) the size of the previous level, - // where d is 2 or 3 depending on whether the images are 2D or 3D - // 1 + x + x^2 + ... = 1/(1-x) - // for x = 1/(2^2), we get 1/(1-1/4) = 4/3 - // for x = 1/(2^3), we get 1/(1-1/8) = 8/7 - size_t allLevelsMemoryUsage = - mTarget == LOCAL_GL_TEXTURE_3D - ? level0MemoryUsage * 8 / 7 - : level0MemoryUsage * 4 / 3; - result += allLevelsMemoryUsage; - } else { - for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++) - result += ImageInfoAtFace(face, level).MemoryUsage(); - } + for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++) + result += ImageInfoAtFace(face, level).MemoryUsage(); } return result; } @@ -88,15 +76,24 @@ WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImage if (mHaveGeneratedMipmap) return true; + if (GetMaxMipmapLevel() < GetBaseMipmapLevel()) + return false; + // We want a copy here so we can modify it temporarily. - ImageInfo expected = ImageInfoAt(texImageTarget, 0); + ImageInfo expected = ImageInfoAt(texImageTarget, GetBaseMipmapLevel()); // checks if custom level>0 images are all defined up to the highest level defined // and have the expected dimensions - for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { + for (size_t level = GetBaseMipmapLevel(); level <= GetMaxMipmapLevel(); ++level) { const ImageInfo& actual = ImageInfoAt(texImageTarget, level); if (actual != expected) return false; + + // Check the raw value here, not the clamped one, since we don't want + // to terminate early if there aren't enough levels defined. + if (level == mMaxMipmapLevel) + return true; + expected.mWidth = std::max(1, expected.mWidth / 2); expected.mHeight = std::max(1, expected.mHeight / 2); expected.mDepth = std::max(1, expected.mDepth / 2); @@ -185,7 +182,7 @@ WebGLTexture::SetCustomMipmap() { // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info, // and are power-of-two. - ImageInfo imageInfo = ImageInfoAtFace(0, 0); + ImageInfo imageInfo = ImageInfoAtFace(0, GetBaseMipmapLevel()); NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?"); @@ -198,7 +195,7 @@ WebGLTexture::SetCustomMipmap() { EnsureMaxLevelWithCustomImagesAtLeast(maxLevel); - for (size_t level = 1; level <= maxLevel; ++level) { + for (size_t level = GetBaseMipmapLevel() + 1; level <= GetMaxMipmapLevel(); ++level) { imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1); imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1); imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1); @@ -223,7 +220,7 @@ WebGLTexture::IsMipmapComplete() const { MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D || mTarget == LOCAL_GL_TEXTURE_3D); - if (!ImageInfoAtFace(0, 0).IsPositive()) + if (!ImageInfoAtFace(0, GetBaseMipmapLevel()).IsPositive()) return false; if (mHaveGeneratedMipmap) return true; @@ -262,7 +259,7 @@ WebGLTexture::ResolvedFakeBlackStatus() { // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec. for (size_t face = 0; face < mFacesCount; ++face) { - if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) { + if (ImageInfoAtFace(face, GetBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) { // In case of undefined texture image, we don't print any message because this is a very common // and often legitimate case (asynchronous texture loading). mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index b7cca286be05..134f25094677 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -213,6 +213,9 @@ protected: bool mHaveGeneratedMipmap; // set by generateMipmap bool mImmutable; // set by texStorage* + size_t mBaseMipmapLevel; // set by texParameter (defaults to 0) + size_t mMaxMipmapLevel; // set by texParameter (defaults to 1000) + WebGLTextureFakeBlackStatus mFakeBlackStatus; void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) { @@ -283,6 +286,17 @@ public: bool IsImmutable() const { return mImmutable; } void SetImmutable() { mImmutable = true; } + void SetBaseMipmapLevel(unsigned level) { mBaseMipmapLevel = level; } + void SetMaxMipmapLevel(unsigned level) { mMaxMipmapLevel = level; } + size_t GetBaseMipmapLevel() const { + // Clamp to [0, levels - 1] + return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages); + } + size_t GetMaxMipmapLevel() const { + // Clamp to [base, levels - 1] + return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages); + } + size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; } // Returns the current fake-black-status, except if it was Unknown, diff --git a/dom/crypto/CryptoKey.cpp b/dom/crypto/CryptoKey.cpp index 002fdf9521df..13ab8f932ebe 100644 --- a/dom/crypto/CryptoKey.cpp +++ b/dom/crypto/CryptoKey.cpp @@ -395,7 +395,12 @@ CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData, } } - return SECKEY_ExtractPublicKey(spki.get()); + ScopedSECKEYPublicKey tmp(SECKEY_ExtractPublicKey(spki.get())); + if (!tmp.get() || !PublicKeyValid(tmp.get())) { + return nullptr; + } + + return SECKEY_CopyPublicKey(tmp); } nsresult @@ -843,6 +848,10 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk, } key->u.ec.publicValue = *point; + if (!PublicKeyValid(key)) { + return nullptr; + } + return SECKEY_CopyPublicKey(key); } @@ -881,6 +890,26 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKey* aPubKey, } } +bool +CryptoKey::PublicKeyValid(SECKEYPublicKey* aPubKey) +{ + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot.get()) { + return false; + } + + // This assumes that NSS checks the validity of a public key when + // it is imported into a PKCS#11 module, and returns CK_INVALID_HANDLE + // if it is invalid. + CK_OBJECT_HANDLE id = PK11_ImportPublicKey(slot, aPubKey, PR_FALSE); + if (id == CK_INVALID_HANDLE) { + return false; + } + + SECStatus rv = PK11_DestroyObject(slot, id); + return (rv == SECSuccess); +} + bool CryptoKey::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const { diff --git a/dom/crypto/CryptoKey.h b/dom/crypto/CryptoKey.h index d1f6f71d2f18..966151b5388f 100644 --- a/dom/crypto/CryptoKey.h +++ b/dom/crypto/CryptoKey.h @@ -171,6 +171,8 @@ public: JsonWebKey& aRetVal, const nsNSSShutDownPreventionLock& /*proofOfLock*/); + static bool PublicKeyValid(SECKEYPublicKey* aPubKey); + // Structured clone methods use these to clone keys bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; bool ReadStructuredClone(JSStructuredCloneReader* aReader); diff --git a/dom/crypto/WebCryptoCommon.h b/dom/crypto/WebCryptoCommon.h index 891c4c981105..9b548d534f00 100644 --- a/dom/crypto/WebCryptoCommon.h +++ b/dom/crypto/WebCryptoCommon.h @@ -27,6 +27,7 @@ #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5" #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP" #define WEBCRYPTO_ALG_ECDH "ECDH" +#define WEBCRYPTO_ALG_ECDSA "ECDSA" // WebCrypto key formats #define WEBCRYPTO_KEY_FORMAT_RAW "raw" @@ -84,6 +85,9 @@ #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256" #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384" #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512" +#define JWK_ALG_ECDSA_P_256 "ES256" +#define JWK_ALG_ECDSA_P_384 "ES384" +#define JWK_ALG_ECDSA_P_521 "ES521" // JWK usages #define JWK_USE_ENC "enc" @@ -225,6 +229,8 @@ NormalizeToken(const nsString& aName, nsString& aDest) aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP); } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) { aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA); // Named curve values } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) { aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256); diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index e627b11a8b44..a05104997fff 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -66,7 +66,8 @@ enum TelemetryAlgorithm { // Later additions TA_AES_KW = 19, TA_ECDH = 20, - TA_PBKDF2 = 21 + TA_PBKDF2 = 21, + TA_ECDSA = 22, }; // Convenience functions for extracting / converting information @@ -782,10 +783,9 @@ public: mMgfMechanism = CKG_MGF1_SHA384; break; case CKM_SHA512: mMgfMechanism = CKG_MGF1_SHA512; break; - default: { + default: mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; - } } } @@ -955,49 +955,97 @@ private: } }; -class RsassaPkcs1Task : public WebCryptoTask +class AsymmetricSignVerifyTask : public WebCryptoTask { public: - RsassaPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm, - CryptoKey& aKey, - const CryptoOperationData& aSignature, - const CryptoOperationData& aData, - bool aSign) + AsymmetricSignVerifyTask(JSContext* aCx, + const ObjectOrString& aAlgorithm, + CryptoKey& aKey, + const CryptoOperationData& aSignature, + const CryptoOperationData& aData, + bool aSign) : mOidTag(SEC_OID_UNKNOWN) , mPrivKey(aKey.GetPrivateKey()) , mPubKey(aKey.GetPublicKey()) , mSign(aSign) , mVerified(false) + , mEcdsa(false) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); - - CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); - ATTEMPT_BUFFER_INIT(mData, aData); if (!aSign) { ATTEMPT_BUFFER_INIT(mSignature, aSignature); } - // Look up the SECOidTag based on the KeyAlgorithm - // static_cast is safe because we only get here if the algorithm name - // is RSASSA-PKCS1-v1_5, and that only happens if we've constructed - // an RsaHashedKeyAlgorithm - CK_MECHANISM_TYPE mech; - mech = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash); + nsString algName; + mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); + if (NS_FAILED(mEarlyRv)) { + return; + } - switch (mech) { - case CKM_SHA_1: - mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; - case CKM_SHA256: - mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; - case CKM_SHA384: - mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; - case CKM_SHA512: - mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; - default: { - mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + // Look up the SECOidTag + if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + mEcdsa = false; + Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); + CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); + + // For RSA, the hash name comes from the key algorithm + nsString hashName = aKey.Algorithm().mRsa.mHash.mName; + switch (MapAlgorithmNameToMechanism(hashName)) { + case CKM_SHA_1: + mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; + case CKM_SHA256: + mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; + case CKM_SHA384: + mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; + case CKM_SHA512: + mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; + default: + mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return; + } + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + mEcdsa = true; + Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA); + CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA); + + // For ECDSA, the hash name comes from the algorithm parameter + RootedDictionary params(aCx); + mEarlyRv = Coerce(aCx, params, aAlgorithm); + if (NS_FAILED(mEarlyRv)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } + + nsString hashName; + mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); + if (NS_FAILED(mEarlyRv)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } + + CK_MECHANISM_TYPE hashMechanism = MapAlgorithmNameToMechanism(hashName); + if (hashMechanism == UNKNOWN_CK_MECHANISM) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } + + switch (hashMechanism) { + case CKM_SHA_1: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; + case CKM_SHA256: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; + case CKM_SHA384: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; + case CKM_SHA512: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; + default: + mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return; + } + } else { + // This shouldn't happen; CreateSignVerifyTask shouldn't create + // one of these unless it's for the above algorithms. + MOZ_ASSERT(false); } // Check that we have the appropriate key @@ -1015,6 +1063,7 @@ private: CryptoBuffer mData; bool mSign; bool mVerified; + bool mEcdsa; virtual nsresult DoCrypto() MOZ_OVERRIDE { @@ -1022,44 +1071,53 @@ private: if (mSign) { ScopedSECItem signature((SECItem*) PORT_Alloc(sizeof(SECItem))); ScopedSGNContext ctx(SGN_NewContext(mOidTag, mPrivKey)); - if (!ctx) { + if (!signature.get() || !ctx.get()) { return NS_ERROR_DOM_OPERATION_ERR; } - rv = MapSECStatus(SGN_Begin(ctx)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + rv = MapSECStatus(SEC_SignData(signature, mData.Elements(), + mData.Length(), mPrivKey, mOidTag)); - rv = MapSECStatus(SGN_Update(ctx, mData.Elements(), mData.Length())); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - - rv = MapSECStatus(SGN_End(ctx, signature)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - - ATTEMPT_BUFFER_ASSIGN(mSignature, signature); - } else { - ScopedSECItem signature(mSignature.ToSECItem()); - if (!signature) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } - - ScopedVFYContext ctx(VFY_CreateContext(mPubKey, signature, - mOidTag, nullptr)); - if (!ctx) { - int err = PORT_GetError(); - if (err == SEC_ERROR_BAD_SIGNATURE) { - mVerified = false; - return NS_OK; + if (mEcdsa) { + // DER-decode the signature + int signatureLength = PK11_SignatureLen(mPrivKey); + ScopedSECItem rawSignature(DSAU_DecodeDerSigToLen(signature.get(), + signatureLength)); + if (!rawSignature.get()) { + return NS_ERROR_DOM_OPERATION_ERR; } - return NS_ERROR_DOM_OPERATION_ERR; + + ATTEMPT_BUFFER_ASSIGN(mSignature, rawSignature); + } else { + ATTEMPT_BUFFER_ASSIGN(mSignature, signature); } - rv = MapSECStatus(VFY_Begin(ctx)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + } else { + ScopedSECItem signature; - rv = MapSECStatus(VFY_Update(ctx, mData.Elements(), mData.Length())); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + if (mEcdsa) { + // DER-encode the signature + ScopedSECItem rawSignature(mSignature.ToSECItem()); + if (!rawSignature.get()) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } - rv = MapSECStatus(VFY_End(ctx)); + signature = (SECItem*) PORT_Alloc(sizeof(SECItem)); + if (!signature.get()) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + rv = MapSECStatus(DSAU_EncodeDerSigWithLen(signature, rawSignature, + rawSignature->len)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + } else { + signature = mSignature.ToSECItem(); + if (!signature) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + } + + rv = MapSECStatus(VFY_VerifyData(mData.Elements(), mData.Length(), + mPubKey, signature, mOidTag, nullptr)); mVerified = NS_SUCCEEDED(rv); } @@ -1661,12 +1719,23 @@ private: virtual nsresult AfterCrypto() MOZ_OVERRIDE { - // Check permissions for the requested operation - if (mKey->GetKeyType() == CryptoKey::PRIVATE && - mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) { - return NS_ERROR_DOM_DATA_ERR; + uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0; + if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + privateAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; + publicAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; + } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + privateAllowedUsages = CryptoKey::SIGN; + publicAllowedUsages = CryptoKey::VERIFY; } + // Check permissions for the requested operation + if ((mKey->GetKeyType() == CryptoKey::PRIVATE && + mKey->HasUsageOtherThan(privateAllowedUsages)) || + (mKey->GetKeyType() == CryptoKey::PUBLIC && + mKey->HasUsageOtherThan(publicAllowedUsages))) { + return NS_ERROR_DOM_DATA_ERR; + } + mKey->Algorithm().MakeEc(mAlgName, mNamedCurve); if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { @@ -1991,7 +2060,8 @@ public: mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; return; } - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); if (NS_FAILED(mEarlyRv)) { @@ -2014,7 +2084,8 @@ public: } // Set key usages. - if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { privateAllowedUsages = CryptoKey::SIGN; publicAllowedUsages = CryptoKey::VERIFY; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { @@ -2048,7 +2119,7 @@ public: } // If no usages ended up being allowed, DataError - if (!mKeyPair.mPrivateKey.get()->HasAnyUsage() || + if (!mKeyPair.mPublicKey.get()->HasAnyUsage() && !mKeyPair.mPrivateKey.get()->HasAnyUsage()) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; return; @@ -2176,10 +2247,9 @@ public: case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break; case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break; case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break; - default: { + default: mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; - } } ATTEMPT_BUFFER_INIT(mSalt, params.mSalt) @@ -2544,8 +2614,10 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { - return new RsassaPkcs1Task(aCx, aAlgorithm, aKey, aSignature, aData, aSign); + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature, + aData, aSign); } return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); @@ -2618,7 +2690,8 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx, algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); } else { @@ -2694,7 +2767,8 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx, return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages); } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) || - algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { + algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) || + algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA)) { return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages); } else { return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); diff --git a/dom/crypto/test/test-vectors.js b/dom/crypto/test/test-vectors.js index e4dee263c54f..8d8c607d7137 100644 --- a/dom/crypto/test/test-vectors.js +++ b/dom/crypto/test/test-vectors.js @@ -608,4 +608,54 @@ tv = { x: "XOe4bjsyZgQD5jcS7wmY3q4QJ_rsPBvp92-TTf61jpg", } }, + + // NIST ECDSA test vectors + // http://csrc.nist.gov/groups/STM/cavp/index.html + ecdsa_verify: { + pub_jwk: { + "kty": "EC", + "crv": "P-521", + + // 0061387fd6b95914e885f912edfbb5fb274655027f216c4091ca83e19336740fd8 + // 1aedfe047f51b42bdf68161121013e0d55b117a14e4303f926c8debb77a7fdaad1 + "x": "AGE4f9a5WRTohfkS7fu1-ydGVQJ_IWxAkcqD4ZM2dA_Y" + + "Gu3-BH9RtCvfaBYRIQE-DVWxF6FOQwP5Jsjeu3en_arR", + // 00e7d0c75c38626e895ca21526b9f9fdf84dcecb93f2b233390550d2b1463b7ee3 + // f58df7346435ff0434199583c97c665a97f12f706f2357da4b40288def888e59e6 + "y": "AOfQx1w4Ym6JXKIVJrn5_fhNzsuT8rIzOQVQ0rFGO37j" + + "9Y33NGQ1_wQ0GZWDyXxmWpfxL3BvI1faS0Aoje-Ijlnm", + }, + + "data": util.hex2abv( + "9ecd500c60e701404922e58ab20cc002651fdee7cbc9336adda33e4c1088fab1" + + "964ecb7904dc6856865d6c8e15041ccf2d5ac302e99d346ff2f686531d255216" + + "78d4fd3f76bbf2c893d246cb4d7693792fe18172108146853103a51f824acc62" + + "1cb7311d2463c3361ea707254f2b052bc22cb8012873dcbb95bf1a5cc53ab89f" + ), + "sig": util.hex2abv( + "004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" + + "99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" + + "0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" + + "4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac566e8ee3b43" + ), + + // Same as "sig", but with the last few octets set to 0 + "sig_tampered": util.hex2abv( + "004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" + + "99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" + + "0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" + + "4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac56600000000" + ) + }, + + ecdsa_bad: { + pub_jwk: { + "kty": "EC", + "crv": "P-521", + "x": "BhOH_WuVkU6IX5Eu37tfsnRlUCfyFsQJHKg-GTNnQP2B" + + "rt_gR_UbQr32gWESEBPg1VsRehTkMD-SbI3rt3p_2q0B", + "y": "AUNouOdGgHsraPNhXNeNdhpGTd15GPyN9R0iWWL98ePc" + + "JD4mUQD/DsEzNZ4zLkTdSa/Y5fOP6GEzVzQy0zwC+goD" + } + } } diff --git a/dom/crypto/test/test_WebCrypto.html b/dom/crypto/test/test_WebCrypto.html index 9768a3a73bb9..d0b74527c3a5 100644 --- a/dom/crypto/test/test_WebCrypto.html +++ b/dom/crypto/test/test_WebCrypto.html @@ -1308,6 +1308,32 @@ TestArray.addTest( doCheckRSASSA().then(error(that), complete(that)); } ); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Test that we reject generating keys without any usage", + function() { + var that = this; + var alg = { + name: "RSA-OAEP", + hash: "SHA-256", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]) + }; + + function generateKey(usages) { + return crypto.subtle.generateKey(alg, false, usages); + } + + generateKey(["encrypt", "decrypt"]).then(function () { + return generateKey(["encrypt"]); + }).then(function () { + return generateKey(["decrypt"]); + }).then(function () { + return generateKey(["sign"]) + }, error(that)).then(error(that), complete(that)); + } +); /*]]>*/ diff --git a/dom/crypto/test/test_WebCrypto_ECDSA.html b/dom/crypto/test/test_WebCrypto_ECDSA.html new file mode 100644 index 000000000000..74d1845dd8a5 --- /dev/null +++ b/dom/crypto/test/test_WebCrypto_ECDSA.html @@ -0,0 +1,162 @@ + + + + +WebCrypto Test Suite + + + + + + + + + + + + + + + + + + + + + +
+ + +
RUN ALL
+ +
+ Summary: + 0 passed, + 0 failed, + 0 pending. +
+
+ + + + + + + +
TestResultTime
+ +
+ + +
+ + + diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index cebeeffad75e..d2be9cf83985 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -76,6 +76,7 @@ Event::ConstructorInit(EventTarget* aOwner, } mPrivateDataDuplicated = false; + mWantsPopupControlCheck = false; if (aEvent) { mEvent = aEvent; @@ -655,12 +656,20 @@ PopupAllowedForEvent(const char *eventName) // static PopupControlState -Event::GetEventPopupControlState(WidgetEvent* aEvent) +Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) { // generally if an event handler is running, new windows are disallowed. // check for exceptions: PopupControlState abuse = openAbused; + if (aDOMEvent && aDOMEvent->InternalDOMEvent()->GetWantsPopupControlCheck()) { + nsAutoString type; + aDOMEvent->GetType(type); + if (PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())) { + return openAllowed; + } + } + switch(aEvent->mClass) { case eBasicEventClass: // For these following events only allow popups if they're diff --git a/dom/events/Event.h b/dom/events/Event.h index de2c1db7bc85..1ffd085fe84c 100644 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -30,6 +30,7 @@ namespace dom { class EventTarget; class ErrorEvent; class ProgressEvent; +class WantsPopupControlCheck; // Dummy class so we can cast through it to get from nsISupports to // Event subclasses with only two non-ambiguous static casts. @@ -113,7 +114,8 @@ public: // Returns true if the event should be trusted. bool Init(EventTarget* aGlobal); - static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent); + static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent, + nsIDOMEvent* aDOMEvent = nullptr); static void PopupAllowedEventsChanged(); @@ -235,6 +237,17 @@ protected: void SetEventType(const nsAString& aEventTypeArg); already_AddRefed GetTargetFromFrame(); + friend class WantsPopupControlCheck; + void SetWantsPopupControlCheck(bool aCheck) + { + mWantsPopupControlCheck = aCheck; + } + + bool GetWantsPopupControlCheck() + { + return IsTrusted() && mWantsPopupControlCheck; + } + /** * IsChrome() returns true if aCx is chrome context or the event is created * in chrome's thread. Otherwise, false. @@ -248,6 +261,28 @@ protected: bool mEventIsInternal; bool mPrivateDataDuplicated; bool mIsMainThreadEvent; + // True when popup control check should rely on event.type, not + // WidgetEvent.message. + bool mWantsPopupControlCheck; +}; + +class MOZ_STACK_CLASS WantsPopupControlCheck +{ +public: + WantsPopupControlCheck(nsIDOMEvent* aEvent) : mEvent(aEvent->InternalDOMEvent()) + { + mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck(); + mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted()); + } + + ~WantsPopupControlCheck() + { + mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck); + } + +private: + Event* mEvent; + bool mOriginalWantsPopupControlCheck; }; } // namespace dom diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 288707af9c2c..82a55045d631 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -976,7 +976,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext, nsAutoTObserverArray::EndLimitedIterator iter(mListeners); Maybe popupStatePusher; if (mIsMainThreadELM) { - popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent)); + popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent)); } bool hasListener = false; diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 373b60fe054a..a966c873ff63 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -944,16 +944,21 @@ EventStateManager::ExecuteAccessKey(nsTArray& aAccessCharCodes, return false; } -bool -EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix) +// static +void +EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix) { aPrefix.Truncate(); nsAutoString separator, modifierText; nsContentUtils::GetModifierSeparatorText(separator); - nsCOMPtr container = mPresContext->GetContainerWeak(); + nsCOMPtr container = aElement->OwnerDoc()->GetDocShell(); int32_t modifierMask = GetAccessModifierMaskFor(container); + if (modifierMask == -1) { + return; + } + if (modifierMask & NS_MODIFIER_CONTROL) { nsContentUtils::GetControlText(modifierText); aPrefix.Append(modifierText + separator); @@ -974,7 +979,6 @@ EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix) nsContentUtils::GetShiftText(modifierText); aPrefix.Append(modifierText + separator); } - return !aPrefix.IsEmpty(); } void diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index 20073f590c6c..68c0809853b3 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -40,6 +40,7 @@ class WheelTransaction; namespace dom { class DataTransfer; +class Element; class TabParent; } // namespace dom @@ -169,7 +170,7 @@ public: */ uint32_t GetRegisteredAccessKey(nsIContent* aContent); - bool GetAccessKeyLabelPrefix(nsAString& aPrefix); + static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix); nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer, bool aHaveHotspot, float aHotspotX, float aHotspotY, diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini index 081c141e47e1..ac452c415ab2 100644 --- a/dom/events/test/mochitest.ini +++ b/dom/events/test/mochitest.ini @@ -22,6 +22,7 @@ skip-if = buildapp == 'b2g' skip-if = buildapp == 'b2g' [test_bug288392.html] [test_bug299673-1.html] +[test_bug1037990.html] [test_bug299673-2.html] [test_bug322588.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage diff --git a/dom/events/test/test_bug1037990.html b/dom/events/test/test_bug1037990.html new file mode 100644 index 000000000000..025c8744b288 --- /dev/null +++ b/dom/events/test/test_bug1037990.html @@ -0,0 +1,61 @@ + + + + + + Test for Bug 1037990 + + + + +Mozilla Bug 1037990 +

+ +
+
+ + + diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index fbc87aa7515b..bd76394859c8 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -6,95 +6,360 @@ #include "Fetch.h" #include "nsIStringStream.h" +#include "nsIUnicodeDecoder.h" #include "nsIUnicodeEncoder.h" +#include "nsDOMString.h" +#include "nsNetUtil.h" +#include "nsStreamUtils.h" #include "nsStringStream.h" +#include "mozilla/ErrorResult.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/Headers.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/Request.h" +#include "mozilla/dom/Response.h" #include "mozilla/dom/URLSearchParams.h" namespace mozilla { namespace dom { +namespace { nsresult -ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit, +ExtractFromArrayBuffer(const ArrayBuffer& aBuffer, + nsIInputStream** aStream) +{ + aBuffer.ComputeLengthAndData(); + //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. + return NS_NewByteInputStream(aStream, + reinterpret_cast(aBuffer.Data()), + aBuffer.Length(), NS_ASSIGNMENT_COPY); +} + +nsresult +ExtractFromArrayBufferView(const ArrayBufferView& aBuffer, + nsIInputStream** aStream) +{ + aBuffer.ComputeLengthAndData(); + //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. + return NS_NewByteInputStream(aStream, + reinterpret_cast(aBuffer.Data()), + aBuffer.Length(), NS_ASSIGNMENT_COPY); +} + +nsresult +ExtractFromBlob(const File& aFile, nsIInputStream** aStream, + nsCString& aContentType) +{ + nsRefPtr impl = aFile.Impl(); + nsresult rv = impl->GetInternalStream(aStream); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsString type; + impl->GetType(type); + aContentType = NS_ConvertUTF16toUTF8(type); + return NS_OK; +} + +nsresult +ExtractFromScalarValueString(const nsString& aStr, + nsIInputStream** aStream, + nsCString& aContentType) +{ + nsCOMPtr encoder = EncodingUtils::EncoderForEncoding("UTF-8"); + if (!encoder) { + return NS_ERROR_OUT_OF_MEMORY; + } + + int32_t destBufferLen; + nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCString encoded; + if (!encoded.SetCapacity(destBufferLen, fallible_t())) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char* destBuffer = encoded.BeginWriting(); + int32_t srcLen = (int32_t) aStr.Length(); + int32_t outLen = destBufferLen; + rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(outLen <= destBufferLen); + encoded.SetLength(outLen); + + aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8"); + + return NS_NewCStringInputStream(aStream, encoded); +} + +nsresult +ExtractFromURLSearchParams(const URLSearchParams& aParams, + nsIInputStream** aStream, + nsCString& aContentType) +{ + nsAutoString serialized; + aParams.Stringify(serialized); + aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8"); + return NS_NewStringInputStream(aStream, serialized); +} +} + +nsresult +ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit, nsIInputStream** aStream, nsCString& aContentType) { MOZ_ASSERT(aStream); - nsresult rv; - nsCOMPtr byteStream; if (aBodyInit.IsArrayBuffer()) { const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer(); - buf.ComputeLengthAndData(); - //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. - rv = NS_NewByteInputStream(getter_AddRefs(byteStream), - reinterpret_cast(buf.Data()), - buf.Length(), NS_ASSIGNMENT_COPY); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + return ExtractFromArrayBuffer(buf, aStream); } else if (aBodyInit.IsArrayBufferView()) { const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView(); - buf.ComputeLengthAndData(); - //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. - rv = NS_NewByteInputStream(getter_AddRefs(byteStream), - reinterpret_cast(buf.Data()), - buf.Length(), NS_ASSIGNMENT_COPY); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + return ExtractFromArrayBufferView(buf, aStream); + } else if (aBodyInit.IsBlob()) { + const File& blob = aBodyInit.GetAsBlob(); + return ExtractFromBlob(blob, aStream, aContentType); } else if (aBodyInit.IsScalarValueString()) { - nsString str = aBodyInit.GetAsScalarValueString(); - - nsCOMPtr encoder = EncodingUtils::EncoderForEncoding("UTF-8"); - if (!encoder) { - return NS_ERROR_OUT_OF_MEMORY; - } - - int32_t destBufferLen; - rv = encoder->GetMaxLength(str.get(), str.Length(), &destBufferLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsCString encoded; - if (!encoded.SetCapacity(destBufferLen, fallible_t())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - char* destBuffer = encoded.BeginWriting(); - int32_t srcLen = (int32_t) str.Length(); - int32_t outLen = destBufferLen; - rv = encoder->Convert(str.get(), &srcLen, destBuffer, &outLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(outLen <= destBufferLen); - encoded.SetLength(outLen); - rv = NS_NewCStringInputStream(getter_AddRefs(byteStream), encoded); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8"); + nsAutoString str; + str.Assign(aBodyInit.GetAsScalarValueString()); + return ExtractFromScalarValueString(str, aStream, aContentType); } else if (aBodyInit.IsURLSearchParams()) { URLSearchParams& params = aBodyInit.GetAsURLSearchParams(); - nsString serialized; - params.Stringify(serialized); - rv = NS_NewStringInputStream(getter_AddRefs(byteStream), serialized); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8"); + return ExtractFromURLSearchParams(params, aStream, aContentType); } - MOZ_ASSERT(byteStream); - byteStream.forget(aStream); - return NS_OK; + NS_NOTREACHED("Should never reach here"); + return NS_ERROR_FAILURE; } +nsresult +ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit, + nsIInputStream** aStream, + nsCString& aContentType) +{ + MOZ_ASSERT(aStream); + + if (aBodyInit.IsArrayBuffer()) { + const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer(); + return ExtractFromArrayBuffer(buf, aStream); + } else if (aBodyInit.IsArrayBufferView()) { + const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView(); + return ExtractFromArrayBufferView(buf, aStream); + } else if (aBodyInit.IsBlob()) { + const File& blob = aBodyInit.GetAsBlob(); + return ExtractFromBlob(blob, aStream, aContentType); + } else if (aBodyInit.IsScalarValueString()) { + nsAutoString str; + str.Assign(aBodyInit.GetAsScalarValueString()); + return ExtractFromScalarValueString(str, aStream, aContentType); + } else if (aBodyInit.IsURLSearchParams()) { + URLSearchParams& params = aBodyInit.GetAsURLSearchParams(); + return ExtractFromURLSearchParams(params, aStream, aContentType); + } + + NS_NOTREACHED("Should never reach here"); + return NS_ERROR_FAILURE; +} + +namespace { +nsresult +DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded) +{ + nsCOMPtr decoder = + EncodingUtils::DecoderForEncoding("UTF-8"); + if (!decoder) { + return NS_ERROR_FAILURE; + } + + int32_t destBufferLen; + nsresult rv = + decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char16_t* destBuffer = aDecoded.BeginWriting(); + int32_t srcLen = (int32_t) aBuffer.Length(); + int32_t outLen = destBufferLen; + rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(outLen <= destBufferLen); + aDecoded.SetLength(outLen); + return NS_OK; +} +} + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv) +{ + nsRefPtr promise = Promise::Create(DerivedClass()->GetParentObject(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + if (BodyUsed()) { + aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR); + return nullptr; + } + + SetBodyUsed(); + + // While the spec says to do this asynchronously, all the body constructors + // right now only accept bodies whose streams are backed by an in-memory + // buffer that can be read without blocking. So I think this is fine. + nsCOMPtr stream; + DerivedClass()->GetBody(getter_AddRefs(stream)); + + if (!stream) { + aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0, + NS_ASSIGNMENT_COPY); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + AutoJSAPI api; + api.Init(DerivedClass()->GetParentObject()); + JSContext* cx = api.cx(); + + // We can make this assertion because for now we only support memory backed + // structures for the body argument for a Request. + MOZ_ASSERT(NS_InputStreamIsBuffered(stream)); + nsCString buffer; + uint64_t len; + aRv = stream->Available(&len); + if (aRv.Failed()) { + return nullptr; + } + + aRv = NS_ReadInputStreamToString(stream, buffer, len); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + buffer.SetLength(len); + + switch (aType) { + case CONSUME_ARRAYBUFFER: { + JS::Rooted arrayBuffer(cx); + arrayBuffer = + ArrayBuffer::Create(cx, buffer.Length(), + reinterpret_cast(buffer.get())); + JS::Rooted val(cx); + val.setObjectOrNull(arrayBuffer); + promise->MaybeResolve(cx, val); + return promise.forget(); + } + case CONSUME_BLOB: { + // XXXnsm it is actually possible to avoid these duplicate allocations + // for the Blob case by having the Blob adopt the stream's memory + // directly, but I've not added a special case for now. + // + // FIXME(nsm): Use nsContentUtils::CreateBlobBuffer once blobs have been fixed on + // workers. + uint32_t blobLen = buffer.Length(); + void* blobData = moz_malloc(blobLen); + nsRefPtr blob; + if (blobData) { + memcpy(blobData, buffer.BeginReading(), blobLen); + blob = File::CreateMemoryFile(DerivedClass()->GetParentObject(), blobData, blobLen, + NS_ConvertUTF8toUTF16(mMimeType)); + } else { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } + + promise->MaybeResolve(blob); + return promise.forget(); + } + case CONSUME_JSON: { + nsAutoString decoded; + aRv = DecodeUTF8(buffer, decoded); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + JS::Rooted json(cx); + if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) { + JS::Rooted exn(cx); + if (JS_GetPendingException(cx, &exn)) { + JS_ClearPendingException(cx); + promise->MaybeReject(cx, exn); + } + } + promise->MaybeResolve(cx, json); + return promise.forget(); + } + case CONSUME_TEXT: { + nsAutoString decoded; + aRv = DecodeUTF8(buffer, decoded); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + promise->MaybeResolve(decoded); + return promise.forget(); + } + } + + NS_NOTREACHED("Unexpected consume body type"); + // Silence warnings. + return nullptr; +} + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv); + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv); + +template +void +FetchBody::SetMimeType(ErrorResult& aRv) +{ + // Extract mime type. + nsTArray contentTypeValues; + MOZ_ASSERT(DerivedClass()->GetInternalHeaders()); + DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + // HTTP ABNF states Content-Type may have only one value. + // This is from the "parse a header value" of the fetch spec. + if (contentTypeValues.Length() == 1) { + mMimeType = contentTypeValues[0]; + ToLowerCase(mMimeType); + } +} + +template +void +FetchBody::SetMimeType(ErrorResult& aRv); + +template +void +FetchBody::SetMimeType(ErrorResult& aRv); } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Fetch.h b/dom/fetch/Fetch.h index 86ba71c2b3b6..5c0eac3e30ac 100644 --- a/dom/fetch/Fetch.h +++ b/dom/fetch/Fetch.h @@ -13,16 +13,93 @@ class nsIInputStream; namespace mozilla { namespace dom { +class Promise; + /* * Creates an nsIInputStream based on the fetch specifications 'extract a byte * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract. * Stores content type in out param aContentType. */ nsresult -ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit, +ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit, nsIInputStream** aStream, nsCString& aContentType); +/* + * Non-owning version. + */ +nsresult +ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit, + nsIInputStream** aStream, + nsCString& aContentType); + +template +class FetchBody { +public: + bool + BodyUsed() { return mBodyUsed; } + + already_AddRefed + ArrayBuffer(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_ARRAYBUFFER, aRv); + } + + already_AddRefed + Blob(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_BLOB, aRv); + } + + already_AddRefed + Json(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_JSON, aRv); + } + + already_AddRefed + Text(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_TEXT, aRv); + } + +protected: + FetchBody() + : mBodyUsed(false) + { + } + + void + SetBodyUsed() + { + mBodyUsed = true; + } + + void + SetMimeType(ErrorResult& aRv); + +private: + enum ConsumeType + { + CONSUME_ARRAYBUFFER, + CONSUME_BLOB, + // FormData not supported right now, + CONSUME_JSON, + CONSUME_TEXT, + }; + + Derived* + DerivedClass() const + { + return static_cast(const_cast(this)); + } + + already_AddRefed + ConsumeBody(ConsumeType aType, ErrorResult& aRv); + + bool mBodyUsed; + nsCString mMimeType; +}; } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Headers.cpp b/dom/fetch/Headers.cpp index ee7ad0c09ea7..a56f62934a68 100644 --- a/dom/fetch/Headers.cpp +++ b/dom/fetch/Headers.cpp @@ -10,13 +10,6 @@ #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/Preferences.h" -#include "nsCharSeparatedTokenizer.h" -#include "nsContentUtils.h" -#include "nsDOMString.h" -#include "nsNetUtil.h" -#include "nsPIDOMWindow.h" -#include "nsReadableUtils.h" - namespace mozilla { namespace dom { @@ -61,18 +54,19 @@ Headers::Constructor(const GlobalObject& aGlobal, const Optional& aInit, ErrorResult& aRv) { - nsRefPtr headers = new Headers(aGlobal.GetAsSupports()); + nsRefPtr ih = new InternalHeaders(); + nsRefPtr headers = new Headers(aGlobal.GetAsSupports(), ih); if (!aInit.WasPassed()) { return headers.forget(); } if (aInit.Value().IsHeaders()) { - headers->Fill(aInit.Value().GetAsHeaders(), aRv); + ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv); } else if (aInit.Value().IsByteStringSequenceSequence()) { - headers->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv); + ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv); } else if (aInit.Value().IsByteStringMozMap()) { - headers->Fill(aInit.Value().GetAsByteStringMozMap(), aRv); + ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv); } if (aRv.Failed()) { @@ -88,14 +82,15 @@ Headers::Constructor(const GlobalObject& aGlobal, const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, ErrorResult& aRv) { - nsRefPtr headers = new Headers(aGlobal.GetAsSupports()); + nsRefPtr ih = new InternalHeaders(); + nsRefPtr headers = new Headers(aGlobal.GetAsSupports(), ih); if (aInit.IsHeaders()) { - headers->Fill(aInit.GetAsHeaders(), aRv); + ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv); } else if (aInit.IsByteStringSequenceSequence()) { - headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv); + ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv); } else if (aInit.IsByteStringMozMap()) { - headers->Fill(aInit.GetAsByteStringMozMap(), aRv); + ih->Fill(aInit.GetAsByteStringMozMap(), aRv); } if (NS_WARN_IF(aRv.Failed())) { @@ -105,153 +100,6 @@ Headers::Constructor(const GlobalObject& aGlobal, return headers.forget(); } -Headers::Headers(const Headers& aOther) - : mOwner(aOther.mOwner) - , mGuard(aOther.mGuard) -{ - ErrorResult result; - Fill(aOther, result); - MOZ_ASSERT(!result.Failed()); -} - -void -Headers::Append(const nsACString& aName, const nsACString& aValue, - ErrorResult& aRv) -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) { - return; - } - - mList.AppendElement(Entry(lowerName, aValue)); -} - -void -Headers::Delete(const nsACString& aName, ErrorResult& aRv) -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidMutableHeader(lowerName, nullptr, aRv)) { - return; - } - - // remove in reverse order to minimize copying - for (int32_t i = mList.Length() - 1; i >= 0; --i) { - if (lowerName == mList[i].mName) { - mList.RemoveElementAt(i); - } - } -} - -void -Headers::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidName(lowerName, aRv)) { - return; - } - - for (uint32_t i = 0; i < mList.Length(); ++i) { - if (lowerName == mList[i].mName) { - aValue = mList[i].mValue; - return; - } - } - - // No value found, so return null to content - aValue.SetIsVoid(true); -} - -void -Headers::GetAll(const nsACString& aName, nsTArray& aResults, - ErrorResult& aRv) const -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidName(lowerName, aRv)) { - return; - } - - aResults.SetLength(0); - for (uint32_t i = 0; i < mList.Length(); ++i) { - if (lowerName == mList[i].mName) { - aResults.AppendElement(mList[i].mValue); - } - } -} - -bool -Headers::Has(const nsACString& aName, ErrorResult& aRv) const -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidName(lowerName, aRv)) { - return false; - } - - for (uint32_t i = 0; i < mList.Length(); ++i) { - if (lowerName == mList[i].mName) { - return true; - } - } - return false; -} - -void -Headers::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) -{ - nsAutoCString lowerName; - ToLowerCase(aName, lowerName); - - if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) { - return; - } - - int32_t firstIndex = INT32_MAX; - - // remove in reverse order to minimize copying - for (int32_t i = mList.Length() - 1; i >= 0; --i) { - if (lowerName == mList[i].mName) { - firstIndex = std::min(firstIndex, i); - mList.RemoveElementAt(i); - } - } - - if (firstIndex < INT32_MAX) { - Entry* entry = mList.InsertElementAt(firstIndex); - entry->mName = lowerName; - entry->mValue = aValue; - } else { - mList.AppendElement(Entry(lowerName, aValue)); - } -} - -void -Headers::Clear() -{ - mList.Clear(); -} - -void -Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv) -{ - // Rather than re-validate all current headers, just require code to set - // this prior to populating the Headers object. Allow setting immutable - // late, though, as that is pretty much required to have a useful, immutable - // headers object. - if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) { - aRv.Throw(NS_ERROR_FAILURE); - } - mGuard = aGuard; -} - JSObject* Headers::WrapObject(JSContext* aCx) { @@ -261,109 +109,5 @@ Headers::WrapObject(JSContext* aCx) Headers::~Headers() { } - -// static -bool -Headers::IsSimpleHeader(const nsACString& aName, const nsACString* aValue) -{ - // Note, we must allow a null content-type value here to support - // get("content-type"), but the IsInvalidValue() check will prevent null - // from being set or appended. - return aName.EqualsLiteral("accept") || - aName.EqualsLiteral("accept-language") || - aName.EqualsLiteral("content-language") || - (aName.EqualsLiteral("content-type") && - (!aValue || nsContentUtils::IsAllowedNonCorsContentType(*aValue))); -} - -//static -bool -Headers::IsInvalidName(const nsACString& aName, ErrorResult& aRv) -{ - if (!NS_IsValidHTTPToken(aName)) { - NS_ConvertUTF8toUTF16 label(aName); - aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label); - return true; - } - - return false; -} - -// static -bool -Headers::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv) -{ - if (!NS_IsReasonableHTTPHeaderValue(aValue)) { - NS_ConvertUTF8toUTF16 label(aValue); - aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label); - return true; - } - return false; -} - -bool -Headers::IsImmutable(ErrorResult& aRv) const -{ - if (mGuard == HeadersGuardEnum::Immutable) { - aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE); - return true; - } - return false; -} - -bool -Headers::IsForbiddenRequestHeader(const nsACString& aName) const -{ - return mGuard == HeadersGuardEnum::Request && - nsContentUtils::IsForbiddenRequestHeader(aName); -} - -bool -Headers::IsForbiddenRequestNoCorsHeader(const nsACString& aName, - const nsACString* aValue) const -{ - return mGuard == HeadersGuardEnum::Request_no_cors && - !IsSimpleHeader(aName, aValue); -} - -bool -Headers::IsForbiddenResponseHeader(const nsACString& aName) const -{ - return mGuard == HeadersGuardEnum::Response && - nsContentUtils::IsForbiddenResponseHeader(aName); -} - -void -Headers::Fill(const Headers& aInit, ErrorResult& aRv) -{ - const nsTArray& list = aInit.mList; - for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) { - const Entry& entry = list[i]; - Append(entry.mName, entry.mValue, aRv); - } -} - -void -Headers::Fill(const Sequence>& aInit, ErrorResult& aRv) -{ - for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) { - const Sequence& tuple = aInit[i]; - if (tuple.Length() != 2) { - aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE); - return; - } - Append(tuple[0], tuple[1], aRv); - } -} - -void -Headers::Fill(const MozMap& aInit, ErrorResult& aRv) -{ - nsTArray keys; - aInit.GetKeys(keys); - for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) { - Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv); - } -} } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Headers.h b/dom/fetch/Headers.h index aa945581ae1d..6cd6140d1c16 100644 --- a/dom/fetch/Headers.h +++ b/dom/fetch/Headers.h @@ -13,6 +13,8 @@ #include "nsClassHashtable.h" #include "nsWrapperCache.h" +#include "InternalHeaders.h" + class nsPIDOMWindow; namespace mozilla { @@ -24,38 +26,34 @@ namespace dom { template class MozMap; class HeadersOrByteStringSequenceSequenceOrByteStringMozMap; +/** + * This Headers class is only used to represent the content facing Headers + * object. It is actually backed by an InternalHeaders implementation. Gecko + * code should NEVER use this, except in the Request and Response + * implementations, where they must always be created from the backing + * InternalHeaders object. + */ class Headers MOZ_FINAL : public nsISupports , public nsWrapperCache { NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Headers) + friend class Request; + friend class Response; + private: - struct Entry - { - Entry(const nsACString& aName, const nsACString& aValue) - : mName(aName) - , mValue(aValue) - { } - - Entry() { } - - nsCString mName; - nsCString mValue; - }; - nsCOMPtr mOwner; - HeadersGuardEnum mGuard; - nsTArray mList; + nsRefPtr mInternalHeaders; public: - explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None) + explicit Headers(nsISupports* aOwner, InternalHeaders* aInternalHeaders) : mOwner(aOwner) - , mGuard(aGuard) + , mInternalHeaders(aInternalHeaders) { } - explicit Headers(const Headers& aOther); + explicit Headers(const Headers& aOther) MOZ_DELETE; static bool PrefEnabled(JSContext* cx, JSObject* obj); @@ -70,56 +68,59 @@ public: ErrorResult& aRv); void Append(const nsACString& aName, const nsACString& aValue, - ErrorResult& aRv); - void Delete(const nsACString& aName, ErrorResult& aRv); - void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const; - void GetAll(const nsACString& aName, nsTArray& aResults, - ErrorResult& aRv) const; - bool Has(const nsACString& aName, ErrorResult& aRv) const; - void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv); + ErrorResult& aRv) + { + mInternalHeaders->Append(aName, aValue, aRv); + } - void Clear(); + void Delete(const nsACString& aName, ErrorResult& aRv) + { + mInternalHeaders->Delete(aName, aRv); + } + + void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const + { + mInternalHeaders->Get(aName, aValue, aRv); + } + + void GetAll(const nsACString& aName, nsTArray& aResults, + ErrorResult& aRv) const + { + mInternalHeaders->GetAll(aName, aResults, aRv); + } + + bool Has(const nsACString& aName, ErrorResult& aRv) const + { + return mInternalHeaders->Has(aName, aRv); + } + + void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) + { + mInternalHeaders->Set(aName, aValue, aRv); + } // ChromeOnly - HeadersGuardEnum Guard() const { return mGuard; } - void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv); + HeadersGuardEnum Guard() const + { + return mInternalHeaders->Guard(); + } + + void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv) + { + mInternalHeaders->SetGuard(aGuard, aRv); + } virtual JSObject* WrapObject(JSContext* aCx); nsISupports* GetParentObject() const { return mOwner; } - void Fill(const Headers& aInit, ErrorResult& aRv); private: - // Since Headers is also an nsISupports, the above constructor can - // accidentally be invoked as new Headers(Headers*[, implied None guard]) when - // the intention is to use the copy constructor. Explicitly disallow it. - Headers(Headers* aOther) MOZ_DELETE; - virtual ~Headers(); - static bool IsSimpleHeader(const nsACString& aName, - const nsACString* aValue = nullptr); - static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv); - static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv); - bool IsImmutable(ErrorResult& aRv) const; - bool IsForbiddenRequestHeader(const nsACString& aName) const; - bool IsForbiddenRequestNoCorsHeader(const nsACString& aName, - const nsACString* aValue = nullptr) const; - bool IsForbiddenResponseHeader(const nsACString& aName) const; - - bool IsInvalidMutableHeader(const nsACString& aName, - const nsACString* aValue, - ErrorResult& aRv) const + InternalHeaders* + GetInternalHeaders() const { - return IsInvalidName(aName, aRv) || - (aValue && IsInvalidValue(*aValue, aRv)) || - IsImmutable(aRv) || - IsForbiddenRequestHeader(aName) || - IsForbiddenRequestNoCorsHeader(aName, aValue) || - IsForbiddenResponseHeader(aName); + return mInternalHeaders; } - - void Fill(const Sequence>& aInit, ErrorResult& aRv); - void Fill(const MozMap& aInit, ErrorResult& aRv); }; } // namespace dom diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp new file mode 100644 index 000000000000..5fe681037f48 --- /dev/null +++ b/dom/fetch/InternalHeaders.cpp @@ -0,0 +1,272 @@ +/* -*- 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 "mozilla/dom/InternalHeaders.h" + +#include "mozilla/ErrorResult.h" + +#include "nsCharSeparatedTokenizer.h" +#include "nsContentUtils.h" +#include "nsNetUtil.h" +#include "nsReadableUtils.h" + +namespace mozilla { +namespace dom { + +void +InternalHeaders::Append(const nsACString& aName, const nsACString& aValue, + ErrorResult& aRv) +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidMutableHeader(lowerName, aValue, aRv)) { + return; + } + + mList.AppendElement(Entry(lowerName, aValue)); +} + +void +InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv) +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidMutableHeader(lowerName, aRv)) { + return; + } + + // remove in reverse order to minimize copying + for (int32_t i = mList.Length() - 1; i >= 0; --i) { + if (lowerName == mList[i].mName) { + mList.RemoveElementAt(i); + } + } +} + +void +InternalHeaders::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidName(lowerName, aRv)) { + return; + } + + for (uint32_t i = 0; i < mList.Length(); ++i) { + if (lowerName == mList[i].mName) { + aValue = mList[i].mValue; + return; + } + } + + // No value found, so return null to content + aValue.SetIsVoid(true); +} + +void +InternalHeaders::GetAll(const nsACString& aName, nsTArray& aResults, + ErrorResult& aRv) const +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidName(lowerName, aRv)) { + return; + } + + aResults.SetLength(0); + for (uint32_t i = 0; i < mList.Length(); ++i) { + if (lowerName == mList[i].mName) { + aResults.AppendElement(mList[i].mValue); + } + } +} + +bool +InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidName(lowerName, aRv)) { + return false; + } + + for (uint32_t i = 0; i < mList.Length(); ++i) { + if (lowerName == mList[i].mName) { + return true; + } + } + return false; +} + +void +InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) +{ + nsAutoCString lowerName; + ToLowerCase(aName, lowerName); + + if (IsInvalidMutableHeader(lowerName, aValue, aRv)) { + return; + } + + int32_t firstIndex = INT32_MAX; + + // remove in reverse order to minimize copying + for (int32_t i = mList.Length() - 1; i >= 0; --i) { + if (lowerName == mList[i].mName) { + firstIndex = std::min(firstIndex, i); + mList.RemoveElementAt(i); + } + } + + if (firstIndex < INT32_MAX) { + Entry* entry = mList.InsertElementAt(firstIndex); + entry->mName = lowerName; + entry->mValue = aValue; + } else { + mList.AppendElement(Entry(lowerName, aValue)); + } +} + +void +InternalHeaders::Clear() +{ + mList.Clear(); +} + +void +InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv) +{ + // Rather than re-validate all current headers, just require code to set + // this prior to populating the InternalHeaders object. Allow setting immutable + // late, though, as that is pretty much required to have a useful, immutable + // headers object. + if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) { + aRv.Throw(NS_ERROR_FAILURE); + } + mGuard = aGuard; +} + +InternalHeaders::~InternalHeaders() +{ +} + +// static +bool +InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue) +{ + // Note, we must allow a null content-type value here to support + // get("content-type"), but the IsInvalidValue() check will prevent null + // from being set or appended. + return aName.EqualsLiteral("accept") || + aName.EqualsLiteral("accept-language") || + aName.EqualsLiteral("content-language") || + (aName.EqualsLiteral("content-type") && + nsContentUtils::IsAllowedNonCorsContentType(aValue)); +} + +//static +bool +InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv) +{ + if (!NS_IsValidHTTPToken(aName)) { + NS_ConvertUTF8toUTF16 label(aName); + aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label); + return true; + } + + return false; +} + +// static +bool +InternalHeaders::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv) +{ + if (!NS_IsReasonableHTTPHeaderValue(aValue)) { + NS_ConvertUTF8toUTF16 label(aValue); + aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label); + return true; + } + return false; +} + +bool +InternalHeaders::IsImmutable(ErrorResult& aRv) const +{ + if (mGuard == HeadersGuardEnum::Immutable) { + aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE); + return true; + } + return false; +} + +bool +InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const +{ + return mGuard == HeadersGuardEnum::Request && + nsContentUtils::IsForbiddenRequestHeader(aName); +} + +bool +InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName) const +{ + return mGuard == HeadersGuardEnum::Request_no_cors && + !IsSimpleHeader(aName, EmptyCString()); +} + +bool +InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName, + const nsACString& aValue) const +{ + return mGuard == HeadersGuardEnum::Request_no_cors && + !IsSimpleHeader(aName, aValue); +} + +bool +InternalHeaders::IsForbiddenResponseHeader(const nsACString& aName) const +{ + return mGuard == HeadersGuardEnum::Response && + nsContentUtils::IsForbiddenResponseHeader(aName); +} + +void +InternalHeaders::Fill(const InternalHeaders& aInit, ErrorResult& aRv) +{ + const nsTArray& list = aInit.mList; + for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) { + const Entry& entry = list[i]; + Append(entry.mName, entry.mValue, aRv); + } +} + +void +InternalHeaders::Fill(const Sequence>& aInit, ErrorResult& aRv) +{ + for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) { + const Sequence& tuple = aInit[i]; + if (tuple.Length() != 2) { + aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE); + return; + } + Append(tuple[0], tuple[1], aRv); + } +} + +void +InternalHeaders::Fill(const MozMap& aInit, ErrorResult& aRv) +{ + nsTArray keys; + aInit.GetKeys(keys); + for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) { + Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv); + } +} +} // namespace dom +} // namespace mozilla diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h new file mode 100644 index 000000000000..9d046585ef87 --- /dev/null +++ b/dom/fetch/InternalHeaders.h @@ -0,0 +1,116 @@ +/* -*- 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 mozilla_dom_InternalHeaders_h +#define mozilla_dom_InternalHeaders_h + +// needed for HeadersGuardEnum. +#include "mozilla/dom/HeadersBinding.h" +#include "mozilla/dom/UnionTypes.h" + +#include "nsClassHashtable.h" +#include "nsWrapperCache.h" + +class nsPIDOMWindow; + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +template class MozMap; +class HeadersOrByteStringSequenceSequenceOrByteStringMozMap; + +class InternalHeaders MOZ_FINAL +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders) + +private: + struct Entry + { + Entry(const nsACString& aName, const nsACString& aValue) + : mName(aName) + , mValue(aValue) + { } + + Entry() { } + + nsCString mName; + nsCString mValue; + }; + + HeadersGuardEnum mGuard; + nsTArray mList; + +public: + explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None) + : mGuard(aGuard) + { + } + + explicit InternalHeaders(const InternalHeaders& aOther) + : mGuard(aOther.mGuard) + { + ErrorResult result; + Fill(aOther, result); + MOZ_ASSERT(!result.Failed()); + } + + void Append(const nsACString& aName, const nsACString& aValue, + ErrorResult& aRv); + void Delete(const nsACString& aName, ErrorResult& aRv); + void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const; + void GetAll(const nsACString& aName, nsTArray& aResults, + ErrorResult& aRv) const; + bool Has(const nsACString& aName, ErrorResult& aRv) const; + void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv); + + void Clear(); + + HeadersGuardEnum Guard() const { return mGuard; } + void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv); + + void Fill(const InternalHeaders& aInit, ErrorResult& aRv); + void Fill(const Sequence>& aInit, ErrorResult& aRv); + void Fill(const MozMap& aInit, ErrorResult& aRv); +private: + virtual ~InternalHeaders(); + + static bool IsSimpleHeader(const nsACString& aName, + const nsACString& aValue); + static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv); + static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv); + bool IsImmutable(ErrorResult& aRv) const; + bool IsForbiddenRequestHeader(const nsACString& aName) const; + bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const; + bool IsForbiddenRequestNoCorsHeader(const nsACString& aName, + const nsACString& aValue) const; + bool IsForbiddenResponseHeader(const nsACString& aName) const; + + bool IsInvalidMutableHeader(const nsACString& aName, + ErrorResult& aRv) const + { + return IsInvalidMutableHeader(aName, EmptyCString(), aRv); + } + + bool IsInvalidMutableHeader(const nsACString& aName, + const nsACString& aValue, + ErrorResult& aRv) const + { + return IsInvalidName(aName, aRv) || + IsInvalidValue(aValue, aRv) || + IsImmutable(aRv) || + IsForbiddenRequestHeader(aName) || + IsForbiddenRequestNoCorsHeader(aName, aValue) || + IsForbiddenResponseHeader(aName); + } +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_InternalHeaders_h diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp index 207869fa0a5c..077f7f8e23b1 100644 --- a/dom/fetch/InternalRequest.cpp +++ b/dom/fetch/InternalRequest.cpp @@ -24,7 +24,7 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult nsRefPtr copy = new InternalRequest(); copy->mURL.Assign(mURL); copy->SetMethod(mMethod); - copy->mHeaders = new Headers(*mHeaders); + copy->mHeaders = new InternalHeaders(*mHeaders); copy->mBodyStream = mBodyStream; copy->mPreserveContentCodings = true; diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h index 5b3e75d195fc..664e64ae0b3e 100644 --- a/dom/fetch/InternalRequest.h +++ b/dom/fetch/InternalRequest.h @@ -6,7 +6,8 @@ #ifndef mozilla_dom_InternalRequest_h #define mozilla_dom_InternalRequest_h -#include "mozilla/dom/Headers.h" +#include "mozilla/dom/HeadersBinding.h" +#include "mozilla/dom/InternalHeaders.h" #include "mozilla/dom/RequestBinding.h" #include "mozilla/dom/UnionTypes.h" @@ -55,7 +56,7 @@ public: explicit InternalRequest() : mMethod("GET") - , mHeaders(new Headers(nullptr, HeadersGuardEnum::None)) + , mHeaders(new InternalHeaders(HeadersGuardEnum::None)) , mContextFrameType(FRAMETYPE_NONE) , mReferrerType(REFERRER_CLIENT) , mMode(RequestMode::No_cors) @@ -159,6 +160,12 @@ public: return mSynchronous; } + RequestMode + Mode() const + { + return mMode; + } + void SetMode(RequestMode aMode) { @@ -177,8 +184,8 @@ public: return mContext; } - Headers* - Headers_() + InternalHeaders* + Headers() { return mHeaders; } @@ -225,7 +232,7 @@ private: nsCString mMethod; nsCString mURL; - nsRefPtr mHeaders; + nsRefPtr mHeaders; nsCOMPtr mBodyStream; // nsContentPolicyType does not cover the complete set defined in the spec, diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp new file mode 100644 index 000000000000..ceaf131ce3f0 --- /dev/null +++ b/dom/fetch/InternalResponse.cpp @@ -0,0 +1,24 @@ +/* -*- 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/. */ + +#include "InternalResponse.h" + +#include "nsIDOMFile.h" + +#include "mozilla/dom/InternalHeaders.h" + +namespace mozilla { +namespace dom { + +InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) + : mType(ResponseType::Default) + , mStatus(aStatus) + , mStatusText(aStatusText) + , mHeaders(new InternalHeaders(HeadersGuardEnum::Response)) +{ +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h new file mode 100644 index 000000000000..e9c7f1b81830 --- /dev/null +++ b/dom/fetch/InternalResponse.h @@ -0,0 +1,105 @@ +/* -*- 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 mozilla_dom_InternalResponse_h +#define mozilla_dom_InternalResponse_h + +#include "nsIInputStream.h" +#include "nsISupportsImpl.h" + +#include "mozilla/dom/ResponseBinding.h" + +namespace mozilla { +namespace dom { + +class InternalHeaders; + +class InternalResponse MOZ_FINAL +{ + friend class FetchDriver; + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse) + + InternalResponse(uint16_t aStatus, const nsACString& aStatusText); + + explicit InternalResponse(const InternalResponse& aOther) MOZ_DELETE; + + static already_AddRefed + NetworkError() + { + nsRefPtr response = new InternalResponse(0, EmptyCString()); + response->mType = ResponseType::Error; + return response.forget(); + } + + ResponseType + Type() const + { + return mType; + } + + bool + IsError() const + { + return Type() == ResponseType::Error; + } + + // FIXME(nsm): Return with exclude fragment. + nsCString& + GetUrl() + { + return mURL; + } + + uint16_t + GetStatus() const + { + return mStatus; + } + + const nsCString& + GetStatusText() const + { + return mStatusText; + } + + InternalHeaders* + Headers() + { + return mHeaders; + } + + void + GetBody(nsIInputStream** aStream) + { + nsCOMPtr stream = mBody; + stream.forget(aStream); + } + + void + SetBody(nsIInputStream* aBody) + { + mBody = aBody; + } + +private: + ~InternalResponse() + { } + + ResponseType mType; + nsCString mTerminationReason; + nsCString mURL; + const uint16_t mStatus; + const nsCString mStatusText; + nsRefPtr mHeaders; + nsCOMPtr mBody; + nsCString mContentType; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_InternalResponse_h diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index 092c271bc557..c151073ce818 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -5,25 +5,16 @@ #include "Request.h" -#include "nsIUnicodeDecoder.h" #include "nsIURI.h" - -#include "nsDOMString.h" -#include "nsNetUtil.h" #include "nsPIDOMWindow.h" -#include "nsStreamUtils.h" -#include "nsStringStream.h" #include "mozilla/ErrorResult.h" -#include "mozilla/dom/EncodingUtils.h" -#include "mozilla/dom/File.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Fetch.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/URL.h" #include "mozilla/dom/workers/bindings/URL.h" -// dom/workers #include "WorkerPrivate.h" namespace mozilla { @@ -31,7 +22,7 @@ namespace dom { NS_IMPL_CYCLE_COLLECTING_ADDREF(Request) NS_IMPL_CYCLE_COLLECTING_RELEASE(Request) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY @@ -39,9 +30,9 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request) NS_INTERFACE_MAP_END Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest) - : mOwner(aOwner) + : FetchBody() + , mOwner(aOwner) , mRequest(aRequest) - , mBodyUsed(false) { } @@ -164,24 +155,24 @@ Request::Constructor(const GlobalObject& aGlobal, request->SetMethod(method); } - nsRefPtr domRequest = new Request(global, request); - nsRefPtr domRequestHeaders = domRequest->Headers_(); + nsRefPtr requestHeaders = request->Headers(); - nsRefPtr headers; + nsRefPtr headers; if (aInit.mHeaders.WasPassed()) { - headers = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv); + nsRefPtr h = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv); if (aRv.Failed()) { return nullptr; } + headers = h->GetInternalHeaders(); } else { - headers = new Headers(*domRequestHeaders); + headers = new InternalHeaders(*requestHeaders); } - domRequestHeaders->Clear(); + requestHeaders->Clear(); - if (domRequest->Mode() == RequestMode::No_cors) { + if (request->Mode() == RequestMode::No_cors) { nsCString method; - domRequest->GetMethod(method); + request->GetMethod(method); ToLowerCase(method); if (!method.EqualsASCII("get") && !method.EqualsASCII("head") && @@ -191,19 +182,19 @@ Request::Constructor(const GlobalObject& aGlobal, return nullptr; } - domRequestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv); + requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv); if (aRv.Failed()) { return nullptr; } } - domRequestHeaders->Fill(*headers, aRv); + requestHeaders->Fill(*headers, aRv); if (aRv.Failed()) { return nullptr; } if (aInit.mBody.WasPassed()) { - const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value(); + const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value(); nsCOMPtr stream; nsCString contentType; aRv = ExtractByteStreamFromBody(bodyInit, @@ -214,9 +205,9 @@ Request::Constructor(const GlobalObject& aGlobal, request->SetBody(stream); if (!contentType.IsVoid() && - !domRequestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { - domRequestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"), - contentType, aRv); + !requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { + requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"), + contentType, aRv); } if (aRv.Failed()) { @@ -224,21 +215,8 @@ Request::Constructor(const GlobalObject& aGlobal, } } - // Extract mime type. - nsTArray contentTypeValues; - domRequestHeaders->GetAll(NS_LITERAL_CSTRING("Content-Type"), - contentTypeValues, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // HTTP ABNF states Content-Type may have only one value. - // This is from the "parse a header value" of the fetch spec. - if (contentTypeValues.Length() == 1) { - domRequest->mMimeType = contentTypeValues[0]; - ToLowerCase(domRequest->mMimeType); - } - + nsRefPtr domRequest = new Request(global, request); + domRequest->SetMimeType(aRv); return domRequest.forget(); } @@ -252,181 +230,15 @@ Request::Clone() const return request.forget(); } -namespace { -nsresult -DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded) +Headers* +Request::Headers_() { - nsCOMPtr decoder = - EncodingUtils::DecoderForEncoding("UTF-8"); - if (!decoder) { - return NS_ERROR_FAILURE; + if (!mHeaders) { + mHeaders = new Headers(mOwner, mRequest->Headers()); } - int32_t destBufferLen; - nsresult rv = - decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - char16_t* destBuffer = aDecoded.BeginWriting(); - int32_t srcLen = (int32_t) aBuffer.Length(); - int32_t outLen = destBufferLen; - rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(outLen <= destBufferLen); - aDecoded.SetLength(outLen); - return NS_OK; -} + return mHeaders; } -already_AddRefed -Request::ConsumeBody(ConsumeType aType, ErrorResult& aRv) -{ - nsRefPtr promise = Promise::Create(mOwner, aRv); - if (aRv.Failed()) { - return nullptr; - } - - if (BodyUsed()) { - aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR); - return nullptr; - } - - SetBodyUsed(); - - // While the spec says to do this asynchronously, all the body constructors - // right now only accept bodies whose streams are backed by an in-memory - // buffer that can be read without blocking. So I think this is fine. - nsCOMPtr stream; - mRequest->GetBody(getter_AddRefs(stream)); - - if (!stream) { - aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0, - NS_ASSIGNMENT_COPY); - if (aRv.Failed()) { - return nullptr; - } - } - - AutoJSAPI api; - api.Init(mOwner); - JSContext* cx = api.cx(); - - // We can make this assertion because for now we only support memory backed - // structures for the body argument for a Request. - MOZ_ASSERT(NS_InputStreamIsBuffered(stream)); - nsCString buffer; - uint64_t len; - aRv = stream->Available(&len); - if (aRv.Failed()) { - return nullptr; - } - - aRv = NS_ReadInputStreamToString(stream, buffer, len); - if (aRv.Failed()) { - return nullptr; - } - - buffer.SetLength(len); - - switch (aType) { - case CONSUME_ARRAYBUFFER: { - JS::Rooted arrayBuffer(cx); - arrayBuffer = - ArrayBuffer::Create(cx, buffer.Length(), - reinterpret_cast(buffer.get())); - JS::Rooted val(cx); - val.setObjectOrNull(arrayBuffer); - promise->MaybeResolve(cx, val); - return promise.forget(); - } - case CONSUME_BLOB: { - // XXXnsm it is actually possible to avoid these duplicate allocations - // for the Blob case by having the Blob adopt the stream's memory - // directly, but I've not added a special case for now. - // - // This is similar to nsContentUtils::CreateBlobBuffer, but also deals - // with worker wrapping. - uint32_t blobLen = buffer.Length(); - void* blobData = moz_malloc(blobLen); - nsRefPtr blob; - if (blobData) { - memcpy(blobData, buffer.BeginReading(), blobLen); - blob = File::CreateMemoryFile(GetParentObject(), blobData, blobLen, - NS_ConvertUTF8toUTF16(mMimeType)); - } else { - aRv = NS_ERROR_OUT_OF_MEMORY; - return nullptr; - } - - promise->MaybeResolve(blob); - return promise.forget(); - } - case CONSUME_JSON: { - nsString decoded; - aRv = DecodeUTF8(buffer, decoded); - if (aRv.Failed()) { - return nullptr; - } - - JS::Rooted json(cx); - if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) { - JS::Rooted exn(cx); - if (JS_GetPendingException(cx, &exn)) { - JS_ClearPendingException(cx); - promise->MaybeReject(cx, exn); - } - } - promise->MaybeResolve(cx, json); - return promise.forget(); - } - case CONSUME_TEXT: { - nsString decoded; - aRv = DecodeUTF8(buffer, decoded); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeResolve(decoded); - return promise.forget(); - } - } - - NS_NOTREACHED("Unexpected consume body type"); - // Silence warnings. - return nullptr; -} - -already_AddRefed -Request::ArrayBuffer(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_ARRAYBUFFER, aRv); -} - -already_AddRefed -Request::Blob(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_BLOB, aRv); -} - -already_AddRefed -Request::Json(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_JSON, aRv); -} - -already_AddRefed -Request::Text(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_TEXT, aRv); -} } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h index 7d78891b7fa8..01417a04a485 100644 --- a/dom/fetch/Request.h +++ b/dom/fetch/Request.h @@ -9,6 +9,7 @@ #include "nsISupportsImpl.h" #include "nsWrapperCache.h" +#include "mozilla/dom/Fetch.h" #include "mozilla/dom/InternalRequest.h" // Required here due to certain WebIDL enums/classes being declared in both // files. @@ -21,10 +22,12 @@ namespace mozilla { namespace dom { class Headers; +class InternalHeaders; class Promise; class Request MOZ_FINAL : public nsISupports , public nsWrapperCache + , public FetchBody { NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request) @@ -74,13 +77,22 @@ public: aReferrer.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mReferrerURL); } - Headers* Headers_() const { return mRequest->Headers_(); } + InternalHeaders* + GetInternalHeaders() const + { + return mRequest->Headers(); + } + + Headers* Headers_(); + + void + GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); } static already_AddRefed Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput, const RequestInit& aInit, ErrorResult& rv); - nsISupports* GetParentObject() const + nsIGlobalObject* GetParentObject() const { return mOwner; } @@ -88,51 +100,15 @@ public: already_AddRefed Clone() const; - already_AddRefed - ArrayBuffer(ErrorResult& aRv); - - already_AddRefed - Blob(ErrorResult& aRv); - - already_AddRefed - Json(ErrorResult& aRv); - - already_AddRefed - Text(ErrorResult& aRv); - - bool - BodyUsed() const - { - return mBodyUsed; - } - already_AddRefed GetInternalRequest(); private: - enum ConsumeType - { - CONSUME_ARRAYBUFFER, - CONSUME_BLOB, - // FormData not supported right now, - CONSUME_JSON, - CONSUME_TEXT, - }; - ~Request(); - already_AddRefed - ConsumeBody(ConsumeType aType, ErrorResult& aRv); - - void - SetBodyUsed() - { - mBodyUsed = true; - } - nsCOMPtr mOwner; nsRefPtr mRequest; - bool mBodyUsed; - nsCString mMimeType; + // Lazily created. + nsRefPtr mHeaders; }; } // namespace dom diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp index 385553de7083..f22337930ee8 100644 --- a/dom/fetch/Response.cpp +++ b/dom/fetch/Response.cpp @@ -4,30 +4,35 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Response.h" -#include "nsDOMString.h" -#include "nsPIDOMWindow.h" -#include "nsIURI.h" + #include "nsISupportsImpl.h" +#include "nsIURI.h" +#include "nsPIDOMWindow.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Promise.h" +#include "nsDOMString.h" + +#include "InternalResponse.h" + namespace mozilla { namespace dom { NS_IMPL_CYCLE_COLLECTING_ADDREF(Response) NS_IMPL_CYCLE_COLLECTING_RELEASE(Response) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner, mHeaders) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -Response::Response(nsISupports* aOwner) - : mOwner(aOwner) - , mHeaders(new Headers(aOwner)) +Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse) + : FetchBody() + , mOwner(aGlobal) + , mInternalResponse(aInternalResponse) { } @@ -38,11 +43,9 @@ Response::~Response() /* static */ already_AddRefed Response::Error(const GlobalObject& aGlobal) { - ErrorResult result; - ResponseInit init; - init.mStatus = 0; - Optional body; - nsRefPtr r = Response::Constructor(aGlobal, body, init, result); + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + nsRefPtr error = InternalResponse::NetworkError(); + nsRefPtr r = new Response(global, error); return r.forget(); } @@ -52,87 +55,109 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, { ErrorResult result; ResponseInit init; - Optional body; + Optional body; nsRefPtr r = Response::Constructor(aGlobal, body, init, result); return r.forget(); } /*static*/ already_AddRefed -Response::Constructor(const GlobalObject& global, - const Optional& aBody, - const ResponseInit& aInit, ErrorResult& rv) +Response::Constructor(const GlobalObject& aGlobal, + const Optional& aBody, + const ResponseInit& aInit, ErrorResult& aRv) { - nsRefPtr response = new Response(global.GetAsSupports()); - return response.forget(); + if (aInit.mStatus < 200 || aInit.mStatus > 599) { + aRv.Throw(NS_ERROR_RANGE_ERR); + return nullptr; + } + + nsCString statusText; + if (aInit.mStatusText.WasPassed()) { + statusText = aInit.mStatusText.Value(); + nsACString::const_iterator start, end; + statusText.BeginReading(start); + statusText.EndReading(end); + if (FindCharInReadable('\r', start, end)) { + aRv.ThrowTypeError(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR); + return nullptr; + } + // Reset iterator since FindCharInReadable advances it. + statusText.BeginReading(start); + if (FindCharInReadable('\n', start, end)) { + aRv.ThrowTypeError(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR); + return nullptr; + } + } else { + // Since we don't support default values for ByteString. + statusText = NS_LITERAL_CSTRING("OK"); + } + + nsRefPtr internalResponse = + new InternalResponse(aInit.mStatus, statusText); + + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + nsRefPtr r = new Response(global, internalResponse); + + if (aInit.mHeaders.WasPassed()) { + internalResponse->Headers()->Clear(); + + // Instead of using Fill, create an object to allow the constructor to + // unwrap the HeadersInit. + nsRefPtr headers = + Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + if (aBody.WasPassed()) { + nsCOMPtr bodyStream; + nsCString contentType; + aRv = ExtractByteStreamFromBody(aBody.Value(), getter_AddRefs(bodyStream), contentType); + internalResponse->SetBody(bodyStream); + + if (!contentType.IsVoid() && + !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { + internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv); + } + + if (aRv.Failed()) { + return nullptr; + } + } + + r->SetMimeType(aRv); + return r.forget(); } +// FIXME(nsm): Bug 1073231: This is currently unspecced! already_AddRefed Response::Clone() { - nsRefPtr response = new Response(mOwner); + nsCOMPtr global = do_QueryInterface(mOwner); + nsRefPtr response = new Response(global, mInternalResponse); return response.forget(); } -already_AddRefed -Response::ArrayBuffer(ErrorResult& aRv) +void +Response::SetBody(nsIInputStream* aBody) { - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); + // FIXME(nsm): Do we flip bodyUsed here? + mInternalResponse->SetBody(aBody); } -already_AddRefed -Response::Blob(ErrorResult& aRv) +Headers* +Response::Headers_() { - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; + if (!mHeaders) { + mHeaders = new Headers(mOwner, mInternalResponse->Headers()); } - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -already_AddRefed -Response::Json(ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -already_AddRefed -Response::Text(ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -bool -Response::BodyUsed() -{ - return false; + return mHeaders; } } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h index dfaea9b1f68b..85711ced5ff7 100644 --- a/dom/fetch/Response.h +++ b/dom/fetch/Response.h @@ -9,25 +9,32 @@ #include "nsWrapperCache.h" #include "nsISupportsImpl.h" +#include "mozilla/dom/Fetch.h" #include "mozilla/dom/ResponseBinding.h" #include "mozilla/dom/UnionTypes.h" +#include "InternalResponse.h" + class nsPIDOMWindow; namespace mozilla { namespace dom { class Headers; +class InternalHeaders; class Promise; class Response MOZ_FINAL : public nsISupports , public nsWrapperCache + , public FetchBody { NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response) public: - explicit Response(nsISupports* aOwner); + Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse); + + Response(const Response& aOther) MOZ_DELETE; JSObject* WrapObject(JSContext* aCx) @@ -38,29 +45,37 @@ public: ResponseType Type() const { - return ResponseType::Error; + return mInternalResponse->Type(); } void GetUrl(DOMString& aUrl) const { - aUrl.AsAString() = EmptyString(); + aUrl.AsAString() = NS_ConvertUTF8toUTF16(mInternalResponse->GetUrl()); } uint16_t Status() const { - return 400; + return mInternalResponse->GetStatus(); } void GetStatusText(nsCString& aStatusText) const { - aStatusText = EmptyCString(); + aStatusText = mInternalResponse->GetStatusText(); } - Headers* - Headers_() const { return mHeaders; } + InternalHeaders* + GetInternalHeaders() const + { + return mInternalResponse->Headers(); + } + + Headers* Headers_(); + + void + GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); } static already_AddRefed Error(const GlobalObject& aGlobal); @@ -70,10 +85,10 @@ public: static already_AddRefed Constructor(const GlobalObject& aGlobal, - const Optional& aBody, + const Optional& aBody, const ResponseInit& aInit, ErrorResult& rv); - nsISupports* GetParentObject() const + nsIGlobalObject* GetParentObject() const { return mOwner; } @@ -81,24 +96,14 @@ public: already_AddRefed Clone(); - already_AddRefed - ArrayBuffer(ErrorResult& aRv); - - already_AddRefed - Blob(ErrorResult& aRv); - - already_AddRefed - Json(ErrorResult& aRv); - - already_AddRefed - Text(ErrorResult& aRv); - - bool - BodyUsed(); + void + SetBody(nsIInputStream* aBody); private: ~Response(); - nsCOMPtr mOwner; + nsCOMPtr mOwner; + nsRefPtr mInternalResponse; + // Lazily created nsRefPtr mHeaders; }; diff --git a/dom/fetch/moz.build b/dom/fetch/moz.build index c5491304cf5a..9d6b9474d298 100644 --- a/dom/fetch/moz.build +++ b/dom/fetch/moz.build @@ -7,7 +7,9 @@ EXPORTS.mozilla.dom += [ 'Fetch.h', 'Headers.h', + 'InternalHeaders.h', 'InternalRequest.h', + 'InternalResponse.h', 'Request.h', 'Response.h', ] @@ -15,7 +17,9 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'Fetch.cpp', 'Headers.cpp', + 'InternalHeaders.cpp', 'InternalRequest.cpp', + 'InternalResponse.cpp', 'Request.cpp', 'Response.cpp', ] diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 74e388cf9406..0d33cd14673c 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -24,6 +24,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIXPConnect.h" #include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/Event.h" #include "mozilla/Services.h" #include "nsContentPermissionHelper.h" #ifdef MOZ_B2G @@ -360,19 +361,31 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { nsCOMPtr window = mNotification->GetOwner(); - if (!window) { + if (!window || !window->IsCurrentInnerWindow()) { // Window has been closed, this observer is not valid anymore return NS_ERROR_FAILURE; } if (!strcmp("alertclickcallback", aTopic)) { - nsIDocument* doc = window ? window->GetExtantDoc() : nullptr; - if (doc) { - nsContentUtils::DispatchChromeEvent(doc, window, - NS_LITERAL_STRING("DOMWebNotificationClicked"), - true, true); + + nsCOMPtr event; + NS_NewDOMEvent(getter_AddRefs(event), mNotification, nullptr, nullptr); + nsresult rv = event->InitEvent(NS_LITERAL_STRING("click"), false, true); + NS_ENSURE_SUCCESS(rv, rv); + event->SetTrusted(true); + WantsPopupControlCheck popupControlCheck(event); + bool doDefaultAction = true; + mNotification->DispatchEvent(event, &doDefaultAction); + if (doDefaultAction) { + nsIDocument* doc = window ? window->GetExtantDoc() : nullptr; + if (doc) { + // Browser UI may use DOMWebNotificationClicked to focus the tab + // from which the event was dispatched. + nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(), + NS_LITERAL_STRING("DOMWebNotificationClicked"), + true, true); + } } - mNotification->DispatchTrustedEvent(NS_LITERAL_STRING("click")); } else if (!strcmp("alertfinished", aTopic)) { nsCOMPtr notificationStorage = do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID); diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index d8fc59477428..ec70c22afa0c 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -2857,7 +2857,6 @@ nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL, principal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_OBJECT_SUBREQUEST, - nullptr, // aChannelPolicy nullptr, // aLoadGroup listenerPeer); diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index 54f2afb92a0a..ab00a1d97216 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -662,7 +662,6 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) principal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy loadGroup, callbacks); diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp index ae5bdcc70a3b..dbed18fce279 100644 --- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -835,6 +835,11 @@ AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) { static_cast(aStream), aIndex, AUDIO_DEVICE_OUT_EARPIECE); + status += AudioSystem::setStreamVolumeIndex( + static_cast(aStream), + aIndex, + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET); + return status ? NS_ERROR_FAILURE : NS_OK; #endif } diff --git a/dom/webidl/Fetch.webidl b/dom/webidl/Fetch.webidl index a1c66f3579d8..1c7de5efe9af 100644 --- a/dom/webidl/Fetch.webidl +++ b/dom/webidl/Fetch.webidl @@ -8,10 +8,9 @@ */ typedef object JSON; -// FIXME(nsm): Bug 1071290: Blobs can't be passed as unions in workers. // FIXME(nsm): Bug 739173: FormData is not available in workers. // typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or ScalarValueString or URLSearchParams) BodyInit; -typedef (ArrayBuffer or ArrayBufferView or ScalarValueString or URLSearchParams) BodyInit; +typedef (ArrayBuffer or ArrayBufferView or Blob or ScalarValueString or URLSearchParams) BodyInit; [NoInterfaceObject, Exposed=(Window,Worker)] interface Body { diff --git a/dom/webidl/SubtleCrypto.webidl b/dom/webidl/SubtleCrypto.webidl index a4e1b07950cb..09bd3ac97ba3 100644 --- a/dom/webidl/SubtleCrypto.webidl +++ b/dom/webidl/SubtleCrypto.webidl @@ -87,6 +87,9 @@ dictionary EcdhKeyDeriveParams : Algorithm { required CryptoKey public; }; +dictionary EcdsaParams : Algorithm { + required AlgorithmIdentifier hash; +}; /***** JWK *****/ diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index c4f6aa37c082..1f4b4b6841b8 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -6,7 +6,6 @@ #include "ScriptLoader.h" #include "nsIChannel.h" -#include "nsIChannelPolicy.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsIHttpChannel.h" @@ -17,7 +16,6 @@ #include "nsIURI.h" #include "jsapi.h" -#include "nsChannelPolicy.h" #include "nsError.h" #include "nsContentPolicyUtils.h" #include "nsContentUtils.h" @@ -104,23 +102,6 @@ ChannelFromScriptURL(nsIPrincipal* principal, NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR); } - // Get Content Security Policy from parent document to pass into channel. - nsCOMPtr csp; - rv = principal->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr channelPolicy; - if (csp) { - channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = channelPolicy->SetContentSecurityPolicy(csp); - NS_ENSURE_SUCCESS(rv, rv); - - rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT); - NS_ENSURE_SUCCESS(rv, rv); - } - uint32_t flags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI; nsCOMPtr channel; @@ -131,7 +112,6 @@ ChannelFromScriptURL(nsIPrincipal* principal, parentDoc, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_SCRIPT, - channelPolicy, loadGroup, nullptr, // aCallbacks flags, @@ -148,7 +128,6 @@ ChannelFromScriptURL(nsIPrincipal* principal, nullPrincipal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_SCRIPT, - channelPolicy, loadGroup, nullptr, // aCallbacks flags, diff --git a/dom/workers/test/fetch/mochitest.ini b/dom/workers/test/fetch/mochitest.ini index ded2d970f35c..84492fca80ac 100644 --- a/dom/workers/test/fetch/mochitest.ini +++ b/dom/workers/test/fetch/mochitest.ini @@ -2,6 +2,8 @@ support-files = worker_interfaces.js worker_test_request.js + worker_test_response.js [test_interfaces.html] [test_request.html] +[test_response.html] diff --git a/dom/workers/test/fetch/test_response.html b/dom/workers/test/fetch/test_response.html new file mode 100644 index 000000000000..e1bbd399ed65 --- /dev/null +++ b/dom/workers/test/fetch/test_response.html @@ -0,0 +1,48 @@ + + + + + Bug 1039846 - Test Response object in worker + + + + +

+ +

+
+
+
+
+
diff --git a/dom/workers/test/fetch/worker_test_request.js b/dom/workers/test/fetch/worker_test_request.js
index fde748e4b997..a3504dd56a5a 100644
--- a/dom/workers/test/fetch/worker_test_request.js
+++ b/dom/workers/test/fetch/worker_test_request.js
@@ -131,7 +131,6 @@ function testBodyUsed() {
   });
 }
 
-// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
 function testBodyCreation() {
   var text = "κόσμε";
   var req1 = new Request("", { body: text });
@@ -150,6 +149,11 @@ function testBodyCreation() {
     is("Hello", v, "Extracted string should match");
   });
 
+  var reqblob = new Request("", { body: new Blob([text]) });
+  var pblob = reqblob.text().then(function(v) {
+    is(v, text, "Extracted string should match");
+  });
+
   var params = new URLSearchParams();
   params.append("item", "Geckos");
   params.append("feature", "stickyfeet");
@@ -162,7 +166,7 @@ function testBodyCreation() {
     is(extracted.get("quantity"), "700", "Param should match");
   });
 
-  return Promise.all([p1, p2, p2b, p3]);
+  return Promise.all([p1, p2, p2b, pblob, p3]);
 }
 
 function testBodyExtraction() {
diff --git a/dom/workers/test/fetch/worker_test_response.js b/dom/workers/test/fetch/worker_test_response.js
new file mode 100644
index 000000000000..ce11ca318f36
--- /dev/null
+++ b/dom/workers/test/fetch/worker_test_response.js
@@ -0,0 +1,128 @@
+function ok(a, msg) {
+  dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
+  postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
+}
+
+function is(a, b, msg) {
+  dump("IS: " + (a===b) + "  =>  " + a + " | " + b + " " + msg + "\n");
+  postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
+}
+
+function testDefaultCtor() {
+  var res = new Response();
+  is(res.type, "default", "Default Response type is default");
+  ok(res.headers instanceof Headers, "Response should have non-null Headers object");
+  is(res.url, "", "URL should be empty string");
+  is(res.status, 200, "Default status is 200");
+  is(res.statusText, "OK", "Default statusText is OK");
+}
+
+function testClone() {
+  var res = (new Response("This is a body", {
+              status: 404,
+              statusText: "Not Found",
+              headers: { "Content-Length": 5 },
+            })).clone();
+  is(res.status, 404, "Response status is 404");
+  is(res.statusText, "Not Found", "Response statusText is POST");
+  ok(res.headers instanceof Headers, "Response should have non-null Headers object");
+  is(res.headers.get('content-length'), "5", "Response content-length should be 5.");
+}
+
+function testBodyUsed() {
+  var res = new Response("Sample body");
+  ok(!res.bodyUsed, "bodyUsed is initially false.");
+  return res.text().then((v) => {
+    is(v, "Sample body", "Body should match");
+    ok(res.bodyUsed, "After reading body, bodyUsed should be true.");
+  }).then(() => {
+    return res.blob().then((v) => {
+      ok(false, "Attempting to read body again should fail.");
+    }, (e) => {
+      ok(true, "Attempting to read body again should fail.");
+    })
+  });
+}
+
+function testBodyCreation() {
+  var text = "κόσμε";
+  var res1 = new Response(text);
+  var p1 = res1.text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  });
+
+  var res2 = new Response(new Uint8Array([72, 101, 108, 108, 111]));
+  var p2 = res2.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var res2b = new Response((new Uint8Array([72, 101, 108, 108, 111])).buffer);
+  var p2b = res2b.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var resblob = new Response(new Blob([text]));
+  var pblob = resblob.text().then(function(v) {
+    is(v, text, "Extracted string should match");
+  });
+
+  var params = new URLSearchParams();
+  params.append("item", "Geckos");
+  params.append("feature", "stickyfeet");
+  params.append("quantity", "700");
+  var res3 = new Response(params);
+  var p3 = res3.text().then(function(v) {
+    var extracted = new URLSearchParams(v);
+    is(extracted.get("item"), "Geckos", "Param should match");
+    is(extracted.get("feature"), "stickyfeet", "Param should match");
+    is(extracted.get("quantity"), "700", "Param should match");
+  });
+
+  return Promise.all([p1, p2, p2b, pblob, p3]);
+}
+
+function testBodyExtraction() {
+  var text = "κόσμε";
+  var newRes = function() { return new Response(text); }
+  return newRes().text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  }).then(function() {
+    return newRes().blob().then(function(v) {
+      ok(v instanceof Blob, "Should resolve to Blob");
+      var fs = new FileReaderSync();
+      is(fs.readAsText(v), text, "Decoded Blob should match original");
+    });
+  }).then(function() {
+    return newRes().json().then(function(v) {
+      ok(false, "Invalid json should reject");
+    }, function(e) {
+      ok(true, "Invalid json should reject");
+    })
+  }).then(function() {
+    return newRes().arrayBuffer().then(function(v) {
+      ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
+      var dec = new TextDecoder();
+      is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
+    });
+  })
+}
+
+onmessage = function() {
+  var done = function() { postMessage({ type: 'finish' }) }
+
+  testDefaultCtor();
+  testClone();
+
+  Promise.resolve()
+    .then(testBodyCreation)
+    .then(testBodyUsed)
+    .then(testBodyExtraction)
+    // Put more promise based tests here.
+    .then(done)
+    .catch(function(e) {
+      ok(false, "Some Response tests failed " + e);
+      done();
+    })
+}
diff --git a/dom/xbl/nsXBLService.cpp b/dom/xbl/nsXBLService.cpp
index 22d2b07d370b..eac4d6c9fa03 100644
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1076,7 +1076,6 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
                              requestingPrincipal,
                              nsILoadInfo::SEC_NORMAL,
                              nsIContentPolicy::TYPE_OTHER,
-                             nullptr,   // aChannelPolicy
                              loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
diff --git a/dom/xml/XMLDocument.cpp b/dom/xml/XMLDocument.cpp
index ebd093a5f548..2d1bc1d20974 100644
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -449,7 +449,6 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
                                   static_cast(this),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_XMLHTTPREQUEST,
-                     nullptr,   // aChannelPolicy
                      loadGroup,
                      req,
                      nsIRequest::LOAD_BACKGROUND);
diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp
index ebcc484d21d6..b2a78db2e47d 100644
--- a/dom/xslt/base/txURIUtils.cpp
+++ b/dom/xslt/base/txURIUtils.cpp
@@ -64,7 +64,6 @@ URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode)
                                     sourceDoc,
                                     nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                                     nsIContentPolicy::TYPE_OTHER,
-                                    nullptr,   // aChannelPolicy
                                     loadGroup);
 
         if (NS_FAILED(rv)) {
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
index ec313edf974f..30f9b1f68aa0 100644
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -465,7 +465,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
                                 aReferrerPrincipal,
                                 nsILoadInfo::SEC_NORMAL,
                                 nsIContentPolicy::TYPE_STYLESHEET,
-                                nullptr,
                                 loadGroup);
 
     NS_ENSURE_SUCCESS(rv, rv);
diff --git a/embedding/browser/nsContextMenuInfo.cpp b/embedding/browser/nsContextMenuInfo.cpp
index 6a15401444b2..0b4733071c0b 100644
--- a/embedding/browser/nsContextMenuInfo.cpp
+++ b/embedding/browser/nsContextMenuInfo.cpp
@@ -23,7 +23,6 @@
 #include "nsUnicharUtils.h"
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentPolicy.h"
 #include "nsAutoPtr.h"
@@ -268,22 +267,9 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRe
   nsCOMPtr primitiveValue;
   nsAutoString bgStringValue;
 
-  // get Content Security Policy to pass to LoadImage
   nsCOMPtr doc(do_QueryInterface(document));
-  nsCOMPtr principal;
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  if (doc) {
-    principal = doc->NodePrincipal();
-    nsresult rv = principal->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (csp) {
-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-      channelPolicy->SetContentSecurityPolicy(csp);
-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
-    }
-  }
-  
+  nsCOMPtr principal = doc ? doc->NodePrincipal() : nullptr;
+
   while (true) {
     nsCOMPtr domElement(do_QueryInterface(domNode));
     // bail for the parent node of the root element or null argument
@@ -310,7 +296,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRe
 
           return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,
                                nullptr, nullptr, nsIRequest::LOAD_NORMAL,
-                               nullptr, channelPolicy, EmptyString(), aRequest);
+                               nullptr, EmptyString(), aRequest);
         }
       }
 
diff --git a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
index cbfef03aa9fa..dad12ded7f69 100644
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1205,7 +1205,6 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // aLoadGroup
                        static_cast(this),
                        loadFlags);
diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.cpp b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
index 0ee2e3fbc8b2..63368902dfc7 100644
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -281,7 +281,6 @@ nsresult nsAutoConfig::downloadAutoConfig()
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // loadGroup
                        nullptr,  // aCallbacks
                        nsIRequest::INHIBIT_PERSISTENT_CACHING |
diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp
index a270469426e8..96e6dd21766e 100644
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1275,7 +1275,14 @@ TemporaryRef
 DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
 #ifdef CAIRO_HAS_XLIB_SURFACE
-  if (cairo_surface_get_type(mSurface) != CAIRO_SURFACE_TYPE_XLIB) {
+  cairo_surface_type_t ctype = cairo_surface_get_type(mSurface);
+  if (aSurface->GetType() == SurfaceType::CAIRO &&
+      cairo_surface_get_type(
+        static_cast(aSurface)->GetSurface()) == ctype) {
+    return aSurface;
+  }
+
+  if (ctype != CAIRO_SURFACE_TYPE_XLIB) {
     return aSurface;
   }
 
diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h
index 1318ed95a3ab..cdcaf7e4fea0 100644
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -558,7 +558,7 @@ public:
    * this method would be preferred since it only involves 12 floating-point
    * multiplications.)
    */
-  Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
+  Matrix4x4 &PreTranslate(Float aX, Float aY, Float aZ)
   {
     _41 += aX * _11 + aY * _21 + aZ * _31;
     _42 += aX * _12 + aY * _22 + aZ * _32;
@@ -609,7 +609,7 @@ public:
   /**
    * Similar to PreTranslate, but applies a scale instead of a translation.
    */
-  Matrix4x4 &Scale(Float aX, Float aY, Float aZ)
+  Matrix4x4 &PreScale(Float aX, Float aY, Float aZ)
   {
     _11 *= aX;
     _12 *= aX;
@@ -663,7 +663,7 @@ public:
   Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ)
   {
     // Translate to the origin before applying this matrix
-    Translate(-aX, -aY, -aZ);
+    PreTranslate(-aX, -aY, -aZ);
 
     // Translate back into position after applying this matrix
     PostTranslate(aX, aY, aZ);
@@ -777,42 +777,6 @@ public:
       }
   }
 
-  void ScalePost(Float aX, Float aY, Float aZ)
-  {
-    _11 *= aX;
-    _21 *= aX;
-    _31 *= aX;
-    _41 *= aX;
-
-    _12 *= aY;
-    _22 *= aY;
-    _32 *= aY;
-    _42 *= aY;
-
-    _13 *= aZ;
-    _23 *= aZ;
-    _33 *= aZ;
-    _43 *= aZ;
-  }
-
-  void TranslatePost(Float aX, Float aY, Float aZ)
-  {
-      _11 += _14 * aX;
-      _21 += _24 * aX;
-      _31 += _34 * aX;
-      _41 += _44 * aX;
-
-      _12 += _14 * aY;
-      _22 += _24 * aY;
-      _32 += _34 * aY;
-      _42 += _44 * aY;
-
-      _13 += _14 * aZ;
-      _23 += _24 * aZ;
-      _33 += _34 * aZ;
-      _43 += _44 * aZ;
-  }
-
   bool FuzzyEqual(const Matrix4x4& o) const
   {
     return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) &&
diff --git a/gfx/2d/PathHelpers.cpp b/gfx/2d/PathHelpers.cpp
index 87379374f41a..e53ed3974989 100644
--- a/gfx/2d/PathHelpers.cpp
+++ b/gfx/2d/PathHelpers.cpp
@@ -162,6 +162,65 @@ AppendEllipseToPath(PathBuilder* aPathBuilder,
   AppendRoundedRectToPath(aPathBuilder, rect, radii);
 }
 
+bool
+SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2,
+                                  const DrawTarget& aDrawTarget)
+{
+  Matrix mat = aDrawTarget.GetTransform();
+  if (mat.HasNonTranslation()) {
+    return false;
+  }
+  if (aP1.x != aP2.x && aP1.y != aP2.y) {
+    return false; // not a horizontal or vertical line
+  }
+  Point p1 = aP1 + mat.GetTranslation(); // into device space
+  Point p2 = aP2 + mat.GetTranslation();
+  p1.Round();
+  p2.Round();
+  p1 -= mat.GetTranslation(); // back into user space
+  p2 -= mat.GetTranslation();
+  if (aP1.x == aP2.x) {
+    // snap vertical line, adding 0.5 to align it to be mid-pixel:
+    aP1 = p1 + Point(0.5, 0);
+    aP2 = p2 + Point(0.5, 0);
+  } else {
+    // snap horizontal line, adding 0.5 to align it to be mid-pixel:
+    aP1 = p1 + Point(0, 0.5);
+    aP2 = p2 + Point(0, 0.5);
+  }
+  return true;
+}
+
+void
+StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget,
+                        const ColorPattern& aColor,
+                        const StrokeOptions& aStrokeOptions)
+{
+  if (aRect.IsEmpty()) {
+    return;
+  }
+
+  Point p1 = aRect.TopLeft();
+  Point p2 = aRect.BottomLeft();
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
+
+  p1 = aRect.BottomLeft();
+  p2 = aRect.BottomRight();
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
+
+  p1 = aRect.TopLeft();
+  p2 = aRect.TopRight();
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
+
+  p1 = aRect.TopRight();
+  p2 = aRect.BottomRight();
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
+}
+
 } // namespace gfx
 } // namespace mozilla
 
diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h
index 80963cd1af4f..ea69d18fb433 100644
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -156,6 +156,31 @@ GFX2D_API void AppendEllipseToPath(PathBuilder* aPathBuilder,
                                    const Point& aCenter,
                                    const Size& aDimensions);
 
+/**
+ * If aDrawTarget's transform only contains a translation, and if this line is
+ * a horizontal or vertical line, this function will snap the line's vertices
+ * to align with the device pixel grid so that stroking the line with a one
+ * pixel wide stroke will result in a crisp line that is not antialiased over
+ * two pixels across its width.
+ *
+ * @return Returns true if this function snaps aRect's vertices, else returns
+ *   false.
+ */
+GFX2D_API bool SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2,
+                                                 const DrawTarget& aDrawTarget);
+
+/**
+ * This function paints each edge of aRect separately, snapping the edges using
+ * SnapLineToDevicePixelsForStroking. Stroking the edges as separate paths
+ * helps ensure not only that the stroke spans a single row of device pixels if
+ * possible, but also that the ends of stroke dashes start and end on device
+ * pixels too.
+ */
+GFX2D_API void StrokeSnappedEdgesOfRect(const Rect& aRect,
+                                        DrawTarget& aDrawTarget,
+                                        const ColorPattern& aColor,
+                                        const StrokeOptions& aStrokeOptions);
+
 static inline bool
 UserToDevicePixelSnapped(Rect& aRect, const Matrix& aTransform)
 {
diff --git a/gfx/layers/ImageLayers.cpp b/gfx/layers/ImageLayers.cpp
index daabe084543d..0b699fbb7085 100644
--- a/gfx/layers/ImageLayers.cpp
+++ b/gfx/layers/ImageLayers.cpp
@@ -38,8 +38,8 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSu
         sourceRect.width != 0.0 && sourceRect.height != 0.0) {
       NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
                    "No other scalemodes than stretch and none supported yet.");
-      local.Scale(mScaleToSize.width / sourceRect.width,
-                  mScaleToSize.height / sourceRect.height, 1.0);
+      local.PreScale(mScaleToSize.width / sourceRect.width,
+                     mScaleToSize.height / sourceRect.height, 1.0);
     }
   }
   // Snap our local transform first, and snap the inherited transform as well.
diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp
index bf5e26b516e3..5c5179401319 100644
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -467,7 +467,7 @@ LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFu
 void
 LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset)
 {
-  mTransform.TranslatePost(aOffset.x, aOffset.y, 0);
+  mTransform.PostTranslate(aOffset.x, aOffset.y, 0);
 }
 
 } // namespace layers
diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp
index 364f2daf31ab..67ea78c9c403 100644
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -717,7 +717,7 @@ Layer::GetTransform() const
   Matrix4x4 transform = mTransform;
   transform.PostScale(mPostXScale, mPostYScale, 1.0f);
   if (const ContainerLayer* c = AsContainerLayer()) {
-    transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
+    transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   }
   return transform;
 }
@@ -733,7 +733,7 @@ Layer::GetLocalTransform()
 
   transform.PostScale(mPostXScale, mPostYScale, 1.0f);
   if (ContainerLayer* c = AsContainerLayer()) {
-    transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
+    transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   }
 
   return transform;
diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp
index 2d46e60fe797..a79acb42089c 100644
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -174,9 +174,9 @@ TranslateShadowLayer2D(Layer* aLayer,
   // transform, we must apply the inverse resolution scale here.
   Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
   if (ContainerLayer* c = aLayer->AsContainerLayer()) {
-    layerTransform3D.Scale(1.0f/c->GetPreXScale(),
-                           1.0f/c->GetPreYScale(),
-                           1);
+    layerTransform3D.PreScale(1.0f/c->GetPreXScale(),
+                              1.0f/c->GetPreYScale(),
+                              1);
   }
   layerTransform3D.PostScale(1.0f/aLayer->GetPostXScale(),
                              1.0f/aLayer->GetPostYScale(),
@@ -620,9 +620,9 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
     // will apply the pre- and post-scale again when computing the effective
     // transform, we must apply the inverses here.
     if (ContainerLayer* container = aLayer->AsContainerLayer()) {
-      transform.Scale(1.0f/container->GetPreXScale(),
-                      1.0f/container->GetPreYScale(),
-                      1);
+      transform.PreScale(1.0f/container->GetPreXScale(),
+                         1.0f/container->GetPreYScale(),
+                         1);
     }
     transform.PostScale(1.0f/aLayer->GetPostXScale(),
                         1.0f/aLayer->GetPostYScale(),
@@ -639,7 +639,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
     // bottom-most scrollable metrics because that should have the most accurate
     // cumulative resolution for aLayer.
     LayoutDeviceToLayerScale resolution = bottom.mCumulativeResolution;
-    oldTransform.Scale(resolution.scale, resolution.scale, 1);
+    oldTransform.PreScale(resolution.scale, resolution.scale, 1);
 
     // For the purpose of aligning fixed and sticky layers, we disregard
     // the overscroll transform when computing the 'aCurrentTransformForRoot'
@@ -767,9 +767,9 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
   // will apply the pre- and post-scale again when computing the effective
   // transform, we must apply the inverses here.
   if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
-    transform.Scale(1.0f/container->GetPreXScale(),
-                    1.0f/container->GetPreYScale(),
-                    1);
+    transform.PreScale(1.0f/container->GetPreXScale(),
+                       1.0f/container->GetPreYScale(),
+                        1);
   }
   transform.PostScale(1.0f/aScrollbar->GetPostXScale(),
                       1.0f/aScrollbar->GetPostYScale(),
@@ -914,11 +914,11 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
   // transform, we must apply the inverse resolution scale here.
   Matrix4x4 computedTransform = oldTransform * treeTransform;
   if (ContainerLayer* container = aLayer->AsContainerLayer()) {
-    computedTransform.Scale(1.0f/container->GetPreXScale(),
-                            1.0f/container->GetPreYScale(),
-                            1);
+    computedTransform.PreScale(1.0f/container->GetPreXScale(),
+                               1.0f/container->GetPreYScale(),
+                               1);
   }
-  computedTransform.ScalePost(1.0f/aLayer->GetPostXScale(),
+  computedTransform.PostScale(1.0f/aLayer->GetPostXScale(),
                               1.0f/aLayer->GetPostYScale(),
                               1);
   layerComposite->SetShadowTransform(computedTransform);
@@ -927,7 +927,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
 
   // Apply resolution scaling to the old transform - the layer tree as it is
   // doesn't have the necessary transform to display correctly.
-  oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
+  oldTransform.PreScale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
 
   // Make sure that overscroll and under-zoom are represented in the old
   // transform so that fixed position content moves and scales accordingly.
@@ -948,9 +948,9 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
     overscrollTranslation.y = contentScreenRect.YMost() -
       (userScroll.y + metrics.mCompositionBounds.height);
   }
-  oldTransform.Translate(overscrollTranslation.x,
-                         overscrollTranslation.y,
-                         overscrollTranslation.z);
+  oldTransform.PreTranslate(overscrollTranslation.x,
+                            overscrollTranslation.y,
+                            overscrollTranslation.z);
 
   gfx::Size underZoomScale(1.0f, 1.0f);
   if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) {
@@ -961,7 +961,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
     underZoomScale.height = (mContentRect.height * userZoom.scale) /
       metrics.mCompositionBounds.height;
   }
-  oldTransform.Scale(underZoomScale.width, underZoomScale.height, 1);
+  oldTransform.PreScale(underZoomScale.width, underZoomScale.height, 1);
 
   // Make sure fixed position layers don't move away from their anchor points
   // when we're asynchronously panning or zooming
diff --git a/gfx/layers/composite/FPSCounter.cpp b/gfx/layers/composite/FPSCounter.cpp
index 81c6ff8d124a..f03eb778b5a3 100644
--- a/gfx/layers/composite/FPSCounter.cpp
+++ b/gfx/layers/composite/FPSCounter.cpp
@@ -383,7 +383,7 @@ static void DrawDigits(unsigned int aValue,
   float textureWidth = FontWidth * 10;
   gfx::Float opacity = 1;
   gfx::Matrix4x4 transform;
-  transform.Scale(FontScaleX, FontScaleY, 1);
+  transform.PreScale(FontScaleX, FontScaleY, 1);
 
   for (size_t n = 0; n < 3; ++n) {
     unsigned int digit = aValue % (divisor * 10) / divisor;
diff --git a/gfx/layers/composite/ImageLayerComposite.cpp b/gfx/layers/composite/ImageLayerComposite.cpp
index 99d7b491b961..d91a49d1197d 100644
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -129,8 +129,8 @@ ImageLayerComposite::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransform
         sourceRect.width != 0.0 && sourceRect.height != 0.0) {
       NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
                    "No other scalemodes than stretch and none supported yet.");
-      local.Scale(mScaleToSize.width / sourceRect.width,
-                  mScaleToSize.height / sourceRect.height, 1.0);
+      local.PreScale(mScaleToSize.width / sourceRect.width,
+                     mScaleToSize.height / sourceRect.height, 1.0);
     }
   }
   // Snap our local transform first, and snap the inherited transform as well.
diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp
index 541e82051363..caed637c50dd 100644
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -855,7 +855,7 @@ LayerManagerComposite::ComputeRenderIntegrity()
     Layer* rootScrollable = rootScrollableLayers[0];
     const FrameMetrics& metrics = LayerMetricsWrapper::TopmostScrollableMetrics(rootScrollable);
     Matrix4x4 transform = rootScrollable->GetEffectiveTransform();
-    transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
+    transform.PostScale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
 
     // Clip the screen rect to the document bounds
     Rect documentBounds =
diff --git a/gfx/layers/composite/TextRenderer.cpp b/gfx/layers/composite/TextRenderer.cpp
index 873fcf039a11..99e007a82eab 100644
--- a/gfx/layers/composite/TextRenderer.cpp
+++ b/gfx/layers/composite/TextRenderer.cpp
@@ -134,7 +134,7 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
   chain.mPrimaryEffect = effect;
 
   Matrix4x4 transform = aTransform;
-  transform.Scale(scaleFactor, scaleFactor, 1.0f);
+  transform.PreScale(scaleFactor, scaleFactor, 1.0f);
   mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16),
                         Rect(-10000, -10000, 20000, 20000), chain, 1.0f, transform);
 }
diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp
index 615ebabc14ea..0d7cdb400dd2 100644
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -556,8 +556,8 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
 
   // Make sure the resolution and difference in frame resolution are accounted
   // for in the layer transform.
-  aTransform.Scale(1/(resolution * layerScale.width),
-                   1/(resolution * layerScale.height), 1);
+  aTransform.PreScale(1/(resolution * layerScale.width),
+                      1/(resolution * layerScale.height), 1);
 
   uint32_t rowCount = 0;
   uint32_t tileX = 0;
diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp
index 1768203afca5..590399be7bba 100644
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -670,7 +670,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
   Matrix4x4 transform = layer->AsLayerComposite()->GetShadowTransform();
   if (ContainerLayer* c = layer->AsContainerLayer()) {
     // Undo the scale transform applied by AsyncCompositionManager::SampleValue
-    transform.ScalePost(1.0f/c->GetInheritedXScale(),
+    transform.PostScale(1.0f/c->GetInheritedXScale(),
                         1.0f/c->GetInheritedYScale(),
                         1.0f);
   }
@@ -694,7 +694,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
 
   // Undo the translation to the origin of the reference frame applied by
   // AsyncCompositionManager::SampleValue
-  transform.Translate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
+  transform.PreTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
 
   // Undo the rebasing applied by
   // nsDisplayTransform::GetResultingTransformMatrixInternal
diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp
index 116b8fc15672..07b349024fc6 100644
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -494,7 +494,7 @@ ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker
 bool
 ShadowLayerForwarder::InWorkerThread()
 {
-  return GetMessageLoop()->id() == MessageLoop::current()->id();
+  return MessageLoop::current() && (GetMessageLoop()->id() == MessageLoop::current()->id());
 }
 
 static void RemoveTextureWorker(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone)
diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
index 690e935f5df4..09faa68b8ca7 100644
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -698,8 +698,8 @@ TEST_F(APZCBasicTester, ComplexTransform) {
     Matrix4x4(),
     Matrix4x4(),
   };
-  transforms[0].ScalePost(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
-  transforms[1].ScalePost(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
+  transforms[0].PostScale(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
+  transforms[1].PostScale(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
 
   nsTArray > layers;
   nsRefPtr lm;
diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp
index 5be6e24ccd9c..a9de345e9535 100644
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -88,7 +88,6 @@ gfxContext::gfxContext(DrawTarget *aTarget, const Point& aDeviceOffset)
   : mPathIsRect(false)
   , mTransformChanged(false)
   , mRefCairo(nullptr)
-  , mSurface(nullptr)
   , mFlags(0)
   , mDT(aTarget)
   , mOriginalDT(aTarget)
@@ -130,24 +129,6 @@ gfxContext::~gfxContext()
   MOZ_COUNT_DTOR(gfxContext);
 }
 
-gfxASurface *
-gfxContext::OriginalSurface()
-{
-    if (mSurface) {
-        return mSurface;
-    }
-
-    if (mOriginalDT && mOriginalDT->GetBackendType() == BackendType::CAIRO) {
-        cairo_surface_t *s =
-            (cairo_surface_t*)mOriginalDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
-        if (s) {
-            mSurface = gfxASurface::Wrap(s);
-            return mSurface;
-        }
-    }
-    return nullptr;
-}
-
 already_AddRefed
 gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy)
 {
diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h
index ce4653e5d22d..e5a1bd690ed2 100644
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -60,11 +60,6 @@ public:
      */
     static already_AddRefed ContextForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
 
-    /**
-     * Return the surface that this gfxContext was created with
-     */
-    gfxASurface *OriginalSurface();
-
     /**
      * Return the current transparency group target, if any, along
      * with its device offsets from the top.  If no group is
@@ -517,10 +512,6 @@ public:
      * how drawing something will modify the destination. For example, the
      * OVER operator will do alpha blending of source and destination, while
      * SOURCE will replace the destination with the source.
-     *
-     * Note that if the flag FLAG_SIMPLIFY_OPERATORS is set on this
-     * gfxContext, the actual operator set might change for optimization
-     * purposes.  Check the comments below around that flag.
      */
     void SetOperator(GraphicsOperator op);
     GraphicsOperator CurrentOperator() const;
@@ -593,32 +584,12 @@ public:
 
     mozilla::gfx::Point GetDeviceOffset() const;
 
-    /**
-     ** Flags
-     **/
-
     enum {
-        /* If this flag is set, operators other than CLEAR, SOURCE, or
-         * OVER will be converted to OVER before being sent to cairo.
-         *
-         * This is most useful with a printing surface, where
-         * operators such as ADD are used to avoid seams for on-screen
-         * display, but where such errors aren't noticeable in print.
-         * This approach is currently used in border rendering.
-         *
-         * However, when printing complex renderings such as SVG,
-         * care should be taken to clear this flag.
-         */
-        FLAG_SIMPLIFY_OPERATORS = (1 << 0),
-        /**
+         /**
          * When this flag is set, snapping to device pixels is disabled.
          * It simply never does anything.
          */
         FLAG_DISABLE_SNAPPING = (1 << 1),
-        /**
-         * Disable copying of backgrounds in PushGroupAndCopyBackground.
-         */
-        FLAG_DISABLE_COPY_BACKGROUND = (1 << 2)
     };
 
     void SetFlag(int32_t aFlag) { mFlags |= aFlag; }
@@ -732,7 +703,6 @@ private:
   const AzureState &CurrentState() const { return mStateStack[mStateStack.Length() - 1]; }
 
   cairo_t *mRefCairo;
-  nsRefPtr mSurface;
   int32_t mFlags;
 
   mozilla::RefPtr mDT;
@@ -906,15 +876,12 @@ public:
     }
     ~gfxContextAutoDisableSubpixelAntialiasing()
     {
-        if (mSurface) {
-            mSurface->SetSubpixelAntialiasingEnabled(mSubpixelAntialiasingEnabled);
-        } else if (mDT) {
+        if (mDT) {
             mDT->SetPermitSubpixelAA(mSubpixelAntialiasingEnabled);
         }
     }
 
 private:
-    nsRefPtr mSurface;
     mozilla::RefPtr mDT;
     bool mSubpixelAntialiasingEnabled;
 };
diff --git a/image/public/imgILoader.idl b/image/public/imgILoader.idl
index cf751632aae7..491eda22ae63 100644
--- a/image/public/imgILoader.idl
+++ b/image/public/imgILoader.idl
@@ -16,7 +16,6 @@ interface nsIStreamListener;
 interface nsIURI;
 
 interface nsISimpleEnumerator;
-interface nsIChannelPolicy;
 
 #include "nsIRequest.idl" // for nsLoadFlags
 
@@ -27,7 +26,7 @@ interface nsIChannelPolicy;
  * @version 0.3
  * @see imagelib2
  */
-[scriptable, builtinclass, uuid(c8126129-8dac-43cd-b1ba-3896fba2dd01)]
+[scriptable, builtinclass, uuid(046d5fa6-ac59-489d-b51e-0ffe57e8df59)]
 interface imgILoader : nsISupports
 {
   // Extra flags to pass to loadImage if you want a load to use CORS
@@ -62,8 +61,7 @@ interface imgILoader : nsISupports
                              in imgINotificationObserver aObserver,
                              in nsISupports aCX,
                              in nsLoadFlags aLoadFlags,
-                             in nsISupports cacheKey,
-                             in nsIChannelPolicy channelPolicy);
+                             in nsISupports cacheKey);
 
   /**
    * Start the load and decode of an image.
diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp
index 4694958b0cc2..24664b063901 100644
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -20,6 +20,7 @@ Decoder::Decoder(RasterImage &aImage)
   , mImageData(nullptr)
   , mColormap(nullptr)
   , mDecodeFlags(0)
+  , mBytesDecoded(0)
   , mDecodeDone(false)
   , mDataError(false)
   , mFrameCount(0)
@@ -93,8 +94,11 @@ Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
   MOZ_ASSERT(NS_IsMainThread() || aStrategy == DECODE_ASYNC);
 
   // We're strict about decoder errors
-  NS_ABORT_IF_FALSE(!HasDecoderError(),
-                    "Not allowed to make more decoder calls after error!");
+  MOZ_ASSERT(!HasDecoderError(),
+             "Not allowed to make more decoder calls after error!");
+
+  // Keep track of the total number of bytes written.
+  mBytesDecoded += aCount;
 
   // If a data error occured, just ignore future data
   if (HasDataError())
diff --git a/image/src/Decoder.h b/image/src/Decoder.h
index 9cd4b8bc8084..077f8f5ed85c 100644
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -101,6 +101,8 @@ public:
     mObserver = aObserver;
   }
 
+  size_t BytesDecoded() const { return mBytesDecoded; }
+
   // The number of frames we have, including anything in-progress. Thus, this
   // is only 0 if we haven't begun any frames.
   uint32_t GetFrameCount() { return mFrameCount; }
@@ -234,6 +236,7 @@ protected:
   uint32_t mColormapSize;
 
   uint32_t mDecodeFlags;
+  size_t mBytesDecoded;
   bool mDecodeDone;
   bool mDataError;
 
diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp
index 09f2beb81f00..05307d6117d0 100644
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -62,7 +62,9 @@ using namespace gfx;
 using namespace layers;
 
 namespace image {
+
 using std::ceil;
+using std::min;
 
 // a mask for flags that will affect the decoding
 #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
@@ -319,7 +321,6 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
 #endif
   mDecodingMonitor("RasterImage Decoding Monitor"),
   mDecoder(nullptr),
-  mBytesDecoded(0),
   mInDecoder(false),
   mStatusDiff(ImageStatusDiff::NoChange()),
   mNotifying(false),
@@ -1535,7 +1536,7 @@ RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
   // Starting a new part's frames, let's clean up before we add any
   // This needs to happen just before we start getting EnsureFrame() call(s),
   // so that there's no gap for anything to miss us.
-  if (mMultipart && mBytesDecoded == 0) {
+  if (mMultipart && (!mDecoder || mDecoder->BytesDecoded() == 0)) {
     // Our previous state may have been animated, so let's clean up
     if (mAnimating)
       StopAnimation();
@@ -2095,8 +2096,6 @@ RasterImage::ShutdownDecoder(eShutdownIntent aIntent)
     mSourceData.Clear();
   }
 
-  mBytesDecoded = 0;
-
   return NS_OK;
 }
 
@@ -2117,10 +2116,6 @@ RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy
 
   CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
 
-  // Keep track of the total number of bytes written over the lifetime of the
-  // decoder
-  mBytesDecoded += aCount;
-
   return NS_OK;
 }
 
@@ -2252,7 +2247,7 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
   // If we've already got a full decoder running, and have already decoded
   // some bytes, we have nothing to do if we haven't been asked to do some
   // sync decoding
-  if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded &&
+  if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0 &&
       aDecodeType != SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
     return NS_OK;
   }
@@ -2260,10 +2255,11 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
 
   // If we don't have any bytes to flush to the decoder, we can't do anything.
-  // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
-  // the source data.
-  if (mBytesDecoded > mSourceData.Length())
+  // mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're
+  // not storing the source data.
+  if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) {
     return NS_OK;
+  }
 
   // After acquiring the lock we may have finished some more decoding, so
   // we need to repeat the following three checks after getting the lock.
@@ -2285,8 +2281,8 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
   }
 
   // If we've already got a full decoder running, and have already
-  // decoded some bytes, we have nothing to do
-  if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded) {
+  // decoded some bytes, we have nothing to do.
+  if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0) {
     return NS_OK;
   }
 
@@ -2304,13 +2300,14 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
 
     rv = FinishedSomeDecoding();
     CONTAINER_ENSURE_SUCCESS(rv);
-
-    MOZ_ASSERT(mDecoder);
   }
 
+  MOZ_ASSERT(mDecoder);
+
   // If we've read all the data we have, we're done
-  if (mHasSourceData && mBytesDecoded == mSourceData.Length())
+  if (mHasSourceData && mDecoder->BytesDecoded() == mSourceData.Length()) {
     return NS_OK;
+  }
 
   // If we can do decoding now, do so.  Small images will decode completely,
   // large images will decode a bit and post themselves to the event loop
@@ -2377,10 +2374,11 @@ RasterImage::SyncDecode()
     return NS_OK;
 
   // If we don't have any bytes to flush to the decoder, we can't do anything.
-  // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
-  // the source data.
-  if (mBytesDecoded > mSourceData.Length())
+  // mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're
+  // not storing the source data.
+  if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) {
     return NS_OK;
+  }
 
   // If we have a decoder open with different flags than what we need, shut it
   // down
@@ -2411,8 +2409,11 @@ RasterImage::SyncDecode()
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
+  MOZ_ASSERT(mDecoder);
+
   // Write everything we have
-  rv = DecodeSomeData(mSourceData.Length() - mBytesDecoded, DECODE_SYNC);
+  rv = DecodeSomeData(mSourceData.Length() - mDecoder->BytesDecoded(),
+                      DECODE_SYNC);
   CONTAINER_ENSURE_SUCCESS(rv);
 
   // When we're doing a sync decode, we want to get as much information from the
@@ -2772,8 +2773,7 @@ RasterImage::RequestDiscard()
 nsresult
 RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy)
 {
-  // We should have a decoder if we get here
-  NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
+  MOZ_ASSERT(mDecoder, "Should have a decoder");
 
   mDecodingMonitor.AssertCurrentThreadIn();
 
@@ -2788,20 +2788,20 @@ RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy)
     }
   }
 
-  // If we have nothing else to decode, return
-  if (mBytesDecoded == mSourceData.Length())
+  // If we have nothing else to decode, return.
+  if (mDecoder->BytesDecoded() == mSourceData.Length()) {
     return NS_OK;
+  }
 
-  MOZ_ASSERT(mBytesDecoded < mSourceData.Length());
+  MOZ_ASSERT(mDecoder->BytesDecoded() < mSourceData.Length());
 
   // write the proper amount of data
-  size_t bytesToDecode = std::min(aMaxBytes,
-                                  mSourceData.Length() - mBytesDecoded);
-  nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
-                               bytesToDecode,
-                               aStrategy);
+  size_t bytesToDecode = min(aMaxBytes,
+                             mSourceData.Length() - mDecoder->BytesDecoded());
+  return WriteToDecoder(mSourceData.Elements() + mDecoder->BytesDecoded(),
+                        bytesToDecode,
+                        aStrategy);
 
-  return rv;
 }
 
 // There are various indicators that tell us we're finished with the decode
@@ -2813,7 +2813,7 @@ RasterImage::IsDecodeFinished()
 {
   // Precondition
   mDecodingMonitor.AssertCurrentThreadIn();
-  NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!");
+  MOZ_ASSERT(mDecoder, "Should have a decoder");
 
   // The decode is complete if we got what we wanted.
   if (mDecoder->IsSizeDecode()) {
@@ -2838,7 +2838,7 @@ RasterImage::IsDecodeFinished()
   // (NB - This can be the case even for non-erroneous images because
   // Decoder::GetDecodeDone() might not return true until after we call
   // Decoder::Finish() in ShutdownDecoder())
-  if (mHasSourceData && (mBytesDecoded == mSourceData.Length())) {
+  if (mHasSourceData && (mDecoder->BytesDecoded() == mSourceData.Length())) {
     return true;
   }
 
@@ -3031,7 +3031,7 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
         // SpeedHistogram return HistogramCount.
         Telemetry::ID id = decoder->SpeedHistogram();
         if (id < Telemetry::HistogramCount) {
-          int32_t KBps = int32_t(request->mImage->mBytesDecoded /
+          int32_t KBps = int32_t(decoder->BytesDecoded() /
                                  (1024 * request->mDecodeTime.ToSeconds()));
           Telemetry::Accumulate(id, KBps);
         }
@@ -3207,7 +3207,8 @@ RasterImage::DecodePool::RequestDecode(RasterImage* aImg)
   if (!aImg->mDecoder->NeedsNewFrame()) {
     // No matter whether this is currently being decoded, we need to update the
     // number of bytes we want it to decode.
-    aImg->mDecodeRequest->mBytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
+    aImg->mDecodeRequest->mBytesToDecode =
+      aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded();
 
     if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING ||
         aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) {
@@ -3255,7 +3256,7 @@ RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrateg
     if (aImg->mDecoder &&
         !aImg->mError &&
         !aImg->IsDecodeFinished() &&
-        aImg->mSourceData.Length() > aImg->mBytesDecoded) {
+        aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded()) {
       RequestDecode(aImg);
     }
   }
@@ -3299,7 +3300,7 @@ RasterImage::DecodePool::DecodeJob::Run()
 
   mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE;
 
-  size_t oldByteCount = mImage->mBytesDecoded;
+  size_t oldByteCount = mImage->mDecoder->BytesDecoded();
 
   DecodeType type = DECODE_TYPE_UNTIL_DONE_BYTES;
 
@@ -3311,7 +3312,7 @@ RasterImage::DecodePool::DecodeJob::Run()
 
   DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, type, mRequest->mBytesToDecode);
 
-  size_t bytesDecoded = mImage->mBytesDecoded - oldByteCount;
+  size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount;
 
   mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE;
 
@@ -3442,7 +3443,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
   }
 
   if (bytesToDecode == 0) {
-    bytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
+    bytesToDecode = aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded();
   }
 
   int32_t chunkCount = 0;
@@ -3456,7 +3457,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
   //  * we run out of time.
   // We also try to decode at least one "chunk" if we've allocated a new frame,
   // even if we have no more data to send to the decoder.
-  while ((aImg->mSourceData.Length() > aImg->mBytesDecoded &&
+  while ((aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded() &&
           bytesToDecode > 0 &&
           !aImg->IsDecodeFinished() &&
           !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) &&
diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h
index 2ef4899ad6b6..9dd2cde72c8d 100644
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -656,7 +656,6 @@ private: // data
   // Decoder and friends
   nsRefPtr          mDecoder;
   nsRefPtr    mDecodeRequest;
-  size_t                     mBytesDecoded;
 
   bool                       mInDecoder;
   // END LOCKED MEMBER VARIABLES
diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
index 0ac8d497a9dc..a96e00796d4c 100644
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -635,7 +635,6 @@ static nsresult NewImageChannel(nsIChannel **aResult,
                                 nsILoadGroup *aLoadGroup,
                                 const nsCString& aAcceptHeader,
                                 nsLoadFlags aLoadFlags,
-                                nsIChannelPolicy *aPolicy,
                                 nsIPrincipal *aLoadingPrincipal,
                                 nsISupports *aRequestingContext)
 {
@@ -691,7 +690,6 @@ static nsresult NewImageChannel(nsIChannel **aResult,
                              requestingPrincipal,
                              securityFlags,
                              nsIContentPolicy::TYPE_IMAGE,
-                             aPolicy,
                              nullptr,   // loadGroup
                              callbacks,
                              aLoadFlags);
@@ -1445,7 +1443,6 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
                                                 nsISupports *aCX,
                                                 nsLoadFlags aLoadFlags,
                                                 imgRequestProxy **aProxyRequest,
-                                                nsIChannelPolicy *aPolicy,
                                                 nsIPrincipal* aLoadingPrincipal,
                                                 int32_t aCORSMode)
 {
@@ -1493,7 +1490,6 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
                          aLoadGroup,
                          mAcceptHeader,
                          aLoadFlags,
-                         aPolicy,
                          aLoadingPrincipal,
                          aCX);
     if (NS_FAILED(rv)) {
@@ -1573,7 +1569,6 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
                                 nsLoadFlags aLoadFlags,
                                 bool aCanMakeNewChannel,
                                 imgRequestProxy **aProxyRequest,
-                                nsIChannelPolicy *aPolicy,
                                 nsIPrincipal* aLoadingPrincipal,
                                 int32_t aCORSMode)
 {
@@ -1678,7 +1673,7 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
 
     return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
                                          aReferrerURI, aLoadGroup, aObserver,
-                                         aCX, aLoadFlags, aProxyRequest, aPolicy,
+                                         aCX, aLoadFlags, aProxyRequest,
                                          aLoadingPrincipal, aCORSMode);
   }
 
@@ -1853,7 +1848,6 @@ NS_IMETHODIMP imgLoader::LoadImageXPCOM(nsIURI *aURI,
                                    nsISupports *aCX,
                                    nsLoadFlags aLoadFlags,
                                    nsISupports *aCacheKey,
-                                   nsIChannelPolicy *aPolicy,
                                    imgIRequest **_retval)
 {
     imgRequestProxy *proxy;
@@ -1866,29 +1860,32 @@ NS_IMETHODIMP imgLoader::LoadImageXPCOM(nsIURI *aURI,
                                 aCX,
                                 aLoadFlags,
                                 aCacheKey,
-                                aPolicy,
                                 EmptyString(),
                                 &proxy);
     *_retval = proxy;
     return result;
 }
 
-
-
-/* imgIRequest loadImage(in nsIURI aURI, in nsIURI aInitialDocumentURL, in nsIURI aReferrerURI, in nsIPrincipal aLoadingPrincipal, in nsILoadGroup aLoadGroup, in imgINotificationObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in nsIChannelPolicy channelPolicy); */
-
+// imgIRequest loadImage(in nsIURI aURI,
+//                       in nsIURI aInitialDocumentURL,
+//                       in nsIURI aReferrerURI,
+//                       in nsIPrincipal aLoadingPrincipal,
+//                       in nsILoadGroup aLoadGroup,
+//                       in imgINotificationObserver aObserver,
+//                       in nsISupports aCX,
+//                       in nsLoadFlags aLoadFlags,
+//                       in nsISupports cacheKey);
 nsresult imgLoader::LoadImage(nsIURI *aURI,
-			      nsIURI *aInitialDocumentURI,
-			      nsIURI *aReferrerURI,
-			      nsIPrincipal* aLoadingPrincipal,
-			      nsILoadGroup *aLoadGroup,
-			      imgINotificationObserver *aObserver,
-			      nsISupports *aCX,
-			      nsLoadFlags aLoadFlags,
-			      nsISupports *aCacheKey,
-			      nsIChannelPolicy *aPolicy,
-			      const nsAString& initiatorType,
-			      imgRequestProxy **_retval)
+                              nsIURI *aInitialDocumentURI,
+                              nsIURI *aReferrerURI,
+                              nsIPrincipal* aLoadingPrincipal,
+                              nsILoadGroup *aLoadGroup,
+                              imgINotificationObserver *aObserver,
+                              nsISupports *aCX,
+                              nsLoadFlags aLoadFlags,
+                              nsISupports *aCacheKey,
+                              const nsAString& initiatorType,
+                              imgRequestProxy **_retval)
 {
 	VerifyCacheSizes();
 
@@ -1966,7 +1963,7 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
   if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
     if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
                       aLoadGroup, aObserver, aCX, requestFlags, true,
-                      _retval, aPolicy, aLoadingPrincipal, corsmode)) {
+                      _retval, aLoadingPrincipal, corsmode)) {
       request = entry->GetRequest();
 
       // If this entry has no proxies, its request has no reference to the entry.
@@ -2008,7 +2005,6 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
                          aLoadGroup,
                          mAcceptHeader,
                          requestFlags,
-                         aPolicy,
                          aLoadingPrincipal,
                          aCX);
     if (NS_FAILED(rv))
@@ -2192,7 +2188,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel *channel, imgINotificationOb
       // XXX -- should this be changed? it's pretty much verbatim from the old
       // code, but seems nonsensical.
       if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver, aCX,
-                        requestFlags, false, nullptr, nullptr, nullptr,
+                        requestFlags, false, nullptr, nullptr,
                         imgIRequest::CORS_NONE)) {
         request = entry->GetRequest();
       } else {
diff --git a/image/src/imgLoader.h b/image/src/imgLoader.h
index 334a3a16b260..620457651086 100644
--- a/image/src/imgLoader.h
+++ b/image/src/imgLoader.h
@@ -29,7 +29,6 @@ class imgINotificationObserver;
 class nsILoadGroup;
 class imgCacheExpirationTracker;
 class imgMemoryReporter;
-class nsIChannelPolicy;
 
 namespace mozilla {
 namespace image {
@@ -258,7 +257,6 @@ public:
                      nsISupports *aCX,
                      nsLoadFlags aLoadFlags,
                      nsISupports *aCacheKey,
-                     nsIChannelPolicy *aPolicy,
                      const nsAString& initiatorType,
                      imgRequestProxy **_retval);
   nsresult LoadImageWithChannel(nsIChannel *channel,
@@ -340,7 +338,6 @@ private: // methods
                        imgINotificationObserver *aObserver, nsISupports *aCX,
                        nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
                        imgRequestProxy **aProxyRequest,
-                       nsIChannelPolicy *aPolicy,
                        nsIPrincipal* aLoadingPrincipal,
                        int32_t aCORSMode);
 
@@ -351,7 +348,6 @@ private: // methods
                                        imgINotificationObserver *aObserver,
                                        nsISupports *aCX, nsLoadFlags aLoadFlags,
                                        imgRequestProxy **aProxyRequest,
-                                       nsIChannelPolicy *aPolicy,
                                        nsIPrincipal* aLoadingPrincipal,
                                        int32_t aCORSMode);
 
diff --git a/image/test/unit/async_load_tests.js b/image/test/unit/async_load_tests.js
index 970ae812ee86..c4cdcd0730c0 100644
--- a/image/test/unit/async_load_tests.js
+++ b/image/test/unit/async_load_tests.js
@@ -96,7 +96,7 @@ function checkSecondLoad()
   var listener = new ImageListener(checkClone, secondLoadDone);
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                 .createScriptedObserver(listener);
-  requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null));
+  requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null));
   listener.synchronous = false;
 }
 
@@ -194,7 +194,7 @@ function startImageCallback(otherCb)
     var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); });
     var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                   .createScriptedObserver(listener2);
-    requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null));
+    requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null));
     listener2.synchronous = false;
 
     // Now that we've started another load, chain to the callback.
@@ -221,7 +221,7 @@ function run_test()
   var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone);
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                 .createScriptedObserver(listener);
-  var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null);
+  var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null);
   requests.push(req);
 
   // Ensure that we don't cause any mayhem when we lock an image.
diff --git a/image/test/unit/test_private_channel.js b/image/test/unit/test_private_channel.js
index 36aa8ee784c5..318dece2afa1 100644
--- a/image/test/unit/test_private_channel.js
+++ b/image/test/unit/test_private_channel.js
@@ -77,7 +77,7 @@ function loadImage(isPrivate, callback) {
   var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
   loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate);
   var loader = isPrivate ? gPrivateLoader : gPublicLoader;
-  requests.push(loader.loadImageXPCOM(uri, null, null, null, loadGroup, outer, null, 0, null, null));
+  requests.push(loader.loadImageXPCOM(uri, null, null, null, loadGroup, outer, null, 0, null));
   listener.synchronous = false;
 }
 
diff --git a/js/public/UbiNodeTraverse.h b/js/public/UbiNodeTraverse.h
index d64e02726951..e5a2a33b233e 100644
--- a/js/public/UbiNodeTraverse.h
+++ b/js/public/UbiNodeTraverse.h
@@ -95,6 +95,15 @@ struct BreadthFirst {
     // as many starting points as you like. Return false on OOM.
     bool addStart(Node node) { return pending.append(node); }
 
+    // Add |node| as a starting point for the traversal (see addStart) and also
+    // add it to the |visited| set. Return false on OOM.
+    bool addStartVisited(Node node) {
+        typename NodeMap::AddPtr ptr = visited.lookupForAdd(node);
+        if (!ptr && !visited.add(ptr, node, typename Handler::NodeData()))
+            return false;
+        return addStart(node);
+    }
+
     // True if the handler wants us to compute edge names; doing so can be
     // expensive in time and memory. True by default.
     bool wantNames;
diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp
index 891dc01e7f07..f7dec84460ee 100644
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -472,6 +472,14 @@ LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle module.maxHeapLength()) {
+        ScopedJSFreePtr msg(
+            JS_smprintf("ArrayBuffer byteLength 0x%x is greater than maximum length of 0x%x",
+                        heapLength,
+                        module.maxHeapLength()));
+        return LinkFail(cx, msg.get());
+    }
+
     // If we've generated the code with signal handlers in mind (for bounds
     // checks on x64 and for interrupt callback requesting on all platforms),
     // we need to be able to use signals at runtime. In particular, a module
@@ -493,7 +501,7 @@ LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handleruntime());
 
     HandleValue globalVal = args.get(0);
     HandleValue importVal = args.get(1);
@@ -571,11 +579,19 @@ ChangeHeap(JSContext *cx, AsmJSModule &module, CallArgs args)
 
     Rooted newBuffer(cx, &bufferArg.toObject().as());
     uint32_t heapLength = newBuffer->byteLength();
-    if (heapLength & module.heapLengthMask() || heapLength < module.minHeapLength()) {
+    if (heapLength & module.heapLengthMask() ||
+        heapLength < module.minHeapLength() ||
+        heapLength > module.maxHeapLength())
+    {
         args.rval().set(BooleanValue(false));
         return true;
     }
 
+    if (!module.hasArrayView()) {
+        args.rval().set(BooleanValue(true));
+        return true;
+    }
+
     MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength));
     MOZ_ASSERT(!IsDeprecatedAsmJSHeapLength(heapLength));
 
@@ -678,15 +694,14 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
         }
     }
 
-    // An asm.js module is specialized to its heap's base address and length
-    // which is normally immutable except for the neuter operation that occurs
-    // when an ArrayBuffer is transfered. Throw an internal error if we're
-    // about to run with a neutered heap.
-    if (module.maybeHeapBufferObject() &&
-        module.maybeHeapBufferObject()->is() &&
-        module.maybeHeapBufferObject()->as().isNeutered())
-    {
-        js_ReportOverRecursed(cx);
+    // The correct way to handle this situation would be to allocate a new range
+    // of PROT_NONE memory and module.changeHeap to this memory. That would
+    // cause every access to take the out-of-bounds signal-handler path which
+    // does the right thing. For now, just throw an out-of-memory exception
+    // since these can technically pop out anywhere and the full fix may
+    // actually OOM when trying to allocate the PROT_NONE memory.
+    if (module.hasDetachedHeap()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
         return false;
     }
 
diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp
index 572fe9f4b5b1..6db17357ec55 100644
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -54,6 +54,36 @@ using mozilla::PodEqual;
 using mozilla::Compression::LZ4;
 using mozilla::Swap;
 
+// At any time, the executable code of an asm.js module can be protected (as
+// part of RequestInterruptForAsmJSCode). When we touch the executable outside
+// of executing it (which the AsmJSFaultHandler will correctly handle), we need
+// to guard against this by unprotecting the code (if it has been protected) and
+// preventing it from being protected while we are touching it.
+class AutoUnprotectCode
+{
+    JSRuntime *rt_;
+    JSRuntime::AutoLockForInterrupt lock_;
+    const AsmJSModule &module_;
+    const bool protectedBefore_;
+
+  public:
+    AutoUnprotectCode(JSContext *cx, const AsmJSModule &module)
+      : rt_(cx->runtime()),
+        lock_(rt_),
+        module_(module),
+        protectedBefore_(module_.codeIsProtected(rt_))
+    {
+        if (protectedBefore_)
+            module_.unprotectCode(rt_);
+    }
+
+    ~AutoUnprotectCode()
+    {
+        if (protectedBefore_)
+            module_.protectCode(rt_);
+    }
+};
+
 static uint8_t *
 AllocateExecutableMemory(ExclusiveContext *cx, size_t bytes)
 {
@@ -78,6 +108,8 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t
     bufferArgumentName_(nullptr),
     code_(nullptr),
     interruptExit_(nullptr),
+    prevLinked_(nullptr),
+    nextLinked_(nullptr),
     dynamicallyLinked_(false),
     loadedFromCache_(false),
     profilingEnabled_(false),
@@ -88,6 +120,7 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t
     pod.funcPtrTableAndExitBytes_ = SIZE_MAX;
     pod.functionBytes_ = UINT32_MAX;
     pod.minHeapLength_ = RoundUpToNextValidAsmJSHeapLength(0);
+    pod.maxHeapLength_ = 0x80000000;
     pod.strict_ = strict;
     pod.usesSignalHandlers_ = canUseSignalHandlers;
 
@@ -115,6 +148,11 @@ AsmJSModule::~AsmJSModule()
 
     for (size_t i = 0; i < numFunctionCounts(); i++)
         js_delete(functionCounts(i));
+
+    if (prevLinked_)
+        *prevLinked_ = nextLinked_;
+    if (nextLinked_)
+        nextLinked_->prevLinked_ = prevLinked_;
 }
 
 void
@@ -446,6 +484,14 @@ AsmJSReportOverRecursed()
     js_ReportOverRecursed(cx);
 }
 
+static void
+OnDetached()
+{
+    // See hasDetachedHeap comment in LinkAsmJS.
+    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
+}
+
 static bool
 AsmJSHandleExecutionInterrupt()
 {
@@ -629,6 +675,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
         return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
       case AsmJSImm_ReportOverRecursed:
         return RedirectCall(FuncCast(AsmJSReportOverRecursed), Args_General0);
+      case AsmJSImm_OnDetached:
+        return RedirectCall(FuncCast(OnDetached), Args_General0);
       case AsmJSImm_HandleExecutionInterrupt:
         return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0);
       case AsmJSImm_InvokeFromAsmJS_Ignore:
@@ -836,6 +884,43 @@ AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer
     restoreHeapToInitialState(maybePrevBuffer);
 }
 
+bool
+AsmJSModule::detachHeap(JSContext *cx)
+{
+    MOZ_ASSERT(isDynamicallyLinked());
+    MOZ_ASSERT(maybeHeap_);
+
+    // Content JS should not be able to run (and detach heap) from within an
+    // interrupt callback, but in case it does, fail. Otherwise, the heap can
+    // change at an arbitrary instruction and break the assumption below.
+    if (interrupted_) {
+        JS_ReportError(cx, "attempt to detach from inside interrupt handler");
+        return false;
+    }
+
+    // Even if this->active(), to reach here, the activation must have called
+    // out via an FFI stub. FFI stubs check if heapDatum() is null on reentry
+    // and throw an exception if so.
+    MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_IonFFI ||
+                            activation()->exitReason() == AsmJSExit::Reason_SlowFFI);
+
+    AutoUnprotectCode auc(cx, *this);
+    restoreHeapToInitialState(maybeHeap_);
+
+    MOZ_ASSERT(hasDetachedHeap());
+    return true;
+}
+
+bool
+js::OnDetachAsmJSArrayBuffer(JSContext *cx, Handle buffer)
+{
+    for (AsmJSModule *m = cx->runtime()->linkedAsmJSModules; m; m = m->nextLinked()) {
+        if (buffer == m->maybeHeapBufferObject() && !m->detachHeap(cx))
+            return false;
+    }
+    return true;
+}
+
 static void
 AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj)
 {
@@ -1477,36 +1562,6 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
     return cursor;
 }
 
-// At any time, the executable code of an asm.js module can be protected (as
-// part of RequestInterruptForAsmJSCode). When we touch the executable outside
-// of executing it (which the AsmJSFaultHandler will correctly handle), we need
-// to guard against this by unprotecting the code (if it has been protected) and
-// preventing it from being protected while we are touching it.
-class AutoUnprotectCode
-{
-    JSRuntime *rt_;
-    JSRuntime::AutoLockForInterrupt lock_;
-    const AsmJSModule &module_;
-    const bool protectedBefore_;
-
-  public:
-    AutoUnprotectCode(JSContext *cx, const AsmJSModule &module)
-      : rt_(cx->runtime()),
-        lock_(rt_),
-        module_(module),
-        protectedBefore_(module_.codeIsProtected(rt_))
-    {
-        if (protectedBefore_)
-            module_.unprotectCode(rt_);
-    }
-
-    ~AutoUnprotectCode()
-    {
-        if (protectedBefore_)
-            module_.protectCode(rt_);
-    }
-};
-
 bool
 AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const
 {
@@ -1561,6 +1616,8 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) con
 bool
 AsmJSModule::changeHeap(Handle newHeap, JSContext *cx)
 {
+    MOZ_ASSERT(hasArrayView());
+
     // Content JS should not be able to run (and change heap) from within an
     // interrupt callback, but in case it does, fail to change heap. Otherwise,
     // the heap can change at every single instruction which would prevent
diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h
index 0bb8a38df398..4b7a464eebd0 100644
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -774,6 +774,7 @@ class AsmJSModule
         size_t                            codeBytes_;     // function bodies and stubs
         size_t                            totalBytes_;    // function bodies, stubs, and global data
         uint32_t                          minHeapLength_;
+        uint32_t                          maxHeapLength_;
         uint32_t                          heapLengthMask_;
         uint32_t                          numGlobalScalarVars_;
         uint32_t                          numGlobalSimdVars_;
@@ -818,6 +819,8 @@ class AsmJSModule
     uint8_t *                             interruptExit_;
     StaticLinkData                        staticLinkData_;
     HeapPtrArrayBufferObjectMaybeShared   maybeHeap_;
+    AsmJSModule **                        prevLinked_;
+    AsmJSModule *                         nextLinked_;
     bool                                  dynamicallyLinked_;
     bool                                  loadedFromCache_;
     bool                                  profilingEnabled_;
@@ -827,6 +830,10 @@ class AsmJSModule
     // Access must be synchronized via the runtime's interrupt lock.
     mutable bool                          codeIsProtected_;
 
+    void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer);
+    void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode,
+                               ExclusiveContext *cx);
+
   public:
     explicit AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t srcBodyStart,
                          bool strict, bool canUseSignalHandlers);
@@ -884,6 +891,9 @@ class AsmJSModule
     uint32_t minHeapLength() const {
         return pod.minHeapLength_;
     }
+    uint32_t maxHeapLength() const {
+        return pod.maxHeapLength_;
+    }
     uint32_t heapLengthMask() const {
         MOZ_ASSERT(pod.hasFixedMinHeapLength_);
         return pod.heapLengthMask_;
@@ -1044,19 +1054,28 @@ class AsmJSModule
     /*************************************************************************/
     // These functions are called while parsing/compiling function bodies:
 
-    void addChangeHeap(uint32_t mask, uint32_t min) {
+    bool hasArrayView() const {
+        MOZ_ASSERT(isFinishedWithModulePrologue());
+        return pod.hasArrayView_;
+    }
+    void addChangeHeap(uint32_t mask, uint32_t min, uint32_t max) {
         MOZ_ASSERT(isFinishedWithModulePrologue());
         MOZ_ASSERT(!pod.hasFixedMinHeapLength_);
         MOZ_ASSERT(IsValidAsmJSHeapLength(mask + 1));
         MOZ_ASSERT(min >= RoundUpToNextValidAsmJSHeapLength(0));
+        MOZ_ASSERT(max <= pod.maxHeapLength_);
+        MOZ_ASSERT(min <= max);
         pod.heapLengthMask_ = mask;
         pod.minHeapLength_ = min;
+        pod.maxHeapLength_ = max;
         pod.hasFixedMinHeapLength_ = true;
     }
     bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
         MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
         if (pod.hasFixedMinHeapLength_ && len > pod.minHeapLength_)
             return false;
+        if (len > pod.maxHeapLength_)
+            return false;
         len = RoundUpToNextValidAsmJSHeapLength(len);
         if (len > pod.minHeapLength_)
             pod.minHeapLength_ = len;
@@ -1228,10 +1247,6 @@ class AsmJSModule
     /*************************************************************************/
     // These accessor functions can be used after finish():
 
-    bool hasArrayView() const {
-        MOZ_ASSERT(isFinished());
-        return pod.hasArrayView_;
-    }
     unsigned numFFIs() const {
         MOZ_ASSERT(isFinished());
         return pod.numFFIs_;
@@ -1440,23 +1455,37 @@ class AsmJSModule
     // specializes it to a particular set of arguments. In particular, this
     // binds the code to a particular heap (via initHeap) and set of global
     // variables. A given asm.js module cannot be dynamically linked more than
-    // once so, if JS tries, the module is cloned.
-    void setIsDynamicallyLinked() {
+    // once so, if JS tries, the module is cloned. When linked, an asm.js module
+    // is kept in a list so that it can be updated if the linked buffer is
+    // detached.
+    void setIsDynamicallyLinked(JSRuntime *rt) {
         MOZ_ASSERT(!isDynamicallyLinked());
         dynamicallyLinked_ = true;
+        nextLinked_ = rt->linkedAsmJSModules;
+        prevLinked_ = &rt->linkedAsmJSModules;
+        if (nextLinked_)
+            nextLinked_->prevLinked_ = &nextLinked_;
+        rt->linkedAsmJSModules = this;
         MOZ_ASSERT(isDynamicallyLinked());
     }
+
     void initHeap(Handle heap, JSContext *cx);
-    void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer);
-    void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer,
-                               uint8_t *prevCode,
-                               ExclusiveContext *cx);
-    bool clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const;
     bool changeHeap(Handle newHeap, JSContext *cx);
+    bool detachHeap(JSContext *cx);
+
+    bool clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const;
 
     /*************************************************************************/
     // Functions that can be called after dynamic linking succeeds:
 
+    AsmJSModule *nextLinked() const {
+        MOZ_ASSERT(isDynamicallyLinked());
+        return nextLinked_;
+    }
+    bool hasDetachedHeap() const {
+        MOZ_ASSERT(isDynamicallyLinked());
+        return hasArrayView() && !heapDatum();
+    }
     CodePtr entryTrampoline(const ExportedFunction &func) const {
         MOZ_ASSERT(isDynamicallyLinked());
         MOZ_ASSERT(!func.isChangeHeap());
@@ -1511,6 +1540,10 @@ LookupAsmJSModuleInCache(ExclusiveContext *cx,
                          ScopedJSDeletePtr *module,
                          ScopedJSFreePtr *compilationTimeReport);
 
+// This function must be called for every detached ArrayBuffer.
+extern bool
+OnDetachAsmJSArrayBuffer(JSContext *cx, Handle buffer);
+
 // An AsmJSModuleObject is an internal implementation object (i.e., not exposed
 // directly to user script) which manages the lifetime of an AsmJSModule. A
 // JSObject is necessary since we want LinkAsmJS/CallAsmJS JSFunctions to be
diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp
index 0aec45a6a6e4..6f808e7830f2 100644
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1329,6 +1329,7 @@ class MOZ_STACK_CLASS ModuleCompiler
     NonAssertingLabel              stackOverflowLabel_;
     NonAssertingLabel              asyncInterruptLabel_;
     NonAssertingLabel              syncInterruptLabel_;
+    NonAssertingLabel              onDetachedLabel_;
 
     UniquePtr errorString_;
     uint32_t                       errorOffset_;
@@ -1522,6 +1523,7 @@ class MOZ_STACK_CLASS ModuleCompiler
     Label &stackOverflowLabel() { return stackOverflowLabel_; }
     Label &asyncInterruptLabel() { return asyncInterruptLabel_; }
     Label &syncInterruptLabel() { return syncInterruptLabel_; }
+    Label &onDetachedLabel() { return onDetachedLabel_; }
     bool hasError() const { return errorString_ != nullptr; }
     const AsmJSModule &module() const { return *module_.get(); }
     bool usesSignalHandlersForInterrupt() const { return module_->usesSignalHandlersForInterrupt(); }
@@ -1658,9 +1660,9 @@ class MOZ_STACK_CLASS ModuleCompiler
         Global *global = moduleLifo_.new_(Global::ByteLength);
         return global && globals_.putNew(name, global);
     }
-    bool addChangeHeap(PropertyName *name, ParseNode *fn, uint32_t mask, uint32_t min) {
+    bool addChangeHeap(PropertyName *name, ParseNode *fn, uint32_t mask, uint32_t min, uint32_t max) {
         hasChangeHeap_ = true;
-        module_->addChangeHeap(mask, min);
+        module_->addChangeHeap(mask, min, max);
         Global *global = moduleLifo_.new_(Global::ChangeHeap);
         if (!global)
             return false;
@@ -4164,8 +4166,9 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, Scalar::Type *viewType,
 
         unsigned elementSize = 1 << TypedArrayShift(*viewType);
         if (!f.m().tryRequireHeapLengthToBeAtLeast(byteOffset + elementSize)) {
-            return f.failf(indexExpr, "constant index outside heap size declared by the "
-                                      "change-heap function (0x%x)", f.m().minHeapLength());
+            return f.failf(indexExpr, "constant index outside heap size range declared by the "
+                                      "change-heap function (0x%x - 0x%x)",
+                                      f.m().minHeapLength(), f.m().module().maxHeapLength());
         }
 
         *needsBoundsCheck = NO_BOUNDS_CHECK;
@@ -6545,41 +6548,58 @@ CheckByteLengthCall(ModuleCompiler &m, ParseNode *pn, PropertyName *newBufferNam
 
 static bool
 CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBufferName,
-                         uint32_t *mask, uint32_t *minimumLength)
+                         uint32_t *mask, uint32_t *minLength, uint32_t *maxLength)
 {
-    if (!cond->isKind(PNK_OR))
-        return m.fail(cond, "expecting byteLength & K || byteLength <= L");
+    if (!cond->isKind(PNK_OR) || !BinaryLeft(cond)->isKind(PNK_OR))
+        return m.fail(cond, "expecting byteLength & K || byteLength <= L || byteLength > M");
 
-    ParseNode *leftCond = BinaryLeft(cond);
-    ParseNode *rightCond = BinaryRight(cond);
+    ParseNode *cond1 = BinaryLeft(BinaryLeft(cond));
+    ParseNode *cond2 = BinaryRight(BinaryLeft(cond));
+    ParseNode *cond3 = BinaryRight(cond);
 
-    if (!leftCond->isKind(PNK_BITAND))
-        return m.fail(leftCond, "expecting byteLength & K");
+    if (!cond1->isKind(PNK_BITAND))
+        return m.fail(cond1, "expecting byteLength & K");
 
-    if (!CheckByteLengthCall(m, BinaryLeft(leftCond), newBufferName))
+    if (!CheckByteLengthCall(m, BinaryLeft(cond1), newBufferName))
         return false;
 
-    ParseNode *maskNode = BinaryRight(leftCond);
+    ParseNode *maskNode = BinaryRight(cond1);
     if (!IsLiteralInt(m, maskNode, mask))
         return m.fail(maskNode, "expecting integer literal mask");
     if ((*mask & 0xffffff) != 0xffffff)
         return m.fail(maskNode, "mask value must have the bits 0xffffff set");
 
-    if (!rightCond->isKind(PNK_LE))
-        return m.fail(rightCond, "expecting byteLength <= L");
+    if (!cond2->isKind(PNK_LE))
+        return m.fail(cond2, "expecting byteLength <= L");
 
-    if (!CheckByteLengthCall(m, BinaryLeft(rightCond), newBufferName))
+    if (!CheckByteLengthCall(m, BinaryLeft(cond2), newBufferName))
         return false;
 
-    ParseNode *minLengthNode = BinaryRight(rightCond);
+    ParseNode *minLengthNode = BinaryRight(cond2);
     uint32_t minLengthExclusive;
     if (!IsLiteralInt(m, minLengthNode, &minLengthExclusive))
-        return m.fail(minLengthNode, "expecting integer limit literal");
+        return m.fail(minLengthNode, "expecting integer literal");
     if (minLengthExclusive < 0xffffff)
-        return m.fail(minLengthNode, "limit value must be >= 0xffffff");
+        return m.fail(minLengthNode, "literal must be >= 0xffffff");
 
     // Add one to convert from exclusive (the branch rejects if ==) to inclusive.
-    *minimumLength = minLengthExclusive + 1;
+    *minLength = minLengthExclusive + 1;
+
+    if (!cond3->isKind(PNK_GT))
+        return m.fail(cond3, "expecting byteLength > M");
+
+    if (!CheckByteLengthCall(m, BinaryLeft(cond3), newBufferName))
+        return false;
+
+    ParseNode *maxLengthNode = BinaryRight(cond3);
+    if (!IsLiteralInt(m, maxLengthNode, maxLength))
+        return m.fail(maxLengthNode, "expecting integer literal");
+    if (*maxLength > 0x80000000)
+        return m.fail(maxLengthNode, "literal must be <= 0x80000000");
+
+    if (*maxLength < *minLength)
+        return m.fail(maxLengthNode, "maximum length must be greater or equal to minimum length");
+
     return true;
 }
 
@@ -6665,8 +6685,8 @@ CheckChangeHeap(ModuleCompiler &m, ParseNode *fn, bool *validated)
     if (ParseNode *elseStmt = TernaryKid3(stmtIter))
         return m.fail(elseStmt, "unexpected else statement");
 
-    uint32_t mask, min;
-    if (!CheckHeapLengthCondition(m, cond, newBufferName, &mask, &min))
+    uint32_t mask, min, max;
+    if (!CheckHeapLengthCondition(m, cond, newBufferName, &mask, &min, &max))
         return false;
 
     if (!CheckReturnBoolLiteral(m, thenStmt, false))
@@ -6713,7 +6733,7 @@ CheckChangeHeap(ModuleCompiler &m, ParseNode *fn, bool *validated)
     if (stmtIter)
         return m.fail(stmtIter, "expecting end of function");
 
-    return m.addChangeHeap(changeHeapName, fn, mask, min);
+    return m.addChangeHeap(changeHeapName, fn, mask, min, max);
 }
 
 static bool
@@ -7620,6 +7640,27 @@ FillArgumentArray(ModuleCompiler &m, const VarTypeVector &argTypes,
     }
 }
 
+// If an FFI detaches its heap (viz., via ArrayBuffer.transfer), it must
+// call change-heap to another heap (viz., the new heap returned by transfer)
+// before returning to asm.js code. If the application fails to do this (if the
+// heap pointer is null), jump to a stub.
+static void
+GenerateCheckForHeapDetachment(ModuleCompiler &m, Register scratch)
+{
+    if (!m.module().hasArrayView())
+        return;
+
+    MacroAssembler &masm = m.masm();
+    AssertStackAlignment(masm, ABIStackAlignment);
+#if defined(JS_CODEGEN_X86)
+    CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), scratch);
+    masm.append(AsmJSGlobalAccess(label, AsmJSHeapGlobalDataOffset));
+    masm.branchTestPtr(Assembler::Zero, scratch, scratch, &m.onDetachedLabel());
+#else
+    masm.branchTestPtr(Assembler::Zero, HeapReg, HeapReg, &m.onDetachedLabel());
+#endif
+}
+
 static bool
 GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                       unsigned exitIndex, Label *throwLabel)
@@ -7703,8 +7744,10 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e
         MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
     }
 
-    // The heap pointer may have changed during the FFI, so reload it.
+    // The heap pointer may have changed during the FFI, so reload it and test
+    // for detachment.
     masm.loadAsmJSHeapRegisterFromGlobalData();
+    GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0);
 
     Label profilingReturn;
     GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::SlowFFI, &profilingReturn);
@@ -7913,14 +7956,18 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
 
     MOZ_ASSERT(masm.framePushed() == framePushed);
 
-    // Reload pinned registers after all calls into arbitrary JS.
+    // Reload the global register since Ion code can clobber any register.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     JS_STATIC_ASSERT(MaybeSavedGlobalReg > 0);
     masm.loadPtr(Address(StackPointer, savedGlobalOffset), GlobalReg);
 #else
     JS_STATIC_ASSERT(MaybeSavedGlobalReg == 0);
 #endif
+
+    // The heap pointer has to be reloaded anyway since Ion could have clobbered
+    // it. Additionally, the FFI may have detached the heap buffer.
     masm.loadAsmJSHeapRegisterFromGlobalData();
+    GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0);
 
     Label profilingReturn;
     GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::IonFFI, &profilingReturn);
@@ -8081,6 +8128,20 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
     return m.finishGeneratingInlineStub(&m.stackOverflowLabel()) && !masm.oom();
 }
 
+static bool
+GenerateOnDetachedLabelExit(ModuleCompiler &m, Label *throwLabel)
+{
+    MacroAssembler &masm = m.masm();
+    masm.bind(&m.onDetachedLabel());
+    masm.assertStackAlignment(ABIStackAlignment);
+
+    // For now, OnDetached always throws (see OnDetached comment).
+    masm.call(AsmJSImmPtr(AsmJSImm_OnDetached));
+    masm.jump(throwLabel);
+
+    return m.finishGeneratingInlineStub(&m.onDetachedLabel()) && !masm.oom();
+}
+
 static const RegisterSet AllRegsExceptSP =
     RegisterSet(GeneralRegisterSet(Registers::AllMask &
                                    ~(uint32_t(1) << Registers::StackPointer)),
@@ -8134,7 +8195,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel)
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // restore all GP/FP registers (except SP)
-    masm.loadAsmJSHeapRegisterFromGlobalData();  // In case there was a changeHeap
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
 #elif defined(JS_CODEGEN_MIPS)
@@ -8176,7 +8236,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel)
     // during jump delay slot.
     masm.pop(HeapReg);
     masm.as_jr(HeapReg);
-    masm.loadAsmJSHeapRegisterFromGlobalData();  // In case there was a changeHeap
 #elif defined(JS_CODEGEN_ARM)
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<findObjects([query])
+:   Return an array of [`Debugger.Object`][object] instances referring to each
+    live object allocated in the scope of the debuggee globals that matches
+    *query*. Each instance appears only once in the array. *Query* is an object
+    whose properties restrict which objects are returned; an object must meet
+    all the criteria given by *query* to be returned. If *query* is omitted, we
+    return the [`Debugger.Object`][object] instances for all objects allocated
+    in the scope of debuggee globals.
+
+    The *query* object may have the following properties:
+
+    `class`
+    :   If present, only return objects whose internal `[[Class]]`'s name
+        matches the given string. Note that in some cases, the prototype object
+        for a given constructor has the same `[[Class]]` as the instances that
+        refer to it, but cannot itself be used as a valid instance of the
+        class. Code gathering objects by class name may need to examine them
+        further before trying to use them.
+
+    All properties of *query* are optional. Passing an empty object returns all
+    objects in debuggee globals.
+
+    Unlike `findScripts`, this function is deterministic and will never return
+    [`Debugger.Object`s][object] referring to previously unreachable objects
+    that had not been collected yet.
+
 clearBreakpoint(handler)
 :   Remove all breakpoints set in this `Debugger` instance that use
     handler as their handler. Note that, if breakpoints using other
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index da4ee15c22c2..0bdc72b83eb0 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1254,6 +1254,34 @@ ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext *pc, HandleAtom name,
+                              Definition *dn)
+{
+    MOZ_ASSERT(dn->isLet());
+    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
+    if (stmt && stmt->type == STMT_SWITCH)
+        return dn->pn_cookie.slot() < stmt->firstDominatingLexicalInCase;
+    return false;
+}
+
+static void
+AssociateUsesWithOuterDefinition(ParseNode *pnu, Definition *dn, Definition *outer_dn,
+                                 bool markUsesAsLet)
+{
+    uint32_t dflags = markUsesAsLet ? PND_LET : 0;
+    while (true) {
+        pnu->pn_lexdef = outer_dn;
+        pnu->pn_dflags |= dflags;
+        if (!pnu->pn_link)
+            break;
+        pnu = pnu->pn_link;
+    }
+    pnu->pn_link = outer_dn->dn_uses;
+    outer_dn->dn_uses = dn->dn_uses;
+    dn->dn_uses = nullptr;
+}
+
 /*
  * Beware: this function is called for functions nested in other functions or
  * global scripts but not for functions compiled through the Function
@@ -1338,7 +1366,7 @@ Parser::leaveFunction(ParseNode *fn, ParseContext::leaveFunction(ParseNode *fn, ParseContextisLet()) {
-                        while (true) {
-                            pnu->pn_dflags |= PND_LET;
-                            if (!pnu->pn_link)
-                                break;
-                            pnu = pnu->pn_link;
-                        }
-                        pnu = dn->dn_uses;
-                    }
-
-                    while (true) {
-                        pnu->pn_lexdef = outer_dn;
-                        if (!pnu->pn_link)
-                            break;
-                        pnu = pnu->pn_link;
-                    }
-                    pnu->pn_link = outer_dn->dn_uses;
-                    outer_dn->dn_uses = dn->dn_uses;
-                    dn->dn_uses = nullptr;
+                    //
+                    // Similarly, if we are closing over a lexical binding
+                    // from another case in a switch, those uses also need to
+                    // be marked as needing dead zone checks.
+                    RootedAtom name(context, atom);
+                    bool markUsesAsLet = outer_dn->isLet() &&
+                                         (bodyLevelHoistedUse ||
+                                          IsNonDominatingInScopedSwitch(outerpc, name, outer_dn));
+                    AssociateUsesWithOuterDefinition(pnu, dn, outer_dn, markUsesAsLet);
                 }
 
                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
@@ -1872,6 +1890,13 @@ Parser::addFreeVariablesFromLazyFunction(JSFunction *fun,
         // Note that body-level function declaration statements are always
         // hoisted to the top, so all accesses to free let variables need the
         // dead zone check.
+        //
+        // Subtlety: we don't need to check for closing over a non-dominating
+        // lexical binding in a switch, as lexical declarations currently
+        // disable syntax parsing. So a non-dominating but textually preceding
+        // lexical declaration would have aborted syntax parsing, and a
+        // textually following declaration would return true for
+        // handler.isPlaceholderDefinition(dn) below.
         if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse)
             freeVariables[i].setIsHoistedUse();
 
@@ -3142,7 +3167,7 @@ Parser::noteNameUse(HandlePropertyName name, Node pn)
             handler.setFlag(pn, PND_DEOPTIMIZED);
         } else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) {
             // See comments above StmtInfoPC and switchStatement for how
-            // firstDominatingLetInCase is computed.
+            // firstDominatingLexicalInCase is computed.
             MOZ_ASSERT(stmt->firstDominatingLexicalInCase <= stmt->staticBlock().numVariables());
             handler.markMaybeUninitializedLexicalUseInSwitch(pn, dn,
                                                              stmt->firstDominatingLexicalInCase);
diff --git a/js/src/jit-test/tests/asm.js/testNeuter.js b/js/src/jit-test/tests/asm.js/testNeuter.js
index a8d89ff17b9e..587fdf234558 100644
--- a/js/src/jit-test/tests/asm.js/testNeuter.js
+++ b/js/src/jit-test/tests/asm.js/testNeuter.js
@@ -1,81 +1,113 @@
 load(libdir + "asm.js");
+load(libdir + "asserts.js");
 
-function f(stdlib, foreign, buffer) {
-    "use asm";
-    var i32 = new stdlib.Int32Array(buffer);
-    function set(i,j) {
-        i=i|0;
-        j=j|0;
-        i32[i>>2] = j;
-    }
-    function get(i) {
-        i=i|0;
-        return i32[i>>2]|0
-    }
-    return {get:get, set:set}
-}
-if (isAsmJSCompilationAvailable())
-    assertEq(isAsmJSModule(f), true);
+if (!isAsmJSCompilationAvailable())
+    quit();
 
-var i32 = new Int32Array(1024);
-var buffer = i32.buffer;
-var {get, set} = f(this, null, buffer);
-if (isAsmJSCompilationAvailable())
-    assertEq(isAsmJSFunction(get) && isAsmJSFunction(set), true);
+var m = asmCompile('stdlib', 'foreign', 'buffer',
+                  `"use asm";
+                   var i32 = new stdlib.Int32Array(buffer);
+                   function set(i,j) {
+                       i=i|0;
+                       j=j|0;
+                       i32[i>>2] = j;
+                   }
+                   function get(i) {
+                       i=i|0;
+                       return i32[i>>2]|0
+                   }
+                   return {get:get, set:set}`);
 
+var buffer = new ArrayBuffer(BUF_MIN);
+var {get, set} = asmLink(m, this, null, buffer);
 set(4, 42);
 assertEq(get(4), 42);
-
 neuter(buffer, "change-data");
 neuter(buffer, "same-data");
+assertThrowsInstanceOf(() => get(4), InternalError);
 
-// These operations may throw internal errors
-try {
-    assertEq(get(4), 0);
-    set(0, 42);
-    assertEq(get(0), 0);
-} catch (e) {
-    assertEq(String(e).indexOf("InternalError"), 0);
+var buf1 = new ArrayBuffer(BUF_MIN);
+var buf2 = new ArrayBuffer(BUF_MIN);
+var {get:get1, set:set1} = asmLink(m, this, null, buf1);
+var {get:get2, set:set2} = asmLink(m, this, null, buf2);
+set1(0, 13);
+set2(0, 42);
+neuter(buf1, "change-data");
+assertThrowsInstanceOf(() => get1(0), InternalError);
+assertEq(get2(0), 42);
+
+var m = asmCompile('stdlib', 'foreign', 'buffer',
+                  `"use asm";
+                   var i32 = new stdlib.Int32Array(buffer);
+                   var ffi = foreign.ffi;
+                   function inner(i) {
+                       i=i|0;
+                       ffi();
+                       return i32[i>>2]|0
+                   }
+                   return inner`);
+
+var buffer = new ArrayBuffer(BUF_MIN);
+function ffi1() { neuter(buffer, "change-data"); }
+var inner = asmLink(m, this, {ffi:ffi1}, buffer);
+assertThrowsInstanceOf(() => inner(8), InternalError);
+
+var byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
+var m = asmCompile('stdlib', 'foreign', 'buffer',
+                  `"use asm";
+                   var ffi = foreign.ffi;
+                   var I32 = stdlib.Int32Array;
+                   var i32 = new I32(buffer);
+                   var len = stdlib.byteLength;
+                   function changeHeap(newBuffer) {
+                       if (len(newBuffer) & 0xffffff || len(newBuffer) <= 0xffffff || len(newBuffer) > 0x80000000)
+                           return false;
+                       i32 = new I32(newBuffer);
+                       buffer = newBuffer;
+                       return true;
+                   }
+                   function get(i) {
+                       i=i|0;
+                       return i32[i>>2]|0;
+                   }
+                   function inner(i) {
+                       i=i|0;
+                       ffi();
+                       return get(i)|0;
+                   }
+                   return {changeHeap:changeHeap, get:get, inner:inner}`);
+
+var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
+var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
+var buf3 = new ArrayBuffer(BUF_CHANGE_MIN);
+var buf4 = new ArrayBuffer(BUF_CHANGE_MIN);
+new Int32Array(buf2)[13] = 42;
+new Int32Array(buf3)[13] = 1024;
+new Int32Array(buf4)[13] = 1337;
+
+function ffi2() { neuter(buf1, "change-data"); assertEq(changeHeap(buf2), true); }
+var {changeHeap, get:get2, inner} = asmLink(m, this, {ffi:ffi2}, buf1);
+assertEq(inner(13*4), 42);
+
+function ffi3() {
+    assertEq(get2(13*4), 42);
+    assertEq(get2(BUF_CHANGE_MIN), 0)
+    assertEq(get3(13*4), 42);
+    assertEq(get3(BUF_CHANGE_MIN), 0)
+    neuter(buf2, "change-data");
+    assertThrowsInstanceOf(()=>get2(13*4), InternalError);
+    assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError);
+    assertThrowsInstanceOf(()=>get3(13*4), InternalError);
+    assertThrowsInstanceOf(()=>get3(BUF_CHANGE_MIN), InternalError);
+    assertEq(changeHeap(buf3), true);
+    assertThrowsInstanceOf(()=>get2(13*4), InternalError);
+    assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError);
+    assertEq(get3(13*4), 1024);
+    assertEq(get3(BUF_CHANGE_MIN), 0);
+    assertEq(changeHeap(buf4), true);
 }
-
-function f2(stdlib, foreign, buffer) {
-    "use asm";
-    var i32 = new stdlib.Int32Array(buffer);
-    var ffi = foreign.ffi;
-    function inner(i) {
-        i=i|0;
-        ffi();
-        return i32[i>>2]|0
-    }
-    return inner
-}
-if (isAsmJSCompilationAvailable())
-    assertEq(isAsmJSModule(f2), true);
-
-var i32 = new Int32Array(1024);
-var buffer = i32.buffer;
-var threw = false;
-function ffi() {
-    try {
-        neuter(buffer, "same-data");
-    } catch (e) {
-        assertEq(String(e).indexOf("InternalError"), 0);
-        threw = true;
-    }
-    try {
-        neuter(buffer, "change-data");
-    } catch (e) {
-        assertEq(String(e).indexOf("InternalError"), 0);
-        threw = true;
-    }
-}
-var inner = f2(this, {ffi:ffi}, buffer);
-if (isAsmJSCompilationAvailable())
-    assertEq(isAsmJSFunction(inner), true);
-i32[2] = 13;
-var result = inner(8);
-if (threw)
-    assertEq(result, 13);
-else
-    assertEq(result, 0);
-
+var {changeHeap, get:get3, inner} = asmLink(m, this, {ffi:ffi3}, buf2);
+assertEq(inner(13*4), 1337);
+assertThrowsInstanceOf(()=>get2(0), InternalError);
+assertEq(get3(BUF_CHANGE_MIN), 0);
+assertEq(get3(13*4), 1337);
diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js
index 144fa90b3009..e1e2c1dc0d81 100644
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -1,4 +1,5 @@
 load(libdir + "asm.js");
+load(libdir + "asserts.js");
 
 // Single-step profiling currently only works in the ARM simulator
 if (!getBuildConfiguration()["arm-simulator"])
@@ -124,6 +125,15 @@ assertEq(f1(), 32);
 var stacks = disableSingleStepProfiling();
 assertEqualStacks(stacks, ",>,f1>,,>,f2>,,f2>,>,,f1>,>,");
 
+// Detachment exit
+var buf = new ArrayBuffer(BUF_CHANGE_MIN);
+var ffi = function() { neuter(buf, 'change-data') }
+var f = asmLink(asmCompile('g','ffis','buf', USE_ASM + 'var ffi = ffis.ffi; var i32 = new g.Int32Array(buf); function f() { ffi() } return f'), this, {ffi:ffi}, buf);
+enableSingleStepProfiling();
+assertThrowsInstanceOf(f, InternalError);
+var stacks = disableSingleStepProfiling();
+assertEqualStacks(stacks, ",>,f>,,inline stubf>,,inline stubf>,");
+
 // This takes forever to run.
 // Stack-overflow exit test
 //var limit = -1;
diff --git a/js/src/jit-test/tests/asm.js/testResize.js b/js/src/jit-test/tests/asm.js/testResize.js
index 6d5e08cbba5b..a94a67d14fa1 100644
--- a/js/src/jit-test/tests/asm.js/testResize.js
+++ b/js/src/jit-test/tests/asm.js/testResize.js
@@ -72,69 +72,80 @@ const IMPORT1 = "var I8=glob.Int8Array; var i8=new I8(b); " + BYTELENGTH_IMPORT;
 const IMPORT2 = "var I8=glob.Int8Array; var i8=new I8(b); var I32=glob.Int32Array; var i32=new I32(b); var II32=glob.Int32Array; " + BYTELENGTH_IMPORT;
 
        asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function b(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2=1) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,xyz) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch({b2}) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { ;if((len((b2))) & (0xffffff) || (len((b2)) <= (0xffffff))) {;;return false;;} ; i8=new I8(b2);; b=b2;; return true;; } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function ch2(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { 3; if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { b2=b2|0; if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function b(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2=1) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,xyz) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch({b2}) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { ;if((len((b2))) & (0xffffff) || (len((b2)) <= (0xffffff)) || len(b2) > 0x80000000) {;;return false;;} ; i8=new I8(b2);; b=b2;; return true;; } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function ch2(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { 3; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { b2=b2|0; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
 assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(i8(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(xyz) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff && len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) | 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) == 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xfffffe || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x1ffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) < 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xfffffe) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) ; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) {} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) {return false} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return true; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT0 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i7=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=1; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new 1; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I7(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new b(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(1); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2,1); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); xyz=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=1; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; 1; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I32(b2); i32=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new II32(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || 1 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(i8(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(xyz) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff && len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) | 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) == 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xfffffe || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x1ffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) < 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xfffffe || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) < 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1 > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0.0) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) ; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {return false} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return true; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT0 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i7=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=1; b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new 1; b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I7(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new b(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8; b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(1); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2,1); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); xyz=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=1; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; 1; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I32(b2); i32=new I8(b2); b=b2; return true } function f() { return 42 } return f');
+       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new II32(b2); b=b2; return true } function f() { return 42 } return f');
 
 // Tests for no calls in heap index expressions
 
-const SETUP = USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }';
+const SETUP = USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }';
 
        asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] } return f');
        asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] = 0 } return f');
@@ -152,26 +163,28 @@ assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i
 
 // Tests for constant heap accesses when change-heap is used
 
-const HEADER = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & MASK || len(b2) <= MIN) return false; i8=new I8(b2); b=b2; return true } ';
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { i8[0x1000000] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { i8[0xffffff] = 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { i8[0x1000001] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { i8[0x1000000] = 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { return i8[0x1000000]|0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { return i8[0xffffff]|0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { return i8[0x1000001]|0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { return i8[0x1000000]|0 } return f');
+const HEADER = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= MIN || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } ';
+assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0x1000000] = 0 } return f');
+       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0xffffff] = 0 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000001] = 0 } return f');
+       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000000] = 0 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0x1000000]|0 } return f');
+       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0xffffff]|0 } return f');
+assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000001]|0 } return f');
+       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000000]|0 } return f');
 
 // Tests for validation of heap length
 
-var body = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & MASK || len(b2) <= MIN) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return ch';
-var m = asmCompile('glob', 'ffis', 'b', body.replace('MASK', '0xffffff').replace('MIN', '0x1ffffff'));
+var body = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1ffffff || len(b2) > 0x4000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return ch';
+var m = asmCompile('glob', 'ffis', 'b', body);
 assertAsmLinkFail(m, this, null, new ArrayBuffer(BUF_CHANGE_MIN));
 assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1000000));
 var changeHeap = asmLink(m, this, null, new ArrayBuffer(0x2000000));
 assertEq(changeHeap(new ArrayBuffer(0x1000000)), false);
 assertEq(changeHeap(new ArrayBuffer(0x2000000)), true);
 assertEq(changeHeap(new ArrayBuffer(0x2000001)), false);
+assertEq(changeHeap(new ArrayBuffer(0x4000000)), true);
+assertEq(changeHeap(new ArrayBuffer(0x5000000)), false);
 assertThrowsInstanceOf(() => changeHeap(null), TypeError);
 assertThrowsInstanceOf(() => changeHeap({}), TypeError);
 assertThrowsInstanceOf(() => changeHeap(new Int32Array(100)), TypeError);
@@ -184,7 +197,7 @@ assertEq(changeHeap(detached), false);
 
 const CHANGE_HEAP = 'var changeHeap = glob.byteLength;';
 
-var changeHeapSource = `function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true }`;
+var changeHeapSource = `function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }`;
 var body = `var I32=glob.Int32Array; var i32=new I32(b);
             var len=glob.byteLength;` +
             changeHeapSource +
@@ -222,18 +235,23 @@ assertEq(get(4), 13);
 set(BUF_CHANGE_MIN, 262);
 assertEq(get(BUF_CHANGE_MIN), 0);
 
+var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
+var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
+var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
+                   `var len=glob.byteLength;
+                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true }
+                    return ch`);
+var changeHeap = asmLink(m, this, null, buf1);
+assertEq(changeHeap(buf2), true);
+neuter(buf2, "change-data");
+assertEq(changeHeap(buf1), true);
+neuter(buf1, "change-data");
+
 var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
 new Int32Array(buf1)[0] = 13;
 var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
 new Int32Array(buf2)[0] = 42;
 
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
-                   `var len=glob.byteLength;
-                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true }
-                    return ch`);
-var changeHeap = asmLink(m, this, null, buf1);
-changeHeap(buf2);
-
 // Tests for changing heap during an FFI:
 
 // Set the warmup to '2' so we can hit both interp and ion FFI exits
@@ -246,7 +264,7 @@ var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
                    `var ffi=ffis.ffi;
                     var I32=glob.Int32Array; var i32=new I32(b);
                     var len=glob.byteLength;
-                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true }
+                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
                     function test(i) { i=i|0; var sum=0; sum = i32[i>>2]|0; sum = (sum + (ffi()|0))|0; sum = (sum + (i32[i>>2]|0))|0; return sum|0 }
                     return {test:test, changeHeap:ch}`);
 var ffi = function() { changeHeap(changeToBuf); return 1 }
diff --git a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js b/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
index 8d460685013a..bde496899cc1 100644
--- a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
+++ b/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
@@ -20,7 +20,7 @@ new Int32Array(buf2)[0] = 42;
 var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
                    `var I32=glob.Int32Array; var i32=new I32(b);
                     var len=glob.byteLength;
-                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true }
+                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
                     function f() {}
                     function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } }
                     return {loop:loop, changeHeap:changeHeap}`);
diff --git a/js/src/jit-test/tests/asm.js/testTimeout7.js b/js/src/jit-test/tests/asm.js/testTimeout7.js
index ee4df4519256..ce85cebb09c9 100644
--- a/js/src/jit-test/tests/asm.js/testTimeout7.js
+++ b/js/src/jit-test/tests/asm.js/testTimeout7.js
@@ -18,7 +18,7 @@ new Int32Array(buf2)[0] = 42;
 var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
                    `var I32=glob.Int32Array; var i32=new I32(b);
                     var len=glob.byteLength;
-                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true }
+                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
                     function f() {}
                     function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } }
                     return {loop:loop, changeHeap:changeHeap}`);
diff --git a/js/src/jit-test/tests/basic/display-url-in-stack-trace.js b/js/src/jit-test/tests/basic/display-url-in-stack-trace.js
new file mode 100644
index 000000000000..acab47ab61ee
--- /dev/null
+++ b/js/src/jit-test/tests/basic/display-url-in-stack-trace.js
@@ -0,0 +1,27 @@
+eval(`
+  function a() {
+    return b();
+  }
+  //# sourceURL=source-a.js
+`);
+
+eval(`
+  function b() {
+    return c();
+  }
+  //# sourceURL=source-b.js
+`);
+
+eval(`
+  function c() {
+    return Error().stack;
+  }
+  //# sourceURL=source-c.js
+`);
+
+let filenames = a().split(/\n/)
+                   .map(f => f.slice(f.indexOf("@") + 1, f.indexOf(":")));
+print(filenames.join("\n"));
+assertEq(filenames[0], "source-c.js");
+assertEq(filenames[1], "source-b.js");
+assertEq(filenames[2], "source-a.js");
diff --git a/js/src/jit-test/tests/basic/letTDZSwitchClosure.js b/js/src/jit-test/tests/basic/letTDZSwitchClosure.js
new file mode 100644
index 000000000000..c601f9858dd0
--- /dev/null
+++ b/js/src/jit-test/tests/basic/letTDZSwitchClosure.js
@@ -0,0 +1,60 @@
+function assertThrowsReferenceError(f) {
+  var err;
+  try {
+    f();
+  } catch (e) {
+    err = e;
+  }
+  assertEq(err instanceof ReferenceError, true);
+}
+
+function f() {
+    switch (0) {
+        case 1:
+            let x
+        case function() {
+            print(x)
+        }():
+    }
+}
+assertThrowsReferenceError(f);
+
+function g() {
+  switch (0) {
+    case 1:
+      let x;
+    case 0:
+      var inner = function () {
+        print(x);
+      }
+      inner();
+      break;
+  }
+}
+assertThrowsReferenceError(g);
+
+function h() {
+  switch (0) {
+    case 0:
+      var inner = function () {
+        print(x);
+      }
+      inner();
+    case 1:
+      let x;
+  }
+}
+assertThrowsReferenceError(h);
+
+// Tests that a dominating lexical doesn't throw.
+function F() {
+  switch (0) {
+    case 0:
+      let x = 42;
+      var inner = function () {
+        assertEq(x, 42);
+      }
+      inner();
+  }
+}
+F();
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-01.js b/js/src/jit-test/tests/debug/Debugger-findObjects-01.js
new file mode 100644
index 000000000000..4ed43310a92b
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-01.js
@@ -0,0 +1,4 @@
+// In a debugger with no debuggees, findObjects should return no objects.
+
+var dbg = new Debugger;
+assertEq(dbg.findObjects().length, 0);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-02.js b/js/src/jit-test/tests/debug/Debugger-findObjects-02.js
new file mode 100644
index 000000000000..bfb33391f922
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-02.js
@@ -0,0 +1,18 @@
+// In a debuggee with live objects, findObjects finds those objects.
+
+var g = newGlobal();
+
+let defObject = v => g.eval(`this.${v} = { toString: () => "[object ${v}]" }`);
+defObject("a");
+defObject("b");
+defObject("c");
+
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+var aw = gw.makeDebuggeeValue(g.a);
+var bw = gw.makeDebuggeeValue(g.b);
+var cw = gw.makeDebuggeeValue(g.c);
+
+assertEq(dbg.findObjects().indexOf(aw) != -1, true);
+assertEq(dbg.findObjects().indexOf(bw) != -1, true);
+assertEq(dbg.findObjects().indexOf(cw) != -1, true);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-03.js b/js/src/jit-test/tests/debug/Debugger-findObjects-03.js
new file mode 100644
index 000000000000..d391415cc28d
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-03.js
@@ -0,0 +1,12 @@
+// findObjects' result includes objects referenced by other objects.
+
+var g = newGlobal();
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+
+g.eval('this.a = { b: {} };');
+
+var bw = gw.makeDebuggeeValue(g.a.b);
+
+var objects = dbg.findObjects();
+assertEq(objects.indexOf(bw) != -1, true);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-04.js b/js/src/jit-test/tests/debug/Debugger-findObjects-04.js
new file mode 100644
index 000000000000..a01378e35fa6
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-04.js
@@ -0,0 +1,16 @@
+// findObjects' result includes objects captured by closures.
+
+var g = newGlobal();
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+
+g.eval(`
+  this.f = (function () {
+    let a = { foo: () => {} };
+    return () => a;
+  }());
+`);
+
+let objects = dbg.findObjects();
+let aw = gw.makeDebuggeeValue(g.f());
+assertEq(objects.indexOf(aw) != -1, true);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-05.js b/js/src/jit-test/tests/debug/Debugger-findObjects-05.js
new file mode 100644
index 000000000000..05120919640f
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-05.js
@@ -0,0 +1,10 @@
+// findObjects' result doesn't include any duplicates.
+
+var g = newGlobal();
+var dbg = new Debugger();
+dbg.addDebuggee(g);
+
+let objects = dbg.findObjects();
+let set = new Set(objects);
+
+assertEq(objects.length, set.size);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-06.js b/js/src/jit-test/tests/debug/Debugger-findObjects-06.js
new file mode 100644
index 000000000000..8bdedab03a44
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-06.js
@@ -0,0 +1,14 @@
+// In a debugger with multiple debuggees, findObjects finds objects from all debuggees.
+
+var g1 = newGlobal();
+var g2 = newGlobal();
+var dbg = new Debugger();
+var g1w = dbg.addDebuggee(g1);
+var g2w = dbg.addDebuggee(g2);
+
+g1.eval('this.a = {};');
+g2.eval('this.b = {};');
+
+var objects = dbg.findObjects();
+assertEq(objects.indexOf(g1w.makeDebuggeeValue(g1.a)) != -1, true);
+assertEq(objects.indexOf(g2w.makeDebuggeeValue(g2.b)) != -1, true);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-07.js b/js/src/jit-test/tests/debug/Debugger-findObjects-07.js
new file mode 100644
index 000000000000..3e306a86c6d6
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-07.js
@@ -0,0 +1,22 @@
+// findObjects can filter objects by class name.
+
+var g = newGlobal();
+
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+
+g.eval('this.re = /foo/;');
+g.eval('this.d = new Date();');
+
+var rew = gw.makeDebuggeeValue(g.re);
+var dw = gw.makeDebuggeeValue(g.d);
+
+var objects;
+
+objects = dbg.findObjects({ class: "RegExp" });
+assertEq(objects.indexOf(rew) != -1, true);
+assertEq(objects.indexOf(dw) == -1, true);
+
+objects = dbg.findObjects({ class: "Date" });
+assertEq(objects.indexOf(dw) != -1, true);
+assertEq(objects.indexOf(rew) == -1, true);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-08.js b/js/src/jit-test/tests/debug/Debugger-findObjects-08.js
new file mode 100644
index 000000000000..fd6ceb1031d7
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-08.js
@@ -0,0 +1,12 @@
+// Passing bad query properties to Debugger.prototype.findScripts throws.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger();
+var g = newGlobal();
+
+assertThrowsInstanceOf(() => dbg.findObjects({ class: null }), TypeError);
+assertThrowsInstanceOf(() => dbg.findObjects({ class: true }), TypeError);
+assertThrowsInstanceOf(() => dbg.findObjects({ class: 1337 }), TypeError);
+assertThrowsInstanceOf(() => dbg.findObjects({ class: /re/ }), TypeError);
+assertThrowsInstanceOf(() => dbg.findObjects({ class: {}   }), TypeError);
diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-09.js b/js/src/jit-test/tests/debug/Debugger-findObjects-09.js
new file mode 100644
index 000000000000..a50f2be08895
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findObjects-09.js
@@ -0,0 +1,9 @@
+// We don't return objects where our query's class name is the prefix of the
+// object's class name and vice versa.
+
+var dbg = new Debugger();
+var g = newGlobal();
+var gw = dbg.addDebuggee(g);
+
+assertEq(dbg.findObjects({ class: "Objec" }).length, 0);
+assertEq(dbg.findObjects({ class: "Objectttttt" }).length, 0);
diff --git a/js/src/jit-test/tests/ion/bug1076026.js b/js/src/jit-test/tests/ion/bug1076026.js
new file mode 100644
index 000000000000..b5e90a93e0c6
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1076026.js
@@ -0,0 +1,9 @@
+(function f() {
+    let x = (new function() {})
+    __defineGetter__("x", function() {
+        ({
+            e: x
+        })
+    })
+})();
+print(x)
diff --git a/js/src/jit-test/tests/saved-stacks/display-url.js b/js/src/jit-test/tests/saved-stacks/display-url.js
new file mode 100644
index 000000000000..4688fefe013e
--- /dev/null
+++ b/js/src/jit-test/tests/saved-stacks/display-url.js
@@ -0,0 +1,26 @@
+eval(`
+  function a() {
+    return b();
+  }
+  //# sourceURL=source-a.js
+`);
+
+eval(`
+  function b() {
+    return c();
+  }
+  //# sourceURL=source-b.js
+`);
+
+eval(`
+  function c() {
+    return saveStack();
+  }
+  //# sourceURL=source-c.js
+`);
+
+let stack = a();
+print(stack);
+assertEq(stack.source, "source-c.js");
+assertEq(stack.parent.source, "source-b.js");
+assertEq(stack.parent.parent.source, "source-a.js");
diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h
index d2a495e55d13..9a20c1ad9778 100644
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -767,6 +767,7 @@ enum AsmJSImmKind
     AsmJSImm_RuntimeInterrupt,
     AsmJSImm_StackLimit,
     AsmJSImm_ReportOverRecursed,
+    AsmJSImm_OnDetached,
     AsmJSImm_HandleExecutionInterrupt,
     AsmJSImm_InvokeFromAsmJS_Ignore,
     AsmJSImm_InvokeFromAsmJS_ToInt32,
diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
index ed570ca781d1..1b5baaffdae9 100644
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -289,11 +289,17 @@ js::ComputeStackString(JSContext *cx)
                 return nullptr;
 
             /* Now the filename. */
-            const char *cfilename = i.scriptFilename();
-            if (!cfilename)
-                cfilename = "";
-            if (!sb.append(cfilename, strlen(cfilename)))
-                return nullptr;
+
+            /* First, try the `//# sourceURL=some-display-url.js` directive. */
+            if (const char16_t *display = i.scriptDisplayURL()) {
+                if (!sb.append(display, js_strlen(display)))
+                    return nullptr;
+            }
+            /* Second, try the actual filename. */
+            else if (const char *filename = i.scriptFilename()) {
+                if (!sb.append(filename, strlen(filename)))
+                    return nullptr;
+            }
 
             uint32_t column = 0;
             uint32_t line = i.computeLine(&column);
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index 9c12e7704a7b..25f8e76a28f8 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1011,9 +1011,10 @@ Chunk::releaseArena(ArenaHeader *aheader)
     MOZ_ASSERT(!aheader->hasDelayedMarking);
     Zone *zone = aheader->zone;
     JSRuntime *rt = zone->runtimeFromAnyThread();
-    AutoLockGC maybeLock;
+
+    Maybe maybeLock;
     if (rt->gc.isBackgroundSweeping())
-        maybeLock.lock(rt);
+        maybeLock.emplace(rt);
 
     if (rt->gc.isBackgroundSweeping())
         zone->threshold.updateForRemovedArena(rt->gc.tunables);
@@ -1924,11 +1925,11 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind,
                               AutoMaybeStartBackgroundAllocation &maybeStartBGAlloc)
 {
     JSRuntime *rt = zone->runtimeFromAnyThread();
-    AutoLockGC maybeLock;
+    Maybe maybeLock;
 
     // See if we can proceed without taking the GC lock.
     if (backgroundFinalizeState[thingKind] != BFS_DONE)
-        maybeLock.lock(rt);
+        maybeLock.emplace(rt);
 
     ArenaList &al = arenaLists[thingKind];
     ArenaHeader *aheader = al.takeNextArena();
@@ -1941,8 +1942,8 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind,
 
     // Parallel threads have their own ArenaLists, but chunks are shared;
     // if we haven't already, take the GC lock now to avoid racing.
-    if (!maybeLock.locked())
-        maybeLock.lock(rt);
+    if (maybeLock.isNothing())
+        maybeLock.emplace(rt);
 
     Chunk *chunk = rt->gc.pickChunk(zone, maybeStartBGAlloc);
     if (!chunk)
diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp
index 2cf9fe046b25..a03038b65d15 100644
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2931,8 +2931,14 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, NativeObject *obj,
          * Don't add initial undefined types for properties of global objects
          * that are not collated into the JSID_VOID property (see propertySet
          * comment).
+         *
+         * Also don't add initial uninitialized lexical magic values as
+         * appearing in CallObjects.
          */
-        if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
+        MOZ_ASSERT_IF(value.isMagic(JS_UNINITIALIZED_LEXICAL), obj->is());
+        if ((indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) &&
+            !value.isMagic(JS_UNINITIALIZED_LEXICAL))
+        {
             Type type = GetValueType(value);
             types->TypeSet::addType(type, &cx->typeLifoAlloc());
         }
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
index 5a8fd50b537d..a6ab1c6cbd82 100644
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -277,17 +277,6 @@ AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes)
     return ArrayBufferObject::BufferContents::create(p);
 }
 
-bool
-ArrayBufferObject::canNeuter(JSContext *cx)
-{
-    if (isAsmJSArrayBuffer()) {
-        if (!ArrayBufferObject::canNeuterAsmJSArrayBuffer(cx, *this))
-            return false;
-    }
-
-    return true;
-}
-
 void
 ArrayBufferObject::neuterView(JSContext *cx, ArrayBufferViewObject *view,
                               BufferContents newContents)
@@ -298,11 +287,12 @@ ArrayBufferObject::neuterView(JSContext *cx, ArrayBufferViewObject *view,
     MarkObjectStateChange(cx, view);
 }
 
-/* static */ void
+/* static */ bool
 ArrayBufferObject::neuter(JSContext *cx, Handle buffer,
                           BufferContents newContents)
 {
-    MOZ_ASSERT(buffer->canNeuter(cx));
+    if (buffer->isAsmJSArrayBuffer() && !OnDetachAsmJSArrayBuffer(cx, buffer))
+        return false;
 
     // Neuter all views on the buffer, clear out the list of views and the
     // buffer's data.
@@ -321,6 +311,7 @@ ArrayBufferObject::neuter(JSContext *cx, Handle buffer,
 
     buffer->setByteLength(0);
     buffer->setIsNeutered();
+    return true;
 }
 
 void
@@ -495,20 +486,6 @@ ArrayBufferObject::releaseAsmJSArray(FreeOp *fop)
 }
 #endif
 
-bool
-ArrayBufferObject::canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
-{
-    AsmJSActivation *act = cx->mainThread().asmJSActivationStack();
-    for (; act; act = act->prevAsmJS()) {
-        if (act->module().maybeHeapBufferObject() == &buffer)
-            break;
-    }
-    if (!act)
-        return true;
-
-    return false;
-}
-
 ArrayBufferObject::BufferContents
 ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
 {
@@ -708,11 +685,6 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle buffe
 {
     MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
 
-    if (!buffer->canNeuter(cx)) {
-        js_ReportOverRecursed(cx);
-        return BufferContents::createUnowned(nullptr);
-    }
-
     BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind());
     BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
     if (!newContents)
@@ -723,14 +695,20 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle buffe
         // freshly allocated memory that we will never write to and should
         // never get committed.
         buffer->setOwnsData(DoesntOwnData);
-        ArrayBufferObject::neuter(cx, buffer, newContents);
+        if (!ArrayBufferObject::neuter(cx, buffer, newContents)) {
+            js_free(newContents.data());
+            return BufferContents::createUnowned(nullptr);
+        }
         return oldContents;
     }
 
     // Create a new chunk of memory to return since we cannot steal the
     // existing contents away from the buffer.
     memcpy(newContents.data(), oldContents.data(), buffer->byteLength());
-    ArrayBufferObject::neuter(cx, buffer, oldContents);
+    if (!ArrayBufferObject::neuter(cx, buffer, oldContents)) {
+        js_free(newContents.data());
+        return BufferContents::createUnowned(nullptr);
+    }
     return newContents;
 }
 
@@ -1068,19 +1046,18 @@ JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj,
 
     Rooted buffer(cx, &obj->as());
 
-    if (!buffer->canNeuter(cx)) {
-        js_ReportOverRecursed(cx);
-        return false;
-    }
-
     if (changeData == ChangeData && buffer->hasStealableContents()) {
         ArrayBufferObject::BufferContents newContents =
             AllocateArrayBufferContents(cx, buffer->byteLength());
         if (!newContents)
             return false;
-        ArrayBufferObject::neuter(cx, buffer, newContents);
+        if (!ArrayBufferObject::neuter(cx, buffer, newContents)) {
+            js_free(newContents.data());
+            return false;
+        }
     } else {
-        ArrayBufferObject::neuter(cx, buffer, buffer->contents());
+        if (!ArrayBufferObject::neuter(cx, buffer, buffer->contents()))
+            return false;
     }
 
     return true;
@@ -1282,3 +1259,49 @@ js::GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data)
     *length = AsArrayBuffer(obj).byteLength();
     *data = AsArrayBuffer(obj).dataPointer();
 }
+
+JSObject *
+js_InitArrayBufferClass(JSContext *cx, HandleObject obj)
+{
+    Rooted global(cx, cx->compartment()->maybeGlobal());
+    if (global->isStandardClassResolved(JSProto_ArrayBuffer))
+        return &global->getPrototype(JSProto_ArrayBuffer).toObject();
+
+    RootedNativeObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass));
+    if (!arrayBufferProto)
+        return nullptr;
+
+    RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor,
+                                                      cx->names().ArrayBuffer, 1));
+    if (!ctor)
+        return nullptr;
+
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer,
+                                              ctor, arrayBufferProto))
+    {
+        return nullptr;
+    }
+
+    if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
+        return nullptr;
+
+    RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
+    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
+    JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
+                                   JSFunction::NATIVE_FUN, global, NullPtr());
+    if (!getter)
+        return nullptr;
+
+    if (!DefineNativeProperty(cx, arrayBufferProto, byteLengthId, UndefinedHandleValue,
+                              JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs))
+        return nullptr;
+
+    if (!JS_DefineFunctions(cx, ctor, ArrayBufferObject::jsstaticfuncs))
+        return nullptr;
+
+    if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
+        return nullptr;
+
+    return arrayBufferProto;
+}
+
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
index bd5a68038264..e35935dd693e 100644
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -237,10 +237,9 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
      */
     static bool ensureNonInline(JSContext *cx, Handle buffer);
 
-    bool canNeuter(JSContext *cx);
-
     /* Neuter this buffer and all its views. */
-    static void neuter(JSContext *cx, Handle buffer, BufferContents newContents);
+    static MOZ_WARN_UNUSED_RESULT bool
+    neuter(JSContext *cx, Handle buffer, BufferContents newContents);
 
   private:
     void neuterView(JSContext *cx, ArrayBufferViewObject *view,
@@ -279,7 +278,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
     static bool prepareForAsmJS(JSContext *cx, Handle buffer,
                                 bool usesSignalHandlers);
     static bool prepareForAsmJSNoSignals(JSContext *cx, Handle buffer);
-    static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
 
     static void finalize(FreeOp *fop, JSObject *obj);
 
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index a8dd532a2e4b..75db592e55ae 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -32,6 +32,7 @@
     macro(caller, caller, "caller") \
     macro(callFunction, callFunction, "callFunction") \
     macro(caseFirst, caseFirst, "caseFirst") \
+    macro(class_, class_, "class") \
     macro(Collator, Collator, "Collator") \
     macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
     macro(columnNumber, columnNumber, "columnNumber") \
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index 352ef71ce5d4..87f801175800 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -20,6 +20,7 @@
 #include "jit/BaselineJIT.h"
 #include "js/Debug.h"
 #include "js/GCAPI.h"
+#include "js/UbiNodeTraverse.h"
 #include "js/Vector.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/DebuggerMemory.h"
@@ -2982,6 +2983,202 @@ Debugger::findScripts(JSContext *cx, unsigned argc, Value *vp)
     return true;
 }
 
+/*
+ * A class for parsing 'findObjects' query arguments and searching for objects
+ * that match the criteria they represent.
+ */
+class MOZ_STACK_CLASS Debugger::ObjectQuery
+{
+  public:
+    /* Construct an ObjectQuery to use matching scripts for |dbg|. */
+    ObjectQuery(JSContext *cx, Debugger *dbg) :
+        cx(cx), dbg(dbg), className(cx)
+    {}
+
+    /*
+     * Parse the query object |query|, and prepare to match only the objects it
+     * specifies.
+     */
+    bool parseQuery(HandleObject query) {
+        /* Check for the 'class' property */
+        RootedValue cls(cx);
+        if (!JSObject::getProperty(cx, query, query, cx->names().class_, &cls))
+            return false;
+        if (!cls.isUndefined()) {
+            if (!cls.isString()) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+                                     "query object's 'class' property",
+                                     "neither undefined nor a string");
+                return false;
+            }
+            className = cls;
+        }
+        return true;
+    }
+
+    /* Set up this ObjectQuery appropriately for a missing query argument. */
+    void omittedQuery() {
+        className.setUndefined();
+    }
+
+    /*
+     * Traverse the heap to find all relevant objects and add them to the
+     * provided vector.
+     */
+    bool findObjects(AutoObjectVector &objs) {
+        if (!prepareQuery())
+            return false;
+
+        {
+            /*
+             * We can't tolerate the GC moving things around while we're
+             * searching the heap. Check that nothing we do causes a GC.
+             */
+            JS::AutoCheckCannotGC autoCannotGC;
+
+            Traversal traversal(cx, *this, autoCannotGC);
+            if (!traversal.init())
+                return false;
+
+            /* Add each debuggee global as a start point of our traversal. */
+            for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
+                if (!traversal.addStartVisited(JS::ubi::Node(static_cast(r.front()))))
+                    return false;
+            }
+
+            /*
+             * Iterate over all compartments and add traversal start points at
+             * objects that have CCWs in other compartments keeping them alive.
+             */
+            for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
+                JSCompartment *comp = c.get();
+                if (!comp)
+                    continue;
+                for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
+                    const CrossCompartmentKey &key = e.front().key();
+                    if (key.kind != CrossCompartmentKey::ObjectWrapper)
+                        continue;
+                    JSObject *obj = static_cast(key.wrapped);
+                    if (!traversal.addStartVisited(JS::ubi::Node(obj)))
+                        return false;
+                }
+            }
+
+            if (!traversal.traverse())
+                return false;
+
+            /*
+             * Iterate over the visited set of nodes and accumulate all
+             * |JSObject|s matching our criteria in the given vector.
+             */
+            for (Traversal::NodeMap::Range r = traversal.visited.all(); !r.empty(); r.popFront()) {
+                JS::ubi::Node node = r.front().key();
+                if (!node.is())
+                    continue;
+
+                JSObject *obj = node.as();
+
+                if (!className.isUndefined()) {
+                    const char *objClassName = obj->getClass()->name;
+                    if (strcmp(objClassName, classNameCString.ptr()) != 0)
+                        continue;
+                }
+
+                if (!objs.append(obj))
+                    return false;
+            }
+
+            return true;
+        }
+    }
+
+    /*
+     * |ubi::Node::BreadthFirst| interface.
+     *
+     * We use an empty traversal function and just iterate over the traversal's
+     * visited set post-facto in |findObjects|.
+     */
+
+    class NodeData {};
+    typedef JS::ubi::BreadthFirst Traversal;
+    bool operator() (Traversal &, JS::ubi::Node, const JS::ubi::Edge &, NodeData *, bool)
+    {
+        return true;
+    }
+
+  private:
+    /* The context in which we should do our work. */
+    JSContext *cx;
+
+    /* The debugger for which we conduct queries. */
+    Debugger *dbg;
+
+    /*
+     * If this is non-null, matching objects will have a class whose name is
+     * this property.
+     */
+    RootedValue className;
+
+    /* The className member, as a C string. */
+    JSAutoByteString classNameCString;
+
+    /*
+     * Given that either omittedQuery or parseQuery has been called, prepare the
+     * query for matching objects.
+     */
+    bool prepareQuery() {
+        if (className.isString()) {
+            if (!classNameCString.encodeLatin1(cx, className.toString()))
+                return false;
+        }
+
+        return true;
+    }
+};
+
+bool
+Debugger::findObjects(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGGER(cx, argc, vp, "findObjects", args, dbg);
+
+    ObjectQuery query(cx, dbg);
+
+    if (args.length() >= 1) {
+        RootedObject queryObject(cx, NonNullObject(cx, args[0]));
+        if (!queryObject || !query.parseQuery(queryObject))
+            return false;
+    } else {
+        query.omittedQuery();
+    }
+
+    /*
+     * Accumulate the objects in an AutoObjectVector, instead of creating the JS
+     * array as we go, because we mustn't allocate JS objects or GC while we
+     * traverse the heap graph.
+     */
+    AutoObjectVector objects(cx);
+
+    if (!query.findObjects(objects))
+        return false;
+
+    size_t length = objects.length();
+    RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length));
+    if (!result)
+        return false;
+
+    result->ensureDenseInitializedLength(cx, 0, length);
+
+    for (size_t i = 0; i < length; i++) {
+        RootedValue debuggeeVal(cx, ObjectValue(*objects[i]));
+        if (!dbg->wrapDebuggeeValue(cx, &debuggeeVal))
+            return false;
+        result->setDenseElement(i, debuggeeVal);
+    }
+
+    args.rval().setObject(*result);
+    return true;
+}
+
 bool
 Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -3061,6 +3258,7 @@ const JSFunctionSpec Debugger::methods[] = {
     JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
     JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 0, 0),
     JS_FN("findScripts", Debugger::findScripts, 1, 0),
+    JS_FN("findObjects", Debugger::findObjects, 1, 0),
     JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0),
     JS_FN("makeGlobalObjectReference", Debugger::makeGlobalObjectReference, 1, 0),
     JS_FS_END
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
index 47b43b1dd0a1..ad8d4f987d8d 100644
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -271,6 +271,7 @@ class Debugger : private mozilla::LinkedListElement
 
     class FrameRange;
     class ScriptQuery;
+    class ObjectQuery;
 
     bool addDebuggeeGlobal(JSContext *cx, Handle obj);
     bool addDebuggeeGlobal(JSContext *cx, Handle obj,
@@ -369,6 +370,7 @@ class Debugger : private mozilla::LinkedListElement
     static bool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
     static bool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
     static bool findScripts(JSContext *cx, unsigned argc, Value *vp);
+    static bool findObjects(JSContext *cx, unsigned argc, Value *vp);
     static bool findAllGlobals(JSContext *cx, unsigned argc, Value *vp);
     static bool makeGlobalObjectReference(JSContext *cx, unsigned argc, Value *vp);
     static bool construct(JSContext *cx, unsigned argc, Value *vp);
diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h
index b05bb94cf577..86eb79d49efd 100644
--- a/js/src/vm/MallocProvider.h
+++ b/js/src/vm/MallocProvider.h
@@ -68,8 +68,7 @@ struct MallocProvider
             client()->reportAllocationOverflow();
             return nullptr;
         }
-        client()->onOutOfMemory(nullptr, numElems * sizeof(T));
-        return nullptr;
+        return (T *)client()->onOutOfMemory(nullptr, numElems * sizeof(T));
     }
 
     template 
@@ -88,8 +87,7 @@ struct MallocProvider
             client()->updateMallocCounter(bytes);
             return p;
         }
-        client()->onOutOfMemory(nullptr, bytes);
-        return nullptr;
+        return (T *)client()->onOutOfMemory(nullptr, bytes);
     }
 
     template 
@@ -114,8 +112,7 @@ struct MallocProvider
             client()->reportAllocationOverflow();
             return nullptr;
         }
-        client()->onOutOfMemory(nullptr, numElems * sizeof(T));
-        return nullptr;
+        return (T *)client()->onOutOfMemory(nullptr, numElems * sizeof(T));
     }
 
     template 
@@ -134,8 +131,7 @@ struct MallocProvider
             client()->updateMallocCounter(bytes);
             return p;
         }
-        client()->onOutOfMemory(nullptr, bytes);
-        return nullptr;
+        return (T *)client()->onOutOfMemory(nullptr, bytes);
     }
 
     template 
@@ -159,8 +155,7 @@ struct MallocProvider
             client()->reportAllocationOverflow();
             return nullptr;
         }
-        client()->onOutOfMemory(prior, newSize * sizeof(T));
-        return nullptr;
+        return (T *)client()->onOutOfMemory(prior, newSize * sizeof(T));
     }
 
     JS_DECLARE_NEW_METHODS(new_, pod_malloc, MOZ_ALWAYS_INLINE)
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index f2acafe72b71..3a8f51bccb6d 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -197,6 +197,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
     structuredCloneCallbacks(nullptr),
     telemetryCallback(nullptr),
     errorReporter(nullptr),
+    linkedAsmJSModules(nullptr),
     propertyRemovals(0),
 #if !EXPOSE_INTL_API
     thousandsSeparator(0),
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
index 8696d73a9b36..572bd27ab374 100644
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -78,6 +78,7 @@ namespace js {
 class Activation;
 class ActivationIterator;
 class AsmJSActivation;
+class AsmJSModule;
 class MathCache;
 
 namespace jit {
@@ -1080,7 +1081,10 @@ struct JSRuntime : public JS::shadow::Runtime,
     JSErrorReporter     errorReporter;
 
     /* AsmJSCache callbacks are runtime-wide. */
-    JS::AsmJSCacheOps asmJSCacheOps;
+    JS::AsmJSCacheOps   asmJSCacheOps;
+
+    /* Head of the linked list of linked asm.js modules. */
+    js::AsmJSModule    *linkedAsmJSModules;
 
     /*
      * The propertyRemovals counter is incremented for every JSObject::clear,
@@ -1492,31 +1496,17 @@ FreeOp::freeLater(void *p)
 class AutoLockGC
 {
   public:
-    explicit AutoLockGC(JSRuntime *rt = nullptr
+    explicit AutoLockGC(JSRuntime *rt
                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : runtime(rt)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        // Avoid MSVC warning C4390 for non-threadsafe builds.
-        if (rt)
-            rt->lockGC();
+        rt->lockGC();
     }
 
     ~AutoLockGC()
     {
-        if (runtime)
-            runtime->unlockGC();
-    }
-
-    bool locked() const {
-        return !!runtime;
-    }
-
-    void lock(JSRuntime *rt) {
-        MOZ_ASSERT(rt);
-        MOZ_ASSERT(!runtime);
-        runtime = rt;
-        rt->lockGC();
+        runtime->unlockGC();
     }
 
   private:
diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
index 70dcbdea5931..96a4981ff9f6 100644
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -676,10 +676,12 @@ SavedStacks::getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLoca
     // that doesn't employ memoization, and update |locationp|'s slots directly.
 
     if (!iter.hasScript()) {
-        const char *filename = iter.scriptFilename();
-        if (!filename)
-            filename = "";
-        locationp->source = Atomize(cx, filename, strlen(filename));
+        if (const char16_t *displayURL = iter.scriptDisplayURL()) {
+            locationp->source = AtomizeChars(cx, displayURL, js_strlen(displayURL));
+        } else {
+            const char *filename = iter.scriptFilename() ? iter.scriptFilename() : "";
+            locationp->source = Atomize(cx, filename, strlen(filename));
+        }
         if (!locationp->source)
             return false;
 
@@ -694,8 +696,13 @@ SavedStacks::getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLoca
     PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key);
 
     if (!p) {
-        const char *filename = script->filename() ? script->filename() : "";
-        RootedAtom source(cx, Atomize(cx, filename, strlen(filename)));
+        RootedAtom source(cx);
+        if (const char16_t *displayURL = iter.scriptDisplayURL()) {
+            source = AtomizeChars(cx, displayURL, js_strlen(displayURL));
+        } else {
+            const char *filename = script->filename() ? script->filename() : "";
+            source = Atomize(cx, filename, strlen(filename));
+        }
         if (!source)
             return false;
 
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 6047ed43cfa8..05d232b613db 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -957,6 +957,13 @@ FrameIter::scriptFilename() const
     MOZ_CRASH("Unexpected state");
 }
 
+const char16_t *
+FrameIter::scriptDisplayURL() const
+{
+    ScriptSource *ss = scriptSource();
+    return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
+}
+
 unsigned
 FrameIter::computeLine(uint32_t *column) const
 {
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index 9d7e297ee031..e09ba468f75c 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1644,12 +1644,9 @@ class FrameIter
     bool isGeneratorFrame() const;
     bool hasArgs() const { return isNonEvalFunctionFrame(); }
 
-    /*
-     * Get an abstract frame pointer dispatching to either an interpreter,
-     * baseline, or rematerialized optimized frame.
-     */
     ScriptSource *scriptSource() const;
     const char *scriptFilename() const;
+    const char16_t *scriptDisplayURL() const;
     unsigned computeLine(uint32_t *column = nullptr) const;
     JSAtom *functionDisplayAtom() const;
     bool mutedErrors() const;
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
index 351a5fe9ce22..b2f237689ff8 100644
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1815,51 +1815,6 @@ const Class TypedArrayObject::protoClasses[Scalar::TypeMax] = {
     IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray)
 };
 
-JSObject *
-js_InitArrayBufferClass(JSContext *cx, HandleObject obj)
-{
-    Rooted global(cx, cx->compartment()->maybeGlobal());
-    if (global->isStandardClassResolved(JSProto_ArrayBuffer))
-        return &global->getPrototype(JSProto_ArrayBuffer).toObject();
-
-    RootedNativeObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass));
-    if (!arrayBufferProto)
-        return nullptr;
-
-    RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor,
-                                                      cx->names().ArrayBuffer, 1));
-    if (!ctor)
-        return nullptr;
-
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer,
-                                              ctor, arrayBufferProto))
-    {
-        return nullptr;
-    }
-
-    if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
-        return nullptr;
-
-    RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
-    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
-    JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
-                                   JSFunction::NATIVE_FUN, global, NullPtr());
-    if (!getter)
-        return nullptr;
-
-    if (!DefineNativeProperty(cx, arrayBufferProto, byteLengthId, UndefinedHandleValue,
-                              JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs))
-        return nullptr;
-
-    if (!JS_DefineFunctions(cx, ctor, ArrayBufferObject::jsstaticfuncs))
-        return nullptr;
-
-    if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
-        return nullptr;
-
-    return arrayBufferProto;
-}
-
 /* static */ bool
 TypedArrayObject::isOriginalLengthGetter(Native native)
 {
diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
index 2303fdaba857..2ec843d450ab 100644
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -112,7 +112,6 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // aLoadGroup
                        nullptr,  // aCallbacks
                        nsIRequest::LOAD_NORMAL,
diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp
index 6926341d3fa4..2be834268832 100644
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4712,7 +4712,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer,
 
   maskTransform.Invert();
   Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
-  matrix.Translate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
+  matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
   maskLayer->SetBaseTransform(matrix);
 
   // save the details of the clip in user data
diff --git a/layout/base/SelectionCarets.cpp b/layout/base/SelectionCarets.cpp
index 9243db0f3b32..276601a318c4 100644
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -856,7 +856,9 @@ SelectionCarets::NotifySelectionChanged(nsIDOMDocument* aDoc,
     SetVisibility(false);
     return NS_OK;
   }
-  if (aReason & nsISelectionListener::KEYPRESS_REASON) {
+  if (!aReason || (aReason & (nsISelectionListener::DRAG_REASON |
+                               nsISelectionListener::KEYPRESS_REASON |
+                               nsISelectionListener::MOUSEDOWN_REASON))) {
     SetVisibility(false);
   } else {
     UpdateSelectionCarets();
@@ -905,7 +907,7 @@ SelectionCarets::AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
 void
 SelectionCarets::ScrollPositionChanged()
 {
-  if (!mAPZenabled) {
+  if (!mAPZenabled && mVisible) {
     SetVisibility(false);
     //TODO: handling scrolling for selection bubble when APZ is off
     LaunchScrollEndDetector();
diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp
index 1a3dc7042dce..60136cb2a4b1 100644
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1224,7 +1224,7 @@ void
 nsBidiPresUtils::ReorderFrames(nsIFrame*   aFirstFrameOnLine,
                                int32_t     aNumFramesOnLine,
                                WritingMode aLineWM,
-                               nscoord&    aLineWidth,
+                               nscoord     aLineWidth,
                                nscoord     aStart)
 {
   // If this line consists of a line frame, reorder the line frame's children.
@@ -1399,7 +1399,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame*             aFrame,
                                  nscoord&              aStart,
                                  nsContinuationStates* aContinuationStates,
                                  WritingMode           aContainerWM,
-                                 nscoord&              aContainerWidth)
+                                 nscoord               aContainerWidth)
 {
   if (!aFrame)
     return;
@@ -1509,8 +1509,8 @@ void
 nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
                                         nsIFrame* aFirstChild,
                                         WritingMode aLineWM,
-                                        nscoord& aLineWidth,
-                                        nscoord& aStart)
+                                        nscoord aLineWidth,
+                                        nscoord aStart)
 {
   nscoord start = aStart;
   nsIFrame* frame;
diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h
index 3377ab6de57a..7a39a2dda164 100644
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -160,7 +160,7 @@ public:
   static void ReorderFrames(nsIFrame*            aFirstFrameOnLine,
                             int32_t              aNumFramesOnLine,
                             mozilla::WritingMode aLineWM,
-                            nscoord&             aLineWidth,
+                            nscoord              aLineWidth,
                             nscoord              aStart);
 
   /**
@@ -399,7 +399,7 @@ private:
                               nscoord&               aStart,
                               nsContinuationStates*  aContinuationStates,
                               mozilla::WritingMode   aContainerWM,
-                              nscoord&               aContainerWidth);
+                              nscoord                aContainerWidth);
 
   /*
    * Initialize the continuation state(nsFrameContinuationState) to
@@ -452,8 +452,8 @@ private:
   static void RepositionInlineFrames(BidiLineData* aBld,
                                      nsIFrame* aFirstChild,
                                      mozilla::WritingMode aLineWM,
-                                     nscoord& aLineWidth,
-                                     nscoord& aStart);
+                                     nscoord aLineWidth,
+                                     nscoord aStart);
   
   /**
    * Helper method for Resolve()
diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h
index f2f1c7be613a..04dcbc1dfe89 100644
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -14,6 +14,7 @@
 #include "nsStyleStruct.h"
 #include "nsIFrame.h"
 
+class gfxDrawable;
 class nsStyleContext;
 class nsPresContext;
 class nsRenderingContext;
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 835fbc5f486f..3c64492445a6 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -7,6 +7,7 @@
 #define nsLayoutUtils_h__
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/ArrayUtils.h"
 #include "nsChangeHint.h"
 #include "nsAutoPtr.h"
 #include "nsFrameList.h"
@@ -47,8 +48,6 @@ class nsIImageLoadingContent;
 class nsStyleContext;
 class nsBlockFrame;
 class nsContainerFrame;
-class gfxASurface;
-class gfxDrawable;
 class nsView;
 class nsIFrame;
 class nsStyleCoord;
@@ -120,9 +119,12 @@ class nsLayoutUtils
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::gfx::SourceSurface SourceSurface;
+  typedef mozilla::gfx::Color Color;
   typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+  typedef mozilla::gfx::StrokeOptions StrokeOptions;
 
 public:
   typedef mozilla::layers::FrameMetrics FrameMetrics;
@@ -1482,6 +1484,29 @@ public:
                             const nsRect&       aDirty,
                             uint32_t            aImageFlags);
 
+  static inline Color NSColorToColor(nscolor aColor) {
+    return Color(NS_GET_R(aColor)/255.0,
+                 NS_GET_G(aColor)/255.0,
+                 NS_GET_B(aColor)/255.0,
+                 NS_GET_A(aColor)/255.0);
+  }
+
+  static inline void InitDashPattern(StrokeOptions& aStrokeOptions,
+                                     uint8_t aBorderStyle) {
+    if (aBorderStyle == NS_STYLE_BORDER_STYLE_DOTTED) {
+      static Float dot[] = { 1.f, 1.f };
+      aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot);
+      aStrokeOptions.mDashPattern = dot;
+    } else if (aBorderStyle == NS_STYLE_BORDER_STYLE_DASHED) {
+      static Float dash[] = { 5.f, 5.f };
+      aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
+      aStrokeOptions.mDashPattern = dash;
+    } else {
+      aStrokeOptions.mDashLength = 0;
+      aStrokeOptions.mDashPattern = nullptr;
+    }
+  }
+
   /**
    * Convert an nsRect to a gfxRect.
    */
@@ -1713,7 +1738,7 @@ public:
   static bool IsReallyFixedPos(nsIFrame* aFrame);
 
   /**
-   * Obtain a gfxASurface from the given DOM element, if possible.
+   * Obtain a SourceSurface from the given DOM element, if possible.
    * This obtains the most natural surface from the element; that
    * is, the one that can be obtained with the fewest conversions.
    *
@@ -1759,8 +1784,7 @@ public:
   struct SurfaceFromElementResult {
     SurfaceFromElementResult();
 
-    /* mSurface will contain the resulting surface, or will be nullptr on error */
-    nsRefPtr mSurface;
+    /* mSourceSurface will contain the resulting surface, or will be nullptr on error */
     mozilla::RefPtr mSourceSurface;
     /* Contains info for drawing when there is no mSourceSurface. */
     DirectDrawInfo mDrawInfo;
diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp
index b5752093f264..6f9d7b6a2f33 100644
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -61,7 +61,6 @@
 #include "mozilla/dom/DOMParser.h"
 #include "nsDOMSerializer.h"
 #include "nsXMLHttpRequest.h"
-#include "nsChannelPolicy.h"
 
 // view stuff
 #include "nsContentCreatorFunctions.h"
@@ -282,7 +281,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser)
 NS_GENERIC_FACTORY_CONSTRUCTOR(Exception)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService,
                                          DOMRequestService::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManager,
@@ -748,7 +746,6 @@ NS_DEFINE_NAMED_CID(NS_EVENTLISTENERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_GLOBALMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_PARENTPROCESSMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_CHILDPROCESSMESSAGEMANAGER_CID);
-NS_DEFINE_NAMED_CID(NSCHANNELPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_SCRIPTSECURITYMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_PRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_SYSTEMPRINCIPAL_CID);
@@ -1041,7 +1038,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
   { &kNS_GLOBALMESSAGEMANAGER_CID, false, nullptr, CreateGlobalMessageManager },
   { &kNS_PARENTPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateParentMessageManager },
   { &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateChildMessageManager },
-  { &kNSCHANNELPOLICY_CID, false, nullptr, nsChannelPolicyConstructor },
   { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager },
   { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor },
   { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, nsSystemPrincipalConstructor },
@@ -1197,7 +1193,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   { NS_GLOBALMESSAGEMANAGER_CONTRACTID, &kNS_GLOBALMESSAGEMANAGER_CID },
   { NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_PARENTPROCESSMESSAGEMANAGER_CID },
   { NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_CHILDPROCESSMESSAGEMANAGER_CID },
-  { NSCHANNELPOLICY_CONTRACTID, &kNSCHANNELPOLICY_CID },
   { NS_SCRIPTSECURITYMANAGER_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
   { NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
   { NS_PRINCIPAL_CONTRACTID, &kNS_PRINCIPAL_CID },
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c742c78225b0..a767297974de 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -7,8 +7,11 @@
 
 #include "nsImageFrame.h"
 
+#include "gfx2DGlue.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Helpers.h"
 #include "mozilla/MouseEvents.h"
 
 #include "nsCOMPtr.h"
@@ -70,6 +73,7 @@
 #include "mozilla/dom/Link.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 // sizes (pixels) for image icon, padding and border frame
 #define ICON_SIZE        (16)
@@ -1292,19 +1296,19 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
 
 #ifdef DEBUG
 static void PaintDebugImageMap(nsIFrame* aFrame, nsRenderingContext* aCtx,
-     const nsRect& aDirtyRect, nsPoint aPt) {
+                               const nsRect& aDirtyRect, nsPoint aPt)
+{
   nsImageFrame* f = static_cast(aFrame);
   nsRect inner = f->GetInnerArea() + aPt;
-
-  aCtx->SetColor(NS_RGB(0, 0, 0));
-  aCtx->ThebesContext()->Save();
   gfxPoint devPixelOffset =
     nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
                                    aFrame->PresContext()->AppUnitsPerDevPixel());
-  aCtx->ThebesContext()->SetMatrix(
-    aCtx->ThebesContext()->CurrentMatrix().Translate(devPixelOffset));
-  f->GetImageMap()->Draw(aFrame, *aCtx);
-  aCtx->ThebesContext()->Restore();
+  DrawTarget* drawTarget = aCtx->GetDrawTarget();
+  AutoRestoreTransform autoRestoreTransform(drawTarget);
+  drawTarget->SetTransform(
+    drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
+  f->GetImageMap()->Draw(aFrame, *drawTarget,
+                         ColorPattern(Color(0.f, 0.f, 0.f, 1.f)));
 }
 #endif
 
@@ -1458,6 +1462,8 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
+  DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
+
   // Render the image into our content area (the area inside
   // the borders and padding)
   NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width");
@@ -1470,20 +1476,22 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
     nullptr, aFlags);
 
   nsImageMap* map = GetImageMap();
-  if (nullptr != map) {
-    aRenderingContext.ThebesContext()->Save();
+  if (map) {
     gfxPoint devPixelOffset =
       nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
                                      PresContext()->AppUnitsPerDevPixel());
-    aRenderingContext.ThebesContext()->SetMatrix(
-      aRenderingContext.ThebesContext()->CurrentMatrix().Translate(devPixelOffset));
-    aRenderingContext.SetColor(NS_RGB(255, 255, 255));
-    aRenderingContext.SetLineStyle(nsLineStyle_kSolid);
-    map->Draw(this, aRenderingContext);
-    aRenderingContext.SetColor(NS_RGB(0, 0, 0));
-    aRenderingContext.SetLineStyle(nsLineStyle_kDotted);
-    map->Draw(this, aRenderingContext);
-    aRenderingContext.ThebesContext()->Restore();
+    AutoRestoreTransform autoRestoreTransform(drawTarget);
+    drawTarget->SetTransform(
+      drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
+
+    // solid white stroke:
+    map->Draw(this, *drawTarget, ColorPattern(Color(1.f, 1.f, 1.f, 1.f)));
+
+    // then dashed black stroke over the top:
+    StrokeOptions strokeOptions;
+    nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED);
+    map->Draw(this, *drawTarget, ColorPattern(Color(0.f, 0.f, 0.f, 1.f)),
+              strokeOptions);
   }
 }
 
@@ -1931,7 +1939,6 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
                        nullptr,      /* Not associated with any particular document */
                        loadFlags,
                        nullptr,
-                       nullptr,      /* channel policy not needed */
                        EmptyString(),
                        aRequest);
 }
diff --git a/layout/generic/nsImageMap.cpp b/layout/generic/nsImageMap.cpp
index d5baec7ea1d1..b078c6a836c0 100644
--- a/layout/generic/nsImageMap.cpp
+++ b/layout/generic/nsImageMap.cpp
@@ -9,6 +9,7 @@
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
+#include "mozilla/gfx/PathHelpers.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsRenderingContext.h"
@@ -26,6 +27,7 @@
 #endif
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 class Area {
 public:
@@ -35,7 +37,9 @@ public:
   virtual void ParseCoords(const nsAString& aSpec);
 
   virtual bool IsInside(nscoord x, nscoord y) const = 0;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) = 0;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) = 0;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) = 0;
 
   void HasFocus(bool aHasFocus);
@@ -267,7 +271,9 @@ public:
   explicit DefaultArea(nsIContent* aArea);
 
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
@@ -281,21 +287,18 @@ bool DefaultArea::IsInside(nscoord x, nscoord y) const
   return true;
 }
 
-void DefaultArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void DefaultArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                       const ColorPattern& aColor,
+                       const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
-    nsRect r = aFrame->GetRect();
-    r.MoveTo(0, 0);
-    nscoord x1 = r.x;
-    nscoord y1 = r.y;
+    nsRect r(nsPoint(0, 0), aFrame->GetSize());
     const nscoord kOnePixel = nsPresContext::CSSPixelsToAppUnits(1);
-    nscoord x2 = r.XMost() - kOnePixel;
-    nscoord y2 = r.YMost() - kOnePixel;
-    // XXX aRC.DrawRect(r) result is ugly, that's why we use DrawLine.
-    aRC.DrawLine(x1, y1, x1, y2);
-    aRC.DrawLine(x1, y2, x2, y2);
-    aRC.DrawLine(x1, y1, x2, y1);
-    aRC.DrawLine(x2, y1, x2, y2);
+    r.width -= kOnePixel;
+    r.height -= kOnePixel;
+    Rect rect =
+      ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel()));
+    StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions);
   }
 }
 
@@ -313,7 +316,9 @@ public:
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
@@ -375,7 +380,9 @@ bool RectArea::IsInside(nscoord x, nscoord y) const
   return false;
 }
 
-void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void RectArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 4) {
@@ -385,10 +392,10 @@ void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
       nscoord y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[3]);
       NS_ASSERTION(x1 <= x2 && y1 <= y2,
                    "Someone screwed up RectArea::ParseCoords");
-      aRC.DrawLine(x1, y1, x1, y2);
-      aRC.DrawLine(x1, y2, x2, y2);
-      aRC.DrawLine(x1, y1, x2, y1);
-      aRC.DrawLine(x2, y1, x2, y2);
+      nsRect r(x1, y1, x2 - x1, y2 - y1);
+      Rect rect =
+        ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel()));
+      StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions);
     }
   }
 }
@@ -415,7 +422,9 @@ public:
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
@@ -507,23 +516,36 @@ bool PolyArea::IsInside(nscoord x, nscoord y) const
   return false;
 }
 
-void PolyArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void PolyArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 6) {
-      nscoord x0 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      nscoord y0 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      nscoord x1, y1;
+      // Where possible, we want all horizontal and vertical lines to align on
+      // pixel rows or columns, and to start at pixel boundaries so that one
+      // pixel dashing neatly sits on pixels to give us neat lines. To achieve
+      // that we draw each line segment as a separate path, snapping it to
+      // device pixels if applicable.
+      nsPresContext* pc = aFrame->PresContext();
+      Point p1(pc->CSSPixelsToDevPixels(mCoords[0]),
+               pc->CSSPixelsToDevPixels(mCoords[1]));
+      Point p2, p1snapped, p2snapped;
       for (int32_t i = 2; i < mNumCoords; i += 2) {
-        x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i]);
-        y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i+1]);
-        aRC.DrawLine(x0, y0, x1, y1);
-        x0 = x1;
-        y0 = y1;
+        p2.x = pc->CSSPixelsToDevPixels(mCoords[i]);
+        p2.y = pc->CSSPixelsToDevPixels(mCoords[i+1]);
+        p1snapped = p1;
+        p2snapped = p2;
+        SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+        aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
+        p1 = p2;
       }
-      x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      aRC.DrawLine(x0, y0, x1, y1);
+      p2.x = pc->CSSPixelsToDevPixels(mCoords[0]);
+      p2.y = pc->CSSPixelsToDevPixels(mCoords[1]);
+      p1snapped = p1;
+      p2snapped = p2;
+      SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+      aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
     }
   }
 }
@@ -555,7 +577,9 @@ public:
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
@@ -614,20 +638,23 @@ bool CircleArea::IsInside(nscoord x, nscoord y) const
   return false;
 }
 
-void CircleArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void CircleArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                      const ColorPattern& aColor,
+                      const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 3) {
-      nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      nscoord radius = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
-      if (radius < 0) {
+      Point center(aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[0]),
+                   aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[1]));
+      Float diameter =
+        2 * aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[2]);
+      if (diameter <= 0) {
         return;
       }
-      nscoord x = x1 - radius;
-      nscoord y = y1 - radius;
-      nscoord w = 2 * radius;
-      aRC.DrawEllipse(x, y, w, w);
+      RefPtr builder = aDrawTarget.CreatePathBuilder();
+      AppendEllipseToPath(builder, center, Size(diameter, diameter));
+      RefPtr circle = builder->Finish();
+      aDrawTarget.Stroke(circle, aColor, aStrokeOptions);
     }
   }
 }
@@ -868,12 +895,14 @@ nsImageMap::GetAreaAt(uint32_t aIndex) const
 }
 
 void
-nsImageMap::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+nsImageMap::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                 const ColorPattern& aColor,
+                 const StrokeOptions& aStrokeOptions)
 {
   uint32_t i, n = mAreas.Length();
   for (i = 0; i < n; i++) {
     Area* area = mAreas.ElementAt(i);
-    area->Draw(aFrame, aRC);
+    area->Draw(aFrame, aDrawTarget, aColor, aStrokeOptions);
   }
 }
 
diff --git a/layout/generic/nsImageMap.h b/layout/generic/nsImageMap.h
index 239ffbbbd0e3..749f36cc0441 100644
--- a/layout/generic/nsImageMap.h
+++ b/layout/generic/nsImageMap.h
@@ -8,6 +8,7 @@
 #ifndef nsImageMap_h
 #define nsImageMap_h
 
+#include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "nsCoord.h"
 #include "nsTArray.h"
@@ -24,6 +25,10 @@ struct nsRect;
 class nsImageMap MOZ_FINAL : public nsStubMutationObserver,
                              public nsIDOMEventListener
 {
+  typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::ColorPattern ColorPattern;
+  typedef mozilla::gfx::StrokeOptions StrokeOptions;
+
 public:
   nsImageMap();
 
@@ -45,7 +50,9 @@ public:
    */
   nsIContent* GetAreaAt(uint32_t aIndex) const;
 
-  void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
+  void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+            const ColorPattern& aColor,
+            const StrokeOptions& aStrokeOptions = StrokeOptions());
   
   /** 
    * Called just before the nsImageFrame releases us. 
diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp
index b78e012d9e70..bb9ca9afc989 100644
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -313,8 +313,8 @@ nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace,
 #ifdef NOISY_REFLOW
   nsFrame::ListTag(stdout, mBlockReflowState->frame);
   printf(": UpdateBand: %d,%d,%d,%d deltaISize=%d deltaICoord=%d\n",
-         aNewAvailSpace.x, aNewAvailSpace.y,
-         aNewAvailSpace.width, aNewAvailSpace.height, deltaISize, deltaICoord);
+         aNewAvailSpace.IStart(lineWM), aNewAvailSpace.BStart(lineWM),
+         aNewAvailSpace.ISize(lineWM), aNewAvailSpace.BSize(lineWM), deltaISize, deltaICoord);
 #endif
 
   // Update the root span position
@@ -795,8 +795,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
     nsHTMLReflowState& reflowState = *reflowStateHolder;
     reflowState.mLineLayout = this;
     reflowState.mFlags.mIsTopOfPage = mIsTopOfPage;
-    if (reflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE)
-      reflowState.AvailableWidth() = availableSpaceOnLine;
+    if (reflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE) {
+      reflowState.AvailableISize() = availableSpaceOnLine;
+    }
     WritingMode stateWM = reflowState.GetWritingMode();
     pfd->mMargin =
       reflowState.ComputedLogicalMargin().ConvertTo(frameWM, stateWM);
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp
index 2f21016e6b87..2ffb604613a4 100644
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -387,11 +387,10 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
   // container, but our display item is LAYER_ACTIVE_FORCE which
   // forces all layers above to be active.
   MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
-  gfx::Matrix4x4 m;
-  m.Translate(offset.x, offset.y, 0.0);
+  gfx::Matrix4x4 m = gfx::Matrix4x4::Translation(offset.x, offset.y, 0.0);
   // Remote content can't be repainted by us, so we multiply down
   // the resolution that our container expects onto our container.
-  m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
+  m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
   layer->SetBaseTransform(m);
 
   return layer.forget();
diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp
index 1dfeb22d1fc3..8b5493ae8007 100644
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -17,7 +17,6 @@
 #include "mozilla/Preferences.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsFontFaceLoader.h"
-#include "nsIChannelPolicy.h"
 #include "nsIConsoleService.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
@@ -395,16 +394,6 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
   nsCOMPtr loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
 
   nsCOMPtr channel;
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = aUserFontEntry->GetPrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
-  }
   // Note we are calling NS_NewChannelInternal() with both a node and a
   // principal.  This is because the document where the font is being loaded
   // might have a different origin from the principal of the stylesheet
@@ -415,7 +404,6 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
                              aUserFontEntry->GetPrincipal(),
                              nsILoadInfo::SEC_NORMAL,
                              nsIContentPolicy::TYPE_FONT,
-                             channelPolicy,
                              loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1172,17 +1160,6 @@ FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
   nsresult rv;
 
   nsCOMPtr channel;
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = aFontToLoad->GetPrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
-  }
-
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps) {
     return NS_ERROR_FAILURE;
@@ -1196,8 +1173,7 @@ FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
                              ps->GetDocument(),
                              aFontToLoad->GetPrincipal(),
                              nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_FONT,
-                             channelPolicy);
+                             nsIContentPolicy::TYPE_FONT);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 5cf983df3db2..c0773ebc3555 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -60,7 +60,6 @@
 #include "nsIDOMStyleSheet.h"
 #include "nsError.h"
 
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 
 #include "mozilla/dom/EncodingUtils.h"
@@ -1549,20 +1548,10 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
   mSyncCallback = true;
 #endif
   nsCOMPtr loadGroup;
-  // Content Security Policy information to pass into channel
-  nsCOMPtr channelPolicy;
   if (mDocument) {
     loadGroup = mDocument->GetDocumentLoadGroup();
     NS_ASSERTION(loadGroup,
                  "No loadgroup for stylesheet; onload will fire early");
-    nsCOMPtr csp;
-    rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (csp) {
-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-      channelPolicy->SetContentSecurityPolicy(csp);
-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_STYLESHEET);
-    }
   }
 
   nsLoadFlags securityFlags = nsILoadInfo::SEC_NORMAL;
@@ -1581,7 +1570,6 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
                              requestingPrincipal,
                              securityFlags,
                              nsIContentPolicy::TYPE_STYLESHEET,
-                             channelPolicy,
                              loadGroup,
                              nullptr,   // aCallbacks
                              nsIChannel::LOAD_NORMAL |
diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp
index bc98acfee780..40bc8bfa0954 100644
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -1556,7 +1556,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
 
   Point3D translate =
     InterpolateNumerically(translate1, translate2, aProgress);
-  result.Translate(translate.x, translate.y, translate.z);
+  result.PreTranslate(translate.x, translate.y, translate.z);
 
   gfxQuaternion q3 = rotate1.Slerp(rotate2, aProgress);
   Matrix4x4 rotate = q3.ToMatrix();
@@ -1586,7 +1586,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
   Point3D scale =
     InterpolateNumerically(scale1, scale2, aProgress);
   if (scale != Point3D(1.0, 1.0, 1.0)) {
-    result.Scale(scale.x, scale.y, scale.z);
+    result.PreScale(scale.x, scale.y, scale.z);
   }
 
   return To3DMatrix(result);
diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp
index c5d0f0b2283a..1fe8f3d2d479 100644
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -9,7 +9,6 @@
 // Keep others in (case-insensitive) order:
 #include "gfxUtils.h"
 #include "nsGkAtoms.h"
-#include "nsRenderingContext.h"
 #include "nsSVGEffects.h"
 #include "nsSVGElement.h"
 #include "mozilla/dom/SVGFilterElement.h"
diff --git a/layout/svg/nsSVGFilterFrame.h b/layout/svg/nsSVGFilterFrame.h
index 47d3ea475b50..1fcc9eb88848 100644
--- a/layout/svg/nsSVGFilterFrame.h
+++ b/layout/svg/nsSVGFilterFrame.h
@@ -16,7 +16,6 @@ class nsIAtom;
 class nsIContent;
 class nsIFrame;
 class nsIPresShell;
-class nsRenderingContext;
 class nsStyleContext;
 class nsSVGIntegerPair;
 class nsSVGLength2;
diff --git a/layout/svg/nsSVGFilterInstance.cpp b/layout/svg/nsSVGFilterInstance.cpp
index 39d1f10a4e4e..0a7e32593402 100644
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -10,7 +10,6 @@
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "nsISVGChildFrame.h"
-#include "nsRenderingContext.h"
 #include "mozilla/dom/SVGFilterElement.h"
 #include "nsReferencedElement.h"
 #include "nsSVGFilterFrame.h"
diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
index 9d92a7ce1e1d..e26440ca12ca 100644
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -625,6 +625,10 @@ WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
+  if (!aInputImage._length) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
   GMPVideoFrame* ftmp = nullptr;
   GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
   if (err != GMPNoErr) {
diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
index 16ad7089ae4f..bf7df1c89eb9 100644
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -1195,22 +1195,29 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
     const layers::PlanarYCbCrData *data = yuv->GetData();
 
     uint8_t *y = data->mYChannel;
-#ifdef DEBUG
     uint8_t *cb = data->mCbChannel;
     uint8_t *cr = data->mCrChannel;
-#endif
     uint32_t width = yuv->GetSize().width;
     uint32_t height = yuv->GetSize().height;
     uint32_t length = yuv->GetDataSize();
+    // NOTE: length may be rounded up or include 'other' data (see
+    // YCbCrImageDataDeserializerBase::ComputeMinBufferSize())
 
     // SendVideoFrame only supports contiguous YCrCb 4:2:0 buffers
     // Verify it's contiguous and in the right order
-    MOZ_ASSERT(cb == (y + YSIZE(width, height)) &&
-               cr == (cb + CRSIZE(width, height)) &&
-               length == I420SIZE(width, height));
-    // XXX Consider making this a non-debug-only check if we ever implement
+    if (cb != (y + YSIZE(width, height)) ||
+        cr != (cb + CRSIZE(width, height))) {
+      MOZ_ASSERT(false, "Incorrect cb/cr pointers in ProcessVideoChunk()!");
+      return;
+    }
+    if (length < I420SIZE(width, height)) {
+      MOZ_ASSERT(false, "Invalid length for ProcessVideoChunk()");
+      return;
+    }
+    // XXX Consider modifying these checks if we ever implement
     // any subclasses of PlanarYCbCrImage that allow disjoint buffers such
-    // that y+3(width*height)/2 might go outside the allocation.
+    // that y+3(width*height)/2 might go outside the allocation or there are
+    // pads between y, cr and cb.
     // GrallocImage can have wider strides, and so in some cases
     // would encode as garbage.  If we need to encode it we'll either want to
     // modify SendVideoFrame or copy/move the data in the buffer.
@@ -1218,7 +1225,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
     // OK, pass it on to the conduit
     MOZ_MTLOG(ML_DEBUG, "Sending a video frame");
     // Not much for us to do with an error
-    conduit->SendVideoFrame(y, length, width, height, mozilla::kVideoI420, 0);
+    conduit->SendVideoFrame(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0);
   } else if(format == ImageFormat::CAIRO_SURFACE) {
     layers::CairoImage* rgb =
     const_cast(
diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc
index 651f960b1675..a0567ca28ddf 100644
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc
@@ -590,6 +590,11 @@ VCMEncodedFrame* VCMJitterBuffer::ExtractAndSetDecode(uint32_t timestamp) {
   if ((*frame).IsSessionComplete())
     UpdateAveragePacketsPerFrame(frame->NumPackets());
 
+  if (frame->Length() == 0) {
+    // Normally only if MakeDecodable() on an incomplete frame threw it all away
+    ReleaseFrame(frame);
+    return NULL;
+  }
   return frame;
 }
 
diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
index 8ec2349f56a5..764a9f436d90 100644
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
@@ -548,6 +548,9 @@ int VCMSessionInfo::InsertPacket(const VCMPacket& packet,
 
   int returnLength = InsertBuffer(frame_buffer, packet_list_it);
   UpdateCompleteSession();
+  // We call MakeDecodable() before decoding, which removes packets after a loss
+  // (and which means h.264 mode 1 frames with a loss in the first packet will be
+  // totally removed)
   if (decode_error_mode == kWithErrors)
     decodable_ = true;
   else if (decode_error_mode == kSelectiveErrors)
diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp
index 99230e006793..c712544f2d5c 100644
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -13,7 +13,6 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIViewSourceChannel.h"
-#include "nsChannelProperties.h"
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 
diff --git a/mozglue/build/BionicGlue.cpp b/mozglue/build/BionicGlue.cpp
index 524fbc168b16..ec4ec6a23e4f 100644
--- a/mozglue/build/BionicGlue.cpp
+++ b/mozglue/build/BionicGlue.cpp
@@ -180,87 +180,6 @@ PR_GetEnvLock(void)
   return &_pr_envLock;
 }
 
-/* Amazon Kindle Fire HD's libc provides most of the
- * functions in string.h as weak symbols, which dlsym
- * cannot resolve. Thus, we must wrap these functions.
- * See bug 791419.
- */
-
-#ifndef MOZ_WIDGET_GONK
-#include 
-extern "C" NS_EXPORT void* __real_memccpy(void * a0, const void * a1, int a2, size_t a3);
-extern "C" NS_EXPORT void* __real_memchr(const void * a0, int a1, size_t a2);
-extern "C" NS_EXPORT void* __real_memrchr(const void * a0, int a1, size_t a2);
-extern "C" NS_EXPORT int __real_memcmp(const void * a0, const void * a1, size_t a2);
-extern "C" NS_EXPORT void* __real_memcpy(void * a0, const void * a1, size_t a2);
-extern "C" NS_EXPORT void* __real_memmove(void * a0, const void * a1, size_t a2);
-extern "C" NS_EXPORT void* __real_memset(void * a0, int a1, size_t a2);
-extern "C" NS_EXPORT void* __real_memmem(const void * a0, size_t a1, const void * a2, size_t a3);
-extern "C" NS_EXPORT char* __real_index(const char * a0, int a1);
-extern "C" NS_EXPORT char* __real_strchr(const char * a0, int a1);
-extern "C" NS_EXPORT char* __real_strrchr(const char * a0, int a1);
-extern "C" NS_EXPORT size_t __real_strlen(const char * a0);
-extern "C" NS_EXPORT int __real_strcmp(const char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strcpy(char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strcat(char * a0, const char * a1);
-extern "C" NS_EXPORT int __real_strcasecmp(const char * a0, const char * a1);
-extern "C" NS_EXPORT int __real_strncasecmp(const char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT char* __real_strstr(const char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strcasestr(const char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strtok(char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strtok_r(char * a0, const char * a1, char** a2);
-extern "C" NS_EXPORT char* __real_strerror(int a0);
-extern "C" NS_EXPORT int __real_strerror_r(int a0, char * a1, size_t a2);
-extern "C" NS_EXPORT size_t __real_strnlen(const char * a0, size_t a1);
-extern "C" NS_EXPORT char* __real_strncat(char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT int __real_strncmp(const char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT char* __real_strncpy(char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT size_t __real_strlcat(char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT size_t __real_strlcpy(char * a0, const char * a1, size_t a2);
-extern "C" NS_EXPORT size_t __real_strcspn(const char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strpbrk(const char * a0, const char * a1);
-extern "C" NS_EXPORT char* __real_strsep(char ** a0, const char * a1);
-extern "C" NS_EXPORT size_t __real_strspn(const char * a0, const char * a1);
-extern "C" NS_EXPORT int __real_strcoll(const char * a0, const char * a1);
-extern "C" NS_EXPORT size_t __real_strxfrm(char * a0, const char * a1, size_t a2);
-
-extern "C" NS_EXPORT void* __wrap_memccpy(void * a0, const void * a1, int a2, size_t a3) { return __real_memccpy(a0, a1, a2, a3); }
-extern "C" NS_EXPORT void* __wrap_memchr(const void * a0, int a1, size_t a2) { return __real_memchr(a0, a1, a2); }
-extern "C" NS_EXPORT void* __wrap_memrchr(const void * a0, int a1, size_t a2) { return __real_memrchr(a0, a1, a2); }
-extern "C" NS_EXPORT int __wrap_memcmp(const void * a0, const void * a1, size_t a2) { return __real_memcmp(a0, a1, a2); }
-extern "C" NS_EXPORT void* __wrap_memcpy(void * a0, const void * a1, size_t a2) { return __real_memcpy(a0, a1, a2); }
-extern "C" NS_EXPORT void* __wrap_memmove(void * a0, const void * a1, size_t a2) { return __real_memmove(a0, a1, a2); }
-extern "C" NS_EXPORT void* __wrap_memset(void * a0, int a1, size_t a2) { return __real_memset(a0, a1, a2); }
-extern "C" NS_EXPORT void* __wrap_memmem(const void * a0, size_t a1, const void * a2, size_t a3) { return __real_memmem(a0, a1, a2, a3); }
-extern "C" NS_EXPORT char* __wrap_index(const char * a0, int a1) { return __real_index(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strchr(const char * a0, int a1) { return __real_strchr(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strrchr(const char * a0, int a1) { return __real_strrchr(a0, a1); }
-extern "C" NS_EXPORT size_t __wrap_strlen(const char * a0) { return __real_strlen(a0); }
-extern "C" NS_EXPORT int __wrap_strcmp(const char * a0, const char * a1) { return __real_strcmp(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strcpy(char * a0, const char * a1) { return __real_strcpy(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strcat(char * a0, const char * a1) { return __real_strcat(a0, a1); }
-extern "C" NS_EXPORT int __wrap_strcasecmp(const char * a0, const char * a1) { return __real_strcasecmp(a0, a1); }
-extern "C" NS_EXPORT int __wrap_strncasecmp(const char * a0, const char * a1, size_t a2) { return __real_strncasecmp(a0, a1, a2); }
-extern "C" NS_EXPORT char* __wrap_strstr(const char * a0, const char * a1) { return __real_strstr(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strcasestr(const char * a0, const char * a1) { return __real_strcasestr(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strtok(char * a0, const char * a1) { return __real_strtok(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strtok_r(char * a0, const char * a1, char** a2) { return __real_strtok_r(a0, a1, a2); }
-extern "C" NS_EXPORT char* __wrap_strerror(int a0) { return __real_strerror(a0); }
-extern "C" NS_EXPORT int __wrap_strerror_r(int a0, char * a1, size_t a2) { return __real_strerror_r(a0, a1, a2); }
-extern "C" NS_EXPORT size_t __wrap_strnlen(const char * a0, size_t a1) { return __real_strnlen(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strncat(char * a0, const char * a1, size_t a2) { return __real_strncat(a0, a1, a2); }
-extern "C" NS_EXPORT int __wrap_strncmp(const char * a0, const char * a1, size_t a2) { return __real_strncmp(a0, a1, a2); }
-extern "C" NS_EXPORT char* __wrap_strncpy(char * a0, const char * a1, size_t a2) { return __real_strncpy(a0, a1, a2); }
-extern "C" NS_EXPORT size_t __wrap_strlcat(char * a0, const char * a1, size_t a2) { return __real_strlcat(a0, a1, a2); }
-extern "C" NS_EXPORT size_t __wrap_strlcpy(char * a0, const char * a1, size_t a2) { return __real_strlcpy(a0, a1, a2); }
-extern "C" NS_EXPORT size_t __wrap_strcspn(const char * a0, const char * a1) { return __real_strcspn(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strpbrk(const char * a0, const char * a1) { return __real_strpbrk(a0, a1); }
-extern "C" NS_EXPORT char* __wrap_strsep(char ** a0, const char * a1) { return __real_strsep(a0, a1); }
-extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { return __real_strspn(a0, a1); }
-extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return __real_strcoll(a0, a1); }
-extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return __real_strxfrm(a0, a1, a2); }
-#endif
-
 /* Flash plugin uses symbols that are not present in Android >= 4.4 */
 #ifndef MOZ_WIDGET_GONK
 namespace android {
diff --git a/mozglue/linker/BaseElf.cpp b/mozglue/linker/BaseElf.cpp
index 7cefecee03e9..9fb8a6f7232e 100644
--- a/mozglue/linker/BaseElf.cpp
+++ b/mozglue/linker/BaseElf.cpp
@@ -5,8 +5,10 @@
 #include "BaseElf.h"
 #include "Elfxx.h"
 #include "Logging.h"
+#include "mozilla/RefPtr.h"
 
 using namespace Elf;
+using namespace mozilla;
 
 unsigned long
 BaseElf::Hash(const char *symbol)
@@ -22,6 +24,12 @@ BaseElf::Hash(const char *symbol)
   return h;
 }
 
+void *
+BaseElf::GetSymbolPtr(const char *symbol) const
+{
+  return GetSymbolPtr(symbol, Hash(symbol));
+}
+
 void *
 BaseElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
 {
@@ -53,3 +61,155 @@ BaseElf::GetSymbol(const char *symbol, unsigned long hash) const
   }
   return nullptr;
 }
+
+bool
+BaseElf::Contains(void *addr) const
+{
+  return base.Contains(addr);
+}
+
+#ifdef __ARM_EABI__
+const void *
+BaseElf::FindExidx(int *pcount) const
+{
+  if (arm_exidx) {
+    *pcount = arm_exidx.numElements();
+    return arm_exidx;
+  }
+  *pcount = 0;
+  return nullptr;
+}
+#endif
+
+mozilla::TemporaryRef
+LoadedElf::Create(const char *path, void *base_addr)
+{
+  DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = ...", path, base_addr);
+
+  uint8_t mapped;
+  /* If the page is not mapped, mincore returns an error. If base_addr is
+   * nullptr, as would happen if the corresponding binary is prelinked with
+   * the prelink look (but not with the android apriori tool), no page being
+   * mapped there (right?), mincore returns an error, too, which makes
+   * prelinked libraries on glibc unsupported. This is not an interesting
+   * use case for now, so don't try supporting that case.
+   */
+  if (mincore(const_cast(base_addr), PageSize(), &mapped))
+    return nullptr;
+
+  RefPtr elf = new LoadedElf(path);
+
+  const Ehdr *ehdr = Ehdr::validate(base_addr);
+  if (!ehdr)
+    return nullptr;
+
+  Addr min_vaddr = (Addr) -1; // We want to find the lowest and biggest
+  Addr max_vaddr = 0;         // virtual address used by this Elf.
+  const Phdr *dyn = nullptr;
+#ifdef __ARM_EABI__
+  const Phdr *arm_exidx_phdr = nullptr;
+#endif
+
+  Array phdrs(reinterpret_cast(ehdr) + ehdr->e_phoff,
+                    ehdr->e_phnum);
+  for (auto phdr = phdrs.begin(); phdr < phdrs.end(); ++phdr) {
+    switch (phdr->p_type) {
+      case PT_LOAD:
+        if (phdr->p_vaddr < min_vaddr)
+          min_vaddr = phdr->p_vaddr;
+        if (max_vaddr < phdr->p_vaddr + phdr->p_memsz)
+          max_vaddr = phdr->p_vaddr + phdr->p_memsz;
+        break;
+      case PT_DYNAMIC:
+        dyn = &*phdr;
+        break;
+#ifdef __ARM_EABI__
+      case PT_ARM_EXIDX:
+        /* We cannot initialize arm_exidx here
+           because we don't have a base yet */
+        arm_exidx_phdr = &*phdr;
+        break;
+#endif
+    }
+  }
+
+  /* If the lowest PT_LOAD virtual address in headers is not 0, then the ELF
+   * is either prelinked or a non-PIE executable. The former case is not
+   * possible, because base_addr would be nullptr and the mincore test above
+   * would already have made us return.
+   * For a non-PIE executable, PT_LOADs contain absolute addresses, so in
+   * practice, this means min_vaddr should be equal to base_addr. max_vaddr
+   * can thus be adjusted accordingly.
+   */
+  if (min_vaddr != 0) {
+    void *min_vaddr_ptr = reinterpret_cast(
+      static_cast(min_vaddr));
+    if (min_vaddr_ptr != base_addr) {
+      LOG("%s: %p != %p", elf->GetPath(), min_vaddr_ptr, base_addr);
+      return nullptr;
+    }
+    max_vaddr -= min_vaddr;
+  }
+  if (!dyn) {
+    LOG("%s: No PT_DYNAMIC segment found", elf->GetPath());
+    return nullptr;
+  }
+
+  elf->base.Assign(base_addr, max_vaddr);
+
+  if (!elf->InitDyn(dyn))
+    return nullptr;
+
+#ifdef __ARM_EABI__
+  if (arm_exidx_phdr)
+    elf->arm_exidx.InitSize(elf->GetPtr(arm_exidx_phdr->p_vaddr),
+                            arm_exidx_phdr->p_memsz);
+#endif
+
+  DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = %p", path, base_addr,
+    static_cast(elf));
+
+  ElfLoader::Singleton.Register(elf);
+  return elf;
+}
+
+bool
+LoadedElf::InitDyn(const Phdr *pt_dyn)
+{
+  Array dyns;
+  dyns.InitSize(GetPtr(pt_dyn->p_vaddr), pt_dyn->p_filesz);
+
+  size_t symnum = 0;
+  for (auto dyn = dyns.begin(); dyn < dyns.end() && dyn->d_tag; ++dyn) {
+    switch (dyn->d_tag) {
+      case DT_HASH:
+        {
+          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
+          const Elf::Word *hash_table_header = \
+            GetPtr(dyn->d_un.d_ptr);
+          symnum = hash_table_header[1];
+          buckets.Init(&hash_table_header[2], hash_table_header[0]);
+          chains.Init(&*buckets.end());
+        }
+        break;
+      case DT_STRTAB:
+        DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
+        strtab.Init(GetPtr(dyn->d_un.d_ptr));
+        break;
+      case DT_SYMTAB:
+        DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
+        symtab.Init(GetPtr(dyn->d_un.d_ptr));
+        break;
+    }
+  }
+  if (!buckets || !symnum) {
+    ERROR("%s: Missing or broken DT_HASH", GetPath());
+  } else if (!strtab) {
+    ERROR("%s: Missing DT_STRTAB", GetPath());
+  } else if (!symtab) {
+    ERROR("%s: Missing DT_SYMTAB", GetPath());
+  } else {
+    return true;
+  }
+  return false;
+}
diff --git a/mozglue/linker/BaseElf.h b/mozglue/linker/BaseElf.h
index 2c9164e92e7f..5d3a8fd91485 100644
--- a/mozglue/linker/BaseElf.h
+++ b/mozglue/linker/BaseElf.h
@@ -33,20 +33,23 @@ public:
    */
   const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
 
-  BaseElf(const char *path)
-  : LibHandle(path) { }
+  BaseElf(const char *path, Mappable *mappable = nullptr)
+  : LibHandle(path)
+  , mappable(mappable)
+  {
+  }
 
 protected:
    /**
     * Inherited from LibHandle. Those are temporary and are not supposed to
     * be used.
     */
-   virtual void *GetSymbolPtr(const char *symbol) const { return NULL; };
-   virtual bool Contains(void *addr) const { return false; };
+   virtual void *GetSymbolPtr(const char *symbol) const;
+   virtual bool Contains(void *addr) const;
    virtual void *GetBase() const { return GetPtr(0); }
 
 #ifdef __ARM_EABI__
-  virtual const void *FindExidx(int *pcount) const { return NULL; };
+  virtual const void *FindExidx(int *pcount) const;
 #endif
 
   virtual Mappable *GetMappable() const { return NULL; };
@@ -75,6 +78,11 @@ public:
     return reinterpret_cast(base + offset);
   }
 
+  /* Appropriated Mappable */
+  /* /!\ we rely on this being nullptr for BaseElf instances, but not
+   * CustomElf instances. */
+  mozilla::RefPtr mappable;
+
   /* Base address where the library is loaded */
   MappedPtr base;
 
@@ -88,6 +96,46 @@ public:
 
   /* Symbol table */
   UnsizedArray symtab;
+
+#ifdef __ARM_EABI__
+  /* ARM.exidx information used by FindExidx */
+  Array arm_exidx;
+#endif
 };
 
+
+/**
+ * Class for ELF libraries that already loaded in memory.
+ */
+class LoadedElf: public BaseElf
+{
+public:
+  /**
+   * Returns a LoadedElf corresponding to the already loaded ELF
+   * at the given base address.
+   */
+  static mozilla::TemporaryRef Create(const char *path,
+                                                 void *base_addr);
+
+private:
+  LoadedElf(const char *path)
+  : BaseElf(path) { }
+
+  ~LoadedElf()
+  {
+    /* Avoid base's destructor unmapping something that doesn't actually
+     * belong to it. */
+    base.release();
+    ElfLoader::Singleton.Forget(this);
+  }
+
+  /**
+   * Initializes the library according to information found in the given
+   * PT_DYNAMIC header.
+   * Returns whether this succeeded or failed.
+   */
+  bool InitDyn(const Elf::Phdr *pt_dyn);
+};
+
+
 #endif /* BaseElf_h */
diff --git a/mozglue/linker/CustomElf.cpp b/mozglue/linker/CustomElf.cpp
index c258d62f9410..3fad1d593778 100644
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -258,7 +258,9 @@ CustomElf::Load(Mappable *mappable, const char *path, int flags)
                             arm_exidx_phdr->p_memsz);
 #endif
 
-  elf->stats("oneLibLoaded");
+  if (MOZ_UNLIKELY(Logging::isVerbose())) {
+    elf->stats("oneLibLoaded");
+  }
   DEBUG_LOG("CustomElf::Load(\"%s\", 0x%x) = %p", path, flags,
             static_cast(elf));
   return elf;
@@ -276,12 +278,6 @@ CustomElf::~CustomElf()
   ElfLoader::Singleton.Forget(this);
 }
 
-void *
-CustomElf::GetSymbolPtr(const char *symbol) const
-{
-  return BaseElf::GetSymbolPtr(symbol, Hash(symbol));
-}
-
 void *
 CustomElf::GetSymbolPtrInDeps(const char *symbol) const
 {
@@ -333,7 +329,8 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
   if (ElfLoader::Singleton.self_elf) {
     /* We consider the library containing this code a permanent LD_PRELOAD,
      * so, check if the symbol exists here first. */
-    sym = ElfLoader::Singleton.self_elf->GetSymbolPtr(symbol, hash);
+    sym = static_cast(
+      ElfLoader::Singleton.self_elf.get())->GetSymbolPtr(symbol, hash);
     if (sym)
       return sym;
   }
@@ -346,9 +343,12 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
    * happen. */
   for (std::vector >::const_iterator it = dependencies.begin();
        it < dependencies.end(); ++it) {
-    if (!(*it)->IsSystemElf()) {
-      sym = static_cast(
-        static_cast((*it).get()))->GetSymbolPtr(symbol, hash);
+    /* Skip if it's the library containing this code, since we've already
+     * looked at it above. */
+    if (*it == ElfLoader::Singleton.self_elf)
+      continue;
+    if (BaseElf *be = (*it)->AsBaseElf()) {
+      sym = be->GetSymbolPtr(symbol, hash);
     } else {
       sym = (*it)->GetSymbolPtr(symbol);
     }
@@ -358,25 +358,6 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
   return nullptr;
 }
 
-bool
-CustomElf::Contains(void *addr) const
-{
-  return base.Contains(addr);
-}
-
-#ifdef __ARM_EABI__
-const void *
-CustomElf::FindExidx(int *pcount) const
-{
-  if (arm_exidx) {
-    *pcount = arm_exidx.numElements();
-    return arm_exidx;
-  }
-  *pcount = 0;
-  return nullptr;
-}
-#endif
-
 void
 CustomElf::stats(const char *when) const
 {
diff --git a/mozglue/linker/CustomElf.h b/mozglue/linker/CustomElf.h
index 83c048545932..c7242fb465e5 100644
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -35,13 +35,6 @@ public:
    * Inherited from LibHandle/BaseElf
    */
   virtual ~CustomElf();
-  virtual void *GetSymbolPtr(const char *symbol) const;
-  virtual bool Contains(void *addr) const;
-  virtual void *GetBase() const { return GetPtr(0); }
-
-#ifdef __ARM_EABI__
-  virtual const void *FindExidx(int *pcount) const;
-#endif
 
 protected:
   virtual Mappable *GetMappable() const;
@@ -52,7 +45,13 @@ public:
    * used by the caller to give an identifier of the when the stats call is
    * made.
    */
-  void stats(const char *when) const;
+  virtual void stats(const char *when) const;
+
+  /**
+   * Returns the instance, casted as BaseElf. (short of a better way to do
+   * this without RTTI)
+   */
+  virtual BaseElf *AsBaseElf() { return this; }
 
 private:
   /**
@@ -66,9 +65,8 @@ private:
    * Private constructor
    */
   CustomElf(Mappable *mappable, const char *path)
-  : BaseElf(path)
+  : BaseElf(path, mappable)
   , link_map()
-  , mappable(mappable)
   , init(0)
   , fini(0)
   , initialized(false)
@@ -136,9 +134,6 @@ private:
     return CallFunction(GetPtr(addr));
   }
 
-  /* Appropriated Mappable */
-  mozilla::RefPtr mappable;
-
   /* List of dependent libraries */
   std::vector > dependencies;
 
@@ -159,11 +154,6 @@ private:
   bool initialized;
 
   bool has_text_relocs;
-
-#ifdef __ARM_EABI__
-  /* ARM.exidx information used by FindExidx */
-  Array arm_exidx;
-#endif
 };
 
 #endif /* CustomElf_h */
diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp
index 21990e109b34..72f560dc523e 100644
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -452,8 +452,15 @@ void
 ElfLoader::Register(LibHandle *handle)
 {
   handles.push_back(handle);
-  if (dbg && !handle->IsSystemElf())
-    dbg.Add(static_cast(handle));
+}
+
+void
+ElfLoader::Register(CustomElf *handle)
+{
+  Register(static_cast(handle));
+  if (dbg) {
+    dbg.Add(handle);
+  }
 }
 
 void
@@ -466,8 +473,6 @@ ElfLoader::Forget(LibHandle *handle)
   if (it != handles.end()) {
     DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"])", reinterpret_cast(handle),
                                                 handle->GetPath());
-    if (dbg && !handle->IsSystemElf())
-      dbg.Remove(static_cast(handle));
     handles.erase(it);
   } else {
     DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"]): Handle not found",
@@ -475,6 +480,15 @@ ElfLoader::Forget(LibHandle *handle)
   }
 }
 
+void
+ElfLoader::Forget(CustomElf *handle)
+{
+  Forget(static_cast(handle));
+  if (dbg) {
+    dbg.Remove(handle);
+  }
+}
+
 void
 ElfLoader::Init()
 {
@@ -483,49 +497,23 @@ ElfLoader::Init()
    * containing this code is dlopen()ed, it can't call dladdr from a
    * static initializer. */
   if (dladdr(_DYNAMIC, &info) != 0) {
-    /* Ideally, we wouldn't be initializing self_elf this way, but until
-     * SystemElf actually inherits from BaseElf, we'll just do it this
-     * (gross) way. */
-    UniquePtr elf = mozilla::MakeUnique(info.dli_fname);
-    elf->base.Assign(info.dli_fbase, -1);
-    size_t symnum = 0;
-    for (const Elf::Dyn *dyn = _DYNAMIC; dyn->d_tag; dyn++) {
-      switch (dyn->d_tag) {
-        case DT_HASH:
-          {
-            DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
-            const Elf::Word *hash_table_header = \
-              elf->GetPtr(dyn->d_un.d_ptr);
-            symnum = hash_table_header[1];
-            elf->buckets.Init(&hash_table_header[2], hash_table_header[0]);
-            elf->chains.Init(&*elf->buckets.end());
-          }
-          break;
-        case DT_STRTAB:
-          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
-          elf->strtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
-          break;
-        case DT_SYMTAB:
-          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
-          elf->symtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
-          break;
-      }
-    }
-    if (!elf->buckets || !symnum) {
-      ERROR("%s: Missing or broken DT_HASH", info.dli_fname);
-    } else if (!elf->strtab) {
-      ERROR("%s: Missing DT_STRTAB", info.dli_fname);
-    } else if (!elf->symtab) {
-      ERROR("%s: Missing DT_SYMTAB", info.dli_fname);
-    } else {
-      self_elf = Move(elf);
-    }
+    self_elf = LoadedElf::Create(info.dli_fname, info.dli_fbase);
   }
+#if defined(ANDROID)
+  if (dladdr(FunctionPtr(syscall), &info) != 0) {
+    libc = LoadedElf::Create(info.dli_fname, info.dli_fbase);
+  }
+#endif
 }
 
 ElfLoader::~ElfLoader()
 {
   LibHandleList list;
+
+  /* Release self_elf and libc */
+  self_elf = nullptr;
+  libc = nullptr;
+
   /* Build up a list of all library handles with direct (external) references.
    * We actually skip system library handles because we want to keep at least
    * some of these open. Most notably, Mozilla codebase keeps a few libgnome
@@ -534,8 +522,8 @@ ElfLoader::~ElfLoader()
   for (LibHandleList::reverse_iterator it = handles.rbegin();
        it < handles.rend(); ++it) {
     if ((*it)->DirectRefCount()) {
-      if ((*it)->IsSystemElf()) {
-        static_cast(*it)->Forget();
+      if (SystemElf *se = (*it)->AsSystemElf()) {
+        se->Forget();
       } else {
         list.push_back(*it);
       }
@@ -550,7 +538,7 @@ ElfLoader::~ElfLoader()
     list = handles;
     for (LibHandleList::reverse_iterator it = list.rbegin();
          it < list.rend(); ++it) {
-      if ((*it)->IsSystemElf()) {
+      if ((*it)->AsSystemElf()) {
         DEBUG_LOG("ElfLoader::~ElfLoader(): Remaining handle for \"%s\" "
                   "[%d direct refs, %d refs total]", (*it)->GetPath(),
                   (*it)->DirectRefCount(), (*it)->refCount());
@@ -564,19 +552,17 @@ ElfLoader::~ElfLoader()
       }
     }
   }
-  /* Avoid self_elf->base destructor unmapping something that doesn't actually
-   * belong to it. */
-  if (self_elf)
-    self_elf->base.release();
 }
 
 void
 ElfLoader::stats(const char *when)
 {
+  if (MOZ_LIKELY(!Logging::isVerbose()))
+    return;
+
   for (LibHandleList::iterator it = Singleton.handles.begin();
        it < Singleton.handles.end(); ++it)
-    if (!(*it)->IsSystemElf())
-      static_cast(*it)->stats(when);
+    (*it)->stats(when);
 }
 
 #ifdef __ARM_EABI__
@@ -1201,11 +1187,12 @@ void SEGVHandler::handler(int signum, siginfo_t *info, void *context)
   if (info->si_code == SEGV_ACCERR) {
     mozilla::RefPtr handle =
       ElfLoader::Singleton.GetHandleByPtr(info->si_addr);
-    if (handle && !handle->IsSystemElf()) {
-      DEBUG_LOG("Within the address space of a CustomElf");
-      CustomElf *elf = static_cast(static_cast(handle));
-      if (elf->mappable->ensure(info->si_addr))
+    BaseElf *elf;
+    if (handle && (elf = handle->AsBaseElf())) {
+      DEBUG_LOG("Within the address space of %s", handle->GetPath());
+      if (elf->mappable && elf->mappable->ensure(info->si_addr)) {
         return;
+      }
     }
   }
 
diff --git a/mozglue/linker/ElfLoader.h b/mozglue/linker/ElfLoader.h
index c3c8adb8ee83..ab29dd736b46 100644
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -64,8 +64,10 @@ IsSignalHandlingBroken();
 
 }
 
-/* Forward declaration because BaseElf.h includes ElfLoader.h */
+/* Forward declarations for use in LibHandle */
 class BaseElf;
+class CustomElf;
+class SystemElf;
 
 /**
  * Specialize RefCounted template for LibHandle. We may get references to
@@ -203,6 +205,13 @@ public:
   virtual const void *FindExidx(int *pcount) const = 0;
 #endif
 
+  /**
+   * Shows some stats about the Mappable instance. The when argument is to be
+   * used by the caller to give an identifier of the when the stats call is
+   * made.
+   */
+  virtual void stats(const char *when) const { };
+
 protected:
   /**
    * Returns a mappable object for use by MappableMMap and related functions.
@@ -210,13 +219,15 @@ protected:
   virtual Mappable *GetMappable() const = 0;
 
   /**
-   * Returns whether the handle is a SystemElf or not. (short of a better way
-   * to do this without RTTI)
+   * Returns the instance, casted as the wanted type. Returns nullptr if
+   * that's not the actual type. (short of a better way to do this without
+   * RTTI)
    */
   friend class ElfLoader;
   friend class CustomElf;
   friend class SEGVHandler;
-  virtual bool IsSystemElf() const { return false; }
+  virtual BaseElf *AsBaseElf() { return nullptr; }
+  virtual SystemElf *AsSystemElf() { return nullptr; }
 
 private:
   MozRefCountType directRefCnt;
@@ -286,11 +297,11 @@ protected:
   virtual Mappable *GetMappable() const;
 
   /**
-   * Returns whether the handle is a SystemElf or not. (short of a better way
-   * to do this without RTTI)
+   * Returns the instance, casted as SystemElf. (short of a better way to do
+   * this without RTTI)
    */
   friend class ElfLoader;
-  virtual bool IsSystemElf() const { return true; }
+  virtual SystemElf *AsSystemElf() { return this; }
 
   /**
    * Remove the reference to the system linker handle. This avoids dlclose()
@@ -426,12 +437,14 @@ protected:
    * LibHandle subclass creators.
    */
   void Register(LibHandle *handle);
+  void Register(CustomElf *handle);
 
   /**
    * Forget about the given handle. This method is meant to be called by
    * LibHandle subclass destructors.
    */
   void Forget(LibHandle *handle);
+  void Forget(CustomElf *handle);
 
   /* Last error. Used for dlerror() */
   friend class SystemElf;
@@ -448,7 +461,15 @@ private:
 
   /* System loader handle for the library/program containing our code. This
    * is used to resolve wrapped functions. */
-  mozilla::UniquePtr self_elf;
+  mozilla::RefPtr self_elf;
+
+#if defined(ANDROID)
+  /* System loader handle for the libc. This is used to resolve weak symbols
+   * that some libcs contain that the Android linker won't dlsym(). Normally,
+   * we wouldn't treat non-Android differently, but glibc uses versioned
+   * symbols which this linker doesn't support. */
+  mozilla::RefPtr libc;
+#endif
 
   /* Bookkeeping */
   typedef std::vector LibHandleList;
@@ -456,6 +477,7 @@ private:
 
 protected:
   friend class CustomElf;
+  friend class LoadedElf;
   /**
    * Show some stats about Mappables in CustomElfs. The when argument is to
    * be used by the caller to give an identifier of the when the stats call
diff --git a/netwerk/base/public/moz.build b/netwerk/base/public/moz.build
index 9bde21513032..ecba3e7344bb 100644
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -29,7 +29,6 @@ XPIDL_SOURCES += [
     'nsICancelable.idl',
     'nsIChannel.idl',
     'nsIChannelEventSink.idl',
-    'nsIChannelPolicy.idl',
     'nsIChildChannel.idl',
     'nsIContentSniffer.idl',
     'nsICryptoFIPSInfo.idl',
@@ -137,8 +136,6 @@ EXPORTS += [
     'netCore.h',
     'nsASocketHandler.h',
     'nsAsyncRedirectVerifyHelper.h',
-    'nsChannelProperties.h',
-    'nsNetStrings.h',
     'nsNetUtil.h',
     'nsReadLine.h',
     'nsStreamListenerWrapper.h',
diff --git a/netwerk/base/public/nsChannelProperties.h b/netwerk/base/public/nsChannelProperties.h
deleted file mode 100644
index 0323a6f39d13..000000000000
--- a/netwerk/base/public/nsChannelProperties.h
+++ /dev/null
@@ -1,35 +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/. */
-
-#ifndef nsChannelProperties_h__
-#define nsChannelProperties_h__
-
-#include "nsStringGlue.h"
-#ifdef IMPL_LIBXUL
-#include "nsNetStrings.h"
-#endif
-
-/**
- * @file
- * This file contains constants for properties channels can expose.
- * They can be accessed by using QueryInterface to access the nsIPropertyBag
- * or nsIPropertyBag2 interface on a channel and reading the value.
- */
-
-
-/**
- * Exists to allow content policy mechanism to function properly during channel
- * redirects.  Contains security contextual information about the load.
- * Type: nsIChannelPolicy
- */
-#define NS_CHANNEL_PROP_CHANNEL_POLICY_STR "channel-policy"
-
-#ifdef IMPL_LIBXUL
-#define NS_CHANNEL_PROP_CHANNEL_POLICY gNetStrings->kChannelPolicy
-#else
-#define NS_CHANNEL_PROP_CHANNEL_POLICY \
-  NS_LITERAL_STRING(NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
-#endif
-
-#endif
diff --git a/netwerk/base/public/nsIChannelPolicy.idl b/netwerk/base/public/nsIChannelPolicy.idl
deleted file mode 100644
index 5894db08fcc0..000000000000
--- a/netwerk/base/public/nsIChannelPolicy.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-/**
- * A container for policy information to be used during channel creation.
- *
- * This interface exists to allow the content policy mechanism to function
- * properly during channel redirects.  Channels can be created with this
- * interface placed in the property bag and upon redirect, the interface can
- * be transferred from the old channel to the new channel.
- */
-[scriptable, uuid(18045e96-1afe-4162-837a-04691267158c)]
-interface nsIChannelPolicy : nsISupports
-{
-  /**
-   * Indicates what type of content is being loaded, e.g.
-   * nsIContentPolicy::TYPE_IMAGE
-   */
-  attribute unsigned long loadType;
-
-  /**
-   * A nsIContentSecurityPolicy object to determine if the load should
-   * be allowed.
-   */
-  attribute nsISupports contentSecurityPolicy;
-};
diff --git a/netwerk/base/public/nsNetStrings.h b/netwerk/base/public/nsNetStrings.h
deleted file mode 100644
index 653c34dc3f77..000000000000
--- a/netwerk/base/public/nsNetStrings.h
+++ /dev/null
@@ -1,24 +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/. */
-
-#ifndef nsNetStrings_h__
-#define nsNetStrings_h__
-
-#include "nsLiteralString.h"
-
-/**
- * Class on which wide strings are available, to avoid constructing strings
- * wherever these strings are used.
- */
-class nsNetStrings {
-public:
-  nsNetStrings();
-
-  const nsLiteralString kChannelPolicy;
-};
-
-extern nsNetStrings* gNetStrings;
-
-
-#endif
diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h
index 5233547d2033..b23f7ce361cc 100644
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -32,7 +32,6 @@
 #include "nsIIOService.h"
 #include "nsIServiceManager.h"
 #include "nsIChannel.h"
-#include "nsChannelProperties.h"
 #include "nsIInputStreamChannel.h"
 #include "nsITransport.h"
 #include "nsIStreamTransportService.h"
@@ -69,7 +68,6 @@
 #include "nsIWritablePropertyBag2.h"
 #include "nsIIDNService.h"
 #include "nsIChannelEventSink.h"
-#include "nsIChannelPolicy.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
 #include "nsIRedirectChannelRegistrar.h"
@@ -203,7 +201,6 @@ inline nsresult
 NS_NewChannelInternal(nsIChannel**           outChannel,
                       nsIURI*                aUri,
                       nsILoadInfo*           aLoadInfo,
-                      nsIChannelPolicy*      aChannelPolicy = nullptr,
                       nsILoadGroup*          aLoadGroup = nullptr,
                       nsIInterfaceRequestor* aCallbacks = nullptr,
                       nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -237,14 +234,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
     rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
     NS_ENSURE_SUCCESS(rv, rv);
   }
-
-  if (aChannelPolicy) {
-    nsCOMPtr props = do_QueryInterface(channel);
-    if (props) {
-      props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY, aChannelPolicy);
-    }
-  }
-
   channel->SetLoadInfo(aLoadInfo);
 
   // If we're sandboxed, make sure to clear any owner the channel
@@ -264,7 +253,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
                       nsIPrincipal*          aRequestingPrincipal,
                       nsSecurityFlags        aSecurityFlags,
                       nsContentPolicyType    aContentPolicyType,
-                      nsIChannelPolicy*      aChannelPolicy = nullptr,
                       nsILoadGroup*          aLoadGroup = nullptr,
                       nsIInterfaceRequestor* aCallbacks = nullptr,
                       nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -283,7 +271,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                loadInfo,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -296,7 +283,6 @@ NS_NewChannel(nsIChannel**           outChannel,
               nsINode*               aRequestingNode,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
-              nsIChannelPolicy*      aChannelPolicy = nullptr,
               nsILoadGroup*          aLoadGroup = nullptr,
               nsIInterfaceRequestor* aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -309,7 +295,6 @@ NS_NewChannel(nsIChannel**           outChannel,
                                aRequestingNode->NodePrincipal(),
                                aSecurityFlags,
                                aContentPolicyType,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -322,7 +307,6 @@ NS_NewChannel(nsIChannel**           outChannel,
               nsIPrincipal*          aRequestingPrincipal,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
-              nsIChannelPolicy*      aChannelPolicy = nullptr,
               nsILoadGroup*          aLoadGroup = nullptr,
               nsIInterfaceRequestor* aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -334,7 +318,6 @@ NS_NewChannel(nsIChannel**           outChannel,
                                aRequestingPrincipal,
                                aSecurityFlags,
                                aContentPolicyType,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -367,7 +350,6 @@ NS_OpenURIInternal(nsIInputStream**       outStream,
                                       aRequestingPrincipal,
                                       aSecurityFlags,
                                       aContentPolicyType,
-                                      nullptr,   // aChannelPolicy,
                                       aLoadGroup,
                                       aCallbacks,
                                       aLoadFlags,
@@ -424,7 +406,6 @@ NS_OpenURIInternal(nsIStreamListener*     aListener,
   nsresult rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                       aUri,
                                       aLoadInfo,
-                                      nullptr,    // aChannelPolicy
                                       aLoadGroup,
                                       aCallbacks,
                                       aLoadFlags,
@@ -835,7 +816,6 @@ NS_NewStreamLoaderInternal(nsIStreamLoader**        outStream,
                                        aRequestingPrincipal,
                                        aSecurityFlags,
                                        aContentPolicyType,
-                                       nullptr,  // aChannelPolicy
                                        aLoadGroup,
                                        aCallbacks,
                                        aLoadFlags);
diff --git a/netwerk/base/src/moz.build b/netwerk/base/src/moz.build
index a564220f4a34..598c5de3f48b 100644
--- a/netwerk/base/src/moz.build
+++ b/netwerk/base/src/moz.build
@@ -49,7 +49,6 @@ UNIFIED_SOURCES += [
     'nsMediaFragmentURIParser.cpp',
     'nsMIMEInputStream.cpp',
     'nsNetAddr.cpp',
-    'nsNetStrings.cpp',
     'nsNetUtil.cpp',
     'nsPACMan.cpp',
     'nsPreloadedStream.cpp',
diff --git a/netwerk/base/src/nsIncrementalDownload.cpp b/netwerk/base/src/nsIncrementalDownload.cpp
index 5859f50b1d02..d13a81213ab7 100644
--- a/netwerk/base/src/nsIncrementalDownload.cpp
+++ b/netwerk/base/src/nsIncrementalDownload.cpp
@@ -267,7 +267,6 @@ nsIncrementalDownload::ProcessTimeout()
                               nsContentUtils::GetSystemPrincipal(),
                               nsILoadInfo::SEC_NORMAL,
                               nsIContentPolicy::TYPE_OTHER,
-                              nullptr,   // aChannelPolicy
                               nullptr,   // loadGroup
                               this,      // aCallbacks
                               mLoadFlags);
diff --git a/netwerk/base/src/nsNetStrings.cpp b/netwerk/base/src/nsNetStrings.cpp
deleted file mode 100644
index cd3ebfac3037..000000000000
--- a/netwerk/base/src/nsNetStrings.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsNetStrings.h"
-#include "nsChannelProperties.h"
-
-nsNetStrings* gNetStrings;
-
-nsNetStrings::nsNetStrings()
-  : NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
-{}
-
-
diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp
index 51e20fb53d4b..070762956e7a 100644
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -31,7 +31,6 @@
 #include "nsApplicationCache.h"
 #include "nsApplicationCacheService.h"
 #include "nsMimeTypes.h"
-#include "nsNetStrings.h"
 #include "nsDNSPrefetch.h"
 #include "nsAboutProtocolHandler.h"
 #include "nsXULAppAPI.h"
@@ -630,11 +629,9 @@ CreateNewBinaryDetectorFactory(nsISupports *aOuter, REFNSIID aIID, void **aResul
 // Net module startup hook
 static nsresult nsNetStartup()
 {
-    gNetStrings = new nsNetStrings();
-    return gNetStrings ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    return NS_OK;
 }
 
-
 // Net module shutdown hook
 static void nsNetShutdown()
 {
@@ -647,10 +644,6 @@ static void nsNetShutdown()
     net_ShutdownURLHelperOSX();
 #endif
     
-    // Release necko strings
-    delete gNetStrings;
-    gNetStrings = nullptr;
-    
     // Release DNS service reference.
     nsDNSPrefetch::Shutdown();
 
diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp
index 4ba9129cbb87..eaa737f0452e 100644
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -149,7 +149,6 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr, // aChannelPolicy
                      nullptr, // aLoadGroup
                      nullptr, // aCallbacks
                      nsIRequest::LOAD_NORMAL,
diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp
index e464ecfc45ed..8442838bddb7 100644
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -241,7 +241,6 @@ HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr,   // aChannelPolicy
                      nullptr,   // loadGroup
                      nullptr,   // aCallbacks
                      loadFlags,
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
index 41194d233707..474a0e5955a5 100644
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -92,7 +92,6 @@ WyciwygChannelParent::RecvInit(const URIParams&          aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr,   // aChannelPolicy
                      nullptr,   // loadGroup
                      nullptr,   // aCallbacks
                      nsIRequest::LOAD_NORMAL,
diff --git a/netwerk/test/TestPageLoad.cpp b/netwerk/test/TestPageLoad.cpp
index 6402b0e6cb66..fe5002a20193 100644
--- a/netwerk/test/TestPageLoad.cpp
+++ b/netwerk/test/TestPageLoad.cpp
@@ -312,7 +312,6 @@ nsresult auxLoad(char *uriBuf)
                        systemPrincipal,
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,   // aChannelPolicy
                        nullptr,   // loadGroup
                        callbacks);
 
@@ -371,7 +370,6 @@ int main(int argc, char **argv)
                            systemPrincipal,
                            nsILoadInfo::SEC_NORMAL,
                            nsIContentPolicy::TYPE_OTHER,
-                           nullptr,   // aChannelPolicy
                            nullptr,   // loadGroup
                            callbacks);
 
diff --git a/netwerk/test/TestProtocols.cpp b/netwerk/test/TestProtocols.cpp
index c5ed54dec9e1..a707c5be5262 100644
--- a/netwerk/test/TestProtocols.cpp
+++ b/netwerk/test/TestProtocols.cpp
@@ -48,7 +48,6 @@
 #include "nsIPropertyBag2.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsITimedChannel.h"
-#include "nsChannelProperties.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/unused.h"
 #include "nsIScriptSecurityManager.h"
@@ -643,7 +642,6 @@ nsresult StartLoadingURL(const char* aUrlString)
                            systemPrincipal,
                            nsILoadInfo::SEC_NORMAL,
                            nsIContentPolicy::TYPE_OTHER,
-                           nullptr,  // aChannelPolicy
                            nullptr,  // loadGroup
                            callbacks,
                            nsIRequest::LOAD_NORMAL,
diff --git a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
index f2abd0a80632..523b1e68284a 100644
--- a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
@@ -314,3 +314,4 @@ SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED=The certificate was signed using a s
 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE=The server uses key pinning (HPKP) but no trusted certificate chain could be constructed that matches the pinset. Key pinning violations cannot be overridden.
 MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY=The server uses a certificate with a basic constraints extension identifying it as a certificate authority. For a properly-issued certificate, this should not be the case.
 MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE=The server presented a certificate with a key size that is too small to establish a secure connection.
+MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA=An X.509 version 1 certificate that is not a trust anchor was used to issue the server's certificate. X.509 version 1 certificates are deprecated and should not be used to sign other certificates.
diff --git a/security/manager/ssl/src/NSSErrorsService.cpp b/security/manager/ssl/src/NSSErrorsService.cpp
index 75784a7c6626..82bd3a76523c 100644
--- a/security/manager/ssl/src/NSSErrorsService.cpp
+++ b/security/manager/ssl/src/NSSErrorsService.cpp
@@ -142,6 +142,7 @@ NSSErrorsService::GetErrorClass(nsresult aXPCOMErrorCode, uint32_t *aErrorClass)
     case SEC_ERROR_EXPIRED_CERTIFICATE:
     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
       *aErrorClass = ERROR_CLASS_BAD_CERT;
       break;
     // Non-overridable errors.
diff --git a/security/manager/ssl/src/SSLServerCertVerification.cpp b/security/manager/ssl/src/SSLServerCertVerification.cpp
index 9aa3a8a6a491..0e6efdf7187b 100644
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -305,6 +305,7 @@ MapCertErrorToProbeValue(PRErrorCode errorCode)
     case SSL_ERROR_BAD_CERT_DOMAIN:                    return  9;
     case SEC_ERROR_EXPIRED_CERTIFICATE:                return 10;
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: return 11;
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: return 12;
   }
   NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue "
              "handle everything in DetermineCertOverrideErrors?");
@@ -334,6 +335,7 @@ DetermineCertOverrideErrors(CERTCertificate* cert, const char* hostName,
     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     case SEC_ERROR_UNKNOWN_ISSUER:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
     {
       collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
       errorCodeTrust = defaultErrorCodeToReport;
diff --git a/security/manager/ssl/src/nsUsageArrayHelper.cpp b/security/manager/ssl/src/nsUsageArrayHelper.cpp
index 5777a4e6d68a..0ef5fbe0ca89 100644
--- a/security/manager/ssl/src/nsUsageArrayHelper.cpp
+++ b/security/manager/ssl/src/nsUsageArrayHelper.cpp
@@ -151,6 +151,7 @@ nsUsageArrayHelper::verifyFailed(uint32_t *_verified, int err)
   case SEC_ERROR_CA_CERT_INVALID:
   case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
   case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
+  case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
     *_verified = nsNSSCertificate::USAGE_NOT_ALLOWED; break;
   /* These are the cases that have individual error messages */
   case SEC_ERROR_REVOKED_CERTIFICATE:
diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js
index 13300d402f60..bddd5d8581aa 100644
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -64,6 +64,7 @@ const SSL_ERROR_BAD_CERT_ALERT                          = SSL_ERROR_BASE +  17;
 const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE            = MOZILLA_PKIX_ERROR_BASE +   0;
 const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY     = MOZILLA_PKIX_ERROR_BASE +   1;
 const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE            = MOZILLA_PKIX_ERROR_BASE +   2; // -16382
+const MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA             = MOZILLA_PKIX_ERROR_BASE +   3;
 
 // Supported Certificate Usages
 const certificateUsageSSLClient              = 0x0001;
diff --git a/security/manager/ssl/tests/unit/test_cert_overrides.js b/security/manager/ssl/tests/unit/test_cert_overrides.js
index ad4cfc61d5bb..5057270ff66a 100644
--- a/security/manager/ssl/tests/unit/test_cert_overrides.js
+++ b/security/manager/ssl/tests/unit/test_cert_overrides.js
@@ -62,6 +62,7 @@ function check_telemetry() {
   do_check_eq(histogram.counts[ 9], 5); // SSL_ERROR_BAD_CERT_DOMAIN
   do_check_eq(histogram.counts[10], 5); // SEC_ERROR_EXPIRED_CERTIFICATE
   do_check_eq(histogram.counts[11], 2); // MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
+  do_check_eq(histogram.counts[12], 1); // MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA
   run_next_test();
 }
 
@@ -126,6 +127,28 @@ function add_simple_tests() {
   add_cert_override_test("ca-used-as-end-entity.example.com",
                          Ci.nsICertOverrideService.ERROR_UNTRUSTED,
                          getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY));
+
+  // If an X.509 version 1 certificate is not a trust anchor, we will
+  // encounter an overridable error.
+  add_cert_override_test("end-entity-issued-by-v1-cert.example.com",
+                         Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+                         getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA));
+  // If we make that certificate a trust anchor, the connection will succeed.
+  add_test(function() {
+    certOverrideService.clearValidityOverride("end-entity-issued-by-v1-cert.example.com", 8443);
+    let v1Cert = constructCertFromFile("tlsserver/v1Cert.der");
+    setCertTrust(v1Cert, "CTu,,");
+    clearSessionCache();
+    run_next_test();
+  });
+  add_connection_test("end-entity-issued-by-v1-cert.example.com", Cr.NS_OK);
+  // Reset the trust for that certificate.
+  add_test(function() {
+    let v1Cert = constructCertFromFile("tlsserver/v1Cert.der");
+    setCertTrust(v1Cert, ",,");
+    clearSessionCache();
+    run_next_test();
+  });
 }
 
 function add_combo_tests() {
diff --git a/security/manager/ssl/tests/unit/test_cert_version.js b/security/manager/ssl/tests/unit/test_cert_version.js
index 98404aa98a62..1527f60d6a5e 100644
--- a/security/manager/ssl/tests/unit/test_cert_version.js
+++ b/security/manager/ssl/tests/unit/test_cert_version.js
@@ -59,32 +59,23 @@ function run_test() {
   check_ok_ca(cert_from_file('v3_ca.der'));
   check_ca_err(cert_from_file('v3_ca_missing_bc.der'), SEC_ERROR_CA_CERT_INVALID);
 
-  // Classic allows v1 and v2 certs to be CA certs in trust anchor positions and
-  // intermediates when they have a v3 basic constraints extenstion (which
-  // makes them invalid certs). Insanity only allows v1 certs to be CA in
-  // anchor position (even if they have invalid encodings), v2 certs are not
-  // considered CAs in any position.
-  // Note that currently there are no change of behavior based on the
-  // version of the end entity.
-
-  let ee_error = 0;
-  let ca_error = 0;
+  // A v1 certificate may be a CA if it has a basic constraints extension with
+  // CA: TRUE or if it is a trust anchor.
 
   //////////////
   // v1 CA supersection
   //////////////////
 
   // v1 intermediate with v1 trust anchor
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v1_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca.der'), ee_error);
+  let error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca.der'), error);
 
   // v1 intermediate with v3 extensions.
   check_ok_ca(cert_from_file('v1_int_bc-v1_ca.der'));
@@ -97,16 +88,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v1_int_bc-v1_ca.der'));
 
   // A v2 intermediate with a v1 CA
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v1_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca.der'), error);
 
   // A v2 intermediate with basic constraints
   check_ok_ca(cert_from_file('v2_int_bc-v1_ca.der'));
@@ -120,16 +110,15 @@ function run_test() {
 
   // Section is OK. A x509 v3 CA MUST have bc
   // http://tools.ietf.org/html/rfc5280#section-4.2.1.9
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v1_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca.der'), error);
 
   // It is valid for a v1 ca to sign a v3 intemediate.
   check_ok_ca(cert_from_file('v3_int-v1_ca.der'));
@@ -146,16 +135,15 @@ function run_test() {
   // above
 
   // Using A v1 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v1_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
+  error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca_bc.der'), error);
 
   // Using a v1 intermediate with v3 extenstions
   check_ok_ca(cert_from_file('v1_int_bc-v1_ca_bc.der'));
@@ -168,16 +156,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v1_int_bc-v1_ca_bc.der'));
 
   // Using v2 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v1_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca_bc.der'), error);
 
   // Using a v2 intermediate with basic constraints 
   check_ok_ca(cert_from_file('v2_int_bc-v1_ca_bc.der'));
@@ -190,16 +177,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v2_int_bc-v1_ca_bc.der'));
 
   // Using a v3 intermediate that is missing basic constraints (invalid)
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v1_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), error);
 
   // these should pass assuming we are OK with v1 ca signing v3 intermediates
   check_ok_ca(cert_from_file('v3_int-v1_ca_bc.der'));
@@ -217,88 +203,81 @@ function run_test() {
   //////////////////
 
   // v2 ca, v1 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca.der'), ee_error);
+  error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca.der'), error);
 
   // v2 ca, v1 intermediate with basic constraints (invalid)
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca.der'), error);
 
   // v2 ca, v2 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca.der'), error);
 
   // v2 ca, v2 intermediate with basic constraints (invalid)
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca.der'), error);
 
   // v2 ca, v3 intermediate missing basic constraints
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca.der'), error);
 
   // v2 ca, v3 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int-v2_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int-v2_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int-v2_ca.der'), error);
 
   // v2 ca, v1 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v2_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
+  error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca_bc.der'), error);
 
   // v2 ca, v1 intermediate with bc
   check_ok_ca(cert_from_file('v1_int_bc-v2_ca_bc.der'));
@@ -311,16 +290,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca_bc.der'));
 
   // v2 ca, v2 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v2_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca_bc.der'), error);
 
   // v2 ca, v2 intermediate with bc
   check_ok_ca(cert_from_file('v2_int_bc-v2_ca_bc.der'));
@@ -333,16 +311,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v2_int_bc-v2_ca_bc.der'));
 
   // v2 ca, invalid v3 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v2_ca_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), error);
 
   // v2 ca, valid v3 intermediate
   check_ok_ca(cert_from_file('v3_int-v2_ca_bc.der'));
@@ -359,16 +336,15 @@ function run_test() {
   //////////////////
 
   // v3 ca, v1 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v3_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca.der'), ee_error);
+  error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca.der'), error);
 
   // A v1 intermediate with v3 extensions
   check_ok_ca(cert_from_file('v1_int_bc-v3_ca.der'));
@@ -381,16 +357,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v1_int_bc-v3_ca.der'));
 
   // reject a v2 cert as intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v3_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca.der'), error);
 
   // v2 intermediate with bc (invalid)
   check_ok_ca(cert_from_file('v2_int_bc-v3_ca.der'));
@@ -403,16 +378,15 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v2_int_bc-v3_ca.der'));
 
   // invalid v3 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v3_ca.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca.der'), error);
 
   // v1/v2 end entity, v3 intermediate
   check_ok_ca(cert_from_file('v3_int-v3_ca.der'));
@@ -425,76 +399,70 @@ function run_test() {
   check_ok(cert_from_file('v4_bc_ee-v3_int-v3_ca.der'));
 
   // v3 CA, invalid v3 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
+  error = MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA;
+  check_ca_err(cert_from_file('v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca_missing_bc.der'), error);
 
   // Int v1 with BC that is just invalid
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v1_int_bc-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), error);
 
   // Good section (all fail)
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca_missing_bc.der'), error);
 
   // v3 intermediate missing basic constraints is invalid
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v2_int_bc-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), error);
 
   // v3 intermediate missing basic constraints is invalid
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int_missing_bc-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), error);
 
   // With a v3 root missing bc and valid v3 intermediate
-  ca_error = SEC_ERROR_CA_CERT_INVALID;
-  ee_error = SEC_ERROR_CA_CERT_INVALID;
-  check_ca_err(cert_from_file('v3_int-v3_ca_missing_bc.der'), ca_error);
-  check_cert_err(cert_from_file('v1_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v3_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
-  check_cert_err(cert_from_file('v4_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
+  error = SEC_ERROR_CA_CERT_INVALID;
+  check_ca_err(cert_from_file('v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v3_bc_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca_missing_bc.der'), error);
+  check_cert_err(cert_from_file('v4_bc_ee-v3_int-v3_ca_missing_bc.der'), error);
 
   // self-signed
   check_cert_err(cert_from_file('v1_self_signed.der'), SEC_ERROR_UNKNOWN_ISSUER);
diff --git a/security/manager/ssl/tests/unit/tlsserver/cert9.db b/security/manager/ssl/tests/unit/tlsserver/cert9.db
index fe22bc496350..950173131fda 100644
Binary files a/security/manager/ssl/tests/unit/tlsserver/cert9.db and b/security/manager/ssl/tests/unit/tlsserver/cert9.db differ
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp
index 9e4135d91fe0..0e1895d4c32f 100644
--- a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp
@@ -59,6 +59,7 @@ const BadCertHost sBadCertHosts[] =
   { "nsCertTypeNotCritical.example.com", "nsCertTypeNotCritical" },
   { "nsCertTypeCriticalWithExtKeyUsage.example.com", "nsCertTypeCriticalWithExtKeyUsage" },
   { "nsCertTypeCritical.example.com", "nsCertTypeCritical" },
+  { "end-entity-issued-by-v1-cert.example.com", "eeIssuedByV1Cert" },
   { nullptr, nullptr }
 };
 
diff --git a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh
index 736e4a25b52d..fd52b98d6178 100755
--- a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh
+++ b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh
@@ -145,6 +145,31 @@ function make_INT {
   SERIALNO=$(($SERIALNO + 1))
 }
 
+# This creates an X.509 version 1 certificate (note --certVersion 1 and a lack
+# of extensions).
+function make_V1 {
+  NICKNAME="${1}"
+  SUBJECT="${2}"
+  CA="${3}"
+
+  cert_already_exists $NICKNAME
+  if [ $ALREADY_EXISTS -eq 1 ]; then
+    echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
+    return
+  fi
+
+  $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
+                         -n $NICKNAME \
+                         -s "$SUBJECT" \
+                         -c $CA \
+                         -t ",," \
+                         -m $SERIALNO \
+                         --certVersion 1 \
+                         -v 360 -w -1 -z $NOISE_FILE
+
+  SERIALNO=$(($SERIALNO + 1))
+}
+
 function make_EE {
   CERT_RESPONSES="n\n\ny\n2\n7\nhttp://localhost:8080/\n\nn\nn\n"
   NICKNAME="${1}"
@@ -287,4 +312,11 @@ make_EE_with_nsCertType nsCertTypeCritical 'CN=nsCertType Critical' testCA "loca
 make_EE_with_nsCertType nsCertTypeNotCritical 'CN=nsCertType Not Critical' testCA "localhost,*.example.com" "n"
 make_EE_with_nsCertType nsCertTypeCriticalWithExtKeyUsage 'CN=nsCertType Critical With extKeyUsage' testCA "localhost,*.example.com" "y" "--extKeyUsage serverAuth"
 
+# Make an X.509 version 1 certificate that will issue another certificate.
+# By default, this causes an error in verification that we allow overrides for.
+# However, if the v1 certificate is a trust anchor, then verification succeeds.
+make_V1 v1Cert 'CN=V1 Cert' testCA
+export_cert v1Cert v1Cert.der
+make_EE eeIssuedByV1Cert 'CN=EE Issued by V1 Cert' v1Cert "localhost,*.example.com"
+
 cleanup
diff --git a/security/manager/ssl/tests/unit/tlsserver/key4.db b/security/manager/ssl/tests/unit/tlsserver/key4.db
index 9d6453d125c5..02ac22e5a984 100644
Binary files a/security/manager/ssl/tests/unit/tlsserver/key4.db and b/security/manager/ssl/tests/unit/tlsserver/key4.db differ
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp
index 337a36451876..2a10ec44425d 100644
--- a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp
@@ -197,6 +197,47 @@ ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName,
     PrintPRError("PK11_FindCertFromNickname failed");
     return SECFailure;
   }
+  // If an intermediate certificate issued the server certificate (rather than
+  // directly by a trust anchor), we want to send it along in the handshake so
+  // we don't encounter unknown issuer errors when that's not what we're
+  // testing.
+  ScopedCERTCertificateList certList;
+  ScopedCERTCertificate issuerCert(
+    CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer));
+  // If we can't find the issuer cert, continue without it.
+  if (issuerCert) {
+    // Sadly, CERTCertificateList does not have a CERT_NewCertificateList
+    // utility function, so we must create it ourselves. This consists
+    // of creating an arena, allocating space for the CERTCertificateList,
+    // and then transferring ownership of the arena to that list.
+    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+    if (!arena) {
+      PrintPRError("PORT_NewArena failed");
+      return SECFailure;
+    }
+    certList = reinterpret_cast(
+      PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)));
+    if (!certList) {
+      PrintPRError("PORT_ArenaAlloc failed");
+      return SECFailure;
+    }
+    certList->arena = arena.forget();
+    // We also have to manually copy the certificates we care about to the
+    // list, because there aren't any utility functions for that either.
+    certList->certs = reinterpret_cast(
+      PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem)));
+    if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert)
+          != SECSuccess) {
+      PrintPRError("SECITEM_CopyItem failed");
+      return SECFailure;
+    }
+    if (SECITEM_CopyItem(certList->arena, certList->certs + 1,
+                         &issuerCert->derCert) != SECSuccess) {
+      PrintPRError("SECITEM_CopyItem failed");
+      return SECFailure;
+    }
+    certList->len = 2;
+  }
 
   ScopedSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert, nullptr));
   if (!key) {
@@ -206,7 +247,8 @@ ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName,
 
   SSLKEAType certKEA = NSS_FindCertKEAType(cert);
 
-  if (SSL_ConfigSecureServer(fd, cert, key, certKEA) != SECSuccess) {
+  if (SSL_ConfigSecureServerWithCertChain(fd, cert, certList, key, certKEA)
+        != SECSuccess) {
     PrintPRError("SSL_ConfigSecureServer failed");
     return SECFailure;
   }
diff --git a/security/manager/ssl/tests/unit/tlsserver/v1Cert.der b/security/manager/ssl/tests/unit/tlsserver/v1Cert.der
new file mode 100644
index 000000000000..84b9f7273073
Binary files /dev/null and b/security/manager/ssl/tests/unit/tlsserver/v1Cert.der differ
diff --git a/security/pkix/include/pkix/Result.h b/security/pkix/include/pkix/Result.h
index ff76b5ab6715..13511eec7c50 100644
--- a/security/pkix/include/pkix/Result.h
+++ b/security/pkix/include/pkix/Result.h
@@ -124,6 +124,8 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
                      MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY) \
     MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_SIZE, 40, \
                      MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \
+    MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \
+                     MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
                      SEC_ERROR_INVALID_ARGS) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \
diff --git a/security/pkix/include/pkix/pkixnss.h b/security/pkix/include/pkix/pkixnss.h
index d05498a4490b..26ffcf014c4f 100644
--- a/security/pkix/include/pkix/pkixnss.h
+++ b/security/pkix/include/pkix/pkixnss.h
@@ -69,7 +69,8 @@ static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000;
 enum ErrorCode {
   MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0,
   MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1,
-  MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2
+  MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2,
+  MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = ERROR_BASE + 3,
 };
 
 void RegisterErrorTable();
diff --git a/security/pkix/lib/pkixcheck.cpp b/security/pkix/lib/pkixcheck.cpp
index 56aa7205dbce..45c3190b08eb 100644
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -348,10 +348,18 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
     // For compatibility, we must accept v1 trust anchors without basic
     // constraints as CAs.
     //
+    // There are devices with v1 certificates that are unlikely to be trust
+    // anchors. In order to allow applications to treat this case differently
+    // from other basic constraints violations (e.g. allowing certificate error
+    // overrides for only this case), we return a different error code.
+    //
     // TODO: add check for self-signedness?
-    if (endEntityOrCA == EndEntityOrCA::MustBeCA &&
-        trustLevel == TrustLevel::TrustAnchor && version == der::Version::v1) {
-      isCA = true;
+    if (endEntityOrCA == EndEntityOrCA::MustBeCA && version == der::Version::v1) {
+      if (trustLevel == TrustLevel::TrustAnchor) {
+        isCA = true;
+      } else {
+        return Result::ERROR_V1_CERT_USED_AS_CA;
+      }
     }
   }
 
diff --git a/security/pkix/lib/pkixnss.cpp b/security/pkix/lib/pkixnss.cpp
index af2ca6926550..deec8260ebf3 100644
--- a/security/pkix/lib/pkixnss.cpp
+++ b/security/pkix/lib/pkixnss.cpp
@@ -242,7 +242,11 @@ RegisterErrorTable()
       "certificate, this should not be the case." },
     { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE",
       "The server presented a certificate with a key size that is too small "
-      "to establish a secure connection." }
+      "to establish a secure connection." },
+    { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA",
+      "An X.509 version 1 certificate that is not a trust anchor was used to "
+      "issue the server's certificate. X.509 version 1 certificates are "
+      "deprecated and should not be used to sign other certificates." },
   };
   // Note that these error strings are not localizable.
   // When these strings change, update the localization information too.
diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py
index 2b85ba44d596..d6649cf83f79 100644
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -612,7 +612,7 @@ class MochitestOptions(optparse.OptionParser):
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
-            "tab": 10000, # See dependencies of bug 1051230.
+            "tab": 20000, # See dependencies of bug 1051230.
             "geckomediaplugin": 1000, # GMP rarely gets a log, but when it does, it leaks a little.
         }
 
diff --git a/tools/performance/diff-talos.py b/testing/talos/diff-talos.py
similarity index 100%
rename from tools/performance/diff-talos.py
rename to testing/talos/diff-talos.py
diff --git a/testing/talos/talos.json b/testing/talos/talos.json
index 93eda5620ff3..017c4b1566da 100644
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,11 +1,11 @@
 {
     "talos.zip": {
-        "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.49b74c08dad4.zip",
+        "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.04081c46ff03.zip",
         "path": ""
     },
     "global": {
         "talos_repo": "https://hg.mozilla.org/build/talos",
-        "talos_revision": "ced1b2d1c400"
+        "talos_revision": "04081c46ff03"
     },
     "suites": {
         "chromez": {
@@ -54,7 +54,7 @@
             }
         },
         "xperf": {
-            "tests": ["tp5n"],
+            "tests": ["tp5n", "ts_paint_cold"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip",
             "pagesets_parent_dir_path": "talos/page_load_test/",
             "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5n.manifest",
diff --git a/testing/web-platform/meta/media-source/mediasource-buffered.html.ini b/testing/web-platform/meta/media-source/mediasource-buffered.html.ini
index 682414409a21..a8c05eff2f7b 100644
--- a/testing/web-platform/meta/media-source/mediasource-buffered.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-buffered.html.ini
@@ -1,3 +1,15 @@
 [mediasource-buffered.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Demuxed content with different lengths]
+    expected: FAIL
+
+  [Muxed tracks with different lengths]
+    expected: FAIL
+
+  [Demuxed content with an empty buffered range on one SourceBuffer]
+    expected: FAIL
+
+  [Muxed content empty buffered ranges.]
+    expected: FAIL
+
diff --git a/testing/web-platform/meta/media-source/mediasource-duration.html.ini b/testing/web-platform/meta/media-source/mediasource-duration.html.ini
index 1705d3dbbc41..d5973007216c 100644
--- a/testing/web-platform/meta/media-source/mediasource-duration.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-duration.html.ini
@@ -1,3 +1,15 @@
 [mediasource-duration.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test seek starts on duration truncation below currentTime]
+    expected: TIMEOUT
+
+  [Test appendBuffer completes previous seek to truncated duration]
+    disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+
+  [Test endOfStream completes previous seek to truncated duration]
+    expected: TIMEOUT
+
+  [Test setting same duration multiple times does not fire duplicate durationchange]
+    expected: FAIL
+
diff --git a/testing/web-platform/meta/media-source/mediasource-play-then-seek-back.html.ini b/testing/web-platform/meta/media-source/mediasource-play-then-seek-back.html.ini
index 4cfdd320d76c..123980210d0f 100644
--- a/testing/web-platform/meta/media-source/mediasource-play-then-seek-back.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-play-then-seek-back.html.ini
@@ -1,3 +1,6 @@
 [mediasource-play-then-seek-back.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test playing then seeking back.]
+    expected: TIMEOUT
+
diff --git a/testing/web-platform/meta/media-source/mediasource-redundant-seek.html.ini b/testing/web-platform/meta/media-source/mediasource-redundant-seek.html.ini
index fc3feeffb15d..c9fa66c425a4 100644
--- a/testing/web-platform/meta/media-source/mediasource-redundant-seek.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-redundant-seek.html.ini
@@ -1,3 +1,6 @@
 [mediasource-redundant-seek.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test redundant fully prebuffered seek]
+    expected: TIMEOUT
+
diff --git a/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini b/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini
index 34ce5a3b7f22..768228991a7e 100644
--- a/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini
@@ -1,3 +1,9 @@
 [mediasource-seek-beyond-duration.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test seeking beyond updated media duration.]
+    expected: TIMEOUT
+
+  [Test seeking beyond media duration.]
+    disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+
diff --git a/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini b/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini
index 5cf058456f42..6c2702fa32e1 100644
--- a/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini
@@ -1,3 +1,9 @@
 [mediasource-seek-during-pending-seek.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test seeking to a new location before transitioning beyond HAVE_METADATA.]
+    expected: TIMEOUT
+
+  [Test seeking to a new location during a pending seek.]
+    expected: TIMEOUT
+
diff --git a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini
index 5ce54c758586..e8814258d799 100644
--- a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini
@@ -1,3 +1,6 @@
 [mediasource-sourcebuffer-mode.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+  expected: TIMEOUT
+  [Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.]
+    expected: FAIL
+
diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
index b17ab187aef8..4c67e4969c99 100644
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -3534,7 +3534,6 @@ nsDownload::Resume()
                      nsContentUtils::GetSystemPrincipal(),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,  // aChannelPolicy
                      nullptr,  // aLoadGroup
                      ir);
 
diff --git a/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm
index 09da2c89d47f..0eb018400186 100644
--- a/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm
+++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm
@@ -32,13 +32,15 @@ nsParentalControlsService::GetParentalControlsEnabled(bool *aResult)
 NS_IMETHODIMP
 nsParentalControlsService::GetBlockFileDownloadsEnabled(bool *aResult)
 {
-  return NS_ERROR_NOT_AVAILABLE;
+  *aResult = false;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsParentalControlsService::GetLoggingEnabled(bool *aResult)
 {
-  return NS_ERROR_NOT_AVAILABLE;
+  *aResult = false;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -47,7 +49,8 @@ nsParentalControlsService::Log(int16_t aEntryType,
                                nsIURI *aSource,
                                nsIFile *aTarget)
 {
-  return NS_ERROR_NOT_AVAILABLE;
+  // silently drop on the floor
+  return NS_OK;
 }
 
 NS_IMETHODIMP
diff --git a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
index 77aaa0bbf560..731070ed997f 100644
--- a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
@@ -99,7 +99,6 @@ nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
                      nsContentUtils::GetSystemPrincipal(),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,  // aChannelPolicy
                      nullptr,  // aLoadGroup
                      this,     // aInterfaceRequestor
                      loadFlags);
diff --git a/toolkit/content/aboutWebrtc.xhtml b/toolkit/content/aboutWebrtc.xhtml
deleted file mode 100644
index e60f75ef9faf..000000000000
--- a/toolkit/content/aboutWebrtc.xhtml
+++ /dev/null
@@ -1,440 +0,0 @@
-
-
-
-
- %htmlDTD;
-]>
-
-
-  
-    Webrtc Internals
-  
-  
-
-  
-    
-
- - - -
-
- - - diff --git a/toolkit/content/aboutwebrtc/README.txt b/toolkit/content/aboutwebrtc/README.txt new file mode 100644 index 000000000000..76f51c8a2418 --- /dev/null +++ b/toolkit/content/aboutwebrtc/README.txt @@ -0,0 +1,21 @@ +Working with React JSX files +============================ + +The about:webrtc page uses [React](http://facebook.github.io/react/). +The UI is written in JSX files and transpiled to JS before we +commit. You need to install the JSX compiler using npm in order to +compile the .jsx files into regular .js ones: + + npm install -g react-tools + +Run the following command: + + jsx -w -x jsx . . + +jsx can also be do a one-time compile pass instead of watching if the +-w argument is omitted. Be sure to commit any transpiled files at the +same time as changes to their sources. + +IMPORTANT: do not modify the generated files, only their JSX +counterpart. + diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.css b/toolkit/content/aboutwebrtc/aboutWebrtc.css new file mode 100644 index 000000000000..73743988f38f --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.css @@ -0,0 +1,78 @@ +html { + background-color: #EDECEB; + font: message-box; +} + +#logs { + font-family: monospace; +} + +.peer-connections { + padding: 2em; + margin: 1em 0em; + border: 1px solid #AFACA9; + border-radius: 10px; + background: none repeat scroll 0% 0% #FFF; +} + +.peer-connection h3 { + background-color: #DDD; + cursor: pointer; +} + +.peer-connection h3 span:last-child { + float: right; +} + +.peer-connection section { + border: 1px solid #AFACA9; + padding: 10px; +} + +.peer-connection table { + width: 100%; + text-align: center; + border: none; +} + +.peer-connection table th, +.peer-connection table td { + padding: 0.4em; +} + +.peer-connection table tr:nth-child(even) { + background-color: #DDD; +} + +.pcid span:first-child { + font-weight: bold; +} + +.tabs > ul { + list-style-type: none; + margin: 0; + padding: 3px 10px; +} + +.tabs li { + display: inline; + position: relative; + top: 1px; + padding: 3px 10px; +} + +.tabs li > a { + text-decoration: none; + padding: 0 2em; +} + +.tabs li.active { + background-color: #FFF; + border: 1px solid #AFACA9; + border-bottom: none; +} + +.tabs section { + clear: both; +} + diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.js b/toolkit/content/aboutwebrtc/aboutWebrtc.js new file mode 100644 index 000000000000..ffd89e1ee1ae --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.js @@ -0,0 +1,529 @@ +/** @jsx React.DOM */ +/* 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"; + +var Tabs = React.createClass({displayName: 'Tabs', + getDefaultProps: function() { + return {selectedIndex: 0}; + }, + + getInitialState: function() { + return {selectedIndex: this.props.selectedIndex}; + }, + + selectTab: function(index) { + return function(event) { + event.preventDefault(); + this.setState({selectedIndex: index}); + }.bind(this); + }, + + _findSelectedTabContent: function() { + // Using map() to filter children… + // https://github.com/facebook/react/issues/1644#issuecomment-45138113 + return React.Children.map(this.props.children, function(tab, i) { + return i === this.state.selectedIndex ? tab : null; + }.bind(this)) + }, + + render: function() { + var cx = React.addons.classSet; + return ( + React.DOM.div({className: "tabs"}, + React.DOM.ul(null, + React.Children.map(this.props.children, function(tab, i) { + return ( + React.DOM.li({className: cx({active: i === this.state.selectedIndex})}, + React.DOM.a({href: "#", key: i, onClick: this.selectTab(i)}, + tab.props.title + ) + ) + ); + }.bind(this)) + ), + this._findSelectedTabContent() + ) + ); + } +}); + +var Tab = React.createClass({displayName: 'Tab', + render: function() { + return React.DOM.section(null, this.props.children); + } +}); + +var AboutWebRTC = React.createClass({displayName: 'AboutWebRTC', + getInitialState: function() { + return {logs: null, reports: this.props.reports}; + }, + + displayLogs: function() { + WebrtcGlobalInformation.getLogging('', function(logs) { + this.setState({logs: logs, reports: this.state.reports}); + }.bind(this)) + }, + + render: function() { + return ( + React.DOM.div(null, + React.DOM.div({id: "stats"}, + PeerConnections({reports: this.state.reports}) + ), + React.DOM.div({id: "buttons"}, + LogsButton({handler: this.displayLogs}), + DebugButton(null), + AECButton(null) + ), + React.DOM.div({id: "logs"}, + this.state.logs ? Logs({logs: this.state.logs}) : null + ) + ) + ); + } +}); + +var PeerConnections = React.createClass({displayName: 'PeerConnections', + getInitialState: function() { + // Sort the reports to have the more recent at the top + var reports = this.props.reports.slice().sort(function(r1, r2) { + return r2.timestamp - r1.timestamp; + }); + + return {reports: reports}; + }, + + render: function() { + return ( + React.DOM.div({className: "peer-connections"}, + + this.state.reports.map(function(report, i) { + return PeerConnection({key: i, report: report}); + }) + + ) + ); + } +}); + +var PeerConnection = React.createClass({displayName: 'PeerConnection', + getPCInfo: function(report) { + return { + id: report.pcid.match(/id=(\S+)/)[1], + url: report.pcid.match(/http[^)]+/)[0], + closed: report.closed + }; + }, + + getIceCandidatePairs: function(report) { + var candidates = + report.iceCandidateStats.reduce(function(candidates, candidate) { + candidates[candidate.id] = candidate; + + return candidates; + }, {}); + + var pairs = report.iceCandidatePairStats.map(function(pair) { + var localCandidate = candidates[pair.localCandidateId]; + var remoteCandidate = candidates[pair.remoteCandidateId]; + + return { + localCandidate: candidateToString(localCandidate), + remoteCandidate: candidateToString(remoteCandidate), + state: pair.state, + priority: pair.mozPriority, + nominated: pair.nominated, + selected: pair.selected + }; + }); + + var pairedCandidates = pairs.reduce(function(paired, pair) { + paired.add(pair.localCandidate.id); + paired.add(pair.remoteCandidate.id); + + return paired + }, new Set()); + + var unifiedPairs = + report.iceCandidateStats.reduce(function(pairs, candidate) { + if (pairedCandidates.has(candidate)) { + return pairs; + } + + var isLocal = candidate.type === "localcandidate"; + + pairs.push({ + localCandidate: isLocal ? candidateToString(candidate) : null, + remoteCandidate: isLocal ? null : candidateToString(candidate), + state: null, + priority: null, + nominated: null, + selected: null + }); + + return pairs; + }, pairs); + + return unifiedPairs; + }, + + getInitialState: function() { + return { + unfolded: false + }; + }, + + onFold: function() { + this.setState({unfolded: !this.state.unfolded}); + }, + + body: function(report, pairs) { + return ( + React.DOM.div(null, + React.DOM.p({className: "pcid"}, "PeerConnection ID: ", report.pcid), + Tabs(null, + Tab({title: "Ice Stats"}, + IceStats({pairs: pairs}) + ), + Tab({title: "SDP"}, + SDP({type: "local", sdp: report.localSdp}), + SDP({type: "remote", sdp: report.remoteSdp}) + ), + Tab({title: "RTP Stats"}, + RTPStats({report: report}) + ) + ) + ) + ); + }, + + render: function() { + var report = this.props.report; + var pcInfo = this.getPCInfo(report); + var pairs = this.getIceCandidatePairs(report); + + return ( + React.DOM.div({className: "peer-connection"}, + React.DOM.h3({onClick: this.onFold}, + "[", pcInfo.id, "] ", pcInfo.url, " ", pcInfo.closed ? "(closed)" : null, + new Date(report.timestamp).toTimeString() + ), + this.state.unfolded ? this.body(report, pairs) : undefined + ) + ); + } +}); + +var IceStats = React.createClass({displayName: 'IceStats', + sortHeadings: { + "Local candidate": "localCandidate", + "Remote candidate": "remoteCandidate", + "Ice State": "state", + "Priority": "priority", + "Nominated": "nominated", + "Selected": "selected" + }, + + sort: function(key) { + var sorting = this.state.sorting; + var pairs = this.state.pairs.slice().sort(function(pair1, pair2) { + var value1 = pair1[key] ? pair1[key].toString() : ""; + var value2 = pair2[key] ? pair2[key].toString() : ""; + + // Reverse sorting + if (key === sorting) { + return value2.localeCompare(value1); + } + + return value1.localeCompare(value2); + }.bind(this)); + + sorting = (key === sorting) ? null : key; + this.setState({pairs: pairs, sorting: sorting}); + }, + + generateSortHeadings: function() { + return Object.keys(this.sortHeadings).map(function(heading, i) { + var sortKey = this.sortHeadings[heading]; + return ( + React.DOM.th(null, + React.DOM.a({href: "#", onClick: this.sort.bind(this, sortKey)}, + heading + ) + ) + ); + }.bind(this)); + }, + + getInitialState: function() { + return {pairs: this.props.pairs, sorting: null}; + }, + + render: function() { + return ( + React.DOM.table(null, + React.DOM.tbody(null, + React.DOM.tr(null, this.generateSortHeadings()), + this.state.pairs.map(function(pair, i) { + return IceCandidatePair({key: i, pair: pair}); + }) + ) + ) + ); + } +}); + +var IceCandidatePair = React.createClass({displayName: 'IceCandidatePair', + render: function() { + var pair = this.props.pair; + return ( + React.DOM.tr(null, + React.DOM.td(null, pair.localCandidate), + React.DOM.td(null, pair.remoteCandidate), + React.DOM.td(null, pair.state), + React.DOM.td(null, pair.priority), + React.DOM.td(null, pair.nominated ? '✔' : null), + React.DOM.td(null, pair.selected ? '✔' : null) + ) + ); + } +}); + +var SDP = React.createClass({displayName: 'SDP', + render: function() { + var type = labelize(this.props.type); + + return ( + React.DOM.div(null, + React.DOM.h4(null, type, " SDP"), + React.DOM.pre(null, + this.props.sdp + ) + ) + ); + } +}); + +var RTPStats = React.createClass({displayName: 'RTPStats', + getRtpStats: function(report) { + var remoteRtpStats = {}; + var rtpStats = []; + + rtpStats = rtpStats.concat(report.inboundRTPStreamStats || []); + rtpStats = rtpStats.concat(report.outboundRTPStreamStats || []); + + rtpStats.forEach(function(stats) { + if (stats.isRemote) { + remoteRtpStats[stats.id] = stats; + } + }); + + rtpStats.forEach(function(stats) { + if (stats.remoteId) { + stats.remoteRtpStats = remoteRtpStats[stats.remoteId]; + } + }); + + return rtpStats; + }, + + dumpAvStats: function(stats) { + var statsString = ""; + if (stats.mozAvSyncDelay) { + statsString += `A/V sync: ${stats.mozAvSyncDelay} ms `; + } + if (stats.mozJitterBufferDelay) { + statsString += `Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`; + } + + return React.DOM.div(null, statsString); + }, + + dumpCoderStats: function(stats) { + var statsString = ""; + var label; + + if (stats.bitrateMean) { + statsString += ` Avg. bitrate: ${(stats.bitrateMean/1000000).toFixed(2)} Mbps`; + if (stats.bitrateStdDev) { + statsString += ` (${(stats.bitrateStdDev/1000000).toFixed(2)} SD)`; + } + } + + if (stats.framerateMean) { + statsString += ` Avg. framerate: ${(stats.framerateMean).toFixed(2)} fps`; + if (stats.framerateStdDev) { + statsString += ` (${stats.framerateStdDev.toFixed(2)} SD)`; + } + } + + if (stats.droppedFrames) { + statsString += ` Dropped frames: ${stats.droppedFrames}`; + } + if (stats.discardedPackets) { + statsString += ` Discarded packets: ${stats.discardedPackets}`; + } + + if (statsString) { + label = (stats.packetsReceived)? " Decoder:" : " Encoder:"; + statsString = label + statsString; + } + + return React.DOM.div(null, statsString); + }, + + dumpRtpStats: function(stats, type) { + var label = labelize(type); + var time = new Date(stats.timestamp).toTimeString(); + + var statsString = `${label}: ${time} ${stats.type} SSRC: ${stats.ssrc}`; + + if (stats.packetsReceived) { + statsString += ` Received: ${stats.packetsReceived} packets`; + + if (stats.bytesReceived) { + statsString += ` (${round00(stats.bytesReceived/1024)} Kb)`; + } + + statsString += ` Lost: ${stats.packetsLost} Jitter: ${stats.jitter}`; + + if (stats.mozRtt) { + statsString += ` RTT: ${stats.mozRtt} ms`; + } + } else if (stats.packetsSent) { + statsString += ` Sent: ${stats.packetsSent} packets`; + if (stats.bytesSent) { + statsString += ` (${round00(stats.bytesSent/1024)} Kb)`; + } + } + + return React.DOM.div(null, statsString); + }, + + render: function() { + var rtpStats = this.getRtpStats(this.props.report); + + return ( + React.DOM.div(null, + rtpStats.map(function(stats) { + var isAvStats = (stats.mozAvSyncDelay || stats.mozJitterBufferDelay); + var remoteRtpStats = stats.remoteId ? stats.remoteRtpStats : null; + + return [ + React.DOM.h5(null, stats.id), + isAvStats ? this.dumpAvStats(stats) : null, + this.dumpCoderStats(stats), + this.dumpRtpStats(stats, "local"), + remoteRtpStats ? this.dumpRtpStats(remoteRtpStats, "remote") : null + ] + }.bind(this)) + ) + ); + } +}); + +var LogsButton = React.createClass({displayName: 'LogsButton', + render: function() { + return ( + React.DOM.button({onClick: this.props.handler}, "Connection log") + ); + } +}); + +var DebugButton = React.createClass({displayName: 'DebugButton', + getInitialState: function() { + var on = (WebrtcGlobalInformation.debugLevel > 0); + return {on: on}; + }, + + onClick: function() { + if (this.state.on) + WebrtcGlobalInformation.debugLevel = 0; + else + WebrtcGlobalInformation.debugLevel = 65535; + + this.setState({on: !this.state.on}); + }, + + render: function() { + return ( + React.DOM.button({onClick: this.onClick}, + this.state.on ? "Stop debug mode" : "Start debug mode" + ) + ); + } +}); + +var AECButton = React.createClass({displayName: 'AECButton', + getInitialState: function() { + return {on: WebrtcGlobalInformation.aecDebug}; + }, + + onClick: function() { + WebrtcGlobalInformation.aecDebug = !this.state.on; + this.setState({on: WebrtcGlobalInformation.aecDebug}); + }, + + render: function() { + return ( + React.DOM.button({onClick: this.onClick}, + this.state.on ? "Stop AEC logging" : "Start AEC logging" + ) + ); + } +}); + +var Logs = React.createClass({displayName: 'Logs', + render: function() { + return ( + React.DOM.div(null, + React.DOM.h3(null, "Logging:"), + React.DOM.div(null, + this.props.logs.map(function(line, i) { + return React.DOM.div({key: i}, line); + }) + ) + ) + ); + } +}); + +function iceCandidateMapping(iceCandidates) { + var candidates = {}; + iceCandidates = iceCandidates || []; + + iceCandidates.forEach(function(candidate) { + candidates[candidate.id] = candidate; + }); + + return candidates; +} + +function round00(num) { + return Math.round(num * 100) / 100; +} + +function labelize(label) { + return `${label.charAt(0).toUpperCase()}${label.slice(1)}`; +} + +function candidateToString(c) { + var type = c.candidateType; + + if (c.type == "localcandidate" && c.candidateType == "relayed") { + type = `${c.candidateType}-${c.mozLocalTransport}`; + } + + return `${c.ipAddress}:${c.portNumber}/${c.transport}(${type})` +} + +function onLoad() { + WebrtcGlobalInformation.getAllStats(function(globalReport) { + var reports = globalReport.reports; + React.renderComponent(AboutWebRTC({reports: reports}), + document.querySelector("#body")); + }); +} diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.jsx b/toolkit/content/aboutwebrtc/aboutWebrtc.jsx new file mode 100644 index 000000000000..d458f8bfc3ed --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.jsx @@ -0,0 +1,529 @@ +/** @jsx React.DOM */ +/* 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"; + +var Tabs = React.createClass({ + getDefaultProps: function() { + return {selectedIndex: 0}; + }, + + getInitialState: function() { + return {selectedIndex: this.props.selectedIndex}; + }, + + selectTab: function(index) { + return function(event) { + event.preventDefault(); + this.setState({selectedIndex: index}); + }.bind(this); + }, + + _findSelectedTabContent: function() { + // Using map() to filter children… + // https://github.com/facebook/react/issues/1644#issuecomment-45138113 + return React.Children.map(this.props.children, function(tab, i) { + return i === this.state.selectedIndex ? tab : null; + }.bind(this)) + }, + + render: function() { + var cx = React.addons.classSet; + return ( +
+
    { + React.Children.map(this.props.children, function(tab, i) { + return ( +
  • + + {tab.props.title} + +
  • + ); + }.bind(this)) + }
+ {this._findSelectedTabContent()} +
+ ); + } +}); + +var Tab = React.createClass({ + render: function() { + return
{this.props.children}
; + } +}); + +var AboutWebRTC = React.createClass({ + getInitialState: function() { + return {logs: null, reports: this.props.reports}; + }, + + displayLogs: function() { + WebrtcGlobalInformation.getLogging('', function(logs) { + this.setState({logs: logs, reports: this.state.reports}); + }.bind(this)) + }, + + render: function() { + return ( +
+
+ +
+
+ + + +
+
{ + this.state.logs ? : null + }
+
+ ); + } +}); + +var PeerConnections = React.createClass({ + getInitialState: function() { + // Sort the reports to have the more recent at the top + var reports = this.props.reports.slice().sort(function(r1, r2) { + return r2.timestamp - r1.timestamp; + }); + + return {reports: reports}; + }, + + render: function() { + return ( +
+ { + this.state.reports.map(function(report, i) { + return ; + }) + } +
+ ); + } +}); + +var PeerConnection = React.createClass({ + getPCInfo: function(report) { + return { + id: report.pcid.match(/id=(\S+)/)[1], + url: report.pcid.match(/http[^)]+/)[0], + closed: report.closed + }; + }, + + getIceCandidatePairs: function(report) { + var candidates = + report.iceCandidateStats.reduce(function(candidates, candidate) { + candidates[candidate.id] = candidate; + + return candidates; + }, {}); + + var pairs = report.iceCandidatePairStats.map(function(pair) { + var localCandidate = candidates[pair.localCandidateId]; + var remoteCandidate = candidates[pair.remoteCandidateId]; + + return { + localCandidate: candidateToString(localCandidate), + remoteCandidate: candidateToString(remoteCandidate), + state: pair.state, + priority: pair.mozPriority, + nominated: pair.nominated, + selected: pair.selected + }; + }); + + var pairedCandidates = pairs.reduce(function(paired, pair) { + paired.add(pair.localCandidate.id); + paired.add(pair.remoteCandidate.id); + + return paired + }, new Set()); + + var unifiedPairs = + report.iceCandidateStats.reduce(function(pairs, candidate) { + if (pairedCandidates.has(candidate)) { + return pairs; + } + + var isLocal = candidate.type === "localcandidate"; + + pairs.push({ + localCandidate: isLocal ? candidateToString(candidate) : null, + remoteCandidate: isLocal ? null : candidateToString(candidate), + state: null, + priority: null, + nominated: null, + selected: null + }); + + return pairs; + }, pairs); + + return unifiedPairs; + }, + + getInitialState: function() { + return { + unfolded: false + }; + }, + + onFold: function() { + this.setState({unfolded: !this.state.unfolded}); + }, + + body: function(report, pairs) { + return ( +
+

PeerConnection ID: {report.pcid}

+ + + + + + + + + + + + +
+ ); + }, + + render: function() { + var report = this.props.report; + var pcInfo = this.getPCInfo(report); + var pairs = this.getIceCandidatePairs(report); + + return ( +
+

+ [{pcInfo.id}] {pcInfo.url} {pcInfo.closed ? "(closed)" : null} + {new Date(report.timestamp).toTimeString()} +

+ {this.state.unfolded ? this.body(report, pairs) : undefined} +
+ ); + } +}); + +var IceStats = React.createClass({ + sortHeadings: { + "Local candidate": "localCandidate", + "Remote candidate": "remoteCandidate", + "Ice State": "state", + "Priority": "priority", + "Nominated": "nominated", + "Selected": "selected" + }, + + sort: function(key) { + var sorting = this.state.sorting; + var pairs = this.state.pairs.slice().sort(function(pair1, pair2) { + var value1 = pair1[key] ? pair1[key].toString() : ""; + var value2 = pair2[key] ? pair2[key].toString() : ""; + + // Reverse sorting + if (key === sorting) { + return value2.localeCompare(value1); + } + + return value1.localeCompare(value2); + }.bind(this)); + + sorting = (key === sorting) ? null : key; + this.setState({pairs: pairs, sorting: sorting}); + }, + + generateSortHeadings: function() { + return Object.keys(this.sortHeadings).map(function(heading, i) { + var sortKey = this.sortHeadings[heading]; + return ( + + + {heading} + + + ); + }.bind(this)); + }, + + getInitialState: function() { + return {pairs: this.props.pairs, sorting: null}; + }, + + render: function() { + return ( + + + {this.generateSortHeadings()} + {this.state.pairs.map(function(pair, i) { + return ; + })} + +
+ ); + } +}); + +var IceCandidatePair = React.createClass({ + render: function() { + var pair = this.props.pair; + return ( + + {pair.localCandidate} + {pair.remoteCandidate} + {pair.state} + {pair.priority} + {pair.nominated ? '✔' : null} + {pair.selected ? '✔' : null} + + ); + } +}); + +var SDP = React.createClass({ + render: function() { + var type = labelize(this.props.type); + + return ( +
+

{type} SDP

+
+          {this.props.sdp}
+        
+
+ ); + } +}); + +var RTPStats = React.createClass({ + getRtpStats: function(report) { + var remoteRtpStats = {}; + var rtpStats = []; + + rtpStats = rtpStats.concat(report.inboundRTPStreamStats || []); + rtpStats = rtpStats.concat(report.outboundRTPStreamStats || []); + + rtpStats.forEach(function(stats) { + if (stats.isRemote) { + remoteRtpStats[stats.id] = stats; + } + }); + + rtpStats.forEach(function(stats) { + if (stats.remoteId) { + stats.remoteRtpStats = remoteRtpStats[stats.remoteId]; + } + }); + + return rtpStats; + }, + + dumpAvStats: function(stats) { + var statsString = ""; + if (stats.mozAvSyncDelay) { + statsString += `A/V sync: ${stats.mozAvSyncDelay} ms `; + } + if (stats.mozJitterBufferDelay) { + statsString += `Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`; + } + + return
{statsString}
; + }, + + dumpCoderStats: function(stats) { + var statsString = ""; + var label; + + if (stats.bitrateMean) { + statsString += ` Avg. bitrate: ${(stats.bitrateMean/1000000).toFixed(2)} Mbps`; + if (stats.bitrateStdDev) { + statsString += ` (${(stats.bitrateStdDev/1000000).toFixed(2)} SD)`; + } + } + + if (stats.framerateMean) { + statsString += ` Avg. framerate: ${(stats.framerateMean).toFixed(2)} fps`; + if (stats.framerateStdDev) { + statsString += ` (${stats.framerateStdDev.toFixed(2)} SD)`; + } + } + + if (stats.droppedFrames) { + statsString += ` Dropped frames: ${stats.droppedFrames}`; + } + if (stats.discardedPackets) { + statsString += ` Discarded packets: ${stats.discardedPackets}`; + } + + if (statsString) { + label = (stats.packetsReceived)? " Decoder:" : " Encoder:"; + statsString = label + statsString; + } + + return
{statsString}
; + }, + + dumpRtpStats: function(stats, type) { + var label = labelize(type); + var time = new Date(stats.timestamp).toTimeString(); + + var statsString = `${label}: ${time} ${stats.type} SSRC: ${stats.ssrc}`; + + if (stats.packetsReceived) { + statsString += ` Received: ${stats.packetsReceived} packets`; + + if (stats.bytesReceived) { + statsString += ` (${round00(stats.bytesReceived/1024)} Kb)`; + } + + statsString += ` Lost: ${stats.packetsLost} Jitter: ${stats.jitter}`; + + if (stats.mozRtt) { + statsString += ` RTT: ${stats.mozRtt} ms`; + } + } else if (stats.packetsSent) { + statsString += ` Sent: ${stats.packetsSent} packets`; + if (stats.bytesSent) { + statsString += ` (${round00(stats.bytesSent/1024)} Kb)`; + } + } + + return
{statsString}
; + }, + + render: function() { + var rtpStats = this.getRtpStats(this.props.report); + + return ( +
{ + rtpStats.map(function(stats) { + var isAvStats = (stats.mozAvSyncDelay || stats.mozJitterBufferDelay); + var remoteRtpStats = stats.remoteId ? stats.remoteRtpStats : null; + + return [ +
{stats.id}
, + isAvStats ? this.dumpAvStats(stats) : null, + this.dumpCoderStats(stats), + this.dumpRtpStats(stats, "local"), + remoteRtpStats ? this.dumpRtpStats(remoteRtpStats, "remote") : null + ] + }.bind(this)) + }
+ ); + } +}); + +var LogsButton = React.createClass({ + render: function() { + return ( + + ); + } +}); + +var DebugButton = React.createClass({ + getInitialState: function() { + var on = (WebrtcGlobalInformation.debugLevel > 0); + return {on: on}; + }, + + onClick: function() { + if (this.state.on) + WebrtcGlobalInformation.debugLevel = 0; + else + WebrtcGlobalInformation.debugLevel = 65535; + + this.setState({on: !this.state.on}); + }, + + render: function() { + return ( + + ); + } +}); + +var AECButton = React.createClass({ + getInitialState: function() { + return {on: WebrtcGlobalInformation.aecDebug}; + }, + + onClick: function() { + WebrtcGlobalInformation.aecDebug = !this.state.on; + this.setState({on: WebrtcGlobalInformation.aecDebug}); + }, + + render: function() { + return ( + + ); + } +}); + +var Logs = React.createClass({ + render: function() { + return ( +
+

Logging:

+
{ + this.props.logs.map(function(line, i) { + return
{line}
; + }) + }
+
+ ); + } +}); + +function iceCandidateMapping(iceCandidates) { + var candidates = {}; + iceCandidates = iceCandidates || []; + + iceCandidates.forEach(function(candidate) { + candidates[candidate.id] = candidate; + }); + + return candidates; +} + +function round00(num) { + return Math.round(num * 100) / 100; +} + +function labelize(label) { + return `${label.charAt(0).toUpperCase()}${label.slice(1)}`; +} + +function candidateToString(c) { + var type = c.candidateType; + + if (c.type == "localcandidate" && c.candidateType == "relayed") { + type = `${c.candidateType}-${c.mozLocalTransport}`; + } + + return `${c.ipAddress}:${c.portNumber}/${c.transport}(${type})` +} + +function onLoad() { + WebrtcGlobalInformation.getAllStats(function(globalReport) { + var reports = globalReport.reports; + React.renderComponent(, + document.querySelector("#body")); + }); +} diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml b/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml new file mode 100644 index 000000000000..08268b055d23 --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml @@ -0,0 +1,22 @@ + + + + + %htmlDTD; +]> + + + + Webrtc Internals + + + + + + + \n"; - - -# -# If this is SurfingSafari, then catch a wave and you're sitting on top of the world!! -# (and also blat this out to tegu, cause we got no 'dump' statement. -# -if ($request->cgi->var("HTTP_USER_AGENT") =~ /Safari/) { - my %machineMap = - ( - "10.169.105.26" => "boxset", - "10.169.105.21" => "pawn" - ); - my $ip = $request->cgi->var('REMOTE_ADDR'); - my $machine = $machineMap{$ip}; - my $res = eval q{ - use LWP::UserAgent; - use HTTP::Request::Common qw(POST); - my $ua = LWP::UserAgent->new; - $ua->timeout(10); # seconds - my $req = POST('http://tegu.mozilla.org/graph/collect.cgi', - [testname => 'pageload', - tbox => "$machine" . "-aux", - value => $rs->{avgmedian}, - data => $data]); - my $res = $ua->request($req); - return $res; - }; - if ($@) { - warn "Failed to submit startup results: $@"; - } else { - warn "Startup results submitted to server: \n", - $res->status_line, "\n", $res->content, "\n"; - } -} - - -if ($request->param('purge')) { - # now move any old stuff into archive and clean stale entries - # just going with the simple approach of "whoever sees old entries - # first, cleans em up, whether they 'own' them or not". Hopefully, - # the default locking will be sufficient to prevent a race. - close(STDOUT); - sleep(1); - $dbroot = "db"; - $dbh = DBI->connect("DBI:CSV:f_dir=./$dbroot", - {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - $arc = DBI->connect("DBI:CSV:f_dir=./$dbroot/archive", - {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - purgeStaleEntries($id); - $dbh->disconnect(); - $arc->disconnect(); -} - -exit 0; diff --git a/tools/page-loader/echo.pl b/tools/page-loader/echo.pl deleted file mode 100755 index 2d74d115b2a0..000000000000 --- a/tools/page-loader/echo.pl +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/perl -# -# 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 Time::HiRes qw(gettimeofday tv_interval); - -sub encodeHiResTime { - my $timeref = shift; - return unless ref($timeref); - my $time = $$timeref[0] . "-" . $$timeref[1]; - return $time; -} - -my $time = encodeHiResTime([gettimeofday()]); - -print "Content-type: text/html\n\n"; -print <<"ENDOFHTML"; - - - - - -

- This page starts the test. -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

- - - -ENDOFHTML - -exit 0; diff --git a/tools/page-loader/graph.pl b/tools/page-loader/graph.pl deleted file mode 100755 index bb8b04d12992..000000000000 --- a/tools/page-loader/graph.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl -# -# 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 CGI::Carp qw(fatalsToBrowser); -use CGI::Request; -use URLTimingDataSet; -use URLTimingGraph; - -my $request = new CGI::Request; - -my $id = $request->param('id'); #XXX need to check for valid parameter id -my $id2 = $request->param('id2') || undef; # possible comparison test - -# set up the data for the first graph -my $rs = URLTimingDataSet->new($id); -my @data = (); -push @data, [ map($_->[1], @{$rs->{sorted}}) ]; # URL -push @data, [ map($_->[4], @{$rs->{sorted}}) ]; # median -# '7' is the first slot for individual test run data -for (my $idx = 7; $idx < (7+$rs->{count}); $idx++) { - push @data, [ map($_->[$idx], @{$rs->{sorted}}) ]; -} - - -# set up the data for the second graph, if requested a second id -# need to sort according to the first chart's ordering -my $rs2; -if ($id2) { - $rs2 = URLTimingDataSet->new($id2); - my @order = map($_->[0], @{$rs->{sorted}}); # get the first chart's order - my @resort = (); - for my $i (@order) { - for (@{$rs2->{sorted}}) { - if ($i == $_->[0]) { - push @resort, $_; - last; - } - } - } - push @data, [ map($_->[4], @resort) ]; # median - for (my $idx = 7; $idx < (7+$rs2->{count}); $idx++) { - push @data, [ map($_->[$idx], @resort) ]; - } -} - -# and now convert 'NaN' to undef, if they exist in the data. -for (@data) { for (@$_) { $_ = undef if $_ eq "NaN"; } } - -# set up the chart parameters -my $args = {}; -$args->{cgimode} = 1; -$args->{title} = "id=$id"; - -# need to draw first visit as dotted with points -my $types = ['lines','lines']; for (1..$rs->{count}-1) { push @$types, undef; } -my $dclrs = []; for (0..$rs->{count}) { push @$dclrs, 'lred'; } -my $legend = [$id]; for (1..$rs->{count}) { push @$legend, undef; } -if ($id2) { - push @$types, 'lines'; for (1..$rs2->{count}) { push @$types, undef; } - for (0..$rs2->{count}) { push @$dclrs, 'lblue'; } - push @$legend, $id2; for (1..$rs2->{count}) { push @$legend, undef; } -} -$args->{types} = $types; -$args->{dclrs} = $dclrs; -$args->{legend} = $legend; - -#XXX set min to zero, and round max to 1000 -$args->{y_max_value} = maxDataOrCap(); -## nope $args->{y_min_value} = 1000; -$args->{width} = 800; -$args->{height} = 720; - -my $g = URLTimingGraph->new(\@data, $args); -$g->plot(); - -exit; - - -sub maxDataOrCap { - my $max; - warn $rs->{maximum}; - if ($rs2 && ($rs->{maximum} < $rs2->{maximum})) { - $max = $rs2->{maximum}; - } else { - $max = $rs->{maximum}; - } - warn $max; - #return $max > 10000 ? 10000 : 1000*int($max/1000)+1000; - # just return whatever, rounded to 1000 - return 1000*int($max/1000)+1000; -} diff --git a/tools/page-loader/loader.pl b/tools/page-loader/loader.pl deleted file mode 100755 index 3130237f2ad7..000000000000 --- a/tools/page-loader/loader.pl +++ /dev/null @@ -1,618 +0,0 @@ -#!/usr/bin/perl -# -# 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; -use CGI::Request; -use CGI::Carp qw(fatalsToBrowser); -use Time::HiRes qw(gettimeofday tv_interval); -use POSIX qw(strftime); -use DBI; - -# list of test pages, JS to insert, httpbase, filebase, etc. -use PageData; - -use vars qw(%params $req $cgi $dbh $pagedata - $gStartNow $gStartNowStr - $gResponseNow $gLogging); - -$gStartNow = [gettimeofday]; # checkpoint the time -$gStartNowStr = strftime "%Y%m%d%H%M%S", localtime; -$gLogging = 1; - -$req = new CGI::Request; # get the HTTP/CGI request -$cgi = $req->cgi; - -$pagedata = PageData->new; - -setDefaultParams(); - -#XXXdebugcrap -#warn $params{index}, " ", $params{maxidx}; - -if (!defined($req->param('delay'))) { - # give the user a form to pick options (but note that going - # to "loader.pl?delay=1000" immediately starts the test run - outputForm(); -} -elsif (!$req->param('id')) { - initialize(); # do redirect to start the cycle -} -elsif ($params{index} > $params{maxidx}) { - redirectToReport(); # the test is over; spit out a summary - markTestAsComplete(); # close the meta table entry -} -elsif (!isRequestStale()) { - outputPage(); # otherwise, keep dishing out pages - updateDataBase(); # client has the response; now write out stats to db -} - -# cleanup -$req = undef; -$dbh->disconnect() if $dbh; # not strictly required (ignored in some cases anyways) - -#logMessage(sprintf("Page load server responded in %3d msec, total time %3d msec, pid: %d", -# 1000*tv_interval($gStartNow, $gResponseNow), 1000*tv_interval($gStartNow), $$)) -# if $gResponseNow; # log only when a test page has been dished out - -exit 0; - -####################################################################### - -sub logMessage { - print STDERR strftime("[%a %b %d %H:%M:%S %Y] ", localtime), @_, "\n" - if $gLogging; -} - - -sub isRequestStale { - my $limit = 30*60; # 30 minutes, although if we never stalled on mac I'd make it 3 minutes - my $ts = decodeHiResTime($params{s_ts}); - my $delta = tv_interval($ts, $gStartNow); - return undef if $delta < $limit; - # otherwise, punt this request - print "Content-type: text/html\n\n"; - print <<"ENDOFHTML"; -Page Loading Times Test -

The timestamp on the request is too old to continue:
-s_ts=$params{s_ts} was $delta seconds ago. Limit is $limit seconds.

- -ENDOFHTML - return 1; # it's stale -} - - -sub initialize { - updateMetaTable(); - createDataSetTable(); - - # start the test by bouncing off of an echo page - my $script = $cgi->var("SCRIPT_NAME"); - my $server = $cgi->var("SERVER_NAME"); - my $proto = $ENV{SERVER_PORT} == 443 ? 'https://' : 'http://'; - my $me = $proto . $server . $script; - $script =~ /^(.*\/).*$/; - my $loc = "Location: ". $proto . $server . $1 . "echo.pl?"; - for (qw(id index maxcyc delay replace nocache timeout)) { - $loc .= "$_=$params{$_}\&"; - } - $loc .= "url=" . $me; - print $loc, "\n\n"; -} - - -sub redirectToReport { - # n.b., can also add '&sort=1' to get a time sorted list - my $proto = $ENV{SERVER_PORT} == 443 ? 'https://' : 'http://'; - my $loc = "Location: " . $proto . $cgi->var("SERVER_NAME"); - $cgi->var("SCRIPT_NAME") =~ /^(.*\/).*$/; - $loc .= $1 . "report.pl?id=" . $params{id}; - # To use for a tinderbox, comment out the line above and uncomment this: - # $loc .= $1 . "dump.pl?id=" . $params{id} . "&purge=1"; - print $loc, "\n\n"; -} - - -sub generateTestId { - # use the epoch time, in hex, plus a two-character random. - return sprintf "%8X%02X", time(), int(256*rand()); -} - - -sub setDefaultParams { - $params{id} = $req->param('id') || generateTestId(); # "unique" id for this run - $params{index} = $req->param('index') || 0; # request index for the test - $params{maxcyc} = defined($req->param('maxcyc')) ? - $req->param('maxcyc') : 3; # max visits (zero-based count) - $params{delay} = $req->param('delay') || 1000; # setTimeout on the next request (msec) - $params{replace} = $req->param('replace') || 0; # use Location.replace (1) or Location.href (0) - $params{nocache} = $req->param('nocache') || 0; # serve content via uncacheable path - $params{c_part} = $req->param('c_part') || 0; # client time elapsed; page head to onload (msec) - $params{c_intvl} = $req->param('c_intvl') || 0; # client time elapsed; onload to onload event (msec) - $params{c_ts} = $req->param('c_ts') || 0; # client timestamp (.getTime()) (msec) - $params{content} = $req->param('content') || "UNKNOWN"; # name of content page for this data - $params{s_ts} = $req->param('s_ts') || undef; # server timestamp; no default - $params{timeout} = $req->param('timeout') || 30000; # msec; timer will cancel stalled page loading - $params{maxidx} = ($params{maxcyc}+1) * $pagedata->length; # total pages loads to be done - $params{curidx} = $params{index} % $pagedata->length; # current request index into page list - $params{curcyc} = int(($params{index}-1) / $pagedata->length); # current "cycle" (visit) -} - - -sub outputPage { - my $relpath = $pagedata->url($params{curidx}); - my $file = $pagedata->filebase . $relpath; - open (HTML, "<$file") || - die "Can't open file: $file, $!"; - - my $hook = "\n"; - - my $basepath = $pagedata->httpbase; - $basepath =~ s/^http:/https:/i - if $ENV{SERVER_PORT} == 443; - #warn "basepath: $basepath"; - $basepath =~ s#^(.*?)(/base/)$#$1/nocache$2# if ($params{nocache}); - $hook .= ""; - - my $magic = $pagedata->magicString; - my $content = ""; - while () { - s/$magic/$hook/; - $content .= $_; - } - - my $contentTypeHeader; - my $mimetype = $pagedata->mimetype($params{curidx}); - my $charset = $pagedata->charset($params{curidx}); - if ($charset) { - $contentTypeHeader = qq{Content-type: $mimetype; charset="$charset"\n\n}; - } else { - $contentTypeHeader = qq{Content-type: $mimetype\n\n}; - } - #warn $contentTypeHeader; #XXXjrgm testing... - - # N.B., these two cookie headers are obsolete, since I pass server info in - # JS now, to work around a bug in winEmbed with document.cookie. But - # since I _was_ sending two cookies as part of the test, I have to keep - # sending two cookies (at least for now, and it's not a bad thing to test) - #XXX other headers to test/use? - - $gResponseNow = [gettimeofday]; # for logging - { # turn on output autoflush, locally in this block - print "Set-Cookie: moztest_SomeRandomCookie1=somerandomstring\n"; - print "Set-Cookie: moztest_SomeRandomCookie2=somerandomstring\n"; - print $contentTypeHeader; - local $| = 1; - print $content; - } - - return; -} - - -sub encodeHiResTime { - my $timeref = shift; - return unless ref($timeref); - return $$timeref[0] . "-" . $$timeref[1]; -} - - -sub decodeHiResTime { - my $timestr = shift; - return [ split('-', $timestr) ]; -} - - -sub elapsedMilliSeconds { - my ($r_time, $timestr) = @_; - return "NaN" unless $timestr; - my $delta = tv_interval( [ split('-', $timestr) ], $r_time ); - my $delta = int(($delta*1000) - $params{delay}); # adjust for delay (in msec) - return $delta; -} - - -sub updateDataBase { - connectToDataBase(); # (may already be cached) - updateMetaTable(); - updateDataSetTable() unless $params{c_part} == -1; # the initial request -} - - -sub connectToDataBase { - # don't reconnect if already connected. (Other drivers provide this - # for free I think, but not this one). - if (!ref($dbh)) { - $dbh = DBI->connect("DBI:CSV:f_dir=./db", {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - } -} - - -# -# Holds the individual page load data for this id. -# -# (Of course, this should really be a single table for all datasets, but -# that was becoming punitively slow with DBD::CSV. I could have moved to -# a "real" database, but I didn't want to make that a requirement for -# installing this on another server and using this test (e.g., install a -# few modules and you can run this; no sql installation/maintenance required). -# At some point though, I may switch to some sql db, but hopefully still allow -# this to be used with a simple flat file db. (Hmm, maybe I should try a *dbm -# as a compromise (disk based but indexed)). -# -sub createDataSetTable { - my $table = "t" . $params{id}; - return if -f "db/$table"; # don't create it if it exists - logMessage("createDataSetTable:\tdb/$table"); - connectToDataBase(); # cached - - my ($sth, $sql); - $sql = qq{ - CREATE TABLE $table - (DATETIME CHAR(14), - ID CHAR(10), - INDEX INTEGER, - CUR_IDX INTEGER, - CUR_CYC INTEGER, - C_PART INTEGER, - S_INTVL INTEGER, - C_INTVL INTEGER, - CONTENT CHAR(128) - ) - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); - return 1; -} - - -# -# holds the information about all test runs -# -sub createMetaTable { - my $table = shift; - return if -f "db/$table"; # don't create it if it exists - logMessage("createMetaTable:\tdb/$table"); - - my ($sth, $sql); - - $sql = qq{ - CREATE TABLE $table - (DATETIME CHAR(14), - LASTPING CHAR(14), - ID CHAR(8), - INDEX INTEGER, - CUR_IDX INTEGER, - CUR_CYC INTEGER, - CUR_CONTENT CHAR(128), - STATE INTEGER, - BLESSED INTEGER, - MAXCYC INTEGER, - MAXIDX INTEGER, - REPLACE INTEGER, - NOCACHE INTEGER, - DELAY INTEGER, - REMOTE_USER CHAR(16), - HTTP_USER_AGENT CHAR(128), - REMOTE_ADDR CHAR(15), - USER_EMAIL CHAR(32), - USER_COMMENT CHAR(256) - ) - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); - warn 'created meta table'; - return 1; -} - - -sub updateMetaTable { - - connectToDataBase(); # if not already connected - - my $table = "tMetaTable"; - createMetaTable($table); # just returns if already created - - my ($sth, $sql); - - $sql = qq{ - SELECT INDEX, MAXCYC, MAXIDX, REPLACE, NOCACHE, - DELAY, REMOTE_USER, HTTP_USER_AGENT, REMOTE_ADDR - FROM $table - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - - my @dataset = (); - while (my @data = $sth->fetchrow_array()) { - push @dataset, {index => shift @data, - maxcyc => shift @data, - maxidx => shift @data, - replace => shift @data, - nocache => shift @data, - delay => shift @data, - remote_user => shift @data, - http_user_agent => shift @data, - remote_addr => shift @data - }; - } - $sth->finish(); - warn "More than one ID: $params{id} ??" if scalar(@dataset) > 1; - - if (scalar(@dataset) == 0) { - # this is a new dataset and id - initMetaTableRecord($table); - return; - } - - #XXX need to check that values are sane, and not update if they don't - # match certain params. This should not happen in a normal test run. - # However, if a test url was bookmarked or in history, I might get bogus - # data collected after the fact. But I have a stale date set on the URL, - # so that is good enough for now. - # my $ref = shift @dataset; # check some $ref->{foo} - - $sql = qq{ - UPDATE $table - SET LASTPING = ?, - INDEX = ?, - CUR_IDX = ?, - CUR_CYC = ?, - CUR_CONTENT = ?, - STATE = ? - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $params{index}-1, # (index-1) is complete; (index) in progress - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{content}, - 'OPEN' - ); - $sth->finish(); - -} - - -sub markTestAsComplete { - connectToDataBase(); # if not already connected - my $table = "tMetaTable"; - createMetaTable($table); # just returns if already created - my ($sth, $sql); - #XXX should probably check if this ID exists first - $sql = qq{ - UPDATE $table - SET STATE = "COMPLETE" - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); -} - - -sub initMetaTableRecord { - # we know this record doesn't exist, so put in the initial values - my $table = shift; - my ($sth, $sql); - $sql = qq{ - INSERT INTO $table - (DATETIME, - LASTPING, - ID, - INDEX, - CUR_IDX, - CUR_CYC, - CUR_CONTENT, - STATE, - BLESSED, - MAXCYC, - MAXIDX, - REPLACE, - NOCACHE, - DELAY, - REMOTE_USER, - HTTP_USER_AGENT, - REMOTE_ADDR, - USER_EMAIL, - USER_COMMENT - ) - VALUES (?,?,?,?, - ?,?,?,?, - ?,?,?,?, - ?,?,?,?, - ?,?,?) - }; - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $gStartNowStr, - $params{id}, - $params{index}-1, - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{content}, - "INIT", - 0, - $params{maxcyc}, - $params{maxidx}, - $params{replace}, - $params{nocache}, - $params{delay}, - $cgi->var("REMOTE_USER"), - $cgi->var("HTTP_USER_AGENT"), - $cgi->var("REMOTE_ADDR"), - "", - "" - ); - $sth->finish(); -} - - -sub updateDataSetTable { - my $table = shift; - my $table = "t" . $params{id}; - - my ($sth, $sql); - $sql = qq{ - INSERT INTO $table - (DATETIME, - ID, - INDEX, - CUR_IDX, - CUR_CYC, - C_PART, - S_INTVL, - C_INTVL, - CONTENT - ) - VALUES (?,?,?,?, - ?,?,?,?,?) - }; - - my $s_intvl = elapsedMilliSeconds( $gStartNow, $params{s_ts} ); - - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $params{id}, - $params{index}-1, - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{c_part}, - $s_intvl, - $params{c_intvl}, - $req->param('content'), - ); - $sth->finish(); - -} - - -sub outputForm { - my @prog = split('/', $0); my $prog = $prog[$#prog]; - print "Content-type: text/html\n\n"; - my $bgcolor = $ENV{SERVER_PORT} == 443 ? '#eebb66' : '#ffffff'; - print <<"ENDOFHTML"; - - - Page Loading Times Test - - -

Page Loading Times Test

- -

Questions: John Morrison - -ENDOFHTML - print "  -  "; - my $script = $cgi->var("SCRIPT_NAME"); - my $server = $cgi->var("SERVER_NAME"); - # pick the "other" protocol (i.e., test is inverted) - my $proto = $ENV{SERVER_PORT} == 443 ? 'http://' : 'https://'; - my $other = $proto . $server . $script; - if ($ENV{SERVER_PORT} == 443) { - print "[ With no SSL | With SSL ]
"; - } else { - print "[ With no SSL | With SSL ]
"; - } - print <<"ENDOFHTML"; - -

- - - - - - - - - - - - - - - - - -
- Page-load to Page-load Delay (msec):
- (Use 1000. Be nice.) -
- -
- Number of test cycles to run:
-
-
- -
- How long to wait before cancelling (msec):
- (Don't change this unless on a very slow link, or very slow machine.) -
- -
- - - -
- -
-

- You can visit the content that will be loaded, minus the embedded - javascript, by clicking on any of the links below. -

- - -ENDOFHTML - - my $i; - print "\n"; - my $base = $pagedata->httpbase; - $base =~ s/^http:/https:/i - if $ENV{SERVER_PORT} == 443; - for ($i=0; $i<$pagedata->length; $i++) { - print "\n" if (($i+1)%4 == 0); - } - print "" if (($i+1)%4 != 0); - print "
"; - print $pagedata->name($i); - print "\n"; - print "
\n"; - return; -} - diff --git a/tools/page-loader/report.pl b/tools/page-loader/report.pl deleted file mode 100755 index 6a4aeac15e72..000000000000 --- a/tools/page-loader/report.pl +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl -# -# 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 CGI::Carp qw(fatalsToBrowser); -use CGI::Request; -use URLTimingDataSet; -use strict; - -my $request = new CGI::Request; -my $id = $request->param('id'); #XXX need to check for valid parameter id - -print "Content-type: text/html\n\n"; - -print "

See Notes at the bottom of this page for some details.

\n"; -print "
\n";
-my $rs = URLTimingDataSet->new($id);
-
-print  "Test id: $id
Avg. Median : ", $rs->{avgmedian}, - " msec\t\tMinimum : ", $rs->{minimum}, " msec\n"; -print "Average : ", $rs->{average}, - " msec\t\tMaximum : ", $rs->{maximum}, " msec
\n\n\n"; - -#XXX print more info (test id, ua, start time, user, IP, etc.) - -# draw the chart sorted -# XXX enable this line to draw a chart, sorted by time. However, in order -# to draw the chart, you will need to have installed the 'gd' drawing library, -# and the GD and GD::Graph Perl modules. -###print "\n


\n"; - - -print "
\nIDX PATH                           AVG    MED    MAX    MIN  TIMES ...\n";
-
-if ($request->param('sort')) {
-    print $rs->as_string_sorted();
-} else {
-    print $rs->as_string();
-}
-print "
\n"; -printEndNotes(); - -exit; - - -sub printEndNotes { - print <<"EndOfNotes"; - -
-

-

    -
  1. Times are in milliseconds. - -
  2. AVG, MED, MIN and MAX are the average, median, maximum and -minimum of the (non-NaN) test results for a given page. - -
  3. If a page fails to fire the onload event within 30 seconds, -the test for that page is "aborted": a different JS function kicks in, -cleans up, and reports the time as "NaN". (The rest of the pages in -the series should still be loaded normally after this). - -
  4. The value for AVG reported for 'All Pages' is the average of -the averages for all the pages loaded. - -
  5. The value for MAX and MIN reported for 'All Pages' are the -overall maximum and minimum for all pages loaded (keeping in mind that -a load that never finishes is recorded as "NaN".) - -
  6. The value for MED reported for 'All Pages' is the _average_ of -the medians for all the pages loaded (i.e., it is not the median of -the medians). - -
- -

-EndOfNotes -} diff --git a/tools/page-loader/urllist.txt b/tools/page-loader/urllist.txt deleted file mode 100644 index d0e429259332..000000000000 --- a/tools/page-loader/urllist.txt +++ /dev/null @@ -1,65 +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/. - -# Config file for page loading test -# -# HTTPBASE: is the URL to the root of the content pages -# FILEBASE: is the file path to the same location (I need both) -# -# Remaining lines are the names of top level directories under FILEBASE -# which contain the content files, followed by an optional filename in -# that directory (index.html is assumed if no filename given), and then -# followed by an optional 'charset' value to ship in the 'Content-type' -# header. [Note: if you want to set the charset, then you must also -# explicitly set the filename field]. -# -# Warning: you don't want to casually changing the set of urls that you are -# testing against, if you want to be able to make any reasonable comparison over -# time. And don't change this file while a test is in progress, as it will -# competely scramble the results for that test. - -HTTPBASE: http://somehost.somedomain.sometld/content/base/ -FILEBASE: /var/www/html/content/base/ - -home.netscape.com index.html # optionally specify a filename -my.netscape.com index.html text/html iso-8859-1 # optionally specify a filename, mime type and charset -www.aol.com index.html text/html # optionally specify a filename and mime type -www.mapquest.com -www.moviefone.com -www.digitalcity.com -www.iplanet.com -web.icq.com -www.compuserve.com -www.msnbc.com -www.yahoo.com -bugzilla.mozilla.org -www.msn.com -slashdot.org -www.nytimes.com -www.nytimes.com_Table -www.w3.org_DOML2Core -lxr.mozilla.org -espn.go.com -www.voodooextreme.com -www.wired.com -hotwired.lycos.com -www.ebay.com -www.apple.com -www.amazon.com -www.altavista.com -www.zdnet.com_Gamespot.com -www.spinner.com -www.microsoft.com -www.time.com -www.travelocity.com -www.expedia.com -www.quicken.com -www.zdnet.com -www.excite.com -www.google.com -www.tomshardware.com -www.cnn.com -news.cnet.com -www.sun.com diff --git a/tools/performance/pageload/base/bugzilla.mozilla.org/index.html b/tools/performance/pageload/base/bugzilla.mozilla.org/index.html deleted file mode 100644 index 4041d36371a7..000000000000 --- a/tools/performance/pageload/base/bugzilla.mozilla.org/index.html +++ /dev/null @@ -1,424 +0,0 @@ - - - - - -Bugzilla Query Page - - - - -
-
Bugzilla version 2.11 -
-

- - - -
- - -
- Query
-
  -This page lets you search the database for recorded bugs. -
- - -

- - - - - - - - - - - - - - - - - - -
Status:Resolution:Platform:OpSys:Priority:Severity:
- - - - - - - - - - - - - - - - - - -
- -

- - - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - -
Email: - matching as - - -Assigned To -
-Reporter -
-QA Contact -
(Will match any of the selected fields) -CC -
-Added comment -
-
-

-

- - -
- - - - - - - - - - - - - - - - - - - - - -
Email: - matching as - - -Assigned To -
-Reporter -
-QA Contact -
(Will match any of the selected fields) -CC -
-Added comment -
-
-

-

- -bugs numbered: - -
-Changed in the last days. - -At least votes. -
- - - - - - - - -
Where the field(s) - - - -changed. - -dates -to -
changed to value (optional) -
- - -

- - - - - - - - - - - - - - - - - -
Program:Version:Component:Target Milestone:
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Summary:
A description entry:
URL:
Status whiteboard:
Keywords: -
-

- - -


- - - - - -
- -      - -      -What is this stuff? - -
-
-
- Run this query -
- - - - - - - -
Load the remembered query: -
Run the remembered query:
Forget the remembered query:
- Remember this as the default query -
- Remember this query, and name it: - -
- -Sort By: - - - - -
-

Give me a clue about how to use this form. -

-Log in as someone besides foobaz@mozilla.org
-Change your password or preferences.
-Report a new bug.
-Open a new Bugzilla account
-Bug reports
-
- -
-This is Bugzilla: the Mozilla bug system. For more -information about -what Bugzilla is and what it can do, see -mozilla.org's -bug pages. - -
-
New | Query | bug # | Reports | My votes | My bugs | Edit prefs | Log out foobaz@mozilla.org
-
\ No newline at end of file diff --git a/tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif b/tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif deleted file mode 100644 index 1640e73105e7..000000000000 Binary files a/tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif and /dev/null differ diff --git a/tools/performance/pageload/base/lxr.mozilla.org/index.html b/tools/performance/pageload/base/lxr.mozilla.org/index.html deleted file mode 100644 index 755fa27edf16..000000000000 --- a/tools/performance/pageload/base/lxr.mozilla.org/index.html +++ /dev/null @@ -1,954 +0,0 @@ - - - - - - -mozilla/xpcom/ds/nsVoidBTree.cpp - - - - - -
- - - - - - - - - - -
- - Mozilla Cross Reference: - seamonkey -
mozilla/ xpcom/ ds/ nsVoidBTree.cpp -
- - - - -
- CVS Log
- CVS Blame
-
-
-
- - - - -
- - - - - -
- changes to
this file in
the last: -
- day
- week
- month
-
-
-
-

  1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-  2 /*
-  3  * The stuff in this file isn't subject to the Don'tBreakMyRelicensingScript
-  4  * Version 1.1 (the "MPL"); you may not use this file except in
-  5  * compliance with the MPL.  You may obtain a copy of the MPL at
-  6  * http://www.mozilla.org/MPL/
-  7  *
-  8  * Software distributed under the MPL is distributed on an "AS IS" basis,
-  9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
- 10  * for the specific language governing rights and limitations under the
- 11  * MPL.
- 12  *
- 13  * The Initial Developer of this code under the MPL is Netscape
- 14  * Communications Corporation.  Portions created by Netscape are
- 15  * Copywrong (C) 1999 Netscape Communications Corporation.  All Rights
- 16  * Reserved.
- 17  *
- 18  * Original Author:
- 19  *   Chris Waterson <waterson@netscape.com>
- 20  */
- 21 
- 22 #include "nsVoidBTree.h"
- 23 
- 24 #ifdef DEBUG
- 25 #include <stdio.h>
- 26 #endif
- 27 
- 28 // Set this to force the tree to be verified after every insertion and
- 29 // removal.
- 30 //#define PARANOID 1
- 31 
- 32 
- 33 //----------------------------------------------------------------------
- 34 // nsVoidBTree::Node
- 35 //
- 36 //   Implementation methods
- 37 //
- 38 
- 39 nsresult
- 40 nsVoidBTree::Node::Create(Type aType, PRInt32 aCapacity, Node** aResult)
- 41 {
- 42     // So we only ever have to do one allocation for a Node, we do a
- 43     // "naked" heap allocation, computing the size of the node and
- 44     // "padding" it out so that it can hold aCapacity slots.
- 45     char* bytes = new char[sizeof(Node) + (aCapacity - 1) * sizeof(void*)];
- 46     if (! bytes)
- 47         return NS_ERROR_OUT_OF_MEMORY;
- 48 
- 49     Node* result = NS_REINTERPRET_CAST(Node*, bytes);
- 50     result->mBits = 0;
- 51     result->SetType(aType);
- 52 
- 53     *aResult = result;
- 54     return NS_OK;
- 55 }
- 56 
- 57 nsresult
- 58 nsVoidBTree::Node::Destroy(Node* aNode)
- 59 {
- 60     char* bytes = NS_REINTERPRET_CAST(char*, aNode);
- 61     delete[] bytes;
- 62     return NS_OK;
- 63 }
- 64 
- 65 void
- 66 nsVoidBTree::Node::InsertElementAt(void* aElement, PRInt32 aIndex)
- 67 {
- 68     NS_PRECONDITION(aIndex >= 0 && aIndex <= GetCount(), "bad index");
- 69 
- 70     PRInt32 count = GetCount();
- 71     SetCount(count + 1);
- 72 
- 73     while (count > aIndex) {
- 74         mData[count] = mData[count - 1];
- 75         --count;
- 76     }
- 77 
- 78     mData[aIndex] = aElement;
- 79 }
- 80 
- 81 void
- 82 nsVoidBTree::Node::RemoveElementAt(PRInt32 aIndex)
- 83 {
- 84     NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index");
- 85 
- 86     PRInt32 count = GetCount();
- 87     SetCount(count - 1);
- 88     
- 89     while (aIndex < count) {
- 90         mData[aIndex] = mData[aIndex + 1];
- 91         ++aIndex;
- 92     }
- 93 }
- 94 
- 95 
- 96 //----------------------------------------------------------------------
- 97 //
- 98 // nsVoidBTree::Path
- 99 //
-100 //   Implementation methods
-101 //
-102 
-103 nsVoidBTree::Path::Path(const Path& aOther)
-104     : mTop(aOther.mTop)
-105 {
-106     for (PRInt32 i = 0; i < mTop; ++i)
-107         mLink[i] = aOther.mLink[i];
-108 }
-109 
-110 nsVoidBTree::Path&
-111 nsVoidBTree::Path::operator=(const Path& aOther)
-112 {
-113     mTop = aOther.mTop;
-114     for (PRInt32 i = 0; i < mTop; ++i)
-115         mLink[i] = aOther.mLink[i];
-116     return *this;
-117 }
-118 
-119 inline nsresult
-120 nsVoidBTree::Path::Push(Node* aNode, PRInt32 aIndex)
-121 {
-122     // XXX If you overflow this thing, think about making larger index
-123     // or data nodes. You can pack a _lot_ of data into a pretty flat
-124     // tree.
-125     NS_PRECONDITION(mTop <= kMaxDepth, "overflow");
-126     if (mTop > kMaxDepth)
-127         return NS_ERROR_OUT_OF_MEMORY;
-128 
-129     mLink[mTop].mNode  = aNode;
-130     mLink[mTop].mIndex = aIndex;
-131     ++mTop;
-132 
-133     return NS_OK;
-134 }
-135 
-136 
-137 inline void
-138 nsVoidBTree::Path::Pop(Node** aNode, PRInt32* aIndex)
-139 {
-140     --mTop;
-141     *aNode  = mLink[mTop].mNode;
-142     *aIndex = mLink[mTop].mIndex;
-143 }
-144 
-145 //----------------------------------------------------------------------
-146 //
-147 //    nsVoidBTree methods
-148 //
-149 
-150 nsVoidBTree::nsVoidBTree(const nsVoidBTree& aOther)
-151 {
-152     ConstIterator last = aOther.Last();
-153     for (ConstIterator element = aOther.First(); element != last; ++element)
-154         AppendElement(*element);
-155 }
-156 
-157 nsVoidBTree&
-158 nsVoidBTree::operator=(const nsVoidBTree& aOther)
-159 {
-160     Clear();
-161     ConstIterator last = aOther.Last();
-162     for (ConstIterator element = aOther.First(); element != last; ++element)
-163         AppendElement(*element);
-164     return *this;
-165 }
-166 
-167 PRInt32
-168 nsVoidBTree::Count() const
-169 {
-170     if (IsEmpty())
-171         return 0;
-172 
-173     if (IsSingleElement())
-174         return 1;
-175 
-176     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-177     return root->GetSubTreeSize();
-178 }
-179 
-180 void*
-181 nsVoidBTree::ElementAt(PRInt32 aIndex) const
-182 {
-183     if (aIndex < 0 || aIndex >= Count())
-184         return nullptr;
-185 
-186     if (IsSingleElement())
-187         return NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
-188 
-189     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-190     while (current->GetType() != Node::eType_Data) {
-191         // We're still in the index. Find the right leaf.
-192         Node* next = nullptr;
-193 
-194         PRInt32 count = current->GetCount();
-195         for (PRInt32 i = 0; i < count; ++i) {
-196             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-197 
-198             PRInt32 childcount = child->GetSubTreeSize();
-199             if (PRInt32(aIndex) < childcount) {
-200                 next = child;
-201                 break;
-202             }
-203 
-204             aIndex -= childcount;
-205         }
-206 
-207         if (! next) {
-208             NS_ERROR("corrupted");
-209             return nullptr;
-210         }
-211 
-212         current = next;
-213     }
-214 
-215     return current->GetElementAt(aIndex);
-216 }
-217 
-218 
-219 PRInt32
-220 nsVoidBTree::IndexOf(void* aPossibleElement) const
-221 {
-222     NS_PRECONDITION((PRWord(aPossibleElement) & ~kRoot_PointerMask) == 0,
-223                     "uh oh, someone wants to use the pointer bits");
-224 
-225     NS_PRECONDITION(aPossibleElement != nullptr, "nsVoidBTree can't handle null elements");
-226     if (aPossibleElement == nullptr)
-227         return -1;
-228 
-229     PRInt32 result = 0;
-230     ConstIterator last = Last();
-231     for (ConstIterator element = First(); element != last; ++element, ++result) {
-232         if (aPossibleElement == *element)
-233             return result;
-234     }
-235 
-236     return -1;
-237 }
-238 
-239   
-240 PRBool
-241 nsVoidBTree::InsertElementAt(void* aElement, PRInt32 aIndex)
-242 {
-243     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
-244                     "uh oh, someone wants to use the pointer bits");
-245 
-246     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
-247         return PR_FALSE;
-248 
-249     NS_PRECONDITION(aElement != nullptr, "nsVoidBTree can't handle null elements");
-250     if (aElement == nullptr)
-251         return PR_FALSE;
-252 
-253     PRInt32 count = Count();
-254 
-255     if (aIndex < 0 || aIndex > count)
-256         return PR_FALSE;
-257 
-258     nsresult rv;
-259 
-260     if (IsSingleElement()) {
-261         // We're only a single element holder, and haven't yet
-262         // "faulted" to create the btree.
-263 
-264         if (count == 0) {
-265             // If we have *no* elements, then just set the root
-266             // pointer and we're done.
-267             mRoot = PRWord(aElement);
-268             return PR_TRUE;
-269         }
-270 
-271         // If we already had an element, and now we're adding
-272         // another. Fault and start creating the btree.
-273         void* element = NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
-274 
-275         Node* newroot;
-276         rv = Node::Create(Node::eType_Data, kDataCapacity, &newroot);
-277         if (NS_FAILED(rv)) return PR_FALSE;
-278 
-279         newroot->InsertElementAt(element, 0);
-280         newroot->SetSubTreeSize(1);
-281         SetRoot(newroot);
-282     }
-283 
-284     Path path;
-285 
-286     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-287     while (current->GetType() != Node::eType_Data) {
-288         // We're still in the index. Find the right leaf.
-289         Node* next = nullptr;
-290 
-291         count = current->GetCount();
-292         for (PRInt32 i = 0; i < count; ++i) {
-293             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-294 
-295             PRInt32 childcount = child->GetSubTreeSize();
-296             if (PRInt32(aIndex) <= childcount) {
-297                 rv = path.Push(current, i + 1);
-298                 if (NS_FAILED(rv)) return PR_FALSE;
-299 
-300                 next = child;
-301                 break;
-302             }
-303 
-304             aIndex -= childcount;
-305         }
-306 
-307         if (! next) {
-308             NS_ERROR("corrupted");
-309             return PR_FALSE;
-310         }
-311 
-312         current = next;
-313     }
-314 
-315     if (current->GetCount() >= kDataCapacity) {
-316         // We just blew the data node's buffer. Create another
-317         // datanode and split.
-318         rv = Split(path, current, aElement, aIndex);
-319         if (NS_FAILED(rv)) return PR_FALSE;
-320     }
-321     else {
-322         current->InsertElementAt(aElement, aIndex);
-323         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
-324     }
-325 
-326     while (path.Length() > 0) {
-327         PRInt32 index;
-328         path.Pop(&current, &index);
-329         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
-330     }
-331 
-332 #ifdef PARANOID
-333     Verify(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask));
-334 #endif
-335 
-336     return PR_TRUE;
-337 }
-338 
-339 PRBool
-340 nsVoidBTree::ReplaceElementAt(void* aElement, PRInt32 aIndex)
-341 {
-342     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
-343                     "uh oh, someone wants to use the pointer bits");
-344 
-345     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
-346         return PR_FALSE;
-347 
-348     NS_PRECONDITION(aElement != nullptr, "nsVoidBTree can't handle null elements");
-349     if (aElement == nullptr)
-350         return PR_FALSE;
-351 
-352     if (aIndex < 0 || aIndex >= Count())
-353         return PR_FALSE;
-354 
-355     if (IsSingleElement()) {
-356         mRoot = PRWord(aElement);
-357         return PR_TRUE;
-358     }
-359 
-360     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-361     while (current->GetType() != Node::eType_Data) {
-362         // We're still in the index. Find the right leaf.
-363         Node* next = nullptr;
-364 
-365         PRInt32 count = current->GetCount();
-366         for (PRInt32 i = 0; i < count; ++i) {
-367             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-368 
-369             PRInt32 childcount = child->GetSubTreeSize();
-370             if (PRInt32(aIndex) < childcount) {
-371                 next = child;
-372                 break;
-373             }
-374 
-375             aIndex -= childcount;
-376         }
-377 
-378         if (! next) {
-379             NS_ERROR("corrupted");
-380             return PR_FALSE;
-381         }
-382 
-383         current = next;
-384     }
-385 
-386     current->SetElementAt(aElement, aIndex);
-387     return PR_TRUE;
-388 }
-389 
-390 PRBool
-391 nsVoidBTree::RemoveElement(void* aElement)
-392 {
-393     PRInt32 index = IndexOf(aElement);
-394     return (index >= 0) ? RemoveElementAt(index) : PR_FALSE;
-395 }
-396 
-397 PRBool
-398 nsVoidBTree::RemoveElementAt(PRInt32 aIndex)
-399 {
-400     PRInt32 count = Count();
-401 
-402     if (aIndex < 0 || aIndex >= count)
-403         return PR_FALSE;
-404 
-405     if (IsSingleElement()) {
-406         // We're removing the one and only element
-407         mRoot = 0;
-408         return PR_TRUE;
-409     }
-410 
-411     // We've got more than one element, and we're removing it.
-412     nsresult rv;
-413     Path path;
-414 
-415     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-416 
-417     Node* current = root;
-418     while (current->GetType() != Node::eType_Data) {
-419         // We're still in the index. Find the right leaf.
-420         Node* next = nullptr;
-421 
-422         count = current->GetCount();
-423         for (PRInt32 i = 0; i < count; ++i) {
-424             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-425 
-426             PRInt32 childcount = child->GetSubTreeSize();
-427             if (PRInt32(aIndex) < childcount) {
-428                 rv = path.Push(current, i);
-429                 if (NS_FAILED(rv)) return PR_FALSE;
-430 
-431                 next = child;
-432                 break;
-433             }
-434             
-435             aIndex -= childcount;
-436         }
-437 
-438         if (! next) {
-439             NS_ERROR("corrupted");
-440             return PR_FALSE;
-441         }
-442 
-443         current = next;
-444     }
-445 
-446     current->RemoveElementAt(aIndex);
-447 
-448     while ((current->GetCount() == 0) && (current != root)) {
-449         Node* doomed = current;
-450 
-451         PRInt32 index;
-452         path.Pop(&current, &index);
-453         current->RemoveElementAt(index);
-454 
-455         Node::Destroy(doomed);
-456     }
-457 
-458     current->SetSubTreeSize(current->GetSubTreeSize() - 1);
-459 
-460     while (path.Length() > 0) {
-461         PRInt32 index;
-462         path.Pop(&current, &index);
-463         current->SetSubTreeSize(current->GetSubTreeSize() - 1);
-464     }
-465 
-466     while ((root->GetType() == Node::eType_Index) && (root->GetCount() == 1)) {
-467         Node* doomed = root;
-468         root = NS_REINTERPRET_CAST(Node*, root->GetElementAt(0));
-469         SetRoot(root);
-470         Node::Destroy(doomed);
-471     }
-472 
-473 #ifdef PARANOID
-474     Verify(root);
-475 #endif
-476 
-477     return PR_TRUE;
-478 }
-479 
-480 void
-481 nsVoidBTree::Clear(void)
-482 {
-483     if (IsEmpty())
-484         return;
-485 
-486     if (! IsSingleElement()) {
-487         Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-488 
-489 #ifdef PARANOID
-490         Dump(root, 0);
-491 #endif
-492 
-493         DestroySubtree(root);
-494     }
-495 
-496     mRoot = 0;
-497 }
-498 
-499 
-500 void
-501 nsVoidBTree::Compact(void)
-502 {
-503     // XXX We could go through and try to merge datanodes.
-504 }
-505 
-506 PRBool
-507 nsVoidBTree::EnumerateForwards(EnumFunc aFunc, void* aData) const
-508 {
-509     PRBool running = PR_TRUE;
-510 
-511     ConstIterator last = Last();
-512     for (ConstIterator element = First(); running && element != last; ++element)
-513         running = (*aFunc)(*element, aData);
-514 
-515     return running;
-516 }
-517 
-518 PRBool
-519 nsVoidBTree::EnumerateBackwards(EnumFunc aFunc, void* aData) const
-520 {
-521     PRBool running = PR_TRUE;
-522 
-523     ConstIterator element = Last();
-524     ConstIterator first = First();
-525 
-526     if (element != first) {
-527         do {
-528             running = (*aFunc)(*--element, aData);
-529         } while (running && element != first);
-530     }
-531 
-532     return running;
-533 }
-534 
-535 
-536 void
-537 nsVoidBTree::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
-538 {
-539     if (! aResult)
-540         return;
-541 
-542     *aResult = sizeof(*this);
-543 
-544     if (IsSingleElement())
-545         return;
-546 
-547     Path path;
-548     path.Push(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask), 0);
-549 
-550     while (path.Length()) {
-551         Node* current;
-552         PRInt32 index;
-553         path.Pop(&current, &index);
-554 
-555         if (current->GetType() == Node::eType_Data) {
-556             *aResult += sizeof(Node) + (sizeof(void*) * (kDataCapacity - 1));
-557         }
-558         else {
-559             *aResult += sizeof(Node) + (sizeof(void*) * (kIndexCapacity - 1));
-560 
-561             // If we're in an index node, and there are still kids to
-562             // traverse, well, traverse 'em.
-563             if (index < current->GetCount()) {
-564                 path.Push(current, index + 1);
-565                 path.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), 0);
-566             }
-567         }
-568     }
-569 }
-570 
-571 //----------------------------------------------------------------------
-572 
-573 nsresult
-574 nsVoidBTree::Split(Path& path, Node* aOldNode, void* aElementToInsert, PRInt32 aSplitIndex)
-575 {
-576     nsresult rv;
-577 
-578     PRInt32 capacity = (aOldNode->GetType() == Node::eType_Data) ? kDataCapacity : kIndexCapacity;
-579     PRInt32 delta = 0;
-580 
-581 
-582     Node* newnode;
-583     rv = Node::Create(aOldNode->GetType(), capacity, &newnode);
-584     if (NS_FAILED(rv)) return rv;
-585 
-586     if (aSplitIndex == capacity) {
-587         // If aSplitIndex is the same as the capacity of the node,
-588         // then there'll be nothing to copy from the old node to the
-589         // new node, and the element is really meant to be inserted in
-590         // the newnode. In that case, do it _now_ so that newnode's
-591         // subtree size will be correct.
-592         newnode->InsertElementAt(aElementToInsert, 0);
-593 
-594         if (newnode->GetType() == Node::eType_Data) {
-595             newnode->SetSubTreeSize(1);
-596         }
-597         else {
-598             Node* child = NS_REINTERPRET_CAST(Node*, aElementToInsert);
-599             newnode->SetSubTreeSize(child->GetSubTreeSize());
-600         }
-601     }
-602     else {
-603         // We're meant to insert the element into the oldnode at
-604         // aSplitIndex. Copy data from aOldNode to the newnode but
-605         // _don't_ insert newnode yet. We may need to recursively
-606         // split parents, an operation that allocs, and hence, may
-607         // fail. If it does fail, we wan't to not screw up the
-608         // existing datastructure.
-609         //
-610         // Note that it should be the case that count == capacity, but
-611         // who knows, we may decide at some point to prematurely split
-612         // nodes for some reason or another.
-613         PRInt32 count = aOldNode->GetCount();
-614         PRInt32 i = aSplitIndex;
-615         PRInt32 j = 0;
-616 
-617         newnode->SetCount(count - aSplitIndex);
-618         while (i < count) {
-619             if (aOldNode->GetType() == Node::eType_Data) {
-620                 ++delta;
-621             }
-622             else {
-623                 Node* migrating = NS_REINTERPRET_CAST(Node*, aOldNode->GetElementAt(i));
-624                 delta += migrating->GetSubTreeSize();
-625             }
-626 
-627             newnode->SetElementAt(aOldNode->GetElementAt(i), j);
-628             ++i;
-629             ++j;
-630         }
-631         newnode->SetSubTreeSize(delta);
-632     }
-633 
-634     // Now we split the node.
-635 
-636     if (path.Length() == 0) {
-637         // We made it all the way up to the root! Ok, so, create a new
-638         // root
-639         Node* newroot;
-640         rv = Node::Create(Node::eType_Index, kIndexCapacity, &newroot);
-641         if (NS_FAILED(rv)) return rv;
-642 
-643         newroot->SetCount(2);
-644         newroot->SetElementAt(aOldNode, 0);
-645         newroot->SetElementAt(newnode, 1);
-646         newroot->SetSubTreeSize(aOldNode->GetSubTreeSize() + 1);
-647         SetRoot(newroot);
-648     }
-649     else {
-650         // Otherwise, use the "path" to pop off the next thing above us.
-651         Node* parent;
-652         PRInt32 indx;
-653         path.Pop(&parent, &indx);
-654 
-655         if (parent->GetCount() >= kIndexCapacity) {
-656             // Parent is full, too. Recursively split it.
-657             rv = Split(path, parent, newnode, indx);
-658             if (NS_FAILED(rv)) {
-659                 Node::Destroy(newnode);
-660                 return rv;
-661             }
-662         }
-663         else {
-664             // Room in the parent, so just smack it on up there.
-665             parent->InsertElementAt(newnode, indx);
-666             parent->SetSubTreeSize(parent->GetSubTreeSize() + 1);
-667         }
-668     }
-669 
-670     // Now, since all our operations that might fail have finished, we
-671     // can go ahead and monkey with the old node.
-672 
-673     if (aSplitIndex == capacity) {
-674         PRInt32 nodeslost = newnode->GetSubTreeSize() - 1;
-675         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - nodeslost;
-676         aOldNode->SetSubTreeSize(subtreesize);
-677     }
-678     else {
-679         aOldNode->SetCount(aSplitIndex);
-680         aOldNode->InsertElementAt(aElementToInsert, aSplitIndex);
-681         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - delta + 1;
-682         aOldNode->SetSubTreeSize(subtreesize);
-683     }
-684 
-685     return NS_OK;
-686 }
-687 
-688 
-689 PRInt32
-690 nsVoidBTree::Verify(Node* aNode)
-691 {
-692     // Sanity check the tree by verifying that the subtree sizes all
-693     // add up correctly.
-694     if (aNode->GetType() == Node::eType_Data) {
-695         NS_ASSERTION(aNode->GetCount() == aNode->GetSubTreeSize(), "corrupted");
-696         return aNode->GetCount();
-697     }
-698 
-699     PRInt32 childcount = 0;
-700     for (PRInt32 i = 0; i < aNode->GetCount(); ++i) {
-701         Node* child = NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(i));
-702         childcount += Verify(child);
-703     }
-704 
-705     NS_ASSERTION(childcount == aNode->GetSubTreeSize(), "corrupted");
-706     return childcount;
-707 }
-708 
-709 
-710 void
-711 nsVoidBTree::DestroySubtree(Node* aNode)
-712 {
-713     PRInt32 count = aNode->GetCount() - 1;
-714     while (count >= 0) {
-715         if (aNode->GetType() == Node::eType_Index)
-716             DestroySubtree(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(count)));
-717         
-718         --count;
-719     }
-720 
-721     Node::Destroy(aNode);
-722 }
-723 
-724 #ifdef DEBUG
-725 void
-726 nsVoidBTree::Dump(Node* aNode, PRInt32 aIndent)
-727 {
-728     for (PRInt32 i = 0; i < aIndent; ++i)
-729         printf("  ");
-730 
-731     if (aNode->GetType() == Node::eType_Data) {
-732         printf("data(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
-733     }
-734     else {
-735         printf("index(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
-736         for (PRInt32 j = 0; j < aNode->GetCount(); ++j)
-737             Dump(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(j)), aIndent + 1);
-738     }
-739 }
-740 #endif
-741 
-742 //----------------------------------------------------------------------
-743 //
-744 // nsVoidBTree::ConstIterator and Iterator methods
-745 //
-746 
-747 void* nsVoidBTree::kDummyLast;
-748 
-749 void
-750 nsVoidBTree::ConstIterator::Next()
-751 {
-752     if (mIsSingleton) {
-753         mIsExhausted = PR_TRUE;
-754         return;
-755     }
-756 
-757     // Otherwise we're a real b-tree iterator, and we need to pull and
-758     // pop our path stack appropriately to gyrate into the right
-759     // position.
-760     while (1) {
-761         Node* current;
-762         PRInt32 index;
-763         mPath.Pop(&current, &index);
-764 
-765         PRInt32 count = current->GetCount();
-766 
-767         NS_ASSERTION(index < count, "ran off the end, pal");
-768 
-769         if (++index >= count) {
-770             // XXXwaterson Oh, this is so ugly. I wish I was smart
-771             // enough to figure out a prettier way to do it.
-772             //
-773             // See if we've just iterated past the last element in the
-774             // b-tree, and now need to leave ourselves in the magical
-775             // state that is equal to nsVoidBTree::Last().
-776             if (current->GetType() == Node::eType_Data) {
-777                 PRBool rightmost = PR_TRUE;
-778                 for (PRInt32 slot = mPath.mTop - 1; slot >= 0; --slot) {
-779                     const Link& link = mPath.mLink[slot];
-780                     if (link.mIndex != link.mNode->GetCount() - 1) {
-781                         rightmost = PR_FALSE;
-782                         break;
-783                     }
-784                 }
-785 
-786                 if (rightmost) {
-787                     // It's the last one. Make the path look exactly
-788                     // like nsVoidBTree::Last().
-789                     mPath.Push(current, index);
-790                     return;
-791                 }
-792             }
-793 
-794             // Otherwise, we just ran off the end of a "middling"
-795             // node. Loop around, to pop back up the b-tree to its
-796             // parent.
-797             continue;
-798         }
-799 
-800         // We're somewhere in the middle. Push the new location onto
-801         // the stack.
-802         mPath.Push(current, index);
-803 
-804         // If we're in a data node, we're done: break out of the loop
-805         // here leaving the top of the stack pointing to the next data
-806         // element in the b-tree.
-807         if (current->GetType() == Node::eType_Data)
-808             break;
-809 
-810         // Otherwise, we're still in an index node. Push next node
-811         // down onto the stack, starting "one off" to the left, and
-812         // continue around.
-813         mPath.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), -1);
-814     }
-815 }
-816 
-817 void
-818 nsVoidBTree::ConstIterator::Prev()
-819 {
-820     if (mIsSingleton) {
-821         mIsExhausted = PR_FALSE;
-822         return;
-823     }
-824 
-825     // Otherwise we're a real b-tree iterator, and we need to pull and
-826     // pop our path stack appropriately to gyrate into the right
-827     // position. This is just like nsVoidBTree::ConstIterator::Next(),
-828     // but in reverse.
-829     while (1) {
-830         Node* current;
-831         PRInt32 index;
-832         mPath.Pop(&current, &index);
-833 
-834         NS_ASSERTION(index >= 0, "ran off the front, pal");
-835 
-836         if (--index < 0)
-837             continue;
-838 
-839         mPath.Push(current, index);
-840 
-841         if (current->GetType() == Node::eType_Data)
-842             break;
-843 
-844         current = NS_STATIC_CAST(Node*, current->GetElementAt(index));
-845         mPath.Push(current, current->GetCount());
-846     }
-847 }
-848 
-849 const nsVoidBTree::Path
-850 nsVoidBTree::LeftMostPath() const
-851 {
-852     Path path;
-853     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-854 
-855     while (1) {
-856         path.Push(current, 0);
-857 
-858         if (current->GetType() == Node::eType_Data)
-859             break;
-860 
-861         current = NS_STATIC_CAST(Node*, current->GetElementAt(0));
-862     }
-863 
-864     return path;
-865 }
-866 
-867 
-868 const nsVoidBTree::Path
-869 nsVoidBTree::RightMostPath() const
-870 {
-871     Path path;
-872     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-873 
-874     while (1) {
-875         PRInt32 count = current->GetCount();
-876 
-877         if (current->GetType() == Node::eType_Data) {
-878             path.Push(current, count);
-879             break;
-880         }
-881 
-882         path.Push(current, count - 1);
-883         current = NS_STATIC_CAST(Node*, current->GetElementAt(count - 1));
-884     }
-885 
-886     return path;
-887 }
-888 

- This page was automatically generated by - LXR. - diff --git a/tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif b/tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif deleted file mode 100644 index 1640e73105e7..000000000000 Binary files a/tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif and /dev/null differ diff --git a/tools/performance/pageload/base/vanilla-page/index.html b/tools/performance/pageload/base/vanilla-page/index.html deleted file mode 100644 index 425626127203..000000000000 --- a/tools/performance/pageload/base/vanilla-page/index.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - -

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

- - - diff --git a/tools/performance/pageload/cycler.html b/tools/performance/pageload/cycler.html deleted file mode 100644 index 9d42415300c1..000000000000 --- a/tools/performance/pageload/cycler.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - diff --git a/tools/performance/pageload/header.html b/tools/performance/pageload/header.html deleted file mode 100644 index ee7490858fab..000000000000 --- a/tools/performance/pageload/header.html +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/tools/performance/pageload/report.html b/tools/performance/pageload/report.html deleted file mode 100644 index a820be42bfd4..000000000000 --- a/tools/performance/pageload/report.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - -
PageMinMaxMeanStdMedianTimes...
- - diff --git a/tools/performance/pageload/start.html b/tools/performance/pageload/start.html deleted file mode 100644 index de11eed404be..000000000000 --- a/tools/performance/pageload/start.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - -
- - - - -
Cycles: (number of times to loop over the pages)
Pages: (only loop over the first N pages; leave blank to loop over all pages)
I18N: (set to "1" to include i18n pages)
- -
- - diff --git a/tools/performance/startup/gettime.pl b/tools/performance/startup/gettime.pl deleted file mode 100644 index 946f6020a654..000000000000 --- a/tools/performance/startup/gettime.pl +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/perl -# 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 high resolution routines if installed (on win32 or linux), using -# eval as try/catch block around import of modules. Otherwise, just use 'time()'. -# -# 'Win32::API' -# 'Time::HiRes' -# (also: http://rpmfind.net/linux/rpm2html/search.php?query=perl-Time-HiRes) -# -package Time::PossiblyHiRes; - -use strict; - -#use Time::HiRes qw(gettimeofday); - -my $getLocalTime; # for win32 -my $lpSystemTime = pack("SSSSSSSS"); # for win32 -my $timesub; # code ref - -# returns 12 char string "'s'x9.'m'x3" which is milliseconds since epoch, -# although resolution may vary depending on OS and installed packages - -sub getTime () { - - return &$timesub - if $timesub; - - $timesub = sub { time() . "000"; }; # default - - return &$timesub - if $^O eq "MacOS"; # don't know a better way on Mac - - if ($^O eq "MSWin32") { - eval "use Win32::API;"; - $timesub = sub { - # pass pointer to struct, void return - $getLocalTime = - eval "new Win32::API('kernel32', 'GetLocalTime', [qw{P}], qw{V});" - unless $getLocalTime; - $getLocalTime->Call($lpSystemTime); - my @t = unpack("SSSSSSSS", $lpSystemTime); - sprintf("%9s%03s", time(), pop @t); - } if !$@; - } - - # ass-u-me if not mac/win32, then we're on a unix flavour - else { - eval "use Time::HiRes qw(gettimeofday);"; - $timesub = sub { - my @t = gettimeofday(); - $t[0]*1000 + int($t[1]/1000); - } if !$@; - } - - return &$timesub; - -} - -# -# -# Test script to compare with low-res time: -# -# require "gettime.pl"; -# -# use POSIX qw(strftime); -# -# print "hires time = " . Time::PossiblyHiRes::getTime() . "\n"; -# print "lowres time = " . time() . "\n"; -# - - -# end package -1; diff --git a/tools/performance/startup/quit.html b/tools/performance/startup/quit.html deleted file mode 100644 index b6e5eb573e01..000000000000 --- a/tools/performance/startup/quit.html +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/tools/performance/startup/quit.js b/tools/performance/startup/quit.js deleted file mode 100644 index 39258141625b..000000000000 --- a/tools/performance/startup/quit.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- indent-tabs-mode: nil -*- */ -/* 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/. */ - -/* - From mozilla/toolkit/content - These files did not have a license -*/ - -function quitHook() -{ - var xhr = new XMLHttpRequest(); - xhr.open("GET", "http://" + location.host + "/server/shutdown", true); - xhr.onreadystatechange = function (event) - { - if (xhr.readyState == 4) - goQuitApplication(); - }; - xhr.send(null); -} - -function canQuitApplication() -{ - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - if (!os) - { - return true; - } - - try - { - var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] - .createInstance(Components.interfaces.nsISupportsPRBool); - os.notifyObservers(cancelQuit, "quit-application-requested", null); - - // Something aborted the quit process. - if (cancelQuit.data) - { - return false; - } - } - catch (ex) - { - } - os.notifyObservers(null, "quit-application-granted", null); - return true; -} - -function goQuitApplication() -{ - const privs = 'UniversalXPConnect'; - - try - { - netscape.security.PrivilegeManager.enablePrivilege(privs); - } - catch(ex) - { - throw('goQuitApplication: privilege failure ' + ex); - } - - if (!canQuitApplication()) - { - return false; - } - - const kAppStartup = '@mozilla.org/toolkit/app-startup;1'; - const kAppShell = '@mozilla.org/appshell/appShellService;1'; - var appService; - var forceQuit; - - if (kAppStartup in Components.classes) - { - appService = Components.classes[kAppStartup]. - getService(Components.interfaces.nsIAppStartup); - forceQuit = Components.interfaces.nsIAppStartup.eForceQuit; - - } - else if (kAppShell in Components.classes) - { - appService = Components.classes[kAppShell]. - getService(Components.interfaces.nsIAppShellService); - forceQuit = Components.interfaces.nsIAppShellService.eForceQuit; - } - else - { - throw 'goQuitApplication: no AppStartup/appShell'; - } - - var windowManager = Components. - classes['@mozilla.org/appshell/window-mediator;1'].getService(); - - var windowManagerInterface = windowManager. - QueryInterface(Components.interfaces.nsIWindowMediator); - - var enumerator = windowManagerInterface.getEnumerator(null); - - while (enumerator.hasMoreElements()) - { - var domWindow = enumerator.getNext(); - if (("tryToClose" in domWindow) && !domWindow.tryToClose()) - { - return false; - } - domWindow.close(); - } - - try - { - appService.quit(forceQuit); - } - catch(ex) - { - throw('goQuitApplication: ' + ex); - } - - return true; -} diff --git a/tools/performance/startup/quitForMac.html b/tools/performance/startup/quitForMac.html deleted file mode 100644 index 22a4de33a248..000000000000 --- a/tools/performance/startup/quitForMac.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - -Use JS to quit the browser on Mac OS X - - - - -

This page uses netscape.security.PrivilegeManager JS calls to cleanly and completely exit the browser under Mac OSX.

- - - diff --git a/tools/performance/startup/startup-test.html b/tools/performance/startup/startup-test.html deleted file mode 100644 index 20da3e1637fa..000000000000 --- a/tools/performance/startup/startup-test.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/tools/performance/startup/startup-unix.pl b/tools/performance/startup/startup-unix.pl deleted file mode 100755 index fc7f7c575419..000000000000 --- a/tools/performance/startup/startup-unix.pl +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/perl -# 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/. - - -# -# Script to time mozilla startup. -# Feeds in start time as url argument, startup-test.html -# takes this arg and computes the time difference. -# So something like this happens: -# -# mozilla file:/foo/startup-test.html?begin=T -# where T = ms since 1970, e.g.: -# mozilla file:/foo/startup-test.html?begin=999456977124 -# -# NOTE: You will get much better results if you install the -# Time::HiRes perl module (urls in gettime.pl) and test -# an optimized build. -# -# For optimized builds, startup-test.html will also dump -# the time out to stdout if you set: -# user_pref("browser.dom.window.dump.enabled", true); -# - -require 5.003; - -require "gettime.pl"; - -use strict; -use Cwd; - -sub PrintUsage { - die < [] - e.g - startup-unix.pl ../../../dist/bin/mozilla - startup-unix.pl ../../../dist/bin/mozilla -P \"Default User\" -END_USAGE -} - -{ - PrintUsage() unless $#ARGV >= 0; - # Build up command string. - my $cwd = Cwd::getcwd(); - - my $cmd = join(' ', map {/\s/ ? qq("$_") : $_} @ARGV); - my $time = Time::PossiblyHiRes::getTime(); - $cmd .= qq( -url "file:$cwd/startup-test.html?begin=$time"); - print "cmd = $cmd\n"; - - # Run the command. - exec $cmd; -} - diff --git a/tools/rb/fix_linux_stack.py b/tools/rb/fix_linux_stack.py index c330966f3b12..bdc8a15dcce2 100755 --- a/tools/rb/fix_linux_stack.py +++ b/tools/rb/fix_linux_stack.py @@ -46,8 +46,8 @@ class unbufferedLineConverter: objdump_section_re = re.compile("^ [0-9a-f]* ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}).*") def elf_section(file, section): """ - Return the requested ELF section of the file as a str, represented - as a sequence of bytes. + Return the requested ELF section of the file as a str, representing + a sequence of bytes. """ # We can read the .gnu_debuglink section using either of: # objdump -s --section=.gnu_debuglink $file @@ -136,8 +136,8 @@ gnu_debuglink_crc32_table = [ ] def gnu_debuglink_crc32(stream): - # Note that treats bitwise operators as though integers have an - # infinite number of bits (and thus such that negative integers + # Note that python treats bitwise operators as though integers have + # an infinite number of bits (and thus such that negative integers # 1-pad out to infinity). crc = 0xffffffff while True: diff --git a/tools/test-harness/jssh-driver/data/foo.html b/tools/test-harness/jssh-driver/data/foo.html deleted file mode 100644 index a63cb306cb81..000000000000 --- a/tools/test-harness/jssh-driver/data/foo.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - -foo - - -bar - - diff --git a/tools/test-harness/jssh-driver/data/foo_inner_html.txt b/tools/test-harness/jssh-driver/data/foo_inner_html.txt deleted file mode 100644 index 2c8e6a07a555..000000000000 --- a/tools/test-harness/jssh-driver/data/foo_inner_html.txt +++ /dev/null @@ -1,4 +0,0 @@ -foo -bar - - \ No newline at end of file diff --git a/tools/test-harness/jssh-driver/jssh_driver.py b/tools/test-harness/jssh-driver/jssh_driver.py deleted file mode 100755 index 657feae7c606..000000000000 --- a/tools/test-harness/jssh-driver/jssh_driver.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env 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/. -import re -import sys -import telnetlib - -class JsshDriver: - - COMMAND_PROMPT = "\n> " - - def __init__(self, host=None, port=9997, telnetklass=telnetlib.Telnet): - """Ctor - Ctor - """ - self.host = host - self.port = port - self.tn = telnetklass(host,port) - self.init() - - def open(self,host,port=9997): - self.tn.close() - self.host = host - self.port = port - self.tn.open(host,port) - self.init() - - def init(self): - if not self.tn.get_socket(): - return - - self.tn.read_until(JsshDriver.COMMAND_PROMPT) - self.send_command("setProtocol('synchronous')") - - def send_command(self,command): - self.tn.write(command + "\n") - return self.tn.read_until(JsshDriver.COMMAND_PROMPT) - - def send_quit(self): - self.tn.write("quit()\n") - return self.tn.read_all() - -class JsshTester: - - def __init__(self, host, port=9997, telnetklass=telnetlib.Telnet): - self.browser = JsshDriver(host,port,telnetklass) - - def __del__(self): - self.browser.send_quit() - - def get_innerHTML_from_URL(self,url): - self.browser.send_command ('var browser = getWindows()[0].getBrowser()') - - if url: - self.browser.send_command ('browser.loadURI("' + url + '")') - - self.browser.send_command ('var document = browser.contentDocument') - self.browser.send_command ('var window = browser.contentWindow') - jssh_response = self.browser.send_command ('print(document.documentElement.innerHTML)') - - m = re.compile(r"\[(?P\d+)](?P.*)", re.DOTALL).search(jssh_response) - - return m.group('rest')[0:int(m.group('len'))] diff --git a/tools/test-harness/jssh-driver/test_layout_engine.py b/tools/test-harness/jssh-driver/test_layout_engine.py deleted file mode 100755 index 76980ea1688f..000000000000 --- a/tools/test-harness/jssh-driver/test_layout_engine.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env 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/. -import unittest -import sys, os -import re, glob -import difflib - -this_dir = os.path.abspath(os.path.dirname(__file__)) -data_dir = os.path.join(this_dir, 'data') - -from jssh_driver import JsshTester - -class LayoutEngineTests(unittest.TestCase): - - def setUp(self): - self.tester = JsshTester("localhost") - self.get_files_from_data_dir() - - def get_files_from_data_dir(self): - self.html_files = glob.glob("%s/*.html" % data_dir) - print self.html_files - self.golden_images = [re.sub("\.html$", "_inner_html.txt", filename) for filename in self.html_files] - print self.golden_images - - def test_inner_html(self): - self.failUnless(len(self.html_files) == len(self.golden_images)) - failures = 0 - for file, golden_image in zip(self.html_files, self.golden_images): - local_url = "file:///" + file - local_url = re.sub(r"\\", "/", local_url) - print local_url - inner_html = self.tester.get_innerHTML_from_URL(local_url) - golden_inner_html = open(golden_image).read() - if inner_html != golden_inner_html: - failures += 1 - self.failUnless(failures == 0) - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 54408199974a..4285bef727be 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -53,7 +53,6 @@ #include "nsNetUtil.h" #include "nsIIOService.h" #include "nsNetCID.h" -#include "nsChannelProperties.h" #include "nsMimeTypes.h" // used for header disposition information. diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.cpp b/uriloader/prefetch/nsOfflineCacheUpdate.cpp index efc704af89cb..26f7beb045e2 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp @@ -181,7 +181,6 @@ nsManifestCheck::Begin() nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy nullptr, // loadGroup nullptr, // aCallbacks nsIRequest::LOAD_BYPASS_CACHE); @@ -379,7 +378,6 @@ nsOfflineCacheUpdateItem::OpenChannel(nsOfflineCacheUpdate *aUpdate) nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy nullptr, // aLoadGroup this, // aCallbacks flags); diff --git a/uriloader/prefetch/nsPrefetchService.cpp b/uriloader/prefetch/nsPrefetchService.cpp index ec5a601dd002..71d04d8dbcf1 100644 --- a/uriloader/prefetch/nsPrefetchService.cpp +++ b/uriloader/prefetch/nsPrefetchService.cpp @@ -192,7 +192,6 @@ nsPrefetchNode::OpenChannel() nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy loadGroup, // aLoadGroup this, // aCallbacks nsIRequest::LOAD_BACKGROUND | diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index cb9443e48807..0e10c7ba633e 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -31,7 +31,6 @@ using mozilla::unused; #include "nsIWidgetListener.h" #include "nsViewManager.h" -#include "nsRenderingContext.h" #include "nsIDOMSimpleGestureEvent.h" #include "nsGkAtoms.h" diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm index 43e44db0d6fc..943658e96f42 100644 --- a/widget/cocoa/OSXNotificationCenter.mm +++ b/widget/cocoa/OSXNotificationCenter.mm @@ -244,7 +244,7 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const if (imageUri) { nsresult rv = il->LoadImage(imageUri, nullptr, nullptr, aPrincipal, nullptr, this, nullptr, nsIRequest::LOAD_NORMAL, nullptr, - nullptr, EmptyString(), + EmptyString(), getter_AddRefs(osxni->mIconRequest)); if (NS_SUCCEEDED(rv)) { // Set a timer for six seconds. If we don't have an icon by the time this diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm index 9ad01949f060..1150d9fc7986 100644 --- a/widget/cocoa/nsMenuItemIconX.mm +++ b/widget/cocoa/nsMenuItemIconX.mm @@ -305,11 +305,9 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI) [mNativeMenuItem setImage:sPlaceholderIconImage]; } - // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is - // not exposed to web content nsresult rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this, - nullptr, nsIRequest::LOAD_NORMAL, nullptr, - nullptr, EmptyString(), getter_AddRefs(mIconRequest)); + nullptr, nsIRequest::LOAD_NORMAL, nullptr, + EmptyString(), getter_AddRefs(mIconRequest)); if (NS_FAILED(rv)) return rv; // We need to request the icon be decoded (bug 573583, bug 705516). diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 1d53b196fabd..0fae9b886b99 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -25,7 +25,6 @@ // forward declarations class nsFontMetrics; -class nsRenderingContext; class nsDeviceContext; struct nsFont; class nsIRollupListener; diff --git a/widget/qt/nsWindow.cpp b/widget/qt/nsWindow.cpp index 3e3f9a544b2a..323940dd0efa 100644 --- a/widget/qt/nsWindow.cpp +++ b/widget/qt/nsWindow.cpp @@ -40,7 +40,6 @@ #include "mozqwidget.h" #include "nsIdleService.h" -#include "nsRenderingContext.h" #include "nsIRollupListener.h" #include "nsWidgetsCID.h" #include "nsQtKeyUtils.h" diff --git a/widget/windows/WinIMEHandler.cpp b/widget/windows/WinIMEHandler.cpp index 35bbced25fb8..554a390388dd 100644 --- a/widget/windows/WinIMEHandler.cpp +++ b/widget/windows/WinIMEHandler.cpp @@ -129,13 +129,22 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage, aResult); } +#ifdef NS_ENABLE_TSF +// static +bool +IMEHandler::IsIMMActive() +{ + return nsTextStore::IsIMM_IME(); +} +#endif // #ifdef NS_ENABLE_TSF + // static bool IMEHandler::IsComposing() { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::IsComposing(); + return nsTextStore::IsComposing() || nsIMM32Handler::IsComposing(); } #endif // #ifdef NS_ENABLE_TSF @@ -148,7 +157,8 @@ IMEHandler::IsComposingOn(nsWindow* aWindow) { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::IsComposingOn(aWindow); + return nsTextStore::IsComposingOn(aWindow) || + nsIMM32Handler::IsComposingOn(aWindow); } #endif // #ifdef NS_ENABLE_TSF @@ -163,8 +173,24 @@ IMEHandler::NotifyIME(nsWindow* aWindow, #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { switch (aIMENotification.mMessage) { - case NOTIFY_IME_OF_SELECTION_CHANGE: - return nsTextStore::OnSelectionChange(); + case NOTIFY_IME_OF_SELECTION_CHANGE: { + nsresult rv = nsTextStore::OnSelectionChange(); + // If IMM IME is active, we need to notify nsIMM32Handler of updating + // composition change. It will adjust candidate window position or + // composition window position. + if (IsIMMActive()) { + nsIMM32Handler::OnUpdateComposition(aWindow); + } + return rv; + } + case NOTIFY_IME_OF_COMPOSITION_UPDATE: + // If IMM IME is active, we need to notify nsIMM32Handler of updating + // composition change. It will adjust candidate window position or + // composition window position. + if (IsIMMActive()) { + nsIMM32Handler::OnUpdateComposition(aWindow); + } + return NS_OK; case NOTIFY_IME_OF_TEXT_CHANGE: return nsTextStore::OnTextChange(aIMENotification); case NOTIFY_IME_OF_FOCUS: @@ -174,15 +200,23 @@ IMEHandler::NotifyIME(nsWindow* aWindow, return nsTextStore::OnFocusChange(false, aWindow, aWindow->GetInputContext()); case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: + // If IMM IME is active, we should send a mouse button event via IMM. + if (IsIMMActive()) { + return nsIMM32Handler::OnMouseButtonEvent(aWindow, aIMENotification); + } return nsTextStore::OnMouseButtonEvent(aIMENotification); case REQUEST_TO_COMMIT_COMPOSITION: if (nsTextStore::IsComposingOn(aWindow)) { nsTextStore::CommitComposition(false); + } else if (IsIMMActive()) { + nsIMM32Handler::CommitComposition(aWindow); } return NS_OK; case REQUEST_TO_CANCEL_COMPOSITION: if (nsTextStore::IsComposingOn(aWindow)) { nsTextStore::CommitComposition(true); + } else if (IsIMMActive()) { + nsIMM32Handler::CancelComposition(aWindow); } return NS_OK; case NOTIFY_IME_OF_POSITION_CHANGE: @@ -239,7 +273,7 @@ bool IMEHandler::GetOpenState(nsWindow* aWindow) { #ifdef NS_ENABLE_TSF - if (IsTSFAvailable()) { + if (IsTSFAvailable() && !IsIMMActive()) { return nsTextStore::GetIMEOpenState(); } #endif //NS_ENABLE_TSF diff --git a/widget/windows/WinIMEHandler.h b/widget/windows/WinIMEHandler.h index e630bab34ed8..c2ea9e5466f5 100644 --- a/widget/windows/WinIMEHandler.h +++ b/widget/windows/WinIMEHandler.h @@ -122,6 +122,7 @@ private: static bool sPluginHasFocus; static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); } + static bool IsIMMActive(); #endif // #ifdef NS_ENABLE_TSF }; diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp index adb04267ac68..67196ca6e1e5 100644 --- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -74,7 +74,6 @@ nsresult nsDataObj::CStream::Init(nsIURI *pSourceURI, aRequestingNode, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy nullptr, // loadGroup nullptr, // aCallbacks nsIRequest::LOAD_FROM_CACHE); diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 32fd41a4f793..9b46960e19d6 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -36,7 +36,6 @@ using mozilla::plugins::PluginInstanceParent; #include "mozilla/RefPtr.h" #include "nsGfxCIID.h" #include "gfxContext.h" -#include "nsRenderingContext.h" #include "prmem.h" #include "WinUtils.h" #include "nsIWidgetListener.h" diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index a6aaeafc1964..fec664c68ed2 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -949,6 +949,18 @@ ShutdownXPCOM(nsIServiceManager* aServMgr) NS_ShutdownNativeCharsetUtils(); #endif +#if defined(XP_WIN) + // This exit(0) call is intended to be temporary, to get shutdown leak + // checking working on Linux. + // On Windows XP debug, there are intermittent failures in + // dom/media/tests/mochitest/test_peerConnection_basicH264Video.html + // if we don't exit early in a child process. See bug 1073310. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + NS_WARNING("Exiting child process early!"); + exit(0); + } +#endif + // Shutdown xpcom. This will release all loaders and cause others holding // a refcount to the component manager to release it. if (nsComponentManagerImpl::gComponentManager) { @@ -1026,6 +1038,17 @@ ShutdownXPCOM(nsIServiceManager* aServMgr) NS_LogTerm(); +#if defined(MOZ_WIDGET_GONK) + // This exit(0) call is intended to be temporary, to get shutdown leak + // checking working on Linux. + // On debug B2G, the child process crashes very late. Instead, just + // give up so at least we exit cleanly. See bug 1071866. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + NS_WARNING("Exiting child process early!"); + exit(0); + } +#endif + return NS_OK; } diff --git a/xpfe/components/directory/nsDirectoryViewer.cpp b/xpfe/components/directory/nsDirectoryViewer.cpp index 8cf610b8ba9c..b54fde367d8c 100644 --- a/xpfe/components/directory/nsDirectoryViewer.cpp +++ b/xpfe/components/directory/nsDirectoryViewer.cpp @@ -1305,7 +1305,6 @@ nsDirectoryViewerFactory::CreateInstance(const char *aCommand, nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER, - nullptr, // aChannelPolicy aLoadGroup); if (NS_FAILED(rv)) return rv;