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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WebCrypto
+
+
+
RUN ALL
+
+
+ Summary:
+
0 passed,
+
0 failed,
+
0 pending.
+
+
+
+
+
+ Test |
+ Result |
+ Time |
+
+
+
+
+
+
+
+
+
+
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