summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-12-22 01:23:56 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-12-22 01:26:49 +0100
commit54091ecab46c93c2e1b2c689e9179a980beaabe6 (patch)
tree5cead66d889007e1b06c5dbb8e3d37b2538d0557 /dom
parentc1013e9122456b342d65e4eb4c38a7281d8d83d2 (diff)
parent492624a7106ecbc18994b465ca1dd23fa472bf7e (diff)
downloadUXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.gz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.lz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.tar.xz
UXP-54091ecab46c93c2e1b2c689e9179a980beaabe6.zip
Forward to new tree structure.
Diffstat (limited to 'dom')
-rw-r--r--dom/base/nsContentPolicy.cpp21
-rw-r--r--dom/base/nsContentUtils.cpp9
-rw-r--r--dom/base/nsContentUtils.h6
-rw-r--r--dom/base/nsDocument.cpp57
-rw-r--r--dom/base/nsDocument.h11
-rw-r--r--dom/base/nsDocumentEncoder.cpp39
-rw-r--r--dom/base/nsGkAtomList.h1
-rw-r--r--dom/base/nsGlobalWindow.cpp60
-rw-r--r--dom/base/nsHTMLContentSerializer.cpp1
-rw-r--r--dom/base/nsHTMLContentSerializer.h1
-rw-r--r--dom/base/nsIContentSerializer.h1
-rw-r--r--dom/base/nsIDocument.h10
-rw-r--r--dom/base/nsIImageLoadingContent.idl9
-rw-r--r--dom/base/nsImageLoadingContent.cpp101
-rw-r--r--dom/base/nsImageLoadingContent.h17
-rw-r--r--dom/base/nsObjectLoadingContent.cpp14
-rw-r--r--dom/base/nsPlainTextSerializer.cpp59
-rw-r--r--dom/base/nsPlainTextSerializer.h5
-rw-r--r--dom/base/nsScriptLoader.cpp65
-rw-r--r--dom/base/nsScriptLoader.h2
-rwxr-xr-xdom/base/nsXHTMLContentSerializer.cpp3
-rw-r--r--dom/base/nsXHTMLContentSerializer.h1
-rw-r--r--dom/base/nsXMLContentSerializer.cpp9
-rw-r--r--dom/base/nsXMLContentSerializer.h2
-rw-r--r--dom/bindings/BindingUtils.cpp39
-rw-r--r--dom/bindings/Bindings.conf4
-rw-r--r--dom/bindings/Codegen.py494
-rw-r--r--dom/bindings/Configuration.py7
-rw-r--r--dom/bindings/DOMJSProxyHandler.cpp13
-rw-r--r--dom/bindings/DOMJSProxyHandler.h5
-rw-r--r--dom/bindings/Errors.msg5
-rw-r--r--dom/bindings/ToJSValue.cpp6
-rw-r--r--dom/bindings/ToJSValue.h2
-rw-r--r--dom/bindings/TypedArray.h2
-rw-r--r--dom/bindings/parser/WebIDL.py96
-rw-r--r--dom/bindings/parser/tests/test_distinguishability.py1
-rw-r--r--dom/bindings/parser/tests/test_promise.py4
-rw-r--r--dom/bindings/test/test_Object.prototype_props.html6
-rw-r--r--dom/canvas/WebGLContextBuffers.cpp12
-rw-r--r--dom/canvas/WebGLShader.cpp10
-rw-r--r--dom/canvas/test/reftest/filters/liveness-document-open.html46
-rw-r--r--dom/canvas/test/reftest/filters/reftest.list1
-rw-r--r--dom/events/test/test_continuous_wheel_events.html2
-rw-r--r--dom/grid/GridLines.cpp42
-rw-r--r--dom/grid/test/chrome.ini1
-rw-r--r--dom/grid/test/chrome/test_grid_implicit.html63
-rw-r--r--dom/grid/test/chrome/test_grid_line_numbers.html101
-rw-r--r--dom/html/HTMLScriptElement.cpp12
-rw-r--r--dom/html/HTMLScriptElement.h2
-rw-r--r--dom/html/ImageDocument.cpp2
-rw-r--r--dom/html/PluginDocument.cpp2
-rw-r--r--dom/html/VideoDocument.cpp2
-rw-r--r--dom/html/test/file_script_module.html42
-rw-r--r--dom/html/test/file_script_nomodule.html32
-rw-r--r--dom/html/test/mochitest.ini5
-rw-r--r--dom/html/test/test_document.watch.html129
-rw-r--r--dom/html/test/test_script_module.html56
-rw-r--r--dom/indexedDB/ActorsParent.cpp56
-rw-r--r--dom/indexedDB/IDBCursor.cpp8
-rw-r--r--dom/indexedDB/IDBDatabase.cpp3
-rw-r--r--dom/indexedDB/IDBFactory.cpp4
-rw-r--r--dom/indexedDB/IDBKeyRange.cpp2
-rw-r--r--dom/indexedDB/IDBObjectStore.cpp36
-rw-r--r--dom/indexedDB/IndexedDatabaseManager.cpp75
-rw-r--r--dom/indexedDB/IndexedDatabaseManager.h17
-rw-r--r--dom/indexedDB/Key.cpp38
-rw-r--r--dom/indexedDB/Key.h15
-rw-r--r--dom/indexedDB/KeyPath.cpp22
-rw-r--r--dom/indexedDB/KeyPath.h12
-rw-r--r--dom/indexedDB/crashtests/1558522-1.html40
-rw-r--r--dom/indexedDB/crashtests/crashtests.list1
-rw-r--r--dom/indexedDB/test/helpers.js4
-rw-r--r--dom/indexedDB/test/mochitest.ini2
-rw-r--r--dom/indexedDB/test/test_lowDiskSpace.html19
-rw-r--r--dom/indexedDB/test/unit/test_lowDiskSpace.js754
-rw-r--r--dom/indexedDB/test/unit/xpcshell-head-parent-process.js3
-rw-r--r--dom/indexedDB/test/unit/xpcshell-parent-process.ini1
-rw-r--r--dom/interfaces/css/nsIDOMCSSGroupingRule.idl2
-rw-r--r--dom/interfaces/css/nsIDOMCSSStyleSheet.idl2
-rw-r--r--dom/locales/en-US/chrome/plugins.properties6
-rw-r--r--dom/media/AudioStream.h4
-rw-r--r--dom/media/VideoUtils.cpp1
-rw-r--r--dom/media/VideoUtils.h1
-rw-r--r--dom/media/eme/EMEUtils.cpp11
-rw-r--r--dom/media/eme/EMEUtils.h4
-rw-r--r--dom/media/eme/MediaKeySystemAccess.cpp23
-rw-r--r--dom/media/eme/MediaKeySystemAccessManager.cpp5
-rw-r--r--dom/media/gmp/GMPParent.cpp10
-rw-r--r--dom/media/gmp/GMPServiceParent.cpp36
-rw-r--r--dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp2
-rw-r--r--dom/media/test/external/external_media_harness/testcase.py26
-rw-r--r--dom/plugins/base/npapi.h7
-rw-r--r--dom/plugins/base/nptypes.h13
-rw-r--r--dom/plugins/base/nsJSNPRuntime.cpp1
-rw-r--r--dom/plugins/base/nsPluginsDirUnix.cpp16
-rw-r--r--dom/plugins/ipc/PluginInstanceChild.cpp13
-rw-r--r--dom/plugins/ipc/PluginMessageUtils.cpp6
-rw-r--r--dom/plugins/ipc/PluginModuleChild.cpp6
-rw-r--r--dom/plugins/ipc/PluginModuleChild.h2
-rw-r--r--dom/promise/Promise.cpp2312
-rw-r--r--dom/promise/Promise.h319
-rw-r--r--dom/promise/PromiseCallback.cpp571
-rw-r--r--dom/promise/PromiseCallback.h203
-rw-r--r--dom/promise/PromiseDebugging.cpp221
-rw-r--r--dom/promise/PromiseDebugging.h20
-rw-r--r--dom/promise/moz.build3
-rw-r--r--dom/security/nsCSPContext.cpp15
-rw-r--r--dom/security/nsCSPUtils.cpp32
-rw-r--r--dom/security/nsContentSecurityManager.cpp5
-rw-r--r--dom/smil/nsSMILCSSProperty.cpp8
-rw-r--r--dom/storage/DOMStorageCache.cpp5
-rw-r--r--dom/storage/DOMStorageIPC.cpp17
-rw-r--r--dom/storage/DOMStorageManager.cpp17
-rw-r--r--dom/storage/DOMStorageManager.h6
-rw-r--r--dom/storage/DOMStorageObserver.cpp13
-rw-r--r--dom/svg/crashtests/880544-1.svg15
-rw-r--r--dom/svg/crashtests/880544-2.svg15
-rw-r--r--dom/svg/crashtests/880544-3.svg15
-rw-r--r--dom/svg/crashtests/880544-4.svg15
-rw-r--r--dom/svg/crashtests/880544-5.svg15
-rw-r--r--dom/svg/crashtests/crashtests.list5
-rw-r--r--dom/tests/mochitest/ajax/offline/mochitest.ini2
-rw-r--r--dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html91
-rw-r--r--dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html58
-rw-r--r--dom/tests/mochitest/bugs/iframe_bug38959-1.html14
-rw-r--r--dom/tests/mochitest/bugs/iframe_bug38959-2.html14
-rw-r--r--dom/tests/mochitest/bugs/mochitest.ini3
-rw-r--r--dom/tests/mochitest/bugs/test_bug38959.html57
-rw-r--r--dom/tests/mochitest/chrome/queryCaretRectWin.html2
-rw-r--r--dom/tests/mochitest/chrome/selectAtPoint.html12
-rw-r--r--dom/tests/mochitest/localstorage/mochitest.ini1
-rw-r--r--dom/tests/mochitest/localstorage/test_lowDeviceStorage.html76
-rw-r--r--dom/webidl/CSSStyleSheet.webidl2
-rw-r--r--dom/webidl/HTMLScriptElement.webidl2
-rw-r--r--dom/webidl/Promise.webidl61
-rw-r--r--dom/webidl/PromiseDebugging.webidl44
-rw-r--r--dom/webidl/TestInterfaceJS.webidl2
-rw-r--r--dom/webidl/moz.build4
-rw-r--r--dom/workers/WorkerPrivate.cpp6
139 files changed, 1262 insertions, 6095 deletions
diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp
index 5511b9086..534466103 100644
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -22,6 +22,7 @@
#include "nsIDOMWindow.h"
#include "nsITabChild.h"
#include "nsIContent.h"
+#include "nsIImageLoadingContent.h"
#include "nsILoadContext.h"
#include "nsCOMArray.h"
#include "nsContentUtils.h"
@@ -145,6 +146,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
decision);
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
+ // If we are blocking an image, we have to let the
+ // ImageLoadingContent know that we blocked the load.
+ if (externalType == nsIContentPolicy::TYPE_IMAGE ||
+ externalType == nsIContentPolicy::TYPE_IMAGESET) {
+ nsCOMPtr<nsIImageLoadingContent> img =
+ do_QueryInterface(requestingContext);
+ if (img) {
+ img->SetBlockedRequest(*decision);
+ }
+ }
/* policy says no, no point continuing to check */
return NS_OK;
}
@@ -193,6 +204,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
decision);
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
+ // If we are blocking an image, we have to let the
+ // ImageLoadingContent know that we blocked the load.
+ if (externalType == nsIContentPolicy::TYPE_IMAGE ||
+ externalType == nsIContentPolicy::TYPE_IMAGESET) {
+ nsCOMPtr<nsIImageLoadingContent> img =
+ do_QueryInterface(requestingContext);
+ if (img) {
+ img->SetBlockedRequest(*decision);
+ }
+ }
/* policy says no, no point continuing to check */
return NS_OK;
}
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 1f9c17947..800f40fa1 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8478,12 +8478,9 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType
bool
nsContentUtils::IsPreloadType(nsContentPolicyType aType)
{
- if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
- aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
- aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) {
- return true;
- }
- return false;
+ return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
+ aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
+ aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD);
}
nsresult
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 299a8e859..606d67de9 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -9,10 +9,14 @@
#ifndef nsContentUtils_h___
#define nsContentUtils_h___
-#if defined(XP_WIN)
+#ifdef XP_WIN
#include <float.h>
#endif
+#ifdef XP_SOLARIS
+#include <ieeefp.h>
+#endif
+
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/RootingAPI.h"
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index d8abc174f..e2be6b664 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -395,6 +395,21 @@ nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
}
}
+void
+nsIdentifierMapEntry::ClearAndNotify()
+{
+ Element* currentElement = mIdContentList.SafeElementAt(0);
+ mIdContentList.Clear();
+ if (currentElement) {
+ FireChangeCallbacks(currentElement, nullptr);
+ }
+ mNameContentList = nullptr;
+ if (mImageElement) {
+ SetImageElement(nullptr);
+ }
+ mChangeCallbacks = nullptr;
+}
+
namespace {
struct PositionComparator
@@ -1422,12 +1437,12 @@ nsDocument::~nsDocument()
delete mSubDocuments;
mSubDocuments = nullptr;
+ nsAutoScriptBlocker scriptBlocker;
+
// Destroy link map now so we don't waste time removing
// links one by one
DestroyElementMaps();
- nsAutoScriptBlocker scriptBlocker;
-
for (uint32_t indx = mChildren.ChildCount(); indx-- != 0; ) {
mChildren.ChildAt(indx)->UnbindFromTree();
mChildren.RemoveChildAt(indx);
@@ -1972,15 +1987,16 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
delete mSubDocuments;
mSubDocuments = nullptr;
- // Destroy link map now so we don't waste time removing
- // links one by one
- DestroyElementMaps();
-
bool oldVal = mInUnlinkOrDeletion;
mInUnlinkOrDeletion = true;
uint32_t count = mChildren.ChildCount();
{ // Scope for update
MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, true);
+
+ // Destroy link map now so we don't waste time removing
+ // links one by one
+ DestroyElementMaps();
+
for (int32_t i = int32_t(count) - 1; i >= 0; i--) {
nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
@@ -8955,7 +8971,14 @@ nsDocument::DestroyElementMaps()
mStyledLinksCleared = true;
#endif
mStyledLinks.Clear();
+
+ // Notify ID change listeners before clearing the identifier map.
+ for (auto iter = mIdentifierMap.Iter(); !iter.Done(); iter.Next()) {
+ iter.Get()->ClearAndNotify();
+ }
+
mIdentifierMap.Clear();
+
++mExpandoAndGeneration.generation;
}
@@ -9222,19 +9245,23 @@ already_AddRefed<nsIURI>
nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
const nsAString& aSrcAttr,
const nsAString& aSrcsetAttr,
- const nsAString& aSizesAttr)
+ const nsAString& aSizesAttr,
+ bool *aIsImgSet)
{
nsString sourceURL;
+ bool isImgSet;
if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) {
// We're in a <picture> element and found a URI from a source previous to
// this image, use it.
sourceURL = mPreloadPictureFoundSource;
+ isImgSet = true;
} else {
// Otherwise try to use this <img> as a source
HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr,
aSrcsetAttr, aSizesAttr,
NullString(), NullString(),
sourceURL);
+ isImgSet = !aSrcsetAttr.IsEmpty();
}
// Empty sources are not loaded by <img> (i.e. not resolved to the baseURI)
@@ -9252,6 +9279,8 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
return nullptr;
}
+ *aIsImgSet = isImgSet;
+
// We don't clear mPreloadPictureFoundSource because subsequent <img> tags in
// this this <picture> share the same <sources> (though this is not valid per
// spec)
@@ -9260,16 +9289,12 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
void
nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
- ReferrerPolicy aReferrerPolicy)
+ ReferrerPolicy aReferrerPolicy, bool aIsImgSet)
{
// Early exit if the img is already present in the img-cache
// which indicates that the "real" load has already started and
// that we shouldn't preload it.
- int16_t blockingStatus;
- if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) ||
- !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
- this, NodePrincipal(), &blockingStatus,
- nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD)) {
+ if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this))) {
return;
}
@@ -9288,6 +9313,10 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
MOZ_CRASH("Unknown CORS mode!");
}
+ nsContentPolicyType policyType =
+ aIsImgSet ? nsIContentPolicy::TYPE_IMAGESET :
+ nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD;
+
// Image not in cache - trigger preload
RefPtr<imgRequestProxy> request;
nsresult rv =
@@ -9301,7 +9330,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
loadFlags,
NS_LITERAL_STRING("img"),
getter_AddRefs(request),
- nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD);
+ policyType);
// Pin image-reference to avoid evicting it from the img-cache before
// the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 95fd57545..ac600eb43 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -216,6 +216,11 @@ public:
void RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
void* aData, bool aForImage);
+ /**
+ * Remove all elements and notify change listeners.
+ */
+ void ClearAndNotify();
+
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
struct ChangeCallback {
@@ -948,11 +953,13 @@ public:
ResolvePreloadImage(nsIURI *aBaseURI,
const nsAString& aSrcAttr,
const nsAString& aSrcsetAttr,
- const nsAString& aSizesAttr) override;
+ const nsAString& aSizesAttr,
+ bool *aIsImgSet) override;
virtual void MaybePreLoadImage(nsIURI* uri,
const nsAString &aCrossOriginAttr,
- ReferrerPolicy aReferrerPolicy) override;
+ ReferrerPolicy aReferrerPolicy,
+ bool aIsImgSet) override;
virtual void ForgetImagePreload(nsIURI* aURI) override;
virtual void MaybePreconnect(nsIURI* uri,
diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp
index 84b128b15..34eb6ed38 100644
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -82,7 +82,9 @@ protected:
nsAString& aStr,
bool aDontSerializeRoot,
uint32_t aMaxLength = 0);
- nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr);
+ nsresult SerializeNodeEnd(nsINode* aOriginalNode,
+ nsAString& aStr,
+ nsINode* aFixupNode = nullptr);
// This serializes the content of aNode.
nsresult SerializeToStringIterative(nsINode* aNode,
nsAString& aStr);
@@ -405,14 +407,37 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
}
nsresult
-nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
- nsAString& aStr)
+nsDocumentEncoder::SerializeNodeEnd(nsINode* aOriginalNode,
+ nsAString& aStr,
+ nsINode* aFixupNode)
{
- if (!IsVisibleNode(aNode))
+ if (!IsVisibleNode(aOriginalNode))
return NS_OK;
- if (aNode->IsElement()) {
- mSerializer->AppendElementEnd(aNode->AsElement(), aStr);
+ nsINode* node = nullptr;
+ nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
+
+ // Caller didn't do fixup, so we'll do it ourselves
+ if (!aFixupNode) {
+ aFixupNode = aOriginalNode;
+ if (mNodeFixup) {
+ bool dummy;
+ nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aOriginalNode);
+ nsCOMPtr<nsIDOMNode> domNodeOut;
+ mNodeFixup->FixupNode(domNodeIn, &dummy, getter_AddRefs(domNodeOut));
+ fixedNodeKungfuDeathGrip = do_QueryInterface(domNodeOut);
+ node = fixedNodeKungfuDeathGrip;
+ }
+ }
+
+ // Fall back to original node if needed.
+ if (!node)
+ node = aOriginalNode;
+
+ if (node->IsElement()) {
+ mSerializer->AppendElementEnd(node->AsElement(),
+ aOriginalNode->AsElement(),
+ aStr);
}
return NS_OK;
}
@@ -481,7 +506,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
}
if (!aDontSerializeRoot) {
- rv = SerializeNodeEnd(maybeFixedNode, aStr);
+ rv = SerializeNodeEnd(aNode, aStr, maybeFixedNode);
NS_ENSURE_SUCCESS(rv, rv);
}
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index 8fefa0e02..73a3a02b1 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -665,6 +665,7 @@ GK_ATOM(noembed, "noembed")
GK_ATOM(noframes, "noframes")
GK_ATOM(nohref, "nohref")
GK_ATOM(noisolation, "noisolation")
+GK_ATOM(nomodule, "nomodule")
GK_ATOM(nonce, "nonce")
GK_ATOM(none, "none")
GK_ATOM(noresize, "noresize")
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index afaa24f09..47b46dda0 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1026,11 +1026,6 @@ public:
return false;
}
- virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const override;
- virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id) const override;
-
static void ObjectMoved(JSObject *obj, const JSObject *old);
static const nsOuterWindowProxy singleton;
@@ -1398,20 +1393,6 @@ nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
return true;
}
-bool
-nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const
-{
- return js::WatchGuts(cx, proxy, id, callable);
-}
-
-bool
-nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id) const
-{
- return js::UnwatchGuts(cx, proxy, id);
-}
-
void
nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
{
@@ -3224,6 +3205,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
newInnerWindow->mLocalStorage = nullptr;
newInnerWindow->mSessionStorage = nullptr;
+ newInnerWindow->mPerformance = nullptr;
+
+ // This must be called after nulling the internal objects because
+ // we might recreate them here by calling the getter methods, and
+ // store them into the JS slots. If we null them after, the slot
+ // values and the objects will be out of sync.
newInnerWindow->ClearDocumentDependentSlots(cx);
}
} else {
@@ -3364,10 +3351,16 @@ nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
}
mDoc = aDocument;
- ClearDocumentDependentSlots(aCx);
mFocusedNode = nullptr;
mLocalStorage = nullptr;
mSessionStorage = nullptr;
+ mPerformance = nullptr;
+
+ // This must be called after nulling the internal objects because we might
+ // recreate them here by calling the getter methods, and store them into the JS
+ // slots. If we null them after, the slot values and the objects will be
+ // out of sync.
+ ClearDocumentDependentSlots(aCx);
#ifdef DEBUG
mLastOpenedURI = aDocument->GetDocumentURI();
@@ -10957,35 +10950,12 @@ nsGlobalWindow::GetComputedStyleHelperOuter(Element& aElt,
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
- if (!mDocShell) {
+ if (!mDoc) {
return nullptr;
}
- nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
-
- if (!presShell) {
- // Try flushing frames on our parent in case there's a pending
- // style change that will create the presshell.
- auto* parent = nsGlobalWindow::Cast(GetPrivateParent());
- if (!parent) {
- return nullptr;
- }
-
- parent->FlushPendingNotifications(Flush_Frames);
-
- // Might have killed mDocShell
- if (!mDocShell) {
- return nullptr;
- }
-
- presShell = mDocShell->GetPresShell();
- if (!presShell) {
- return nullptr;
- }
- }
-
RefPtr<nsComputedDOMStyle> compStyle =
- NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
+ NS_NewComputedDOMStyle(&aElt, aPseudoElt, mDoc,
aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
nsComputedDOMStyle::eAll);
diff --git a/dom/base/nsHTMLContentSerializer.cpp b/dom/base/nsHTMLContentSerializer.cpp
index ab8b4f2b2..c135c4cf8 100644
--- a/dom/base/nsHTMLContentSerializer.cpp
+++ b/dom/base/nsHTMLContentSerializer.cpp
@@ -301,6 +301,7 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
+ Element* aOriginalElement /* unused */,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
diff --git a/dom/base/nsHTMLContentSerializer.h b/dom/base/nsHTMLContentSerializer.h
index 6f3500e01..8e23d54ca 100644
--- a/dom/base/nsHTMLContentSerializer.h
+++ b/dom/base/nsHTMLContentSerializer.h
@@ -31,6 +31,7 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
nsAString& aStr) override;
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
nsAString& aStr) override;
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
diff --git a/dom/base/nsIContentSerializer.h b/dom/base/nsIContentSerializer.h
index f023cbc90..35014bd2c 100644
--- a/dom/base/nsIContentSerializer.h
+++ b/dom/base/nsIContentSerializer.h
@@ -55,6 +55,7 @@ class nsIContentSerializer : public nsISupports {
nsAString& aStr) = 0;
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
nsAString& aStr) = 0;
NS_IMETHOD Flush(nsAString& aStr) = 0;
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index e5d12ab8f..d76a12d71 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2260,21 +2260,27 @@ public:
* nesting and possible sources, which are used to inform URL selection
* responsive <picture> or <img srcset> images. Unset attributes are expected
* to be marked void.
+ * If this image is for <picture> or <img srcset>, aIsImgSet will be set to
+ * true, false otherwise.
*/
virtual already_AddRefed<nsIURI>
ResolvePreloadImage(nsIURI *aBaseURI,
const nsAString& aSrcAttr,
const nsAString& aSrcsetAttr,
- const nsAString& aSizesAttr) = 0;
+ const nsAString& aSizesAttr,
+ bool *aIsImgSet) = 0;
/**
* Called by nsParser to preload images. Can be removed and code moved
* to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the
* parser-module is linked with gklayout-module. aCrossOriginAttr should
* be a void string if the attr is not present.
+ * aIsImgSet is the value got from calling ResolvePreloadImage, it is true
+ * when this image is for loading <picture> or <img srcset> images.
*/
virtual void MaybePreLoadImage(nsIURI* uri,
const nsAString& aCrossOriginAttr,
- ReferrerPolicyEnum aReferrerPolicy) = 0;
+ ReferrerPolicyEnum aReferrerPolicy,
+ bool aIsImgSet) = 0;
/**
* Called by images to forget an image preload when they start doing
diff --git a/dom/base/nsIImageLoadingContent.idl b/dom/base/nsIImageLoadingContent.idl
index fea261a34..eacc4ac3a 100644
--- a/dom/base/nsIImageLoadingContent.idl
+++ b/dom/base/nsIImageLoadingContent.idl
@@ -104,6 +104,15 @@ interface nsIImageLoadingContent : imgINotificationObserver
imgIRequest getRequest(in long aRequestType);
/**
+ * Call this function when the request was blocked by any of the
+ * security policies enforced.
+ *
+ * @param aContentDecision the decision returned from nsIContentPolicy
+ * (any of the types REJECT_*)
+ */
+ void setBlockedRequest(in int16_t aContentDecision);
+
+ /**
* @return true if the current request's size is available.
*/
[noscript, notxpcom] boolean currentRequestHasSize();
diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp
index 0c6c37b44..4aad55941 100644
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -44,6 +44,7 @@
#include "mozAutoDocUpdate.h"
#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/AutoRestore.h"
#include "mozilla/EventStates.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ImageTracker.h"
@@ -94,7 +95,8 @@ nsImageLoadingContent::nsImageLoadingContent()
mNewRequestsWillNeedAnimationReset(false),
mStateChangerDepth(0),
mCurrentRequestRegistered(false),
- mPendingRequestRegistered(false)
+ mPendingRequestRegistered(false),
+ mIsStartingImageLoad(false)
{
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
mLoadingEnabled = false;
@@ -785,6 +787,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
nsIDocument* aDocument,
nsLoadFlags aLoadFlags)
{
+ MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage.");
+ if (mIsStartingImageLoad) {
+ return NS_OK;
+ }
+
// Pending load/error events need to be canceled in some situations. This
// is not documented in the spec, but can cause site compat problems if not
// done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
@@ -814,6 +821,21 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
}
}
+ AutoRestore<bool> guard(mIsStartingImageLoad);
+ mIsStartingImageLoad = true;
+
+ // Data documents, or documents from DOMParser shouldn't perform image loading.
+ if (aDocument->IsLoadedAsData()) {
+ // This is the only codepath on which we can reach SetBlockedRequest while
+ // our pending request exists. Just clear it out here if we do have one.
+ ClearPendingRequest(NS_BINDING_ABORTED,
+ Some(OnNonvisible::DISCARD_IMAGES));
+ SetBlockedRequest(nsIContentPolicy::REJECT_REQUEST);
+ FireEvent(NS_LITERAL_STRING("error"));
+ FireEvent(NS_LITERAL_STRING("loadend"));
+ return NS_OK;
+ }
+
// URI equality check.
//
// We skip the equality check if our current image was blocked, since in that
@@ -844,23 +866,8 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
"Principal mismatch?");
#endif
- // Are we blocked?
- int16_t cpDecision = nsIContentPolicy::REJECT_REQUEST;
nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType);
- nsContentUtils::CanLoadImage(aNewURI,
- static_cast<nsIImageLoadingContent*>(this),
- aDocument,
- aDocument->NodePrincipal(),
- &cpDecision,
- policyType);
- if (!NS_CP_ACCEPTED(cpDecision)) {
- FireEvent(NS_LITERAL_STRING("error"));
- FireEvent(NS_LITERAL_STRING("loadend"));
- SetBlockedRequest(aNewURI, cpDecision);
- return NS_OK;
- }
-
nsLoadFlags loadFlags = aLoadFlags;
int32_t corsmode = GetCORSMode();
if (corsmode == CORS_ANONYMOUS) {
@@ -878,7 +885,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
referrerPolicy = imgReferrerPolicy;
}
- // Not blocked. Do the load.
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
@@ -932,7 +938,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
FireEvent(NS_LITERAL_STRING("error"));
FireEvent(NS_LITERAL_STRING("loadend"));
- return NS_OK;
}
return NS_OK;
@@ -1212,46 +1217,42 @@ nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
mMostRecentRequestChange = now;
}
- // If we don't have a usable current request, get rid of any half-baked
- // request that might be sitting there and make this one current.
- if (!HaveSize(mCurrentRequest))
- return PrepareCurrentRequest(aImageLoadType);
- // Otherwise, make it pending.
- return PreparePendingRequest(aImageLoadType);
+ // We only want to cancel the existing current request if size is not
+ // available. bz says the web depends on this behavior.
+ // Otherwise, we get rid of any half-baked request that might be sitting there
+ // and make this one current.
+ // TODO: Bug 583491
+ // Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp
+ return HaveSize(mCurrentRequest) ?
+ PreparePendingRequest(aImageLoadType) :
+ PrepareCurrentRequest(aImageLoadType);
}
-void
-nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
+nsresult
+nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision)
{
+ // If this is not calling from LoadImage, for example, from ServiceWorker,
+ // bail out.
+ if (!mIsStartingImageLoad) {
+ return NS_OK;
+ }
+
// Sanity
MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
- // We do some slightly illogical stuff here to maintain consistency with
- // old behavior that people probably depend on. Even in the case where the
- // new image is blocked, the old one should really be canceled with the
- // reason "image source changed". However, apparently there's some abuse
- // over in nsImageFrame where the displaying of the "broken" icon for the
- // next image depends on the cancel reason of the previous image. ugh.
- // XXX(seth): So shouldn't we fix nsImageFrame?!
- ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED,
- Some(OnNonvisible::DISCARD_IMAGES));
-
- // For the blocked case, we only want to cancel the existing current request
- // if size is not available. bz says the web depends on this behavior.
- if (!HaveSize(mCurrentRequest)) {
+ // We should never have a pending request after we got blocked.
+ MOZ_ASSERT(!mPendingRequest, "mPendingRequest should be null.");
+ if (HaveSize(mCurrentRequest)) {
+ // PreparePendingRequest set mPendingRequestFlags, now since we've decided
+ // to block it, we reset it back to 0.
+ mPendingRequestFlags = 0;
+ } else {
mImageBlockingStatus = aContentDecision;
- uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET;
- ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED,
- Some(OnNonvisible::DISCARD_IMAGES));
-
- // We still want to remember what URI we were and if it was an imageset,
- // despite not having an actual request. These are both cleared as part of
- // ClearCurrentRequest() before a new request is started.
- mCurrentURI = aURI;
- mCurrentRequestFlags = keepFlags;
}
+
+ return NS_OK;
}
RefPtr<imgRequestProxy>&
@@ -1262,7 +1263,7 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType)
mImageBlockingStatus = nsIContentPolicy::ACCEPT;
// Get rid of anything that was there previously.
- ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED,
+ ClearCurrentRequest(NS_BINDING_ABORTED,
Some(OnNonvisible::DISCARD_IMAGES));
if (mNewRequestsWillNeedAnimationReset) {
@@ -1281,7 +1282,7 @@ RefPtr<imgRequestProxy>&
nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
{
// Get rid of anything that was there previously.
- ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED,
+ ClearPendingRequest(NS_BINDING_ABORTED,
Some(OnNonvisible::DISCARD_IMAGES));
if (mNewRequestsWillNeedAnimationReset) {
diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h
index 5f7daff72..cfb2a6207 100644
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -303,17 +303,10 @@ protected:
RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType);
/**
- * Called when we would normally call PrepareNextRequest(), but the request was
- * blocked.
- */
- void SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision);
-
- /**
* Returns a COMPtr reference to the current/pending image requests, cleaning
* up and canceling anything that was there before. Note that if you just want
* to get rid of one of the requests, you should call
- * Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate
- * aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED).
+ * Clear*Request(NS_BINDING_ABORTED) instead.
*
* @param aImageLoadType The ImageLoadType for this request
*/
@@ -459,6 +452,14 @@ private:
// registered with the refresh driver.
bool mCurrentRequestRegistered;
bool mPendingRequestRegistered;
+
+ // This member is used in SetBlockedRequest, if it's true, then this call is
+ // triggered from LoadImage.
+ // If this is false, it means this call is from other places like
+ // ServiceWorker, then we will ignore call to SetBlockedRequest for now.
+ //
+ // Also we use this variable to check if some evil code is reentering LoadImage.
+ bool mIsStartingImageLoad;
};
#endif // nsImageLoadingContent_h__
diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp
index 3c850c4cd..4978744e8 100644
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -718,9 +718,9 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
if (mType == eType_Plugin) {
nsIDocument* doc = thisContent->GetComposedDoc();
if (doc && doc->IsActive()) {
- nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc,
- NS_LITERAL_STRING("PluginRemoved"));
- NS_DispatchToCurrentThread(ev);
+ nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc,
+ NS_LITERAL_STRING("PluginRemoved"));
+ NS_DispatchToCurrentThread(ev);
}
}
}
@@ -3628,6 +3628,14 @@ nsObjectLoadingContent::HasGoodFallback() {
}
}
+ // RULE "nosrc":
+ // Use fallback content if the object has not specified a src URI.
+ if (rulesList[i].EqualsLiteral("nosrc")) {
+ if (!mOriginalURI) {
+ return true;
+ }
+ }
+
// RULE "adobelink":
// Don't use fallback content when it has a link to adobe's website.
if (rulesList[i].EqualsLiteral("adobelink")) {
diff --git a/dom/base/nsPlainTextSerializer.cpp b/dom/base/nsPlainTextSerializer.cpp
index ef6bdcac7..98c9cfe32 100644
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -53,7 +53,6 @@ static int32_t GetUnicharStringWidth(const char16_t* pwcs, int32_t n);
// Someday may want to make this non-const:
static const uint32_t TagStackSize = 500;
-static const uint32_t OLStackSize = 100;
nsresult
NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer)
@@ -100,10 +99,6 @@ nsPlainTextSerializer::nsPlainTextSerializer()
mTagStackIndex = 0;
mIgnoreAboveIndex = (uint32_t)kNotFound;
- // initialize the OL stack, where numbers for ordered lists are kept
- mOLStack = new int32_t[OLStackSize];
- mOLStackIndex = 0;
-
mULCount = 0;
mIgnoredChildNodeLevel = 0;
@@ -112,7 +107,6 @@ nsPlainTextSerializer::nsPlainTextSerializer()
nsPlainTextSerializer::~nsPlainTextSerializer()
{
delete[] mTagStack;
- delete[] mOLStack;
NS_WARNING_ASSERTION(mHeadLevel == 0, "Wrong head level!");
}
@@ -189,6 +183,8 @@ nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
// XXX We should let the caller decide whether to do this or not
mFlags &= ~nsIDocumentEncoder::OutputNoFramesContent;
+ MOZ_ASSERT(mOLStack.IsEmpty());
+
return NS_OK;
}
@@ -390,6 +386,7 @@ nsPlainTextSerializer::AppendElementStart(Element* aElement,
NS_IMETHODIMP
nsPlainTextSerializer::AppendElementEnd(Element* aElement,
+ Element* aOriginalElement /* unused */,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@@ -437,6 +434,8 @@ nsPlainTextSerializer::AppendDocumentStart(nsIDocument *aDocument,
return NS_OK;
}
+int32_t kOlStackDummyValue = 0;
+
nsresult
nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag)
{
@@ -615,44 +614,45 @@ nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag)
}
else if (aTag == nsGkAtoms::ul) {
// Indent here to support nested lists, which aren't included in li :-(
- EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
- // Must end the current line before we change indention
+ EnsureVerticalSpace(IsInOLOrUL() ? 0 : 1);
+ // Must end the current line before we change indention
mIndent += kIndentSizeList;
mULCount++;
}
else if (aTag == nsGkAtoms::ol) {
- EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
+ EnsureVerticalSpace(IsInOLOrUL() ? 0 : 1);
if (mFlags & nsIDocumentEncoder::OutputFormatted) {
// Must end the current line before we change indention
- if (mOLStackIndex < OLStackSize) {
- nsAutoString startAttr;
- int32_t startVal = 1;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::start, startAttr))) {
- nsresult rv = NS_OK;
- startVal = startAttr.ToInteger(&rv);
- if (NS_FAILED(rv))
- startVal = 1;
+ nsAutoString startAttr;
+ int32_t startVal = 1;
+ if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::start, startAttr))) {
+ nsresult rv = NS_OK;
+ startVal = startAttr.ToInteger(&rv);
+ if (NS_FAILED(rv)) {
+ startVal = 1;
}
- mOLStack[mOLStackIndex++] = startVal;
}
+ mOLStack.AppendElement(startVal);
} else {
- mOLStackIndex++;
+ mOLStack.AppendElement(kOlStackDummyValue);
}
mIndent += kIndentSizeList; // see ul
}
else if (aTag == nsGkAtoms::li &&
(mFlags & nsIDocumentEncoder::OutputFormatted)) {
if (mTagStackIndex > 1 && IsInOL()) {
- if (mOLStackIndex > 0) {
+ if (!mOLStack.IsEmpty()) {
nsAutoString valueAttr;
if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::value, valueAttr))) {
nsresult rv = NS_OK;
int32_t valueAttrVal = valueAttr.ToInteger(&rv);
- if (NS_SUCCEEDED(rv))
- mOLStack[mOLStackIndex-1] = valueAttrVal;
+ if (NS_SUCCEEDED(rv)) {
+ mOLStack.LastElement() = valueAttrVal;
+ }
}
// This is what nsBulletFrame does for OLs:
- mInIndentString.AppendInt(mOLStack[mOLStackIndex-1]++, 10);
+ mInIndentString.AppendInt(mOLStack.LastElement(), 10);
+ mOLStack.LastElement()++;
}
else {
mInIndentString.Append(char16_t('#'));
@@ -877,7 +877,8 @@ nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
else if (aTag == nsGkAtoms::ul) {
FlushLine();
mIndent -= kIndentSizeList;
- if (--mULCount + mOLStackIndex == 0) {
+ --mULCount;
+ if (!IsInOLOrUL()) {
mFloatingLines = 1;
mLineBreakDue = true;
}
@@ -885,9 +886,9 @@ nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
else if (aTag == nsGkAtoms::ol) {
FlushLine(); // Doing this after decreasing OLStackIndex would be wrong.
mIndent -= kIndentSizeList;
- NS_ASSERTION(mOLStackIndex, "Wrong OLStack level!");
- mOLStackIndex--;
- if (mULCount + mOLStackIndex == 0) {
+ NS_ASSERTION(!mOLStack.IsEmpty(), "Wrong OLStack level!");
+ mOLStack.RemoveElementAt(mOLStack.Length() - 1);
+ if (!IsInOLOrUL()) {
mFloatingLines = 1;
mLineBreakDue = true;
}
@@ -1860,6 +1861,10 @@ nsPlainTextSerializer::IsInOL()
return false;
}
+bool nsPlainTextSerializer::IsInOLOrUL() const {
+ return (mULCount > 0) || !mOLStack.IsEmpty();
+}
+
/*
@return 0 = no header, 1 = h1, ..., 6 = h6
*/
diff --git a/dom/base/nsPlainTextSerializer.h b/dom/base/nsPlainTextSerializer.h
index 95cf5590c..650a8e3e7 100644
--- a/dom/base/nsPlainTextSerializer.h
+++ b/dom/base/nsPlainTextSerializer.h
@@ -61,6 +61,7 @@ public:
mozilla::dom::Element* aOriginalElement,
nsAString& aStr) override;
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
nsAString& aStr) override;
NS_IMETHOD Flush(nsAString& aStr) override;
@@ -80,6 +81,7 @@ private:
void Write(const nsAString& aString);
bool IsInPre();
bool IsInOL();
+ bool IsInOLOrUL() const;
bool IsCurrentNodeConverted();
bool MustSuppressLeaf();
@@ -217,8 +219,7 @@ private:
uint32_t mIgnoreAboveIndex;
// The stack for ordered lists
- int32_t *mOLStack;
- uint32_t mOLStackIndex;
+ AutoTArray<int32_t, 100> mOLStack;
uint32_t mULCount;
diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp
index 1e23d6c5f..3ac00142d 100644
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -654,6 +654,19 @@ nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument,
}
bool
+nsScriptLoader::ModuleScriptsEnabled()
+{
+ static bool sEnabledForContent = false;
+ static bool sCachedPref = false;
+ if (!sCachedPref) {
+ sCachedPref = true;
+ Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false);
+ }
+
+ return nsContentUtils::IsChromeDoc(mDocument) || sEnabledForContent;
+}
+
+bool
nsScriptLoader::ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const
{
// Returns whether we have fetched, or are currently fetching, a module script
@@ -1230,15 +1243,27 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell));
nsSecurityFlags securityFlags;
- // TODO: the spec currently gives module scripts different CORS behaviour to
- // classic scripts.
- securityFlags = aRequest->mCORSMode == CORS_NONE
- ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
- : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
- if (aRequest->mCORSMode == CORS_ANONYMOUS) {
- securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
- } else if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) {
- securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
+ if (aRequest->IsModuleRequest()) {
+ // According to the spec, module scripts have different behaviour to classic
+ // scripts and always use CORS.
+ securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
+ if (aRequest->mCORSMode == CORS_NONE) {
+ securityFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
+ } else if (aRequest->mCORSMode == CORS_ANONYMOUS) {
+ securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
+ } else {
+ MOZ_ASSERT(aRequest->mCORSMode == CORS_USE_CREDENTIALS);
+ securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
+ }
+ } else {
+ securityFlags = aRequest->mCORSMode == CORS_NONE
+ ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
+ : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
+ if (aRequest->mCORSMode == CORS_ANONYMOUS) {
+ securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
+ } else if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) {
+ securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
+ }
}
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
@@ -1434,7 +1459,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
- // Step 12. Check that the script is not an eventhandler
+ // Step 13. Check that the script is not an eventhandler
if (IsScriptEventHandler(scriptContent)) {
return false;
}
@@ -1448,8 +1473,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
nsScriptKind scriptKind = nsScriptKind::Classic;
if (!type.IsEmpty()) {
- // Support type="module" only for chrome documents.
- if (nsContentUtils::IsChromeDoc(mDocument) && type.LowerCaseEqualsASCII("module")) {
+ if (ModuleScriptsEnabled() && type.LowerCaseEqualsASCII("module")) {
scriptKind = nsScriptKind::Module;
} else {
NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false);
@@ -1469,7 +1493,18 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
}
- // Step 14. in the HTML5 spec
+ // "In modern user agents that support module scripts, the script element with
+ // the nomodule attribute will be ignored".
+ // "The nomodule attribute must not be specified on module scripts (and will
+ // be ignored if it is)."
+ if (ModuleScriptsEnabled() &&
+ scriptKind == nsScriptKind::Classic &&
+ scriptContent->IsHTMLElement() &&
+ scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::nomodule)) {
+ return false;
+ }
+
+ // Step 15. and later in the HTML5 spec
nsresult rv = NS_OK;
RefPtr<nsScriptLoadRequest> request;
if (aElement->GetScriptExternal()) {
@@ -1577,7 +1612,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
return false;
}
- if (!aElement->GetParserCreated() && !request->IsModuleRequest()) {
+ if (!aElement->GetParserCreated()) {
// Violate the HTML5 spec in order to make LABjs and the "order" plug-in
// for RequireJS work with their Gecko-sniffed code path. See
// http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
@@ -2768,7 +2803,7 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
}
// TODO: Preload module scripts.
- if (nsContentUtils::IsChromeDoc(mDocument) && aType.LowerCaseEqualsASCII("module")) {
+ if (ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) {
return;
}
diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h
index d30a58441..a00239be5 100644
--- a/dom/base/nsScriptLoader.h
+++ b/dom/base/nsScriptLoader.h
@@ -568,6 +568,8 @@ private:
JS::SourceBufferHolder GetScriptSource(nsScriptLoadRequest* aRequest,
nsAutoString& inlineData);
+ bool ModuleScriptsEnabled();
+
void SetModuleFetchStarted(nsModuleLoadRequest *aRequest);
void SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadRequest *aRequest,
nsresult aResult);
diff --git a/dom/base/nsXHTMLContentSerializer.cpp b/dom/base/nsXHTMLContentSerializer.cpp
index 111ed46c7..0a39ef663 100755
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -514,6 +514,7 @@ nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
bool
nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
bool& aForceFormat,
nsAString& aStr)
{
@@ -532,7 +533,7 @@ nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement,
}
bool dummyFormat;
- return nsXMLContentSerializer::CheckElementEnd(aElement, dummyFormat, aStr);
+ return nsXMLContentSerializer::CheckElementEnd(aElement, aOriginalElement, dummyFormat, aStr);
}
bool
diff --git a/dom/base/nsXHTMLContentSerializer.h b/dom/base/nsXHTMLContentSerializer.h
index 7473ba074..79ecf28f1 100644
--- a/dom/base/nsXHTMLContentSerializer.h
+++ b/dom/base/nsXHTMLContentSerializer.h
@@ -53,6 +53,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
nsAString& aStr) override;
virtual bool CheckElementEnd(mozilla::dom::Element* aContent,
+ mozilla::dom::Element* aOriginalElement,
bool& aForceFormat,
nsAString& aStr) override;
diff --git a/dom/base/nsXMLContentSerializer.cpp b/dom/base/nsXMLContentSerializer.cpp
index 54fadaa94..f12bb8fdc 100644
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -1028,6 +1028,7 @@ nsXMLContentSerializer::AppendEndOfElementStart(Element* aElement,
NS_IMETHODIMP
nsXMLContentSerializer::AppendElementEnd(Element* aElement,
+ Element* aOriginalElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@@ -1035,7 +1036,7 @@ nsXMLContentSerializer::AppendElementEnd(Element* aElement,
nsIContent* content = aElement;
bool forceFormat = false, outputElementEnd;
- outputElementEnd = CheckElementEnd(aElement, forceFormat, aStr);
+ outputElementEnd = CheckElementEnd(aElement, aOriginalElement, forceFormat, aStr);
nsIAtom *name = content->NodeInfo()->NameAtom();
@@ -1161,16 +1162,14 @@ nsXMLContentSerializer::CheckElementStart(nsIContent * aContent,
bool
nsXMLContentSerializer::CheckElementEnd(Element* aElement,
+ Element* aOriginalElement,
bool& aForceFormat,
nsAString& aStr)
{
// We don't output a separate end tag for empty element
aForceFormat = false;
- // XXXbz this is a bit messed up, but by now we don't have our fixed-up
- // version of aElement anymore. Let's hope fixup never changes the localName
- // or namespace...
- return ElementNeedsSeparateEndTag(aElement, aElement);
+ return ElementNeedsSeparateEndTag(aElement, aOriginalElement);
}
bool
diff --git a/dom/base/nsXMLContentSerializer.h b/dom/base/nsXMLContentSerializer.h
index 941acb179..2f76b0892 100644
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -59,6 +59,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
nsAString& aStr) override;
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
nsAString& aStr) override;
NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; }
@@ -263,6 +264,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
* @return boolean true if the element can be output
*/
virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
+ mozilla::dom::Element* aOriginalElement,
bool& aForceFormat,
nsAString& aStr);
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index a26fc4422..b244d4d2a 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1968,8 +1968,6 @@ const js::ObjectOps sInterfaceObjectClassObjectOps = {
nullptr, /* setProperty */
nullptr, /* getOwnPropertyDescriptor */
nullptr, /* deleteProperty */
- nullptr, /* watch */
- nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
InterfaceObjectToString, /* funToString */
@@ -2978,42 +2976,6 @@ ConvertExceptionToPromise(JSContext* cx,
JSObject* promiseScope,
JS::MutableHandle<JS::Value> rval)
{
-#ifndef SPIDERMONKEY_PROMISE
- GlobalObject global(cx, promiseScope);
- if (global.Failed()) {
- return false;
- }
-
- JS::Rooted<JS::Value> exn(cx);
- if (!JS_GetPendingException(cx, &exn)) {
- // This is very important: if there is no pending exception here but we're
- // ending up in this code, that means the callee threw an uncatchable
- // exception. Just propagate that out as-is.
- return false;
- }
-
- JS_ClearPendingException(cx);
-
- nsCOMPtr<nsIGlobalObject> globalObj =
- do_QueryInterface(global.GetAsSupports());
- if (!globalObj) {
- ErrorResult rv;
- rv.Throw(NS_ERROR_UNEXPECTED);
- return !rv.MaybeSetPendingException(cx);
- }
-
- ErrorResult rv;
- RefPtr<Promise> promise = Promise::Reject(globalObj, cx, exn, rv);
- if (rv.MaybeSetPendingException(cx)) {
- // We just give up. We put the exception from the ErrorResult on
- // the JSContext just to make sure to not leak memory on the
- // ErrorResult, but now just put the original exception back.
- JS_SetPendingException(cx, exn);
- return false;
- }
-
- return GetOrCreateDOMReflector(cx, promise, rval);
-#else // SPIDERMONKEY_PROMISE
{
JSAutoCompartment ac(cx, promiseScope);
@@ -3039,7 +3001,6 @@ ConvertExceptionToPromise(JSContext* cx,
// Now make sure we rewrap promise back into the compartment we want
return JS_WrapValue(cx, rval);
-#endif // SPIDERMONKEY_PROMISE
}
/* static */
diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf
index 6f9733c5f..b00af2085 100644
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -694,10 +694,6 @@ DOMInterfaces = {
'headerFile': 'nsGeolocation.h'
},
-'Promise': {
- 'implicitJSContext': [ 'then', 'catch' ],
-},
-
'PromiseDebugging': {
'concrete': False,
},
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index d7d700a96..6b23e8225 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1135,6 +1135,12 @@ class CGHeaders(CGWrapper):
declareIncludes.add("mozilla/dom/Date.h")
else:
bindingHeaders.add("mozilla/dom/Date.h")
+ elif unrolled.isPromise():
+ # See comment in the isInterface() case for why we add
+ # Promise.h to headerSet, not bindingHeaders.
+ headerSet.add("mozilla/dom/Promise.h")
+ # We need ToJSValue to do the Promise to JS conversion.
+ bindingHeaders.add("mozilla/dom/ToJSValue.h")
elif unrolled.isInterface():
if unrolled.isSpiderMonkeyInterface():
bindingHeaders.add("jsfriendapi.h")
@@ -1352,7 +1358,11 @@ def UnionTypes(unionTypes, config):
headers.add("mozilla/dom/Nullable.h")
isSequence = f.isSequence()
f = f.unroll()
- if f.isInterface():
+ if f.isPromise():
+ headers.add("mozilla/dom/Promise.h")
+ # We need ToJSValue to do the Promise to JS conversion.
+ headers.add("mozilla/dom/ToJSValue.h")
+ elif f.isInterface():
if f.isSpiderMonkeyInterface():
headers.add("jsfriendapi.h")
headers.add("mozilla/dom/TypedArray.h")
@@ -1434,7 +1444,11 @@ def UnionConversions(unionTypes, config):
def addHeadersForType(f):
f = f.unroll()
- if f.isInterface():
+ if f.isPromise():
+ headers.add("mozilla/dom/Promise.h")
+ # We need ToJSValue to do the Promise to JS conversion.
+ headers.add("mozilla/dom/ToJSValue.h")
+ elif f.isInterface():
if f.isSpiderMonkeyInterface():
headers.add("jsfriendapi.h")
headers.add("mozilla/dom/TypedArray.h")
@@ -3052,23 +3066,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
else:
unforgeableHolderSetup = None
- if self.descriptor.name == "Promise":
- speciesSetup = CGGeneric(fill(
- """
- #ifndef SPIDERMONKEY_PROMISE
- JS::Rooted<JSObject*> promiseConstructor(aCx, *interfaceCache);
- JS::Rooted<jsid> species(aCx,
- SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::species)));
- if (!JS_DefinePropertyById(aCx, promiseConstructor, species, JS::UndefinedHandleValue,
- JSPROP_SHARED, Promise::PromiseSpecies, nullptr)) {
- $*{failureCode}
- }
- #endif // SPIDERMONKEY_PROMISE
- """,
- failureCode=failureCode))
- else:
- speciesSetup = None
-
if (self.descriptor.interface.isOnGlobalProtoChain() and
needInterfacePrototypeObject):
makeProtoPrototypeImmutable = CGGeneric(fill(
@@ -3094,7 +3091,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
return CGList(
[getParentProto, getConstructorProto, initIds,
prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup,
- speciesSetup, makeProtoPrototypeImmutable],
+ makeProtoPrototypeImmutable],
"\n").define()
@@ -5244,6 +5241,139 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
holderArgs=holderArgs,
dealWithOptional=isOptional and (not nullable or isOwningUnion))
+ if type.isPromise():
+ assert not type.nullable()
+ assert defaultValue is None
+
+ # We always have to hold a strong ref to Promise here, because
+ # Promise::resolve returns an addrefed thing.
+ argIsPointer = isCallbackReturnValue
+ if argIsPointer:
+ declType = CGGeneric("RefPtr<Promise>")
+ else:
+ declType = CGGeneric("OwningNonNull<Promise>")
+
+ # Per spec, what we're supposed to do is take the original
+ # Promise.resolve and call it with the original Promise as this
+ # value to make a Promise out of whatever value we actually have
+ # here. The question is which global we should use. There are
+ # several cases to consider:
+ #
+ # 1) Normal call to API with a Promise argument. This is a case the
+ # spec covers, and we should be using the current Realm's
+ # Promise. That means the current compartment.
+ # 2) Call to API with a Promise argument over Xrays. In practice,
+ # this sort of thing seems to be used for giving an API
+ # implementation a way to wait for conclusion of an asyc
+ # operation, _not_ to expose the Promise to content code. So we
+ # probably want to allow callers to use such an API in a
+ # "natural" way, by passing chrome-side promises; indeed, that
+ # may be all that the caller has to represent their async
+ # operation. That means we really need to do the
+ # Promise.resolve() in the caller (chrome) compartment: if we do
+ # it in the content compartment, we will try to call .then() on
+ # the chrome promise while in the content compartment, which will
+ # throw and we'll just get a rejected Promise. Note that this is
+ # also the reason why a caller who has a chrome Promise
+ # representing an async operation can't itself convert it to a
+ # content-side Promise (at least not without some serious
+ # gyrations).
+ # 3) Promise return value from a callback or callback interface.
+ # Per spec, this should use the Realm of the callback object. In
+ # our case, that's the compartment of the underlying callback,
+ # not the current compartment (which may be the compartment of
+ # some cross-compartment wrapper around said callback).
+ # 4) Return value from a JS-implemented interface. In this case we
+ # have a problem. Our current compartment is the compartment of
+ # the JS implementation. But if the JS implementation returned
+ # a page-side Promise (which is a totally sane thing to do, and
+ # in fact the right thing to do given that this return value is
+ # going right to content script) then we don't want to
+ # Promise.resolve with our current compartment Promise, because
+ # that will wrap it up in a chrome-side Promise, which is
+ # decidedly _not_ what's desired here. So in that case we
+ # should really unwrap the return value and use the global of
+ # the result. CheckedUnwrap should be good enough for that; if
+ # it fails, then we're failing unwrap while in a
+ # system-privileged compartment, so presumably we have a dead
+ # object wrapper. Just error out. Do NOT fall back to using
+ # the current compartment instead: that will return a
+ # system-privileged rejected (because getting .then inside
+ # resolve() failed) Promise to the caller, which they won't be
+ # able to touch. That's not helpful. If we error out, on the
+ # other hand, they will get a content-side rejected promise.
+ # Same thing if the value returned is not even an object.
+ if isCallbackReturnValue == "JSImpl":
+ # Case 4 above. Note that globalObj defaults to the current
+ # compartment global. Note that we don't use $*{exceptionCode}
+ # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
+ # which we don't really want here.
+ assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
+ getPromiseGlobal = fill(
+ """
+ if (!$${val}.isObject()) {
+ aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
+ return nullptr;
+ }
+ JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
+ if (!unwrappedVal) {
+ // A slight lie, but not much of one, for a dead object wrapper.
+ aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
+ return nullptr;
+ }
+ globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
+ """,
+ sourceDescription=sourceDescription)
+ elif isCallbackReturnValue == "Callback":
+ getPromiseGlobal = dedent(
+ """
+ // We basically want our entry global here. Play it safe
+ // and use GetEntryGlobal() to get it, with whatever
+ // principal-clamping it ends up doing.
+ globalObj = GetEntryGlobal()->GetGlobalJSObject();
+ """)
+ else:
+ getPromiseGlobal = ""
+
+ templateBody = fill(
+ """
+ { // Scope for our GlobalObject, FastErrorResult, JSAutoCompartment,
+ // etc.
+
+ JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
+ $*{getPromiseGlobal}
+ JSAutoCompartment ac(cx, globalObj);
+ GlobalObject promiseGlobal(cx, globalObj);
+ if (promiseGlobal.Failed()) {
+ $*{exceptionCode}
+ }
+
+ JS::Rooted<JS::Value> valueToResolve(cx, $${val});
+ if (!JS_WrapValue(cx, &valueToResolve)) {
+ $*{exceptionCode}
+ }
+ binding_detail::FastErrorResult promiseRv;
+ nsCOMPtr<nsIGlobalObject> global =
+ do_QueryInterface(promiseGlobal.GetAsSupports());
+ if (!global) {
+ promiseRv.Throw(NS_ERROR_UNEXPECTED);
+ promiseRv.MaybeSetPendingException(cx);
+ $*{exceptionCode}
+ }
+ $${declName} = Promise::Resolve(global, cx, valueToResolve,
+ promiseRv);
+ if (promiseRv.MaybeSetPendingException(cx)) {
+ $*{exceptionCode}
+ }
+ }
+ """,
+ getPromiseGlobal=getPromiseGlobal,
+ exceptionCode=exceptionCode)
+
+ return JSToNativeConversionInfo(templateBody,
+ declType=declType,
+ dealWithOptional=isOptional)
+
if type.isGeckoInterface():
assert not isEnforceRange and not isClamp
@@ -5282,12 +5412,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# Also, callback return values always end up addrefing anyway, so there
# is no point trying to avoid it here and it makes other things simpler
# since we can assume the return value is a strong ref.
- #
- # Finally, promises need to hold a strong ref because that's what
- # Promise.resolve returns.
assert not descriptor.interface.isCallback()
- isPromise = descriptor.interface.identifier.name == "Promise"
- forceOwningType = isMember or isCallbackReturnValue or isPromise
+ forceOwningType = isMember or isCallbackReturnValue
typeName = descriptor.nativeType
typePtr = typeName + "*"
@@ -5315,143 +5441,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if forceOwningType:
templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
- if isPromise:
- # Per spec, what we're supposed to do is take the original
- # Promise.resolve and call it with the original Promise as this
- # value to make a Promise out of whatever value we actually have
- # here. The question is which global we should use. There are
- # several cases to consider:
- #
- # 1) Normal call to API with a Promise argument. This is a case the
- # spec covers, and we should be using the current Realm's
- # Promise. That means the current compartment.
- # 2) Call to API with a Promise argument over Xrays. In practice,
- # this sort of thing seems to be used for giving an API
- # implementation a way to wait for conclusion of an asyc
- # operation, _not_ to expose the Promise to content code. So we
- # probably want to allow callers to use such an API in a
- # "natural" way, by passing chrome-side promises; indeed, that
- # may be all that the caller has to represent their async
- # operation. That means we really need to do the
- # Promise.resolve() in the caller (chrome) compartment: if we do
- # it in the content compartment, we will try to call .then() on
- # the chrome promise while in the content compartment, which will
- # throw and we'll just get a rejected Promise. Note that this is
- # also the reason why a caller who has a chrome Promise
- # representing an async operation can't itself convert it to a
- # content-side Promise (at least not without some serious
- # gyrations).
- # 3) Promise return value from a callback or callback interface.
- # This is in theory a case the spec covers but in practice it
- # really doesn't define behavior here because it doesn't define
- # what Realm we're in after the callback returns, which is when
- # the argument conversion happens. We will use the current
- # compartment, which is the compartment of the callable (which
- # may itself be a cross-compartment wrapper itself), which makes
- # as much sense as anything else. In practice, such an API would
- # once again be providing a Promise to signal completion of an
- # operation, which would then not be exposed to anyone other than
- # our own implementation code.
- # 4) Return value from a JS-implemented interface. In this case we
- # have a problem. Our current compartment is the compartment of
- # the JS implementation. But if the JS implementation returned
- # a page-side Promise (which is a totally sane thing to do, and
- # in fact the right thing to do given that this return value is
- # going right to content script) then we don't want to
- # Promise.resolve with our current compartment Promise, because
- # that will wrap it up in a chrome-side Promise, which is
- # decidedly _not_ what's desired here. So in that case we
- # should really unwrap the return value and use the global of
- # the result. CheckedUnwrap should be good enough for that; if
- # it fails, then we're failing unwrap while in a
- # system-privileged compartment, so presumably we have a dead
- # object wrapper. Just error out. Do NOT fall back to using
- # the current compartment instead: that will return a
- # system-privileged rejected (because getting .then inside
- # resolve() failed) Promise to the caller, which they won't be
- # able to touch. That's not helpful. If we error out, on the
- # other hand, they will get a content-side rejected promise.
- # Same thing if the value returned is not even an object.
- if isCallbackReturnValue == "JSImpl":
- # Case 4 above. Note that globalObj defaults to the current
- # compartment global. Note that we don't use $*{exceptionCode}
- # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
- # which we don't really want here.
- assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
- getPromiseGlobal = fill(
- """
- if (!$${val}.isObject()) {
- aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
- return nullptr;
- }
- JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
- if (!unwrappedVal) {
- // A slight lie, but not much of one, for a dead object wrapper.
- aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
- return nullptr;
- }
- globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
- """,
- sourceDescription=sourceDescription)
- else:
- getPromiseGlobal = ""
-
- templateBody = fill(
- """
- { // Scope for our GlobalObject, FastErrorResult, JSAutoCompartment,
- // etc.
-
- JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
- $*{getPromiseGlobal}
- JSAutoCompartment ac(cx, globalObj);
- GlobalObject promiseGlobal(cx, globalObj);
- if (promiseGlobal.Failed()) {
- $*{exceptionCode}
- }
-
- JS::Rooted<JS::Value> valueToResolve(cx, $${val});
- if (!JS_WrapValue(cx, &valueToResolve)) {
- $*{exceptionCode}
- }
- binding_detail::FastErrorResult promiseRv;
- #ifdef SPIDERMONKEY_PROMISE
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(promiseGlobal.GetAsSupports());
- if (!global) {
- promiseRv.Throw(NS_ERROR_UNEXPECTED);
- promiseRv.MaybeSetPendingException(cx);
- $*{exceptionCode}
- }
- $${declName} = Promise::Resolve(global, cx, valueToResolve,
- promiseRv);
- if (promiseRv.MaybeSetPendingException(cx)) {
- $*{exceptionCode}
- }
- #else
- JS::Handle<JSObject*> promiseCtor =
- PromiseBinding::GetConstructorObjectHandle(cx);
- if (!promiseCtor) {
- $*{exceptionCode}
- }
- JS::Rooted<JS::Value> resolveThisv(cx, JS::ObjectValue(*promiseCtor));
- JS::Rooted<JS::Value> resolveResult(cx);
- Promise::Resolve(promiseGlobal, resolveThisv, valueToResolve,
- &resolveResult, promiseRv);
- if (promiseRv.MaybeSetPendingException(cx)) {
- $*{exceptionCode}
- }
- nsresult unwrapRv = UNWRAP_OBJECT(Promise, &resolveResult.toObject(), $${declName});
- if (NS_FAILED(unwrapRv)) { // Quite odd
- promiseRv.Throw(unwrapRv);
- promiseRv.MaybeSetPendingException(cx);
- $*{exceptionCode}
- }
- #endif // SPIDERMONKEY_PROMISE
- }
- """,
- getPromiseGlobal=getPromiseGlobal,
- exceptionCode=exceptionCode)
- elif not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
+ if (not descriptor.interface.isConsequential() and
+ not descriptor.interface.isExternal()):
if failureCode is not None:
templateBody += str(CastableObjectUnwrapper(
descriptor,
@@ -5491,24 +5482,12 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# And store our value in ${declName}
templateBody += "${declName} = ${holderName};\n"
- if isPromise:
- if type.nullable():
- codeToSetNull = "${declName} = nullptr;\n"
- templateBody = CGIfElseWrapper(
- "${val}.isNullOrUndefined()",
- CGGeneric(codeToSetNull),
- CGGeneric(templateBody)).define()
- if isinstance(defaultValue, IDLNullValue):
- templateBody = handleDefault(templateBody, codeToSetNull)
- else:
- assert defaultValue is None
- else:
- # Just pass failureCode, not onFailureBadType, here, so we'll report
- # the thing as not an object as opposed to not implementing whatever
- # our interface is.
- templateBody = wrapObjectTemplate(templateBody, type,
- "${declName} = nullptr;\n",
- failureCode)
+ # Just pass failureCode, not onFailureBadType, here, so we'll report
+ # the thing as not an object as opposed to not implementing whatever
+ # our interface is.
+ templateBody = wrapObjectTemplate(templateBody, type,
+ "${declName} = nullptr;\n",
+ failureCode)
declType = CGGeneric(declType)
if holderType is not None:
@@ -6575,6 +6554,19 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return (code, False)
+ if type.isPromise():
+ assert not type.nullable()
+ # The use of ToJSValue here is a bit annoying because the Promise
+ # version is not inlined, but we can't put an inline version in either
+ # ToJSValue.h or BindingUtils.h, because Promise.h includes ToJSValue.h
+ # and that includes BindingUtils.h, so we'd get an include loop if
+ # either of those headers included Promise.h. Trying to write the
+ # conversion by hand here is annoying because we'd have to handle
+ # the various RefPtr, rawptr, NonNull, etc. cases, which ToJSValue will
+ # already handle for us, so we just use the function call.
+ return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result),
+ False)
+
if type.isGeckoInterface() and not type.isCallbackInterface():
descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
if type.nullable():
@@ -6589,14 +6581,6 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
wrapMethod = "GetOrCreateDOMReflector"
wrapArgs = "cx, %s, ${jsvalHandle}" % result
else:
- # Hack: the "Promise" interface is OK to return from
- # non-newobject things even when it's not wrappercached; that
- # happens when using SpiderMonkey promises, and the WrapObject()
- # method will just return the existing reflector, which is just
- # not stored in a wrappercache.
- if (not returnsNewObject and
- descriptor.interface.identifier.name != "Promise"):
- raise MethodNotNewObjectError(descriptor.interface.identifier.name)
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrapArgs = "cx, ${obj}, %s, ${jsvalHandle}" % result
if isConstructorRetval:
@@ -6912,14 +6896,17 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
if returnType.nullable():
result = CGTemplatedType("Nullable", result)
return result, None, None, None, None
- if returnType.isGeckoInterface():
- result = CGGeneric(descriptorProvider.getDescriptor(
- returnType.unroll().inner.identifier.name).nativeType)
- conversion = None
+ if returnType.isGeckoInterface() or returnType.isPromise():
+ if returnType.isGeckoInterface():
+ typeName = descriptorProvider.getDescriptor(
+ returnType.unroll().inner.identifier.name).nativeType
+ else:
+ typeName = "Promise"
if isMember:
- result = CGGeneric("StrongPtrForMember<%s>::Type" % result.define())
+ conversion = None
+ result = CGGeneric("StrongPtrForMember<%s>::Type" % typeName)
else:
- conversion = CGGeneric("StrongOrRawPtr<%s>" % result.define())
+ conversion = CGGeneric("StrongOrRawPtr<%s>" % typeName)
result = CGGeneric("auto")
return result, None, None, None, conversion
if returnType.isCallback():
@@ -7084,7 +7071,9 @@ class CGCallGenerator(CGThing):
if needsConst(a):
arg = CGWrapper(arg, pre="Constify(", post=")")
# And convert NonNull<T> to T&
- if (((a.type.isGeckoInterface() or a.type.isCallback()) and not a.type.nullable()) or
+ if (((a.type.isGeckoInterface() or a.type.isCallback() or
+ a.type.isPromise()) and
+ not a.type.nullable()) or
a.type.isDOMString()):
arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
args.append(arg)
@@ -7208,6 +7197,9 @@ class CGCallGenerator(CGThing):
def getUnionMemberName(type):
+ # Promises can't be in unions, because they're not distinguishable
+ # from anything else.
+ assert not type.isPromise()
if type.isGeckoInterface():
return type.inner.identifier.name
if type.isEnum():
@@ -7337,8 +7329,9 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None
if (type.isString() or type.isPrimitive() or type.isEnum() or
- type.isGeckoInterface() or type.isCallback() or type.isDate()):
- # All of these don't need wrapping
+ type.isGeckoInterface() or type.isCallback() or type.isDate() or
+ type.isPromise()):
+ # All of these don't need wrapping.
return None
raise TypeError("Unknown type; we don't know how to wrap it in constructor "
@@ -7476,58 +7469,12 @@ class CGPerSignatureCall(CGThing):
if needsCx:
argsPre.append("cx")
- # Hack for making Promise.prototype.then work well over Xrays.
- if (not idlNode.isStatic() and
- descriptor.name == "Promise" and
- idlNode.isMethod() and
- idlNode.identifier.name == "then"):
- cgThings.append(CGGeneric(dedent(
- """
- JS::Rooted<JSObject*> calleeGlobal(cx, xpc::XrayAwareCalleeGlobal(&args.callee()));
- """)))
- argsPre.append("calleeGlobal")
-
needsUnwrap = False
argsPost = []
if isConstructor:
- if descriptor.name == "Promise":
- # Hack for Promise for now: pass in our desired proto so the
- # implementation can create the reflector with the right proto.
- argsPost.append("desiredProto")
- # Also, we do not want to enter the content compartment when the
- # Promise constructor is called via Xrays, because we want to
- # create our callback functions that we will hand to our caller
- # in the Xray compartment. The reason we want to do that is the
- # following situation, over Xrays:
- #
- # contentWindow.Promise.race([Promise.resolve(5)])
- #
- # Ideally this would work. Internally, race() does a
- # contentWindow.Promise.resolve() on everything in the array.
- # Per spec, to support subclassing,
- # contentWindow.Promise.resolve has to do:
- #
- # var resolve, reject;
- # var p = new contentWindow.Promise(function(a, b) {
- # resolve = a;
- # reject = b;
- # });
- # resolve(arg);
- # return p;
- #
- # where "arg" is, in this case, the chrome-side return value of
- # Promise.resolve(5). But if the "resolve" function in that
- # case were created in the content compartment, then calling it
- # would wrap "arg" in an opaque wrapper, and that function tries
- # to get .then off the argument, which would throw. So we need
- # to create the "resolve" function in the chrome compartment,
- # and hence want to be running the entire Promise constructor
- # (which creates that function) in the chrome compartment in
- # this case. So don't set needsUnwrap here.
- else:
- needsUnwrap = True
- needsUnwrappedVar = False
- unwrappedVar = "obj"
+ needsUnwrap = True
+ needsUnwrappedVar = False
+ unwrappedVar = "obj"
elif descriptor.interface.isJSImplemented():
if not idlNode.isStatic():
needsUnwrap = True
@@ -7540,11 +7487,6 @@ class CGPerSignatureCall(CGThing):
needsUnwrappedVar = True
argsPre.append("unwrappedObj ? *unwrappedObj : obj")
- if idlNode.isStatic() and not isConstructor and descriptor.name == "Promise":
- # Hack for Promise for now: pass in the "this" value to
- # Promise static methods.
- argsPre.append("args.thisv()")
-
if needsUnwrap and needsUnwrappedVar:
# We cannot assign into obj because it's a Handle, not a
# MutableHandle, so we need a separate Rooted.
@@ -7687,7 +7629,8 @@ class CGPerSignatureCall(CGThing):
returnsNewObject = memberReturnsNewObject(self.idlNode)
if (returnsNewObject and
- self.returnType.isGeckoInterface()):
+ (self.returnType.isGeckoInterface() or
+ self.returnType.isPromise())):
wrapCode += dedent(
"""
static_assert(!IsPointer<decltype(result)>::value,
@@ -9493,6 +9436,8 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_OBJECT"
if t.isRecord():
return "JSVAL_TYPE_OBJECT"
+ if t.isPromise():
+ return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT"
if t.isString():
@@ -9566,6 +9511,8 @@ class CGMemberJITInfo(CGThing):
return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner)
if t.isSequence():
return "JSJitInfo::Object"
+ if t.isPromise():
+ return "JSJitInfo::Object"
if t.isGeckoInterface():
return "JSJitInfo::Object"
if t.isString():
@@ -9752,6 +9699,10 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
# Flat member types have already unwrapped nullables.
assert not type.nullable()
+ # Promise types can never appear in unions, because Promise is not
+ # distinguishable from anything.
+ assert not type.isPromise()
+
if type.isSequence() or type.isRecord():
if type.isSequence():
wrapperType = "Sequence"
@@ -13169,9 +13120,9 @@ class CGDictionary(CGThing):
# continues to match the list in test_Object.prototype_props.html
if (member.identifier.name in
["constructor", "toSource", "toString", "toLocaleString", "valueOf",
- "watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
- "propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
- "__lookupGetter__", "__lookupSetter__", "__proto__"]):
+ "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
+ "__defineGetter__", "__defineSetter__", "__lookupGetter__",
+ "__lookupSetter__", "__proto__"]):
raise TypeError("'%s' member of %s dictionary shadows "
"a property of Object.prototype, and Xrays to "
"Object can't handle that.\n"
@@ -13660,6 +13611,8 @@ class ForwardDeclarationBuilder:
# Note: Spidermonkey interfaces are typedefs, so can't be
# forward-declared
+ elif t.isPromise():
+ self.addInMozillaDom("Promise")
elif t.isCallback():
self.addInMozillaDom(t.callback.identifier.name)
elif t.isDictionary():
@@ -14114,10 +14067,13 @@ class CGNativeMember(ClassMethod):
else:
defaultValue = "%s(0)" % enumName
return enumName, defaultValue, "return ${declName};\n"
- if type.isGeckoInterface():
- iface = type.unroll().inner
- result = CGGeneric(self.descriptorProvider.getDescriptor(
- iface.identifier.name).prettyNativeType)
+ if type.isGeckoInterface() or type.isPromise():
+ if type.isGeckoInterface():
+ iface = type.unroll().inner
+ result = CGGeneric(self.descriptorProvider.getDescriptor(
+ iface.identifier.name).prettyNativeType)
+ else:
+ result = CGGeneric("Promise")
if self.resultAlreadyAddRefed:
if isMember:
holder = "RefPtr"
@@ -14320,11 +14276,18 @@ class CGNativeMember(ClassMethod):
# auto-wrapping in Nullable
return CGUnionStruct.unionTypeDecl(type, isMember), True, False
+ if type.isPromise():
+ assert not type.nullable()
+ if optional or isMember:
+ typeDecl = "OwningNonNull<Promise>"
+ else:
+ typeDecl = "Promise&"
+ return (typeDecl, False, False)
+
if type.isGeckoInterface() and not type.isCallbackInterface():
iface = type.unroll().inner
argIsPointer = type.nullable() or iface.isExternal()
- forceOwningType = (iface.isCallback() or isMember or
- iface.identifier.name == "Promise")
+ forceOwningType = (iface.isCallback() or isMember)
if argIsPointer:
if (optional or isMember) and forceOwningType:
typeDecl = "RefPtr<%s>"
@@ -16958,7 +16921,10 @@ class CGEventGetter(CGNativeMember):
def getMethodBody(self):
type = self.member.type
memberName = CGDictionary.makeMemberName(self.member.identifier.name)
- if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
+ if ((type.isPrimitive() and type.tag() in builtinNames) or
+ type.isEnum() or
+ type.isPromise() or
+ type.isGeckoInterface()):
return "return " + memberName + ";\n"
if type.isDOMString() or type.isByteString() or type.isUSVString():
return "aRetVal = " + memberName + ";\n"
@@ -17369,6 +17335,8 @@ class CGEventClass(CGBindingImplClass):
nativeType = CGGeneric("nsString")
elif type.isByteString():
nativeType = CGGeneric("nsCString")
+ elif type.isPromise():
+ nativeType = CGGeneric("RefPtr<Promise>")
elif type.isGeckoInterface():
iface = type.unroll().inner
nativeType = self.descriptor.getDescriptor(
@@ -17393,7 +17361,7 @@ class CGEventClass(CGBindingImplClass):
innerType = type.inner
if (not innerType.isPrimitive() and not innerType.isEnum() and
not innerType.isDOMString() and not innerType.isByteString() and
- not innerType.isGeckoInterface()):
+ not innerType.isPromise() and not innerType.isGeckoInterface()):
raise TypeError("Don't know how to properly manage GC/CC for "
"event member of type %s" %
type)
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index f80c19c33..a56f2f2fd 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -468,13 +468,6 @@ class Descriptor(DescriptorProvider):
self.wrapperCache = (not self.interface.isCallback() and
not self.interface.isIteratorInterface() and
desc.get('wrapperCache', True))
- # Nasty temporary hack for supporting both DOM and SpiderMonkey promises
- # without too much pain
- if self.interface.identifier.name == "Promise":
- assert self.wrapperCache
- # But really, we're only wrappercached if we have an interface
- # object (that is, when we're not using SpiderMonkey promises).
- self.wrapperCache = self.interface.hasInterfaceObject()
self.name = interface.identifier.name
diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp
index 23f0abd88..49281c1c2 100644
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -275,19 +275,6 @@ DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
}
bool
-BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
- JS::Handle<JSObject*> callable) const
-{
- return js::WatchGuts(cx, proxy, id, callable);
-}
-
-bool
-BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
-{
- return js::UnwatchGuts(cx, proxy, id);
-}
-
-bool
BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const
diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h
index 1781649cc..e3e151b7a 100644
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -72,11 +72,6 @@ public:
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector &props) const override;
- bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
- JS::Handle<JSObject*> callable) const override;
- bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id) const override;
-
protected:
// Hook for subclasses to implement shared ownPropertyKeys()/keys()
// functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg
index 142ccfdd6..c47f75875 100644
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -84,11 +84,6 @@ MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to sho
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")
MSG_DEF(MSG_INVALID_KEYFRAME_OFFSETS, 0, JSEXN_TYPEERR, "Keyframes with specified offsets must be in order and all be in the range [0, 1].")
-MSG_DEF(MSG_ILLEGAL_PROMISE_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Non-constructor value passed to NewPromiseCapability.")
-MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
-MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
-MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
-MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
diff --git a/dom/bindings/ToJSValue.cpp b/dom/bindings/ToJSValue.cpp
index d84428fb3..7afff41e2 100644
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -7,9 +7,7 @@
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/Exceptions.h"
-#ifdef SPIDERMONKEY_PROMISE
#include "mozilla/dom/Promise.h"
-#endif // SPIDERMONKEY_PROMISE
#include "nsAString.h"
#include "nsContentUtils.h"
#include "nsStringBuffer.h"
@@ -66,15 +64,13 @@ ToJSValue(JSContext* aCx,
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
bool
ToJSValue(JSContext* aCx, Promise& aArgument,
JS::MutableHandle<JS::Value> aValue)
{
aValue.setObject(*aArgument.PromiseObj());
- return true;
+ return MaybeWrapObjectValue(aCx, aValue);
}
-#endif // SPIDERMONKEY_PROMISE
} // namespace dom
} // namespace mozilla
diff --git a/dom/bindings/ToJSValue.h b/dom/bindings/ToJSValue.h
index 2021c0b4c..76e91c7bc 100644
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -306,13 +306,11 @@ ToJSValue(JSContext* aCx,
return ToJSValue(aCx, *aArgument, aValue);
}
-#ifdef SPIDERMONKEY_PROMISE
// Accept Promise objects, which need special handling.
MOZ_MUST_USE bool
ToJSValue(JSContext* aCx,
Promise& aArgument,
JS::MutableHandle<JS::Value> aValue);
-#endif // SPIDERMONKEY_PROMISE
// Accept arrays of other things we accept
template <typename T>
diff --git a/dom/bindings/TypedArray.h b/dom/bindings/TypedArray.h
index a86abcd9d..75313e255 100644
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -344,7 +344,7 @@ typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBuffer
// A class for converting an nsTArray to a TypedArray
// Note: A TypedArrayCreator must not outlive the nsTArray it was created from.
// So this is best used to pass from things that understand nsTArray to
-// things that understand TypedArray, as with Promise::ArgumentToJSValue.
+// things that understand TypedArray, as with ToJSValue.
template<typename TypedArrayType>
class TypedArrayCreator
{
diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py
index 8c32a8738..4f602365b 100644
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1597,11 +1597,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
args = attr.args() if attr.hasArgs() else []
- if self.identifier.name == "Promise":
- promiseType = BuiltinTypes[IDLBuiltinType.Types.any]
- else:
- promiseType = None
- retType = IDLWrapperType(self.location, self, promiseType)
+ retType = IDLWrapperType(self.location, self)
if identifier == "Constructor" or identifier == "ChromeConstructor":
name = "constructor"
@@ -1988,7 +1984,8 @@ class IDLType(IDLObject):
'callback',
'union',
'sequence',
- 'record'
+ 'record',
+ 'promise'
)
def __init__(self, location, name):
@@ -2142,9 +2139,8 @@ class IDLUnresolvedType(IDLType):
Unresolved types are interface types
"""
- def __init__(self, location, name, promiseInnerType=None):
+ def __init__(self, location, name):
IDLType.__init__(self, location, name)
- self._promiseInnerType = promiseInnerType
def isComplete(self):
return False
@@ -2171,11 +2167,8 @@ class IDLUnresolvedType(IDLType):
assert self.name.name == obj.identifier.name
return IDLCallbackType(self.location, obj)
- if self._promiseInnerType and not self._promiseInnerType.isComplete():
- self._promiseInnerType = self._promiseInnerType.complete(scope)
-
name = self.name.resolve(scope, None)
- return IDLWrapperType(self.location, obj, self._promiseInnerType)
+ return IDLWrapperType(self.location, obj)
def isDistinguishableFrom(self, other):
raise TypeError("Can't tell whether an unresolved type is or is not "
@@ -2285,7 +2278,9 @@ class IDLNullableType(IDLParameterizedType):
return self.inner.isInterface()
def isPromise(self):
- return self.inner.isPromise()
+ # There is no such thing as a nullable Promise.
+ assert not self.inner.isPromise()
+ return False
def isCallbackInterface(self):
return self.inner.isCallbackInterface()
@@ -2698,13 +2693,11 @@ class IDLTypedef(IDLObjectWithIdentifier):
class IDLWrapperType(IDLType):
- def __init__(self, location, inner, promiseInnerType=None):
+ def __init__(self, location, inner):
IDLType.__init__(self, location, inner.identifier.name)
self.inner = inner
self._identifier = inner.identifier
self.builtin = False
- assert not promiseInnerType or inner.identifier.name == "Promise"
- self._promiseInnerType = promiseInnerType
def __eq__(self, other):
return (isinstance(other, IDLWrapperType) and
@@ -2754,14 +2747,6 @@ class IDLWrapperType(IDLType):
def isEnum(self):
return isinstance(self.inner, IDLEnum)
- def isPromise(self):
- return (isinstance(self.inner, IDLInterface) and
- self.inner.identifier.name == "Promise")
-
- def promiseInnerType(self):
- assert self.isPromise()
- return self._promiseInnerType
-
def isSerializable(self):
if self.isInterface():
if self.inner.isExternal():
@@ -2793,8 +2778,6 @@ class IDLWrapperType(IDLType):
assert False
def isDistinguishableFrom(self, other):
- if self.isPromise():
- return False
if other.isPromise():
return False
if other.isUnion():
@@ -2841,10 +2824,6 @@ class IDLWrapperType(IDLType):
# Let's say true, though ideally we'd only do this when
# exposureSet contains the primary global's name.
return True
- if (self.isPromise() and
- # Check the internal type
- not self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)):
- return False
return iface.exposureSet.issuperset(exposureSet)
def _getDependentObjects(self):
@@ -2872,6 +2851,45 @@ class IDLWrapperType(IDLType):
return set()
+class IDLPromiseType(IDLParameterizedType):
+ def __init__(self, location, innerType):
+ IDLParameterizedType.__init__(self, location, "Promise", innerType)
+
+ def __eq__(self, other):
+ return (isinstance(other, IDLPromiseType) and
+ self.promiseInnerType() == other.promiseInnerType())
+
+ def __str__(self):
+ return self.inner.__str__() + "Promise"
+
+ def isPromise(self):
+ return True
+
+ def promiseInnerType(self):
+ return self.inner
+
+ def tag(self):
+ return IDLType.Tags.promise
+
+ def complete(self, scope):
+ self.inner = self.promiseInnerType().complete(scope)
+ return self
+
+ def unroll(self):
+ # We do not unroll our inner. Just stop at ourselves. That
+ # lets us add headers for both ourselves and our inner as
+ # needed.
+ return self
+
+ def isDistinguishableFrom(self, other):
+ # Promises are not distinguishable from anything.
+ return False
+
+ def isExposedInAllOf(self, exposureSet):
+ # Check the internal type
+ return self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)
+
+
class IDLBuiltinType(IDLType):
Types = enum(
@@ -3990,7 +4008,9 @@ class IDLAttribute(IDLInterfaceMember):
raise WebIDLError("An attribute with [PutForwards] must have an "
"interface type as its type", [self.location])
- if not self.type.isInterface() and self.getExtendedAttribute("SameObject"):
+ if (not self.type.isInterface() and
+ not self.type.isPromise() and
+ self.getExtendedAttribute("SameObject")):
raise WebIDLError("An attribute with [SameObject] must have an "
"interface type as its type", [self.location])
@@ -6394,17 +6414,13 @@ class Parser(Tokenizer):
type = IDLSequenceType(self.getLocation(p, 1), innerType)
p[0] = self.handleNullable(type, p[5])
- # Note: Promise<void> is allowed, so we want to parametrize on
- # ReturnType, not Type. Also, we want this to end up picking up
- # the Promise interface for now, hence the games with IDLUnresolvedType.
+ # Note: Promise<void> is allowed, so we want to parameterize on
+ # ReturnType, not Type. Promise types can't be null, hence no "Null" in there.
def p_NonAnyTypePromiseType(self, p):
"""
- NonAnyType : PROMISE LT ReturnType GT Null
+ NonAnyType : PROMISE LT ReturnType GT
"""
- innerType = p[3]
- promiseIdent = IDLUnresolvedIdentifier(self.getLocation(p, 1), "Promise")
- type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3])
- p[0] = self.handleNullable(type, p[5])
+ p[0] = IDLPromiseType(self.getLocation(p, 1), p[3])
def p_NonAnyTypeRecordType(self, p):
"""
@@ -6423,7 +6439,7 @@ class Parser(Tokenizer):
if p[1].name == "Promise":
raise WebIDLError("Promise used without saying what it's "
- "parametrized over",
+ "parameterized over",
[self.getLocation(p, 1)])
type = None
diff --git a/dom/bindings/parser/tests/test_distinguishability.py b/dom/bindings/parser/tests/test_distinguishability.py
index d7780c1ff..ac515a01d 100644
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -263,7 +263,6 @@ def WebIDLTest(parser, harness):
callback Callback2 = long(short arg);
dictionary Dict {};
dictionary Dict2 {};
- interface _Promise {};
interface TestInterface {%s
};
"""
diff --git a/dom/bindings/parser/tests/test_promise.py b/dom/bindings/parser/tests/test_promise.py
index 55bc07680..091381fab 100644
--- a/dom/bindings/parser/tests/test_promise.py
+++ b/dom/bindings/parser/tests/test_promise.py
@@ -2,7 +2,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
- interface _Promise {};
interface A {
legacycaller Promise<any> foo();
};
@@ -18,7 +17,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
- interface _Promise {};
interface A {
Promise<any> foo();
long foo(long arg);
@@ -35,7 +33,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
- interface _Promise {};
interface A {
long foo(long arg);
Promise<any> foo();
@@ -50,7 +47,6 @@ def WebIDLTest(parser, harness):
parser = parser.reset()
parser.parse("""
- interface _Promise {};
interface A {
Promise<any> foo();
Promise<any> foo(long arg);
diff --git a/dom/bindings/test/test_Object.prototype_props.html b/dom/bindings/test/test_Object.prototype_props.html
index 03147eb03..3ab27c5e4 100644
--- a/dom/bindings/test/test_Object.prototype_props.html
+++ b/dom/bindings/test/test_Object.prototype_props.html
@@ -11,9 +11,9 @@ test(function() {
// Codegen.py's CGDictionary.getMemberDefinition method.
var expected = [
"constructor", "toSource", "toString", "toLocaleString", "valueOf",
- "watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
- "propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
- "__lookupGetter__", "__lookupSetter__", "__proto__"
+ "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
+ "__defineGetter__", "__defineSetter__", "__lookupGetter__",
+ "__lookupSetter__", "__proto__"
];
assert_array_equals(props.sort(), expected.sort());
}, "Own properties of Object.prototype");
diff --git a/dom/canvas/WebGLContextBuffers.cpp b/dom/canvas/WebGLContextBuffers.cpp
index af506c01c..f53f9d7d7 100644
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -9,6 +9,8 @@
#include "WebGLBuffer.h"
#include "WebGLVertexArray.h"
+#include "mozilla/CheckedInt.h"
+
namespace mozilla {
WebGLRefPtr<WebGLBuffer>*
@@ -345,6 +347,16 @@ WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
////
+ const auto checkedSize = CheckedInt<size_t>(size);
+ if (!checkedSize.isValid())
+ return ErrorOutOfMemory("%s: Size too large for platform.", funcName);
+
+#if defined(XP_MACOSX)
+ if (gl->WorkAroundDriverBugs() && size > 1200000000) {
+ return ErrorOutOfMemory("Allocations larger than 1200000000 fail on MacOS.");
+ }
+#endif
+
const UniqueBuffer zeroBuffer(calloc(size, 1));
if (!zeroBuffer)
return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
diff --git a/dom/canvas/WebGLShader.cpp b/dom/canvas/WebGLShader.cpp
index 37380f1e0..69ca03fc4 100644
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -168,16 +168,6 @@ WebGLShader::ShaderSource(const nsAString& source)
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
const NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
- if (mContext->gl->WorkAroundDriverBugs()) {
- const size_t maxSourceLength = 0x3ffff;
- if (sourceCString.Length() > maxSourceLength) {
- mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
- " characters. (Driver workaround)",
- maxSourceLength);
- return;
- }
- }
-
if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) {
printf_stderr("////////////////////////////////////////\n");
printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n");
diff --git a/dom/canvas/test/reftest/filters/liveness-document-open.html b/dom/canvas/test/reftest/filters/liveness-document-open.html
new file mode 100644
index 000000000..b3d76e550
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/liveness-document-open.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<title>canvas filters: remove referenced filter element through document.open()</title>
+
+<body onload="loaded()">
+
+<canvas id="canvas" width="10" height="10"></canvas>
+
+<svg height="0">
+ <filter id="filter">
+ <feFlood flood-color="red"/>
+ </filter>
+</svg>
+
+<script>
+
+function loaded() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ ctx.filter = 'url(#filter)';
+ ctx.fillRect(0, 0, 10, 10); // do a draw first to work around bug 1287316
+
+ document.open();
+
+ // The document.open() call removed #filter from the document. So the filter
+ // reference should now be invalid, and the rect should be drawn without a
+ // filter applied, resulting in black.
+ ctx.fillRect(0, 0, 10, 10);
+
+ try {
+ var data = ctx.getImageData(0, 0, 1, 1).data;
+ if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 255) {
+ // Successfully painted black.
+ document.write('PASS');
+ } else {
+ // Painted something else, like red.
+ document.write('FAIL');
+ }
+ } catch (e) {
+ document.write('getImageData failed');
+ }
+ document.close();
+}
+
+</script>
diff --git a/dom/canvas/test/reftest/filters/reftest.list b/dom/canvas/test/reftest/filters/reftest.list
index 983030715..f5d671e4d 100644
--- a/dom/canvas/test/reftest/filters/reftest.list
+++ b/dom/canvas/test/reftest/filters/reftest.list
@@ -6,6 +6,7 @@ default-preferences pref(canvas.filters.enabled,true)
fuzzy-if(azureSkia,1,1500) == global-alpha.html global-alpha-ref.html
== global-composite-operation.html global-composite-operation-ref.html
== liveness.html ref.html
+== liveness-document-open.html data:text/html,PASS
== multiple-drop-shadows.html shadow-ref.html
== shadow.html shadow-ref.html
== subregion-fill-paint.html subregion-ref.html
diff --git a/dom/events/test/test_continuous_wheel_events.html b/dom/events/test/test_continuous_wheel_events.html
index fc8c69390..e1910afa9 100644
--- a/dom/events/test/test_continuous_wheel_events.html
+++ b/dom/events/test/test_continuous_wheel_events.html
@@ -9,7 +9,7 @@
</head>
<body>
<p id="display"></p>
-<div id="scrollable" style="font-family:monospace; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
+<div id="scrollable" style="font-family:'Courier New'; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
<div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
diff --git a/dom/grid/GridLines.cpp b/dom/grid/GridLines.cpp
index fac645c64..898885346 100644
--- a/dom/grid/GridLines.cpp
+++ b/dom/grid/GridLines.cpp
@@ -90,7 +90,9 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
for (uint32_t i = aTrackInfo->mStartFragmentTrack;
i < aTrackInfo->mEndFragmentTrack + 1;
i++) {
- uint32_t line1Index = i + 1;
+ // Since line indexes are 1-based, calculate a 1-based value
+ // for this track to simplify some calculations.
+ const uint32_t line1Index = i + 1;
startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ?
aTrackInfo->mPositions[i] :
@@ -127,7 +129,8 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
}
}
- if (i >= aTrackInfo->mRepeatFirstTrack &&
+ if (i >= (aTrackInfo->mRepeatFirstTrack +
+ aTrackInfo->mNumLeadingImplicitTracks) &&
repeatIndex < numRepeatTracks) {
numAddedLines += AppendRemovedAutoFits(aTrackInfo,
aLineInfo,
@@ -139,23 +142,30 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
RefPtr<GridLine> line = new GridLine(this);
mLines.AppendElement(line);
+ MOZ_ASSERT(line1Index > 0, "line1Index must be positive.");
+ bool isBeforeFirstExplicit =
+ (line1Index <= aTrackInfo->mNumLeadingImplicitTracks);
+ // Calculate an actionable line number for this line, that could be used
+ // in a css grid property to align a grid item or area at that line.
+ // For implicit lines that appear before line 1, report a number of 0.
+ // We can't report negative indexes, because those have a different
+ // meaning in the css grid spec (negative indexes are negative-1-based
+ // from the end of the grid decreasing towards the front).
+ uint32_t lineNumber = isBeforeFirstExplicit ? 0 :
+ (line1Index - aTrackInfo->mNumLeadingImplicitTracks + numAddedLines);
+ GridDeclaration lineType =
+ (isBeforeFirstExplicit ||
+ line1Index > (aTrackInfo->mNumLeadingImplicitTracks +
+ aTrackInfo->mNumExplicitTracks + 1))
+ ? GridDeclaration::Implicit
+ : GridDeclaration::Explicit;
line->SetLineValues(
lineNames,
nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge),
nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
lastTrackEdge),
- line1Index + numAddedLines,
- (
- // Implicit if there are no explicit tracks, or if the index
- // is before the first explicit track, or after
- // a track beyond the last explicit track.
- (aTrackInfo->mNumExplicitTracks == 0) ||
- (i < aTrackInfo->mNumLeadingImplicitTracks) ||
- (i > aTrackInfo->mNumLeadingImplicitTracks +
- aTrackInfo->mNumExplicitTracks) ?
- GridDeclaration::Implicit :
- GridDeclaration::Explicit
- )
+ lineNumber,
+ lineType
);
if (i < aTrackInfo->mEndFragmentTrack) {
@@ -215,11 +225,13 @@ GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
RefPtr<GridLine> line = new GridLine(this);
mLines.AppendElement(line);
+ uint32_t lineNumber = aTrackInfo->mRepeatFirstTrack +
+ aRepeatIndex + 1;
line->SetLineValues(
aLineNames,
nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge),
nsPresContext::AppUnitsToDoubleCSSPixels(0),
- aTrackInfo->mRepeatFirstTrack + aRepeatIndex + 1,
+ lineNumber,
GridDeclaration::Explicit
);
diff --git a/dom/grid/test/chrome.ini b/dom/grid/test/chrome.ini
index 2241cf9eb..169fa9b89 100644
--- a/dom/grid/test/chrome.ini
+++ b/dom/grid/test/chrome.ini
@@ -2,6 +2,7 @@
[chrome/test_grid_fragmentation.html]
[chrome/test_grid_implicit.html]
[chrome/test_grid_lines.html]
+[chrome/test_grid_line_numbers.html]
[chrome/test_grid_object.html]
[chrome/test_grid_repeats.html]
[chrome/test_grid_tracks.html]
diff --git a/dom/grid/test/chrome/test_grid_implicit.html b/dom/grid/test/chrome/test_grid_implicit.html
index c7782e0e5..1f7142658 100644
--- a/dom/grid/test/chrome/test_grid_implicit.html
+++ b/dom/grid/test/chrome/test_grid_implicit.html
@@ -33,6 +33,11 @@ body {
grid-template-rows: [areaA-end areaB-start areaC-end] 50px [areaA-start areaB-end areaC-start];
}
+.template4 {
+ grid-template-columns: 100px 50px 100px;
+ grid-template-rows: 50px;
+}
+
.box {
background-color: #444;
color: #fff;
@@ -50,6 +55,9 @@ body {
.d {
grid-area: areaD;
}
+.e {
+ grid-column: -7 / 5;
+}
</style>
<script>
@@ -78,9 +86,12 @@ function runTests() {
is(grid.cols.lines[4].type, "implicit", "Grid column line 5 is implicit.");
is(grid.cols.lines[5].type, "implicit", "Grid column line 6 is implicit.");
- is(grid.rows.lines[0].type, "implicit", "Grid row line 1 is implicit.");
- is(grid.rows.lines[1].type, "explicit", "Grid row line 2 is explicit.");
- is(grid.rows.lines[3].type, "explicit", "Grid row line 4 is explicit.");
+ is(grid.rows.lines[0].type, "implicit", "Grid row line 0 is implicit.");
+ is(grid.rows.lines[0].number, 0, "Grid row line 0 has correct number.");
+ is(grid.rows.lines[1].type, "explicit", "Grid row line 1 is explicit.");
+ is(grid.rows.lines[1].number, 1, "Grid row line 1 has correct number.");
+ is(grid.rows.lines[3].type, "explicit", "Grid row line 3 is explicit.");
+ is(grid.rows.lines[3].number, 3, "Grid row line 3 has correct number.");
// test that row line 1 gets the name forced on it by placement of item B
todo_isnot(grid.rows.lines[0].names.indexOf("got-this-name-implicitly"), -1,
@@ -221,6 +232,48 @@ function runTests() {
}
}
+ // test the fourth grid wrapper
+ wrapper = document.getElementById("wrapper4");
+ grid = wrapper.getGridFragments()[0];
+
+ // test column and row line counts
+ is(grid.cols.lines.length, 8,
+ "Grid.cols.lines property expands properly with implicit columns on both sides."
+ );
+ is(grid.rows.lines.length, 2,
+ "Grid.rows.lines property is as expected"
+ );
+
+ if (grid.cols.lines.length == 8) {
+ // check that all the lines get correct implict/explicit type and number
+ let expectedType = [
+ "implicit",
+ "implicit",
+ "implicit",
+ "explicit",
+ "explicit",
+ "explicit",
+ "explicit",
+ "implicit",
+ ];
+ let expectedNumber = [
+ 0,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ ];
+
+ for (let i = 0; i < grid.cols.lines.length; i++) {
+ let line = grid.cols.lines[i];
+ is(line.type, expectedType[i], "Line index " + i + " has expected type.");
+ is(line.number, expectedNumber[i], "Line index " + i + " has expected number.");
+ }
+ }
+
SimpleTest.finish();
}
</script>
@@ -246,5 +299,9 @@ function runTests() {
<div id="boxC" class="box c">C</div>
</div>
+ <div id="wrapper4" class="wrapper template4">
+ <div id="boxE" class="box e">E</div>
+ </div>
+
</body>
</html>
diff --git a/dom/grid/test/chrome/test_grid_line_numbers.html b/dom/grid/test/chrome/test_grid_line_numbers.html
new file mode 100644
index 000000000..c8e5226b6
--- /dev/null
+++ b/dom/grid/test/chrome/test_grid_line_numbers.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+body {
+ margin: 40px;
+}
+.wrapper {
+ display: grid;
+ grid-gap: 0px;
+ background-color: #f00;
+}
+.wrapper > div {
+ background-color: #444;
+ color: #fff;
+}
+.repeatColumns {
+ width: 600px;
+ grid-auto-columns: 50px;
+ grid-template-columns: repeat(auto-fit, 100px);
+}
+.repeatRows {
+ height: 600px;
+ grid-auto-rows: 50px;
+ grid-template-rows: repeat(auto-fit, 100px);
+}
+</style>
+
+<script>
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+
+function testLines(elementName, lines, expectedValues) {
+ is(lines.count, expectedValues.count, elementName + " has expected number of lines.");
+ for (let i = 0; i < lines.length; i++) {
+ is(lines[i].number, expectedValues[i].number, elementName + " line index " + i + " has expected number.");
+ }
+}
+
+function runTests() {
+ let grid;
+ let lines;
+ let expectedValues;
+
+ grid = document.getElementById("gridWithColumns").getGridFragments()[0];
+ lines = grid.cols.lines;
+ expectedValues = [
+ { "number": 0 },
+ { "number": 0 },
+ { "number": 1 },
+ { "number": 2 },
+ { "number": 3 },
+ { "number": 4 },
+ { "number": 5 },
+ { "number": 6 },
+ { "number": 7 },
+ { "number": 8 },
+ ];
+ testLines("gridWithColumns", lines, expectedValues);
+
+ grid = document.getElementById("gridWithRows").getGridFragments()[0];
+ lines = grid.rows.lines;
+ expectedValues = [
+ { "number": 0 },
+ { "number": 0 },
+ { "number": 1 },
+ { "number": 2 },
+ { "number": 3 },
+ { "number": 4 },
+ { "number": 5 },
+ { "number": 6 },
+ { "number": 7 },
+ { "number": 8 },
+ ];
+ testLines("gridWithRows", lines, expectedValues);
+
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body onLoad="runTests();">
+
+<div id="gridWithColumns" class="wrapper repeatColumns">
+<div style="grid-column: -9">A</div>
+<div style="grid-column: 4">B</div>
+<div style="grid-column: 7">C</div>
+</div>
+
+<div id="gridWithRows" class="wrapper repeatRows">
+<div style="grid-row: span 3 / 2">A</div>
+<div style="grid-row: 4">B</div>
+<div style="grid-row: 5">C</div>
+<div style="grid-row: span 2 / 8">D</div>
+</div>
+
+</body>
+</html>
diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp
index 94d09c12c..095b9b77d 100644
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -218,6 +218,18 @@ HTMLScriptElement::SetAsync(bool aValue, ErrorResult& rv)
SetHTMLBoolAttr(nsGkAtoms::async, aValue, rv);
}
+bool
+HTMLScriptElement::NoModule()
+{
+ return GetBoolAttr(nsGkAtoms::nomodule);
+}
+
+void
+HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv)
+{
+ SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv);
+}
+
nsresult
HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h
index 00628bd6d..19ceb414f 100644
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -89,6 +89,8 @@ public:
}
bool Async();
void SetAsync(bool aValue, ErrorResult& rv);
+ bool NoModule();
+ void SetNoModule(bool aValue, ErrorResult& rv);
protected:
virtual ~HTMLScriptElement();
diff --git a/dom/html/ImageDocument.cpp b/dom/html/ImageDocument.cpp
index f83a804be..451d989c3 100644
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -659,7 +659,7 @@ ImageDocument::CreateSyntheticDocument()
NS_ENSURE_SUCCESS(rv, rv);
// Add the image element
- Element* body = GetBodyElement();
+ RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on image document!");
return NS_ERROR_FAILURE;
diff --git a/dom/html/PluginDocument.cpp b/dom/html/PluginDocument.cpp
index 1c923ecc6..f6be8a915 100644
--- a/dom/html/PluginDocument.cpp
+++ b/dom/html/PluginDocument.cpp
@@ -206,7 +206,7 @@ PluginDocument::CreateSyntheticPluginDocument()
NS_ENSURE_SUCCESS(rv, rv);
// then attach our plugin
- Element* body = GetBodyElement();
+ RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on plugin document!");
return NS_ERROR_FAILURE;
diff --git a/dom/html/VideoDocument.cpp b/dom/html/VideoDocument.cpp
index 1bd898564..76b2e326f 100644
--- a/dom/html/VideoDocument.cpp
+++ b/dom/html/VideoDocument.cpp
@@ -90,7 +90,7 @@ VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel,
nsresult rv = MediaDocument::CreateSyntheticDocument();
NS_ENSURE_SUCCESS(rv, rv);
- Element* body = GetBodyElement();
+ RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on video document!");
return NS_ERROR_FAILURE;
diff --git a/dom/html/test/file_script_module.html b/dom/html/test/file_script_module.html
new file mode 100644
index 000000000..78c499265
--- /dev/null
+++ b/dom/html/test/file_script_module.html
@@ -0,0 +1,42 @@
+<html>
+<body>
+ <script>
+// Helper methods.
+function ok(a, msg) {
+ parent.postMessage({ check: !!a, msg }, "*")
+}
+
+function is(a, b, msg) {
+ ok(a === b, msg);
+}
+
+function finish() {
+ parent.postMessage({ done: true }, "*");
+}
+ </script>
+
+ <script id="a" nomodule>42</script>
+ <script id="b">42</script>
+ <script>
+// Let's test the behavior of nomodule attribute and noModule getter/setter.
+var a = document.getElementById("a");
+is(a.noModule, true, "HTMLScriptElement with nomodule attribute has noModule set to true");
+a.removeAttribute("nomodule");
+is(a.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false");
+a.noModule = true;
+ok(a.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute");
+
+var b = document.getElementById("b");
+is(b.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false");
+b.noModule = true;
+ok(b.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute");
+ </script>
+
+ <script>var foo = 42;</script>
+ <script nomodule>foo = 43;</script>
+ <script>
+is(foo, 42, "nomodule HTMLScriptElements should not be executed in modern browsers");
+finish();
+ </script>
+</body>
+</html>
diff --git a/dom/html/test/file_script_nomodule.html b/dom/html/test/file_script_nomodule.html
new file mode 100644
index 000000000..303edb90b
--- /dev/null
+++ b/dom/html/test/file_script_nomodule.html
@@ -0,0 +1,32 @@
+<html>
+<body>
+ <script>
+// Helper methods.
+function ok(a, msg) {
+ parent.postMessage({ check: !!a, msg }, "*")
+}
+
+function is(a, b, msg) {
+ ok(a === b, msg);
+}
+
+function finish() {
+ parent.postMessage({ done: true }, "*");
+}
+ </script>
+
+ <script id="a" nomodule>42</script>
+ <script>
+// Let's test the behavior of nomodule attribute and noModule getter/setter.
+var a = document.getElementById("a");
+ok(!("noModule" in a), "When modules are disabled HTMLScriptElement.noModule is not defined");
+ </script>
+
+ <script>var foo = 42;</script>
+ <script nomodule>foo = 43;</script>
+ <script>
+is(foo, 43, "nomodule attribute is ignored when modules are disabled");
+finish();
+ </script>
+</body>
+</html>
diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini
index 99b425df8..b9da7def8 100644
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -553,7 +553,6 @@ skip-if = true # Disabled for timeouts.
[test_viewport.html]
[test_documentAll.html]
[test_document-element-inserted.html]
-[test_document.watch.html]
[test_bug445004.html]
skip-if = true || toolkit == 'android' # Disabled permanently (bug 559932).
[test_bug446483.html]
@@ -606,3 +605,7 @@ skip-if = os == "android" # up/down arrow keys not supported on android
[test_bug1295719_event_sequence_for_number_keys.html]
[test_bug1310865.html]
[test_bug1315146.html]
+[test_script_module.html]
+support-files =
+ file_script_module.html
+ file_script_nomodule.html \ No newline at end of file
diff --git a/dom/html/test/test_document.watch.html b/dom/html/test/test_document.watch.html
deleted file mode 100644
index 54509823b..000000000
--- a/dom/html/test/test_document.watch.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=903332
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 903332</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript">
-
- /** Test for Bug 903332 **/
-
- var watch1Called;
- function watch1(prop, oldValue, newValue)
- {
- is(watch1Called, false, "watch1Called not reset properly?");
- watch1Called = true;
-
- is(prop, "cookie", "wrong property name passed to watch1");
- return newValue;
- }
-
- var watch2Called;
- function watch2(prop, oldValue, newValue)
- {
- is(watch2Called, false, "watch2Called not reset properly?");
- watch2Called = true;
-
- is(prop, "cookie", "wrong property name passed to watch2");
- return newValue;
- }
-
- // Just in case subsequent tests depend on a particular value...
- var originalValue = document.cookie;
- ok(true, "originalValue: " + originalValue);
-
- var originalPrefix = originalValue.length > 0 ? originalValue + "; " : "";
-
- try
- {
- // trial set (no watch) to verify things work
- document.cookie = "first=set";
- is(document.cookie, originalPrefix + "first=set",
- "first value correct");
-
- // add a watch
- document.watch("cookie", watch1);
-
- // set, check for watch invoked
- watch1Called = false;
- document.cookie = "second=set";
- is(watch1Called, true, "watch1 function should be called");
- is(document.cookie, originalPrefix + "first=set; second=set",
- "second value correct");
-
- // and a second time, just in case
- watch1Called = false;
- document.cookie = "third=set";
- is(watch1Called, true, "watch1 function should be called");
- is(document.cookie, originalPrefix + "first=set; second=set; third=set",
- "third value correct");
-
- // overwrite the current watch with a new one
- document.watch("cookie", watch2);
-
- // set, check for watch invoked
- watch1Called = false;
- watch2Called = false;
- document.cookie = "fourth=set";
- is(watch1Called, false, "watch1 invoked erroneously");
- is(watch2Called, true, "watch2 function should be called");
- is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set",
- "fourth value correct");
-
- // and a second time, just in case
- watch1Called = false;
- watch2Called = false;
- document.cookie = "fifth=set";
- is(watch1Called, false, "watch1 invoked erroneously");
- is(watch2Called, true, "watch2 function should be called");
- is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set",
- "fifth value correct");
-
- // remove the watch
- document.unwatch("cookie");
-
- // check for non-invocation now
- watch1Called = false;
- watch2Called = false;
- document.cookie = "sixth=set";
- is(watch1Called, false, "watch1 shouldn't be called");
- is(watch2Called, false, "watch2 shouldn't be called");
- is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set; sixth=set",
- "sixth value correct");
- }
- finally
- {
- // reset
- document.unwatch("cookie"); // harmless, should be no-op except if bugs
-
- var d = new Date();
- d.setTime(0);
- var suffix = "=; expires=" + d.toGMTString();
-
- document.cookie = "first" + suffix;
- document.cookie = "second" + suffix;
- document.cookie = "third" + suffix;
- document.cookie = "fourth" + suffix;
- document.cookie = "fifth" + suffix;
- document.cookie = "sixth" + suffix;
- }
-
- is(document.cookie, originalValue,
- "document.cookie isn't what it was initially! expect bustage further " +
- "down the line");
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=903332">Mozilla Bug 903332</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/dom/html/test/test_script_module.html b/dom/html/test/test_script_module.html
new file mode 100644
index 000000000..4878bb379
--- /dev/null
+++ b/dom/html/test/test_script_module.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for HTMLScriptElement with nomodule attribute</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+ <script>
+onmessage = (e) => {
+ if ("done" in e.data) {
+ next();
+ } else if ("check" in e.data) {
+ ok(e.data.check, e.data.msg);
+ } else {
+ ok(false, "Unknown message");
+ }
+}
+
+var tests = [
+ function() {
+ SpecialPowers.pushPrefEnv({"set":[["dom.moduleScripts.enabled", true]]})
+ .then(() => {
+ var ifr = document.createElement('iframe');
+ ifr.src = "file_script_module.html";
+ document.body.appendChild(ifr);
+ });
+ },
+
+ function() {
+ SpecialPowers.pushPrefEnv({"set":[["dom.moduleScripts.enabled", false]]})
+ .then(() => {
+ var ifr = document.createElement('iframe');
+ ifr.src = "file_script_nomodule.html";
+ document.body.appendChild(ifr);
+ });
+ },
+];
+
+SimpleTest.waitForExplicitFinish();
+next();
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+ </script>
+
+</body>
+</html>
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index cd998c31c..74afef452 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -4427,18 +4427,6 @@ CreateStorageConnection(nsIFile* aDBFile,
nsresult rv;
bool exists;
- if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
- rv = aDBFile->Exists(&exists);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (!exists) {
- NS_WARNING("Refusing to create database because disk space is low!");
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
- }
-
nsCOMPtr<nsIFileURL> dbFileUrl;
rv = GetDatabaseFileURL(aDBFile,
aPersistenceType,
@@ -19103,23 +19091,6 @@ DatabaseMaintenance::DetermineMaintenanceAction(
return NS_OK;
}
- bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode();
-
- if (QuotaManager::IsRunningXPCShellTests()) {
- // If we're running XPCShell then we want to test both the low disk space
- // and normal disk space code paths so pick semi-randomly based on the
- // current time.
- lowDiskSpace = ((PR_Now() / PR_USEC_PER_MSEC) % 2) == 0;
- }
-
- // If we're low on disk space then the best we can hope for is that an
- // incremental vacuum might free some space. That is a journaled operation so
- // it may not be possible even then.
- if (lowDiskSpace) {
- *aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
- return NS_OK;
- }
-
// This method shouldn't make any permanent changes to the database, so make
// sure everything gets rolled back when we leave.
mozStorageTransaction transaction(aConnection,
@@ -24233,11 +24204,6 @@ CreateFileOp::DoDatabaseWork()
"CreateFileOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- NS_WARNING("Refusing to create file because disk space is low!");
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -24378,10 +24344,6 @@ CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
"CreateObjectStoreOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
#ifdef DEBUG
{
// Make sure that we're not creating an object store with the same name as
@@ -24705,10 +24667,6 @@ RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
"RenameObjectStoreOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
#ifdef DEBUG
{
// Make sure that we're not renaming an object store with the same name as
@@ -24798,7 +24756,6 @@ CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
- MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
MOZ_ASSERT(mMaybeUniqueIndexTable);
PROFILER_LABEL("IndexedDB",
@@ -24849,7 +24806,6 @@ CreateIndexOp::InsertDataFromObjectStoreInternal(
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
- MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
MOZ_ASSERT(mMaybeUniqueIndexTable);
DebugOnly<void*> storageConnection = aConnection->GetStorageConnection();
@@ -24926,10 +24882,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
"CreateIndexOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
#ifdef DEBUG
{
// Make sure that we're not creating an index with the same name and object
@@ -25806,10 +25758,6 @@ RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
"RenameIndexOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
#ifdef DEBUG
{
// Make sure that we're not renaming an index with the same name as another
@@ -26294,10 +26242,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
"ObjectStoreAddOrPutRequestOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
- if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
- return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
- }
-
DatabaseConnection::AutoSavepoint autoSave;
nsresult rv = autoSave.Start(Transaction());
if (NS_WARN_IF(NS_FAILED(rv))) {
diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp
index af88742f0..be0295dc7 100644
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -430,7 +430,7 @@ IDBCursor::Continue(JSContext* aCx,
}
Key key;
- aRv = key.SetFromJSVal(aCx, aKey);
+ aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@@ -536,7 +536,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
}
Key key;
- aRv = key.SetFromJSVal(aCx, aKey);
+ aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@@ -558,7 +558,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
}
Key primaryKey;
- aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
+ aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@@ -718,7 +718,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
const KeyPath& keyPath = objectStore->GetKeyPath();
Key key;
- aRv = keyPath.ExtractKey(aCx, aValue, key);
+ aRv = keyPath.ExtractKey(aCx, aValue, key, /* aCallGetters */ false);
if (aRv.Failed()) {
return nullptr;
}
diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp
index 5592e7f93..6ef352801 100644
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -1257,6 +1257,9 @@ IDBDatabase::LastRelease()
AssertIsOnOwningThread();
CloseInternal();
+
+ // Make sure that file actors created after the database was closed are expired.
+ ExpireFileActors(/* aExpireAll */ true);
if (mBackgroundActor) {
mBackgroundActor->SendDeleteMeInternal();
diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp
index c1ef6353d..66471fe24 100644
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -482,13 +482,13 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
{
Key first, second;
- nsresult rv = first.SetFromJSVal(aCx, aFirst);
+ nsresult rv = first.SetFromJSVal(aCx, aFirst, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;
}
- rv = second.SetFromJSVal(aCx, aSecond);
+ rv = second.SetFromJSVal(aCx, aSecond, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;
diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp
index e61c80617..168fb4a5a 100644
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -24,7 +24,7 @@ GetKeyFromJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
Key& aKey)
{
- nsresult rv = aKey.SetFromJSVal(aCx, aVal);
+ nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB);
return rv;
diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp
index 756792741..cbac30894 100644
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1084,7 +1084,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
if (!aMultiEntry) {
Key key;
- rv = aKeyPath.ExtractKey(aCx, aVal, key);
+ rv = aKeyPath.ExtractKey(aCx, aVal, key, /* aCallGetters */ false);
// If an index's keyPath doesn't match an object, we ignore that object.
if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
@@ -1114,7 +1114,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
}
bool isArray;
- if (!JS_IsArrayObject(aCx, val, &isArray)) {
+ if (NS_WARN_IF(!JS_IsArrayObject(aCx, val, &isArray))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
@@ -1127,14 +1127,31 @@ IDBObjectStore::AppendIndexUpdateInfo(
}
for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
- JS::Rooted<JS::Value> arrayItem(aCx);
- if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
+ JS::RootedId indexId(aCx);
+ if (NS_WARN_IF(!JS_IndexToId(aCx, arrayIndex, &indexId))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ bool hasOwnProperty;
+ if (NS_WARN_IF(
+ !JS_HasOwnPropertyById(aCx, array, indexId, &hasOwnProperty))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ if (!hasOwnProperty) {
+ continue;
+ }
+
+ JS::RootedValue arrayItem(aCx);
+ if (NS_WARN_IF(!JS_GetPropertyById(aCx, array, indexId, &arrayItem))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
Key value;
- if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
+ if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem, /* aCallGetters */ false)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
continue;
@@ -1153,7 +1170,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
}
else {
Key value;
- if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
+ if (NS_FAILED(value.SetFromJSVal(aCx, val, /* aCallGetters */ false)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
return NS_OK;
@@ -1324,12 +1341,12 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
if (!HasValidKeyPath()) {
// Out-of-line keys must be passed in.
- rv = aKey.SetFromJSVal(aCx, aKeyVal);
+ rv = aKey.SetFromJSVal(aCx, aKeyVal, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
return rv;
}
} else if (!isAutoIncrement) {
- rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
+ rv = GetKeyPath().ExtractKey(aCx, aValue, aKey, /* aCallGetters */ false);
if (NS_FAILED(rv)) {
return rv;
}
@@ -1368,7 +1385,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
aValue,
aKey,
&GetAddInfoCallback,
- &data);
+ &data,
+ /* aCallGetters */ false);
} else {
rv = GetAddInfoCallback(aCx, &data);
}
diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp
index 62ba51c08..213de5cc9 100644
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -8,11 +8,9 @@
#include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
#include "nsIConsoleService.h"
-#include "nsIDiskSpaceWatcher.h"
#include "nsIDOMWindow.h"
#include "nsIEventTarget.h"
#include "nsIFile.h"
-#include "nsIObserverService.h"
#include "nsIScriptError.h"
#include "nsIScriptGlobalObject.h"
@@ -64,11 +62,6 @@
#define IDB_STR "indexedDB"
-// The two possible values for the data argument when receiving the disk space
-// observer notification.
-#define LOW_DISK_SPACE_DATA_FULL "full"
-#define LOW_DISK_SPACE_DATA_FREE "free"
-
namespace mozilla {
namespace dom {
namespace indexedDB {
@@ -313,8 +306,6 @@ Atomic<IndexedDatabaseManager::LoggingMode>
IndexedDatabaseManager::sLoggingMode(
IndexedDatabaseManager::Logging_Disabled);
-mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
-
// static
IndexedDatabaseManager*
IndexedDatabaseManager::GetOrCreate()
@@ -329,24 +320,6 @@ IndexedDatabaseManager::GetOrCreate()
if (!gDBManager) {
sIsMainProcess = XRE_IsParentProcess();
- if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
- // See if we're starting up in low disk space conditions.
- nsCOMPtr<nsIDiskSpaceWatcher> watcher =
- do_GetService(DISKSPACEWATCHER_CONTRACTID);
- if (watcher) {
- bool isDiskFull;
- if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) {
- sLowDiskSpaceMode = isDiskFull;
- }
- else {
- NS_WARNING("GetIsDiskFull failed!");
- }
- }
- else {
- NS_WARNING("No disk space watcher component available!");
- }
- }
-
RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
nsresult rv = instance->Init();
@@ -380,13 +353,6 @@ IndexedDatabaseManager::Init()
// During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
// directly.
if (sIsMainProcess) {
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- NS_ENSURE_STATE(obs);
-
- nsresult rv =
- obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
- NS_ENSURE_SUCCESS(rv, rv);
-
mDeleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
NS_ENSURE_STATE(mDeleteTimer);
@@ -680,16 +646,6 @@ IndexedDatabaseManager::IsMainProcess()
return sIsMainProcess;
}
-//static
-bool
-IndexedDatabaseManager::InLowDiskSpaceMode()
-{
- NS_ASSERTION(gDBManager,
- "InLowDiskSpaceMode() called before indexedDB has been "
- "initialized!");
- return sLowDiskSpaceMode;
-}
-
// static
IndexedDatabaseManager::LoggingMode
IndexedDatabaseManager::GetLoggingMode()
@@ -1087,36 +1043,7 @@ IndexedDatabaseManager::GetLocale()
NS_IMPL_ADDREF(IndexedDatabaseManager)
NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
-NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback)
-
-NS_IMETHODIMP
-IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
-{
- NS_ASSERTION(IsMainProcess(), "Wrong process!");
- NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
- if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) {
- NS_ASSERTION(aData, "No data?!");
-
- const nsDependentString data(aData);
-
- if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) {
- sLowDiskSpaceMode = true;
- }
- else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) {
- sLowDiskSpaceMode = false;
- }
- else {
- NS_NOTREACHED("Unknown data value!");
- }
-
- return NS_OK;
- }
-
- NS_NOTREACHED("Unknown topic!");
- return NS_ERROR_UNEXPECTED;
-}
+NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsITimerCallback)
NS_IMETHODIMP
IndexedDatabaseManager::Notify(nsITimer* aTimer)
diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h
index d63c548ec..fb4376426 100644
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -7,8 +7,6 @@
#ifndef mozilla_dom_indexeddatabasemanager_h__
#define mozilla_dom_indexeddatabasemanager_h__
-#include "nsIObserver.h"
-
#include "js/TypeDecls.h"
#include "mozilla/Atomics.h"
#include "mozilla/dom/quota/PersistenceType.h"
@@ -43,8 +41,7 @@ class FileManagerInfo;
} // namespace indexedDB
class IndexedDatabaseManager final
- : public nsIObserver
- , public nsITimerCallback
+ : public nsITimerCallback
{
typedef mozilla::dom::quota::PersistenceType PersistenceType;
typedef mozilla::dom::quota::QuotaManager QuotaManager;
@@ -62,7 +59,6 @@ public:
};
NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
NS_DECL_NSITIMERCALLBACK
// Returns a non-owning reference.
@@ -87,16 +83,6 @@ public:
#endif
static bool
- InLowDiskSpaceMode()
-#ifdef DEBUG
- ;
-#else
- {
- return !!sLowDiskSpaceMode;
- }
-#endif
-
- static bool
InTestingMode();
static bool
@@ -244,7 +230,6 @@ private:
static bool sFullSynchronousMode;
static LazyLogModule sLoggingModule;
static Atomic<LoggingMode> sLoggingMode;
- static mozilla::Atomic<bool> sLowDiskSpaceMode;
};
} // namespace dom
diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp
index 0f693b2c6..575734af2 100644
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -201,8 +201,11 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
}
nsresult
-Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
- uint8_t aTypeOffset, uint16_t aRecursionDepth)
+Key::EncodeJSValInternal(JSContext* aCx,
+ JS::Handle<JS::Value> aVal,
+ uint8_t aTypeOffset,
+ uint16_t aRecursionDepth,
+ bool aCallGetters)
{
static_assert(eMaxType * kMaxArrayCollapse < 256,
"Unable to encode jsvals.");
@@ -257,13 +260,18 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
for (uint32_t index = 0; index < length; index++) {
JS::Rooted<JS::Value> val(aCx);
- if (!JS_GetElement(aCx, obj, index, &val)) {
+ bool ok = aCallGetters ? JS_GetElement(aCx, obj, index, &val)
+ : JS_GetOwnElement(aCx, obj, index, &val);
+ if (!ok) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
- nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
- aRecursionDepth + 1);
+ nsresult rv = EncodeJSValInternal(aCx,
+ val,
+ aTypeOffset,
+ aRecursionDepth + 1,
+ aCallGetters);
if (NS_FAILED(rv)) {
return rv;
}
@@ -406,9 +414,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
nsresult
Key::EncodeJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
- uint8_t aTypeOffset)
+ uint8_t aTypeOffset,
+ bool aCallGetters)
{
- return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
+ return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0, aCallGetters);
}
void
@@ -741,7 +750,8 @@ Key::SetFromValueArray(mozIStorageValueArray* aValues,
nsresult
Key::SetFromJSVal(JSContext* aCx,
- JS::Handle<JS::Value> aVal)
+ JS::Handle<JS::Value> aVal,
+ bool aCallGetters)
{
mBuffer.Truncate();
@@ -750,7 +760,7 @@ Key::SetFromJSVal(JSContext* aCx,
return NS_OK;
}
- nsresult rv = EncodeJSVal(aCx, aVal, 0);
+ nsresult rv = EncodeJSVal(aCx, aVal, 0, aCallGetters);
if (NS_FAILED(rv)) {
Unset();
return rv;
@@ -793,9 +803,15 @@ Key::ToJSVal(JSContext* aCx,
}
nsresult
-Key::AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal)
+Key::AppendItem(JSContext* aCx,
+ bool aFirstOfArray,
+ JS::Handle<JS::Value> aVal,
+ bool aCallGetters)
{
- nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
+ nsresult rv = EncodeJSVal(aCx,
+ aVal,
+ aFirstOfArray ? eMaxType : 0,
+ aCallGetters);
if (NS_FAILED(rv)) {
Unset();
return rv;
diff --git a/dom/indexedDB/Key.h b/dom/indexedDB/Key.h
index 9d70ce6ad..a4fb65b48 100644
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -203,7 +203,7 @@ public:
}
nsresult
- SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal);
+ SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, bool aCallGetters);
nsresult
ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
@@ -212,7 +212,10 @@ public:
ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
nsresult
- AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
+ AppendItem(JSContext* aCx,
+ bool aFirstOfArray,
+ JS::Handle<JS::Value> aVal,
+ bool aCallGetters);
nsresult
ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const;
@@ -283,7 +286,10 @@ private:
// Encoding functions. These append the encoded value to the end of mBuffer
nsresult
- EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset);
+ EncodeJSVal(JSContext* aCx,
+ JS::Handle<JS::Value> aVal,
+ uint8_t aTypeOffset,
+ bool aCallGetters);
void
EncodeString(const nsAString& aString, uint8_t aTypeOffset);
@@ -331,7 +337,8 @@ private:
EncodeJSValInternal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset,
- uint16_t aRecursionDepth);
+ uint16_t aRecursionDepth,
+ bool aCallGetters);
static nsresult
DecodeJSValInternal(const unsigned char*& aPos,
diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp
index 30edd8cd7..0221c9450 100644
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -372,11 +372,13 @@ KeyPath::AppendStringWithValidation(const nsAString& aString)
}
nsresult
-KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const
+KeyPath::ExtractKey(JSContext* aCx,
+ const JS::Value& aValue,
+ Key& aKey,
+ bool aCallGetters) const
{
uint32_t len = mStrings.Length();
JS::Rooted<JS::Value> value(aCx);
-
aKey.Unset();
for (uint32_t i = 0; i < len; ++i) {
@@ -388,7 +390,10 @@ KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const
return rv;
}
- if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) {
+ if (NS_FAILED(aKey.AppendItem(aCx,
+ IsArray() && i == 0,
+ value,
+ aCallGetters))) {
NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset");
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
@@ -437,9 +442,12 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
}
nsresult
-KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue,
- Key& aKey, ExtractOrCreateKeyCallback aCallback,
- void* aClosure) const
+KeyPath::ExtractOrCreateKey(JSContext* aCx,
+ const JS::Value& aValue,
+ Key& aKey,
+ ExtractOrCreateKeyCallback aCallback,
+ void* aClosure,
+ bool aCallGetters) const
{
NS_ASSERTION(IsString(), "This doesn't make sense!");
@@ -455,7 +463,7 @@ KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue,
return rv;
}
- if (NS_FAILED(aKey.AppendItem(aCx, false, value))) {
+ if (NS_FAILED(aKey.AppendItem(aCx, false, value, aCallGetters))) {
NS_ASSERTION(aKey.IsUnset(), "Should be unset");
return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
diff --git a/dom/indexedDB/KeyPath.h b/dom/indexedDB/KeyPath.h
index c133cdc4a..e6e5f57d4 100644
--- a/dom/indexedDB/KeyPath.h
+++ b/dom/indexedDB/KeyPath.h
@@ -72,7 +72,10 @@ public:
Parse(const Nullable<OwningStringOrStringSequence>& aValue, KeyPath* aKeyPath);
nsresult
- ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const;
+ ExtractKey(JSContext* aCx,
+ const JS::Value& aValue,
+ Key& aKey,
+ bool aCallGetters) const;
nsresult
ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
@@ -82,9 +85,12 @@ public:
(*ExtractOrCreateKeyCallback)(JSContext* aCx, void* aClosure);
nsresult
- ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, Key& aKey,
+ ExtractOrCreateKey(JSContext* aCx,
+ const JS::Value& aValue,
+ Key& aKey,
ExtractOrCreateKeyCallback aCallback,
- void* aClosure) const;
+ void* aClosure,
+ bool aCallGetters) const;
inline bool IsValid() const {
return mType != NONEXISTENT;
diff --git a/dom/indexedDB/crashtests/1558522-1.html b/dom/indexedDB/crashtests/1558522-1.html
new file mode 100644
index 000000000..47dd2f843
--- /dev/null
+++ b/dom/indexedDB/crashtests/1558522-1.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+ <script id='worker' type='javascript/worker'>
+ onmessage = function (e) {
+ const file = e.data[0]
+ const db = indexedDB.open('', {})
+ db.onupgradeneeded = function (event) {
+ const store = event.target.result.createObjectStore('IDBStore_0', {})
+ store.add({}, '')
+ }
+ db.onsuccess = function (event) {
+ const transaction = event.target.result.transaction('IDBStore_0', 'readwrite')
+ const store = transaction.objectStore('IDBStore_0')
+ const cursor = store.openCursor()
+ cursor.onsuccess = function (event) {
+ event.target.result.update({
+ data: file
+ })
+ event.target.result.advance(1)
+ }
+
+ event.target.result.close()
+ }
+ }
+
+ </script>
+ <script>
+ let worker;
+
+ function start () {
+ const file = new File([], 'x')
+ const blob = new Blob([document.getElementById('worker').textContent], { type: 'text/javascript' })
+ worker = new Worker(window.URL.createObjectURL(blob))
+ worker.postMessage([file], [])
+ }
+
+ document.addEventListener('DOMContentLoaded', start)
+ </script>
+</head>
+</html> \ No newline at end of file
diff --git a/dom/indexedDB/crashtests/crashtests.list b/dom/indexedDB/crashtests/crashtests.list
index 69f5dab0b..ead6024dc 100644
--- a/dom/indexedDB/crashtests/crashtests.list
+++ b/dom/indexedDB/crashtests/crashtests.list
@@ -1 +1,2 @@
load 726376-1.html
+load 1558522-1.html
diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js
index e6e27f3f3..ffe66ebcd 100644
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -217,10 +217,6 @@ if (!window.runTest) {
function finishTest()
{
- SpecialPowers.notifyObserversInParentProcess(null,
- "disk-space-watcher",
- "free");
-
SimpleTest.executeSoon(function() {
testGenerator.close();
testHarnessGenerator.close();
diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini
index 4ab55a9dc..ca65ea8b6 100644
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -66,7 +66,6 @@ support-files =
unit/test_locale_aware_indexes.js
unit/test_locale_aware_index_getAll.js
unit/test_locale_aware_index_getAllObjects.js
- unit/test_lowDiskSpace.js
unit/test_maximal_serialized_object_size.js
unit/test_multientry.js
unit/test_names_sorted.js
@@ -214,7 +213,6 @@ skip-if = true
[test_key_requirements.html]
[test_keys.html]
[test_leaving_page.html]
-[test_lowDiskSpace.html]
[test_maximal_serialized_object_size.html]
[test_message_manager_ipc.html]
# This test is only supposed to run in the main process.
diff --git a/dom/indexedDB/test/test_lowDiskSpace.html b/dom/indexedDB/test/test_lowDiskSpace.html
deleted file mode 100644
index cffd46549..000000000
--- a/dom/indexedDB/test/test_lowDiskSpace.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
- <title>Indexed Database Low Disk Space Test</title>
-
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
- <script type="text/javascript;version=1.7" src="unit/test_lowDiskSpace.js"></script>
- <script type="text/javascript;version=1.7" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
diff --git a/dom/indexedDB/test/unit/test_lowDiskSpace.js b/dom/indexedDB/test/unit/test_lowDiskSpace.js
deleted file mode 100644
index eaea5797d..000000000
--- a/dom/indexedDB/test/unit/test_lowDiskSpace.js
+++ /dev/null
@@ -1,754 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-"use strict";
-
-var disableWorkerTest = "This test uses SpecialPowers";
-
-var self = this;
-
-var testGenerator = testSteps();
-
-function testSteps()
-{
- const dbName = self.window ? window.location.pathname : "test_lowDiskSpace";
- const dbVersion = 1;
-
- const objectStoreName = "foo";
- const objectStoreOptions = { keyPath: "foo" };
-
- const indexName = "bar";
- const indexOptions = { unique: true };
-
- const dbData = [
- { foo: 0, bar: 0 },
- { foo: 1, bar: 10 },
- { foo: 2, bar: 20 },
- { foo: 3, bar: 30 },
- { foo: 4, bar: 40 },
- { foo: 5, bar: 50 },
- { foo: 6, bar: 60 },
- { foo: 7, bar: 70 },
- { foo: 8, bar: 80 },
- { foo: 9, bar: 90 }
- ];
-
- let lowDiskMode = false;
- function setLowDiskMode(val) {
- let data = val ? "full" : "free";
-
- if (val == lowDiskMode) {
- info("Low disk mode is: " + data);
- }
- else {
- info("Changing low disk mode to: " + data);
- SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
- data);
- lowDiskMode = val;
- }
- }
-
- { // Make sure opening works from the beginning.
- info("Test 1");
-
- setLowDiskMode(false);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- is(event.type, "success", "Opened database without setting low disk mode");
-
- let db = event.target.result;
- db.close();
- }
-
- { // Make sure delete works in low disk mode.
- info("Test 2");
-
- setLowDiskMode(true);
-
- let request = indexedDB.deleteDatabase(dbName);
- request.onerror = errorHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- is(event.type, "success", "Deleted database after setting low disk mode");
- }
-
- { // Make sure creating a db in low disk mode fails.
- info("Test 3");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = expectedErrorHandler("QuotaExceededError");
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = unexpectedSuccessHandler;
- let event = yield undefined;
-
- is(event.type, "error", "Didn't create new database in low disk mode");
- }
-
- { // Make sure opening an already-existing db in low disk mode succeeds.
- info("Test 4");
-
- setLowDiskMode(false);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Created database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
-
- setLowDiskMode(true);
-
- request = indexedDB.open(dbName);
- request.onerror = errorHandler;
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Opened existing database in low disk mode");
-
- db = event.target.result;
- db.close();
- }
-
- { // Make sure upgrading an already-existing db in low disk mode succeeds.
- info("Test 5");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion + 1);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
-
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Created database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
- }
-
- { // Make sure creating objectStores in low disk mode fails.
- info("Test 6");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion + 2);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
-
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let txn = event.target.transaction;
- txn.onerror = expectedErrorHandler("AbortError");
- txn.onabort = grabEventAndContinueHandler;
-
- let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- event = yield undefined;
-
- is(event.type, "abort", "Got correct event type");
- is(event.target.error.name, "QuotaExceededError", "Got correct error type");
-
- request.onerror = expectedErrorHandler("AbortError");
- event = yield undefined;
- }
-
- { // Make sure creating indexes in low disk mode fails.
- info("Test 7");
-
- setLowDiskMode(false);
-
- let request = indexedDB.open(dbName, dbVersion + 2);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
-
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Upgraded database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
-
- setLowDiskMode(true);
-
- request = indexedDB.open(dbName, dbVersion + 3);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
- event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- db = event.target.result;
- db.onerror = errorHandler;
- let txn = event.target.transaction;
- txn.onerror = expectedErrorHandler("AbortError");
- txn.onabort = grabEventAndContinueHandler;
-
- objectStore = event.target.transaction.objectStore(objectStoreName);
- let index = objectStore.createIndex(indexName, indexName, indexOptions);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- event = yield undefined;
-
- is(event.type, "abort", "Got correct event type");
- is(event.target.error.name, "QuotaExceededError", "Got correct error type");
-
- request.onerror = expectedErrorHandler("AbortError");
- event = yield undefined;
- }
-
- { // Make sure deleting indexes in low disk mode succeeds.
- info("Test 8");
-
- setLowDiskMode(false);
-
- let request = indexedDB.open(dbName, dbVersion + 3);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
-
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let objectStore = event.target.transaction.objectStore(objectStoreName);
- let index = objectStore.createIndex(indexName, indexName, indexOptions);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Upgraded database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
-
- setLowDiskMode(true);
-
- request = indexedDB.open(dbName, dbVersion + 4);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
- event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- db = event.target.result;
- db.onerror = errorHandler;
-
- objectStore = event.target.transaction.objectStore(objectStoreName);
- objectStore.deleteIndex(indexName);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Upgraded database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
- }
-
- { // Make sure deleting objectStores in low disk mode succeeds.
- info("Test 9");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion + 5);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
-
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- db.deleteObjectStore(objectStoreName);
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Upgraded database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
-
- // Reset everything.
- indexedDB.deleteDatabase(dbName);
- }
-
-
- { // Add data that the rest of the tests will use.
- info("Adding test data");
-
- setLowDiskMode(false);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = grabEventAndContinueHandler;
- request.onsuccess = unexpectedSuccessHandler;
- let event = yield undefined;
-
- is(event.type, "upgradeneeded", "Upgrading database");
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
- let index = objectStore.createIndex(indexName, indexName, indexOptions);
-
- for (let data of dbData) {
- objectStore.add(data);
- }
-
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "success", "Upgraded database");
- ok(event.target.result === db, "Got the same database");
-
- db.close();
- }
-
- { // Make sure read operations in readonly transactions succeed in low disk
- // mode.
- info("Test 10");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let transaction = db.transaction(objectStoreName);
- let objectStore = transaction.objectStore(objectStoreName);
- let index = objectStore.index(indexName);
-
- let data = dbData[0];
-
- let requestCounter = new RequestCounter();
-
- objectStore.get(data.foo).onsuccess = requestCounter.handler();
- objectStore.mozGetAll().onsuccess = requestCounter.handler();
- objectStore.count().onsuccess = requestCounter.handler();
- index.get(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAll().onsuccess = requestCounter.handler();
- index.getKey(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAllKeys().onsuccess = requestCounter.handler();
- index.count().onsuccess = requestCounter.handler();
-
- let objectStoreDataCount = 0;
-
- request = objectStore.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- objectStoreDataCount++;
- objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(objectStoreDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexDataCount++;
- indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexKeyDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexKeyDataCount++;
- indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexKeyDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- // Wait for all requests.
- yield undefined;
-
- transaction.oncomplete = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "complete", "Transaction succeeded");
-
- db.close();
- }
-
- { // Make sure read operations in readwrite transactions succeed in low disk
- // mode.
- info("Test 11");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let transaction = db.transaction(objectStoreName, "readwrite");
- let objectStore = transaction.objectStore(objectStoreName);
- let index = objectStore.index(indexName);
-
- let data = dbData[0];
-
- let requestCounter = new RequestCounter();
-
- objectStore.get(data.foo).onsuccess = requestCounter.handler();
- objectStore.mozGetAll().onsuccess = requestCounter.handler();
- objectStore.count().onsuccess = requestCounter.handler();
- index.get(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAll().onsuccess = requestCounter.handler();
- index.getKey(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAllKeys().onsuccess = requestCounter.handler();
- index.count().onsuccess = requestCounter.handler();
-
- let objectStoreDataCount = 0;
-
- request = objectStore.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- objectStoreDataCount++;
- objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(objectStoreDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexDataCount++;
- indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexKeyDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexKeyDataCount++;
- indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexKeyDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- // Wait for all requests.
- yield undefined;
-
- transaction.oncomplete = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "complete", "Transaction succeeded");
-
- db.close();
- }
-
- { // Make sure write operations in readwrite transactions fail in low disk
- // mode.
- info("Test 12");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let transaction = db.transaction(objectStoreName, "readwrite");
- let objectStore = transaction.objectStore(objectStoreName);
- let index = objectStore.index(indexName);
-
- let data = dbData[0];
- let newData = { foo: 999, bar: 999 };
-
- let requestCounter = new RequestCounter();
-
- objectStore.add(newData).onerror = requestCounter.errorHandler();
- objectStore.put(newData).onerror = requestCounter.errorHandler();
-
- objectStore.get(data.foo).onsuccess = requestCounter.handler();
- objectStore.mozGetAll().onsuccess = requestCounter.handler();
- objectStore.count().onsuccess = requestCounter.handler();
- index.get(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAll().onsuccess = requestCounter.handler();
- index.getKey(data.bar).onsuccess = requestCounter.handler();
- index.mozGetAllKeys().onsuccess = requestCounter.handler();
- index.count().onsuccess = requestCounter.handler();
-
- let objectStoreDataCount = 0;
-
- request = objectStore.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- objectStoreDataCount++;
- cursor.update(cursor.value).onerror = requestCounter.errorHandler();
- objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(objectStoreDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexDataCount++;
- cursor.update(cursor.value).onerror = requestCounter.errorHandler();
- indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- let indexKeyDataCount = 0;
-
- request = index.openCursor();
- request.onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- indexKeyDataCount++;
- cursor.update(cursor.value).onerror = requestCounter.errorHandler();
- indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
- }
- else {
- is(indexKeyDataCount, dbData.length, "Saw all data");
- requestCounter.decr();
- }
- };
- requestCounter.incr();
-
- // Wait for all requests.
- yield undefined;
-
- transaction.oncomplete = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "complete", "Transaction succeeded");
-
- db.close();
- }
-
- { // Make sure deleting operations in readwrite transactions succeed in low
- // disk mode.
- info("Test 13");
-
- setLowDiskMode(true);
-
- let request = indexedDB.open(dbName, dbVersion);
- request.onerror = errorHandler;
- request.onupgradeneeded = unexpectedSuccessHandler;
- request.onsuccess = grabEventAndContinueHandler;
- let event = yield undefined;
-
- let db = event.target.result;
- db.onerror = errorHandler;
-
- let transaction = db.transaction(objectStoreName, "readwrite");
- let objectStore = transaction.objectStore(objectStoreName);
- let index = objectStore.index(indexName);
-
- let dataIndex = 0;
- let data = dbData[dataIndex++];
-
- let requestCounter = new RequestCounter();
-
- objectStore.delete(data.foo).onsuccess = requestCounter.handler();
-
- objectStore.openCursor().onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- cursor.delete().onsuccess = requestCounter.handler();
- }
- requestCounter.decr();
- };
- requestCounter.incr();
-
- index.openCursor(null, "prev").onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- cursor.delete().onsuccess = requestCounter.handler();
- }
- requestCounter.decr();
- };
- requestCounter.incr();
-
- yield undefined;
-
- objectStore.count().onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.target.result, dbData.length - 3, "Actually deleted something");
-
- objectStore.clear();
- objectStore.count().onsuccess = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.target.result, 0, "Actually cleared");
-
- transaction.oncomplete = grabEventAndContinueHandler;
- event = yield undefined;
-
- is(event.type, "complete", "Transaction succeeded");
-
- db.close();
- }
-
- finishTest();
- yield undefined;
-}
-
-function RequestCounter(expectedType) {
- this._counter = 0;
-}
-RequestCounter.prototype = {
- incr: function() {
- this._counter++;
- },
-
- decr: function() {
- if (!--this._counter) {
- continueToNextStepSync();
- }
- },
-
- handler: function(type, preventDefault) {
- this.incr();
- return function(event) {
- is(event.type, type || "success", "Correct type");
- this.decr();
- }.bind(this);
- },
-
- errorHandler: function(eventType, errorName) {
- this.incr();
- return function(event) {
- is(event.type, eventType || "error", "Correct type");
- is(event.target.error.name, errorName || "QuotaExceededError",
- "Correct error name");
- event.preventDefault();
- event.stopPropagation();
- this.decr();
- }.bind(this);
- }
-};
diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
index def791f52..fe69b1f7b 100644
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -66,9 +66,6 @@ function finishTest()
resetWasm();
resetExperimental();
resetTesting();
-
- SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
- "free");
}
SpecialPowers.removeFiles();
diff --git a/dom/indexedDB/test/unit/xpcshell-parent-process.ini b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
index 04df5f552..2def60c34 100644
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -46,7 +46,6 @@ skip-if = toolkit == 'android'
[test_invalidate.js]
# disabled for the moment.
skip-if = true
-[test_lowDiskSpace.js]
[test_maximal_serialized_object_size.js]
[test_metadata2Restore.js]
[test_metadataRestore.js]
diff --git a/dom/interfaces/css/nsIDOMCSSGroupingRule.idl b/dom/interfaces/css/nsIDOMCSSGroupingRule.idl
index 80f072d16..f3580aeec 100644
--- a/dom/interfaces/css/nsIDOMCSSGroupingRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSGroupingRule.idl
@@ -14,7 +14,7 @@ interface nsIDOMCSSGroupingRule : nsIDOMCSSRule
readonly attribute nsIDOMCSSRuleList cssRules;
unsigned long insertRule(in DOMString rule,
- in unsigned long index)
+ [optional] in unsigned long index)
raises(DOMException);
void deleteRule(in unsigned long index)
raises(DOMException);
diff --git a/dom/interfaces/css/nsIDOMCSSStyleSheet.idl b/dom/interfaces/css/nsIDOMCSSStyleSheet.idl
index b9e13134e..cefe4f704 100644
--- a/dom/interfaces/css/nsIDOMCSSStyleSheet.idl
+++ b/dom/interfaces/css/nsIDOMCSSStyleSheet.idl
@@ -20,7 +20,7 @@ interface nsIDOMCSSStyleSheet : nsIDOMStyleSheet
readonly attribute nsIDOMCSSRuleList cssRules;
unsigned long insertRule(in DOMString rule,
- in unsigned long index)
+ [optional] in unsigned long index)
raises(DOMException);
void deleteRule(in unsigned long index)
raises(DOMException);
diff --git a/dom/locales/en-US/chrome/plugins.properties b/dom/locales/en-US/chrome/plugins.properties
index fe03be59e..d5e65fea7 100644
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -28,7 +28,5 @@ gmp_privacy_info=Privacy Information
openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit http://www.openh264.org/ to view the codec source code and learn more about the implementation.
-eme-adobe_name=Primetime Content Decryption Module provided by Adobe Systems, Incorporated
-eme-adobe_description=Play back protected web video.
-
-widevine_description=Widevine Content Decryption Module provided by Google Inc.
+widevine_name=Widevine Content Decryption Module provided by Google Inc.
+widevine_description2=Play back protected web video.
diff --git a/dom/media/AudioStream.h b/dom/media/AudioStream.h
index acc38b93d..199314d4b 100644
--- a/dom/media/AudioStream.h
+++ b/dom/media/AudioStream.h
@@ -17,6 +17,10 @@
#include "mozilla/UniquePtr.h"
#include "CubebUtils.h"
#include "soundtouch/SoundTouchFactory.h"
+#ifdef XP_SOLARIS
+#include "soundtouch/SoundTouch.h"
+#endif
+
namespace mozilla {
diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp
index c06ba9070..56033c2fa 100644
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -31,7 +31,6 @@ namespace mozilla {
NS_NAMED_LITERAL_CSTRING(kEMEKeySystemClearkey, "org.w3.clearkey");
NS_NAMED_LITERAL_CSTRING(kEMEKeySystemWidevine, "com.widevine.alpha");
-NS_NAMED_LITERAL_CSTRING(kEMEKeySystemPrimetime, "com.adobe.primetime");
using layers::PlanarYCbCrImage;
diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h
index aaf0e9903..eee6561fd 100644
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -47,7 +47,6 @@ class MediaContentType;
// EME Key System String.
extern const nsLiteralCString kEMEKeySystemClearkey;
extern const nsLiteralCString kEMEKeySystemWidevine;
-extern const nsLiteralCString kEMEKeySystemPrimetime;
/**
* ReentrantMonitorConditionallyEnter
diff --git a/dom/media/eme/EMEUtils.cpp b/dom/media/eme/EMEUtils.cpp
index c248b3a24..11eb0026e 100644
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -54,12 +54,6 @@ IsClearkeyKeySystem(const nsAString& aKeySystem)
}
bool
-IsPrimetimeKeySystem(const nsAString& aKeySystem)
-{
- return !CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem);
-}
-
-bool
IsWidevineKeySystem(const nsAString& aKeySystem)
{
return !CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem);
@@ -68,9 +62,6 @@ IsWidevineKeySystem(const nsAString& aKeySystem)
nsString
KeySystemToGMPName(const nsAString& aKeySystem)
{
- if (IsPrimetimeKeySystem(aKeySystem)) {
- return NS_LITERAL_STRING("gmp-eme-adobe");
- }
if (IsClearkeyKeySystem(aKeySystem)) {
return NS_LITERAL_STRING("gmp-clearkey");
}
@@ -88,8 +79,6 @@ ToCDMTypeTelemetryEnum(const nsString& aKeySystem)
return CDMType::eWidevine;
} else if (IsClearkeyKeySystem(aKeySystem)) {
return CDMType::eClearKey;
- } else if (IsPrimetimeKeySystem(aKeySystem)) {
- return CDMType::ePrimetime;
}
return CDMType::eUnknown;
}
diff --git a/dom/media/eme/EMEUtils.h b/dom/media/eme/EMEUtils.h
index 1794f8462..4a2e5da18 100644
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -87,14 +87,10 @@ bool
IsClearkeyKeySystem(const nsAString& aKeySystem);
bool
-IsPrimetimeKeySystem(const nsAString& aKeySystem);
-
-bool
IsWidevineKeySystem(const nsAString& aKeySystem);
enum CDMType {
eClearKey = 0,
- ePrimetime = 1,
eWidevine = 2,
eUnknown = 3
};
diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp
index 4cff464e7..4a5a7a30c 100644
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -134,16 +134,6 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
return EnsureCDMInstalled(aKeySystem, aOutMessage);
}
- if (Preferences::GetBool("media.gmp-eme-adobe.visible", false)) {
- if (IsPrimetimeKeySystem(aKeySystem)) {
- if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
- aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
- return MediaKeySystemStatus::Cdm_disabled;
- }
- return EnsureCDMInstalled(aKeySystem, aOutMessage);
- }
- }
-
if (IsWidevineKeySystem(aKeySystem)) {
if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
@@ -376,19 +366,6 @@ GetSupportedKeySystems()
keySystemConfigs.AppendElement(Move(widevine));
}
}
- {
- if (HavePluginForKeySystem(kEMEKeySystemPrimetime)) {
- KeySystemConfig primetime;
- primetime.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemPrimetime);
- primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
- primetime.mPersistentState = KeySystemFeatureSupport::Required;
- primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required;
- primetime.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
- primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_AAC);
- primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
- keySystemConfigs.AppendElement(Move(primetime));
- }
- }
return keySystemConfigs;
}
diff --git a/dom/media/eme/MediaKeySystemAccessManager.cpp b/dom/media/eme/MediaKeySystemAccessManager.cpp
index 8fefc62ec..ed31059e2 100644
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -95,8 +95,7 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
// Ensure keysystem is supported.
if (!IsWidevineKeySystem(aKeySystem) &&
- !IsClearkeyKeySystem(aKeySystem) &&
- !IsPrimetimeKeySystem(aKeySystem)) {
+ !IsClearkeyKeySystem(aKeySystem)) {
// Not to inform user, because nothing to do if the keySystem is not
// supported.
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
@@ -132,7 +131,7 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg));
if (status == MediaKeySystemStatus::Cdm_not_installed &&
- (IsPrimetimeKeySystem(aKeySystem) || IsWidevineKeySystem(aKeySystem))) {
+ IsWidevineKeySystem(aKeySystem)) {
// These are cases which could be resolved by downloading a new(er) CDM.
// When we send the status to chrome, chrome's GMPProvider will attempt to
// download or update the CDM. In AwaitInstall() we add listeners to wait
diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp
index 418f14736..234ed5c05 100644
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -726,16 +726,6 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFile)
if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
mCanDecrypt = true;
-
-#ifdef XP_WIN
- // Adobe GMP doesn't work without SSE2. Check the tags to see if
- // the decryptor is for the Adobe GMP, and refuse to load it if
- // SSE2 isn't supported.
- if (cap.mAPITags.Contains(kEMEKeySystemPrimetime) &&
- !mozilla::supports_sse2()) {
- return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
- }
-#endif // XP_WIN
}
mCapabilities.AppendElement(Move(cap));
diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp
index 2b4831cd6..fcf9fa920 100644
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -203,29 +203,6 @@ MoveAndOverwrite(nsIFile* aOldParentDir,
}
}
-static void
-MigratePreGecko42StorageDir(nsIFile* aOldStorageDir,
- nsIFile* aNewStorageDir)
-{
- MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("id"));
- MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("storage"));
-}
-
-static void
-MigratePreGecko45StorageDir(nsIFile* aStorageDirBase)
-{
- nsCOMPtr<nsIFile> adobeStorageDir(CloneAndAppend(aStorageDirBase, NS_LITERAL_STRING("gmp-eme-adobe")));
- if (NS_WARN_IF(!adobeStorageDir)) {
- return;
- }
-
- // The base storage dir in pre-45 contained "id" and "storage" subdirs.
- // We assume all storage in the base storage dir that aren't known to GMP
- // storage are records for the Adobe GMP.
- MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("id"));
- MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("storage"));
-}
-
static nsresult
GMPPlatformString(nsAString& aOutPlatform)
{
@@ -308,19 +285,6 @@ GeckoMediaPluginServiceParent::InitStorage()
return rv;
}
- // Prior to 42, GMP storage was stored in $profileDir/gmp/. After 42, it's
- // stored in $profileDir/gmp/$platform/. So we must migrate any old records
- // from the old location to the new location, for forwards compatibility.
- MigratePreGecko42StorageDir(gmpDirWithoutPlatform, mStorageBaseDir);
-
- // Prior to 45, GMP storage was not separated by plugin. In 45 and after,
- // it's stored in $profile/gmp/$platform/$gmpName. So we must migrate old
- // records from the old location to the new location, for forwards
- // compatibility. We assume all directories in the base storage dir that
- // aren't known to GMP storage are records for the Adobe GMP, since it
- // was first.
- MigratePreGecko45StorageDir(mStorageBaseDir);
-
return GeckoMediaPluginService::Init();
}
diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
index cc53d2c93..50a5097ac 100644
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -109,7 +109,6 @@ GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
switch (MediaPrefs::GMPAACPreferred()) {
case 1: rv.emplace(kEMEKeySystemClearkey); break;
- case 2: rv.emplace(kEMEKeySystemPrimetime); break;
default: break;
}
}
@@ -117,7 +116,6 @@ GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
if (MP4Decoder::IsH264(aMimeType)) {
switch (MediaPrefs::GMPH264Preferred()) {
case 1: rv.emplace(kEMEKeySystemClearkey); break;
- case 2: rv.emplace(kEMEKeySystemPrimetime); break;
default: break;
}
}
diff --git a/dom/media/test/external/external_media_harness/testcase.py b/dom/media/test/external/external_media_harness/testcase.py
index 56350ccd9..35a944484 100644
--- a/dom/media/test/external/external_media_harness/testcase.py
+++ b/dom/media/test/external/external_media_harness/testcase.py
@@ -200,19 +200,6 @@ class NetworkBandwidthTestsMixin(object):
self.run_videos(timeout=120)
-reset_adobe_gmp_script = """
-navigator.requestMediaKeySystemAccess('com.adobe.primetime',
-[{initDataTypes: ['cenc']}]).then(
- function(access) {
- marionetteScriptFinished('success');
- },
- function(ex) {
- marionetteScriptFinished(ex);
- }
-);
-"""
-
-
reset_widevine_gmp_script = """
navigator.requestMediaKeySystemAccess('com.widevine.alpha',
[{initDataTypes: ['cenc']}]).then(
@@ -256,21 +243,12 @@ class EMESetupMixin(object):
def reset_GMP_version(self):
if EMESetupMixin.version_needs_reset:
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
- if self.marionette.get_pref('media.gmp-eme-adobe.version'):
- self.marionette.reset_pref('media.gmp-eme-adobe.version')
if self.marionette.get_pref('media.gmp-widevinecdm.version'):
self.marionette.reset_pref('media.gmp-widevinecdm.version')
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
- adobe_result = self.marionette.execute_async_script(
- reset_adobe_gmp_script,
- script_timeout=60000)
widevine_result = self.marionette.execute_async_script(
reset_widevine_gmp_script,
script_timeout=60000)
- if not adobe_result == 'success':
- raise VideoException(
- 'ERROR: Resetting Adobe GMP failed {}'
- .format(adobe_result))
if not widevine_result == 'success':
raise VideoException(
'ERROR: Resetting Widevine GMP failed {}'
@@ -352,10 +330,6 @@ class EMESetupMixin(object):
self.check_and_log_boolean_pref(
'media.mediasource.mp4.enabled', True),
self.check_and_log_boolean_pref(
- 'media.gmp-eme-adobe.enabled', True),
- self.check_and_log_integer_pref(
- 'media.gmp-eme-adobe.version', 1),
- self.check_and_log_boolean_pref(
'media.gmp-widevinecdm.enabled', True),
self.chceck_and_log_version_string_pref(
'media.gmp-widevinecdm.version', '1.0.0.0')
diff --git a/dom/plugins/base/npapi.h b/dom/plugins/base/npapi.h
index 12ac635c7..e554aaabc 100644
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -327,9 +327,12 @@ typedef enum {
#define NP_ABI_GCC3_MASK 0x10000000
/*
* gcc 3.x generated vtables on UNIX and OSX are incompatible with
- * previous compilers.
+ * previous compilers. Flash plugin binaries for Solaris were compiled
+ * with Sun Studio, so this has to be false to make things work. This may
+ * become a problem in the future when/if new plugins are compiled with
+ * GCC, however.
*/
-#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
+#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3) && !defined(XP_SOLARIS))
#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
#else
#define _NP_ABI_MIXIN_FOR_GCC3 0
diff --git a/dom/plugins/base/nptypes.h b/dom/plugins/base/nptypes.h
index c36532472..d0cef6540 100644
--- a/dom/plugins/base/nptypes.h
+++ b/dom/plugins/base/nptypes.h
@@ -22,6 +22,19 @@
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
+#elif defined(__sun)
+ /*
+ * SunOS ships an inttypes.h header that defines [u]int32_t,
+ * but not bool for C.
+ */
+ #include <inttypes.h>
+
+
+ #ifndef __cplusplus
+ typedef int bool;
+ #define true 1
+ #define false 0
+ #endif
#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
/*
* BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp
index 05e0ec4ba..1d42c18d6 100644
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -248,7 +248,6 @@ const static js::ObjectOps sNPObjectJSWrapperObjectOps = {
nullptr, // setProperty
nullptr, // getOwnPropertyDescriptor
nullptr, // deleteProperty
- nullptr, nullptr, // watch/unwatch
nullptr, // getElements
NPObjWrapper_Enumerate,
nullptr,
diff --git a/dom/plugins/base/nsPluginsDirUnix.cpp b/dom/plugins/base/nsPluginsDirUnix.cpp
index e6956c34c..de3b7a2d1 100644
--- a/dom/plugins/base/nsPluginsDirUnix.cpp
+++ b/dom/plugins/base/nsPluginsDirUnix.cpp
@@ -19,7 +19,9 @@
#include "nsIPrefService.h"
#define LOCAL_PLUGIN_DLL_SUFFIX ".so"
-#if defined(LINUX)
+#ifdef XP_SOLARIS
+#define DEFAULT_X11_PATH "/usr/openwin/lib"
+#elif defined(LINUX)
#define DEFAULT_X11_PATH "/usr/X11R6/lib/"
#elif defined(__APPLE__)
#define DEFAULT_X11_PATH "/usr/X11R6/lib"
@@ -92,7 +94,11 @@ static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSon
#define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32
#define PREF_PLUGINS_SONAME "plugin.soname.list"
+#ifdef XP_SOLARIS
+#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX
+#else
#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX
+#endif
/*
this function looks for
user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so");
@@ -264,11 +270,15 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
// at runtime. Explicitly opening Xt/Xext into the global
// namespace before attempting to load the plug-in seems to
// work fine.
-
-
+#if defined(XP_SOLARIS)
+ // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
+ *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
+ pLibrary = *outLibrary;
+#else
// Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
*outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
pLibrary = *outLibrary;
+#endif
if (!pLibrary) {
LoadExtraSharedLibs();
// try reload plugin once more
diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp
index af9db9103..3f2cdbc13 100644
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -310,9 +310,10 @@ PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
switch (aValue) {
case NPNVWindowNPObject:
if (!(actor = mCachedWindowActor)) {
+ result = NPERR_GENERIC_ERROR;
PPluginScriptableObjectChild* actorProtocol;
- CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result);
- if (result == NPERR_NO_ERROR) {
+ if (CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result) &&
+ result == NPERR_NO_ERROR) {
actor = mCachedWindowActor =
static_cast<PluginScriptableObjectChild*>(actorProtocol);
NS_ASSERTION(actor, "Null actor!");
@@ -324,10 +325,10 @@ PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
case NPNVPluginElementNPObject:
if (!(actor = mCachedElementActor)) {
+ result = NPERR_GENERIC_ERROR;
PPluginScriptableObjectChild* actorProtocol;
- CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol,
- &result);
- if (result == NPERR_NO_ERROR) {
+ if (CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol, &result) &&
+ result == NPERR_NO_ERROR) {
actor = mCachedElementActor =
static_cast<PluginScriptableObjectChild*>(actorProtocol);
NS_ASSERTION(actor, "Null actor!");
@@ -338,6 +339,7 @@ PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
break;
default:
+ result = NPERR_GENERIC_ERROR;
NS_NOTREACHED("Don't know what to do with this value type!");
}
@@ -434,6 +436,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
case NPNVWindowNPObject: // Intentional fall-through
case NPNVPluginElementNPObject: {
NPObject* object;
+ *((NPObject**)aValue) = nullptr;
NPError result = InternalGetNPObjectForValue(aVar, &object);
if (result == NPERR_NO_ERROR) {
*((NPObject**)aValue) = object;
diff --git a/dom/plugins/ipc/PluginMessageUtils.cpp b/dom/plugins/ipc/PluginMessageUtils.cpp
index 47653fe6e..5b1d1667f 100644
--- a/dom/plugins/ipc/PluginMessageUtils.cpp
+++ b/dom/plugins/ipc/PluginMessageUtils.cpp
@@ -82,7 +82,7 @@ MediateRace(const MessageChannel::MessageInfo& parent,
}
}
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_SOLARIS)
static string
ReplaceAll(const string& haystack, const string& needle, const string& with)
{
@@ -101,7 +101,7 @@ ReplaceAll(const string& haystack, const string& needle, const string& with)
string
MungePluginDsoPath(const string& path)
{
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_SOLARIS)
// https://bugzilla.mozilla.org/show_bug.cgi?id=519601
return ReplaceAll(path, "netscape", "netsc@pe");
#else
@@ -112,7 +112,7 @@ MungePluginDsoPath(const string& path)
string
UnmungePluginDsoPath(const string& munged)
{
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_SOLARIS)
return ReplaceAll(munged, "netsc@pe", "netscape");
#else
return munged;
diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp
index cbf6e509f..f943dfc42 100644
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -286,7 +286,7 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
// TODO: use PluginPRLibrary here
-#if defined(OS_LINUX) || defined(OS_BSD)
+#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
mShutdownFunc =
(NP_PLUGINSHUTDOWN) PR_FindFunctionSymbol(mLibrary, "NP_Shutdown");
@@ -1821,7 +1821,7 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
AssertPluginThread();
MOZ_ASSERT(mIsChrome);
-#if defined(OS_LINUX) || defined(OS_BSD)
+#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
return true;
#elif defined(OS_WIN) || defined(OS_MACOSX)
*_retval = mGetEntryPointsFunc(&mFunctions);
@@ -1866,7 +1866,7 @@ PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
#endif
NPError result;
-#if defined(OS_LINUX) || defined(OS_BSD)
+#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
result = mInitializeFunc(&sBrowserFuncs, &mFunctions);
#elif defined(OS_WIN) || defined(OS_MACOSX)
result = mInitializeFunc(&sBrowserFuncs);
diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h
index 681743582..5e4fa7d20 100644
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -258,7 +258,7 @@ private:
// we get this from the plugin
NP_PLUGINSHUTDOWN mShutdownFunc;
-#if defined(OS_LINUX) || defined(OS_BSD)
+#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
NP_PLUGINUNIXINIT mInitializeFunc;
#elif defined(OS_WIN) || defined(OS_MACOSX)
NP_PLUGININIT mInitializeFunc;
diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp
index f636a9101..e5279345d 100644
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -30,7 +30,6 @@
#include "nsJSPrincipals.h"
#include "nsJSUtils.h"
#include "nsPIDOMWindow.h"
-#include "PromiseCallback.h"
#include "PromiseDebugging.h"
#include "PromiseNativeHandler.h"
#include "PromiseWorkerProxy.h"
@@ -49,467 +48,45 @@ Atomic<uintptr_t> gIDGenerator(0);
using namespace workers;
-#ifndef SPIDERMONKEY_PROMISE
-// This class processes the promise's callbacks with promise's result.
-class PromiseReactionJob final : public Runnable
-{
-public:
- PromiseReactionJob(Promise* aPromise,
- PromiseCallback* aCallback,
- const JS::Value& aValue)
- : mPromise(aPromise)
- , mCallback(aCallback)
- , mValue(CycleCollectedJSContext::Get()->Context(), aValue)
- {
- MOZ_ASSERT(aPromise);
- MOZ_ASSERT(aCallback);
- MOZ_COUNT_CTOR(PromiseReactionJob);
- }
-
- virtual
- ~PromiseReactionJob()
- {
- NS_ASSERT_OWNINGTHREAD(PromiseReactionJob);
- MOZ_COUNT_DTOR(PromiseReactionJob);
- }
-
-protected:
- NS_IMETHOD
- Run() override
- {
- NS_ASSERT_OWNINGTHREAD(PromiseReactionJob);
-
- MOZ_ASSERT(mPromise->GetWrapper()); // It was preserved!
-
- AutoJSAPI jsapi;
- if (!jsapi.Init(mPromise->GetWrapper())) {
- return NS_ERROR_FAILURE;
- }
- JSContext* cx = jsapi.cx();
-
- JS::Rooted<JS::Value> value(cx, mValue);
- if (!MaybeWrapValue(cx, &value)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- JS_ClearPendingException(cx);
- return NS_OK;
- }
-
- JS::Rooted<JSObject*> asyncStack(cx, mPromise->mAllocationStack);
-
- {
- Maybe<JS::AutoSetAsyncStackForNewCalls> sas;
- if (asyncStack) {
- sas.emplace(cx, asyncStack, "Promise");
- }
- mCallback->Call(cx, value);
- }
-
- return NS_OK;
- }
-
-private:
- RefPtr<Promise> mPromise;
- RefPtr<PromiseCallback> mCallback;
- JS::PersistentRooted<JS::Value> mValue;
- NS_DECL_OWNINGTHREAD;
-};
-
-/*
- * Utilities for thenable callbacks.
- *
- * A thenable is a { then: function(resolve, reject) { } }.
- * `then` is called with a resolve and reject callback pair.
- * Since only one of these should be called at most once (first call wins), the
- * two keep a reference to each other in SLOT_DATA. When either of them is
- * called, the references are cleared. Further calls are ignored.
- */
-namespace {
-void
-LinkThenableCallables(JSContext* aCx, JS::Handle<JSObject*> aResolveFunc,
- JS::Handle<JSObject*> aRejectFunc)
-{
- js::SetFunctionNativeReserved(aResolveFunc, Promise::SLOT_DATA,
- JS::ObjectValue(*aRejectFunc));
- js::SetFunctionNativeReserved(aRejectFunc, Promise::SLOT_DATA,
- JS::ObjectValue(*aResolveFunc));
-}
-
-/*
- * Returns false if callback was already called before, otherwise breaks the
- * links and returns true.
- */
-bool
-MarkAsCalledIfNotCalledBefore(JSContext* aCx, JS::Handle<JSObject*> aFunc)
-{
- JS::Value otherFuncVal =
- js::GetFunctionNativeReserved(aFunc, Promise::SLOT_DATA);
-
- if (!otherFuncVal.isObject()) {
- return false;
- }
-
- JSObject* otherFuncObj = &otherFuncVal.toObject();
- MOZ_ASSERT(js::GetFunctionNativeReserved(otherFuncObj,
- Promise::SLOT_DATA).isObject());
-
- // Break both references.
- js::SetFunctionNativeReserved(aFunc, Promise::SLOT_DATA,
- JS::UndefinedValue());
- js::SetFunctionNativeReserved(otherFuncObj, Promise::SLOT_DATA,
- JS::UndefinedValue());
-
- return true;
-}
-
-Promise*
-GetPromise(JSContext* aCx, JS::Handle<JSObject*> aFunc)
-{
- JS::Value promiseVal = js::GetFunctionNativeReserved(aFunc,
- Promise::SLOT_PROMISE);
-
- MOZ_ASSERT(promiseVal.isObject());
-
- Promise* promise;
- UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise);
- return promise;
-}
-} // namespace
-
-// Runnable to resolve thenables.
-// Equivalent to the specification's ResolvePromiseViaThenableTask.
-class PromiseResolveThenableJob final : public Runnable
-{
-public:
- PromiseResolveThenableJob(Promise* aPromise,
- JS::Handle<JSObject*> aThenable,
- PromiseInit* aThen)
- : mPromise(aPromise)
- , mThenable(CycleCollectedJSContext::Get()->Context(), aThenable)
- , mThen(aThen)
- {
- MOZ_ASSERT(aPromise);
- MOZ_COUNT_CTOR(PromiseResolveThenableJob);
- }
-
- virtual
- ~PromiseResolveThenableJob()
- {
- NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob);
- MOZ_COUNT_DTOR(PromiseResolveThenableJob);
- }
-
-protected:
- NS_IMETHOD
- Run() override
- {
- NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob);
-
- MOZ_ASSERT(mPromise->GetWrapper()); // It was preserved!
-
- AutoJSAPI jsapi;
- // If we ever change which compartment we're working in here, make sure to
- // fix the fast-path for resolved-with-a-Promise in ResolveInternal.
- if (!jsapi.Init(mPromise->GetWrapper())) {
- return NS_ERROR_FAILURE;
- }
- JSContext* cx = jsapi.cx();
-
- JS::Rooted<JSObject*> resolveFunc(cx,
- mPromise->CreateThenableFunction(cx, mPromise, PromiseCallback::Resolve));
-
- if (!resolveFunc) {
- mPromise->HandleException(cx);
- return NS_OK;
- }
-
- JS::Rooted<JSObject*> rejectFunc(cx,
- mPromise->CreateThenableFunction(cx, mPromise, PromiseCallback::Reject));
- if (!rejectFunc) {
- mPromise->HandleException(cx);
- return NS_OK;
- }
-
- LinkThenableCallables(cx, resolveFunc, rejectFunc);
-
- ErrorResult rv;
-
- JS::Rooted<JSObject*> rootedThenable(cx, mThenable);
-
- mThen->Call(rootedThenable, resolveFunc, rejectFunc, rv,
- "promise thenable", CallbackObject::eRethrowExceptions,
- mPromise->Compartment());
-
- rv.WouldReportJSException();
- if (rv.Failed()) {
- JS::Rooted<JS::Value> exn(cx);
- { // Scope for JSAutoCompartment
-
- // Convert the ErrorResult to a JS exception object that we can reject
- // ourselves with. This will be exactly the exception that would get
- // thrown from a binding method whose ErrorResult ended up with
- // whatever is on "rv" right now.
- JSAutoCompartment ac(cx, mPromise->GlobalJSObject());
- DebugOnly<bool> conversionResult = ToJSValue(cx, rv, &exn);
- MOZ_ASSERT(conversionResult);
- }
-
- bool couldMarkAsCalled = MarkAsCalledIfNotCalledBefore(cx, resolveFunc);
-
- // If we could mark as called, neither of the callbacks had been called
- // when the exception was thrown. So we can reject the Promise.
- if (couldMarkAsCalled) {
- bool ok = JS_WrapValue(cx, &exn);
- MOZ_ASSERT(ok);
- if (!ok) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- }
-
- mPromise->RejectInternal(cx, exn);
- }
- // At least one of resolveFunc or rejectFunc have been called, so ignore
- // the exception. FIXME(nsm): This should be reported to the error
- // console though, for debugging.
- }
-
- return rv.StealNSResult();
- }
-
-private:
- RefPtr<Promise> mPromise;
- JS::PersistentRooted<JSObject*> mThenable;
- RefPtr<PromiseInit> mThen;
- NS_DECL_OWNINGTHREAD;
-};
-
-// A struct implementing
-// <http://www.ecma-international.org/ecma-262/6.0/#sec-promisecapability-records>.
-// While the spec holds on to these in some places, in practice those places
-// don't actually need everything from this struct, so we explicitly grab
-// members from it as needed in those situations. That allows us to make this a
-// stack-only struct and keep the rooting simple.
-//
-// We also add an optimization for the (common) case when we discover that the
-// Promise constructor we're supposed to use is in fact the canonical Promise
-// constructor. In that case we will just set mNativePromise in our
-// PromiseCapability and not set mPromise/mResolve/mReject; the correct
-// callbacks will be the standard Promise ones, and we don't really want to
-// synthesize JSFunctions for them in that situation.
-struct MOZ_STACK_CLASS Promise::PromiseCapability
-{
- explicit PromiseCapability(JSContext* aCx)
- : mPromise(aCx)
- , mResolve(aCx)
- , mReject(aCx)
- {}
-
- // Take an exception on aCx and try to convert it into a promise rejection.
- // Note that this can result in a new exception being thrown on aCx, or an
- // exception getting thrown on aRv. On entry to this method, aRv is assumed
- // to not be a failure. This should only be called if NewPromiseCapability
- // succeeded on this PromiseCapability.
- void RejectWithException(JSContext* aCx, ErrorResult& aRv);
-
- // Return a JS::Value representing the promise. This should only be called if
- // NewPromiseCapability succeeded on this PromiseCapability. It makes no
- // guarantees about compartments (e.g. in the mNativePromise case it's in the
- // compartment of the reflector, but in the mPromise case it might be in the
- // compartment of some cross-compartment wrapper for a reflector).
- JS::Value PromiseValue() const;
-
- // All the JS::Value fields of this struct are actually objects, but for our
- // purposes it's simpler to store them as JS::Value.
-
- // [[Promise]].
- JS::Rooted<JSObject*> mPromise;
- // [[Resolve]]. Value in the context compartment.
- JS::Rooted<JS::Value> mResolve;
- // [[Reject]]. Value in the context compartment.
- JS::Rooted<JS::Value> mReject;
- // If mNativePromise is non-null, we should use it, not mPromise.
- RefPtr<Promise> mNativePromise;
-
-private:
- // We don't want to allow creation of temporaries of this type, ever.
- PromiseCapability(const PromiseCapability&) = delete;
- PromiseCapability(PromiseCapability&&) = delete;
-};
-
-void
-Promise::PromiseCapability::RejectWithException(JSContext* aCx,
- ErrorResult& aRv)
-{
- // This method basically implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-ifabruptrejectpromise
- // or at least the parts of it that happen if we have an abrupt completion.
-
- MOZ_ASSERT(!aRv.Failed());
- MOZ_ASSERT(mNativePromise || mPromise,
- "NewPromiseCapability didn't succeed");
-
- JS::Rooted<JS::Value> exn(aCx);
- if (!JS_GetPendingException(aCx, &exn)) {
- // This is an uncatchable exception, so can't be converted into a rejection.
- // Just rethrow that on aRv.
- aRv.ThrowUncatchableException();
- return;
- }
-
- JS_ClearPendingException(aCx);
-
- // If we have a native promise, just reject it without trying to call out into
- // JS.
- if (mNativePromise) {
- mNativePromise->MaybeRejectInternal(aCx, exn);
- return;
- }
-
- JS::Rooted<JS::Value> ignored(aCx);
- if (!JS::Call(aCx, JS::UndefinedHandleValue, mReject, JS::HandleValueArray(exn),
- &ignored)) {
- aRv.NoteJSContextException(aCx);
- }
-}
-
-JS::Value
-Promise::PromiseCapability::PromiseValue() const
-{
- MOZ_ASSERT(mNativePromise || mPromise,
- "NewPromiseCapability didn't succeed");
-
- if (mNativePromise) {
- return JS::ObjectValue(*mNativePromise->GetWrapper());
- }
-
- return JS::ObjectValue(*mPromise);
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
// Promise
NS_IMPL_CYCLE_COLLECTION_CLASS(Promise)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Promise)
-#ifndef SPIDERMONKEY_PROMISE
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- tmp->MaybeReportRejectedOnce();
-#else
- tmp->mResult = JS::UndefinedValue();
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-#endif // SPIDERMONKEY_PROMISE
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
-#ifndef SPIDERMONKEY_PROMISE
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mResolveCallbacks)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mRejectCallbacks)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-#else // SPIDERMONKEY_PROMISE
tmp->mPromiseObj = nullptr;
-#endif // SPIDERMONKEY_PROMISE
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Promise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
-#ifndef SPIDERMONKEY_PROMISE
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveCallbacks)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectCallbacks)
-#endif // SPIDERMONKEY_PROMISE
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Promise)
-#ifndef SPIDERMONKEY_PROMISE
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResult)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAllocationStack)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRejectionStack)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mFullfillmentStack)
- NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-#else // SPIDERMONKEY_PROMISE
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPromiseObj);
-#endif // SPIDERMONKEY_PROMISE
NS_IMPL_CYCLE_COLLECTION_TRACE_END
-#ifndef SPIDERMONKEY_PROMISE
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Promise)
- if (tmp->IsBlack()) {
- tmp->mResult.exposeToActiveJS();
- tmp->mAllocationStack.exposeToActiveJS();
- tmp->mRejectionStack.exposeToActiveJS();
- tmp->mFullfillmentStack.exposeToActiveJS();
- return true;
- }
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
-
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Promise)
- return tmp->IsBlackAndDoesNotNeedTracing(tmp);
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
-
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Promise)
- return tmp->IsBlack();
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
-#endif // SPIDERMONKEY_PROMISE
-
NS_IMPL_CYCLE_COLLECTING_ADDREF(Promise)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Promise)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Promise)
-#ifndef SPIDERMONKEY_PROMISE
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-#endif // SPIDERMONKEY_PROMISE
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(Promise)
NS_INTERFACE_MAP_END
Promise::Promise(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
-#ifndef SPIDERMONKEY_PROMISE
- , mResult(JS::UndefinedValue())
- , mAllocationStack(nullptr)
- , mRejectionStack(nullptr)
- , mFullfillmentStack(nullptr)
- , mState(Pending)
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- , mHadRejectCallback(false)
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
- , mTaskPending(false)
- , mResolvePending(false)
- , mIsLastInChain(true)
- , mWasNotifiedAsUncaught(false)
- , mID(0)
-#else // SPIDERMONKEY_PROMISE
, mPromiseObj(nullptr)
-#endif // SPIDERMONKEY_PROMISE
{
MOZ_ASSERT(mGlobal);
mozilla::HoldJSObjects(this);
-
-#ifndef SPIDERMONKEY_PROMISE
- mCreationTimestamp = TimeStamp::Now();
-#endif // SPIDERMONKEY_PROMISE
}
Promise::~Promise()
{
-#ifndef SPIDERMONKEY_PROMISE
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- MaybeReportRejectedOnce();
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-#endif // SPIDERMONKEY_PROMISE
mozilla::DropJSObjects(this);
}
-#ifdef SPIDERMONKEY_PROMISE
-
-bool
-Promise::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
- JS::MutableHandle<JSObject*> aWrapper)
-{
-#ifdef DEBUG
- binding_detail::AssertReflectorHasGivenProto(aCx, mPromiseObj, aGivenProto);
-#endif // DEBUG
- aWrapper.set(mPromiseObj);
- return true;
-}
-
// static
already_AddRefed<Promise>
Promise::Create(nsIGlobalObject* aGlobal, ErrorResult& aRv)
@@ -884,8 +461,7 @@ Promise::HandleException(JSContext* aCx)
JS::Rooted<JS::Value> exn(aCx);
if (JS_GetPendingException(aCx, &exn)) {
JS_ClearPendingException(aCx);
- // This is only called from MaybeSomething, so it's OK to MaybeReject here,
- // unlike in the version that's used when !SPIDERMONKEY_PROMISE.
+ // This is only called from MaybeSomething, so it's OK to MaybeReject here.
MaybeReject(aCx, exn);
}
}
@@ -902,80 +478,6 @@ Promise::CreateFromExisting(nsIGlobalObject* aGlobal,
return p.forget();
}
-#else // SPIDERMONKEY_PROMISE
-
-JSObject*
-Promise::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return PromiseBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<Promise>
-Promise::Create(nsIGlobalObject* aGlobal, ErrorResult& aRv,
- JS::Handle<JSObject*> aDesiredProto)
-{
- if (!aGlobal) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
- RefPtr<Promise> p = new Promise(aGlobal);
- p->CreateWrapper(aDesiredProto, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
- return p.forget();
-}
-
-void
-Promise::CreateWrapper(JS::Handle<JSObject*> aDesiredProto, ErrorResult& aRv)
-{
- AutoJSAPI jsapi;
- if (!jsapi.Init(mGlobal)) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
- JSContext* cx = jsapi.cx();
-
- JS::Rooted<JS::Value> wrapper(cx);
- if (!GetOrCreateDOMReflector(cx, this, &wrapper, aDesiredProto)) {
- JS_ClearPendingException(cx);
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- dom::PreserveWrapper(this);
-
- // Now grab our allocation stack
- if (!CaptureStack(cx, mAllocationStack)) {
- JS_ClearPendingException(cx);
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- JS::RootedObject obj(cx, &wrapper.toObject());
- JS::dbg::onNewPromise(cx, obj);
-}
-
-void
-Promise::MaybeResolve(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- MaybeResolveInternal(aCx, aValue);
-}
-
-void
-Promise::MaybeReject(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- MaybeRejectInternal(aCx, aValue);
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
void
Promise::MaybeResolveWithUndefined()
{
@@ -999,7 +501,6 @@ Promise::MaybeRejectWithUndefined()
MaybeSomething(JS::UndefinedHandleValue, &Promise::MaybeReject);
}
-#ifdef SPIDERMONKEY_PROMISE
void
Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
{
@@ -1026,7 +527,6 @@ Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
// Now post an event to do the real reporting async
NS_DispatchToMainThread(new AsyncErrorReporter(xpcReport));
}
-#endif // defined(SPIDERMONKEY_PROMISE)
bool
Promise::PerformMicroTaskCheckpoint()
@@ -1132,1422 +632,6 @@ Promise::PerformWorkerDebuggerMicroTaskCheckpoint()
}
}
-#ifndef SPIDERMONKEY_PROMISE
-
-/* static */ bool
-Promise::JSCallback(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
-
- JS::Rooted<JS::Value> v(aCx,
- js::GetFunctionNativeReserved(&args.callee(),
- SLOT_PROMISE));
- MOZ_ASSERT(v.isObject());
-
- Promise* promise;
- if (NS_FAILED(UNWRAP_OBJECT(Promise, &v.toObject(), promise))) {
- return Throw(aCx, NS_ERROR_UNEXPECTED);
- }
-
- v = js::GetFunctionNativeReserved(&args.callee(), SLOT_DATA);
- PromiseCallback::Task task = static_cast<PromiseCallback::Task>(v.toInt32());
-
- if (task == PromiseCallback::Resolve) {
- if (!promise->CaptureStack(aCx, promise->mFullfillmentStack)) {
- return false;
- }
- promise->MaybeResolveInternal(aCx, args.get(0));
- } else {
- promise->MaybeRejectInternal(aCx, args.get(0));
- if (!promise->CaptureStack(aCx, promise->mRejectionStack)) {
- return false;
- }
- }
-
- args.rval().setUndefined();
- return true;
-}
-
-/*
- * Common bits of (JSCallbackThenableResolver/JSCallbackThenableRejecter).
- * Resolves/rejects the Promise if it is ok to do so, based on whether either of
- * the callbacks have been called before or not.
- */
-/* static */ bool
-Promise::ThenableResolverCommon(JSContext* aCx, uint32_t aTask,
- unsigned aArgc, JS::Value* aVp)
-{
- JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
- JS::Rooted<JSObject*> thisFunc(aCx, &args.callee());
- if (!MarkAsCalledIfNotCalledBefore(aCx, thisFunc)) {
- // A function from this pair has been called before.
- args.rval().setUndefined();
- return true;
- }
-
- Promise* promise = GetPromise(aCx, thisFunc);
- MOZ_ASSERT(promise);
-
- if (aTask == PromiseCallback::Resolve) {
- promise->ResolveInternal(aCx, args.get(0));
- } else {
- promise->RejectInternal(aCx, args.get(0));
- }
-
- args.rval().setUndefined();
- return true;
-}
-
-/* static */ bool
-Promise::JSCallbackThenableResolver(JSContext* aCx,
- unsigned aArgc, JS::Value* aVp)
-{
- return ThenableResolverCommon(aCx, PromiseCallback::Resolve, aArgc, aVp);
-}
-
-/* static */ bool
-Promise::JSCallbackThenableRejecter(JSContext* aCx,
- unsigned aArgc, JS::Value* aVp)
-{
- return ThenableResolverCommon(aCx, PromiseCallback::Reject, aArgc, aVp);
-}
-
-/* static */ JSObject*
-Promise::CreateFunction(JSContext* aCx, Promise* aPromise, int32_t aTask)
-{
- // If this function ever changes, make sure to update
- // WrapperPromiseCallback::GetDependentPromise.
- JSFunction* func = js::NewFunctionWithReserved(aCx, JSCallback,
- 1 /* nargs */, 0 /* flags */,
- nullptr);
- if (!func) {
- return nullptr;
- }
-
- JS::Rooted<JSObject*> obj(aCx, JS_GetFunctionObject(func));
-
- JS::Rooted<JS::Value> promiseObj(aCx);
- if (!dom::GetOrCreateDOMReflector(aCx, aPromise, &promiseObj)) {
- return nullptr;
- }
-
- JS::ExposeValueToActiveJS(promiseObj);
- js::SetFunctionNativeReserved(obj, SLOT_PROMISE, promiseObj);
- js::SetFunctionNativeReserved(obj, SLOT_DATA, JS::Int32Value(aTask));
-
- return obj;
-}
-
-/* static */ JSObject*
-Promise::CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask)
-{
- JSNative whichFunc =
- aTask == PromiseCallback::Resolve ? JSCallbackThenableResolver :
- JSCallbackThenableRejecter ;
-
- JSFunction* func = js::NewFunctionWithReserved(aCx, whichFunc,
- 1 /* nargs */, 0 /* flags */,
- nullptr);
- if (!func) {
- return nullptr;
- }
-
- JS::Rooted<JSObject*> obj(aCx, JS_GetFunctionObject(func));
-
- JS::Rooted<JS::Value> promiseObj(aCx);
- if (!dom::GetOrCreateDOMReflector(aCx, aPromise, &promiseObj)) {
- return nullptr;
- }
-
- JS::ExposeValueToActiveJS(promiseObj);
- js::SetFunctionNativeReserved(obj, SLOT_PROMISE, promiseObj);
-
- return obj;
-}
-
-/* static */ already_AddRefed<Promise>
-Promise::Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
- ErrorResult& aRv, JS::Handle<JSObject*> aDesiredProto)
-{
- nsCOMPtr<nsIGlobalObject> global;
- global = do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- RefPtr<Promise> promise = Create(global, aRv, aDesiredProto);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- promise->CallInitFunction(aGlobal, aInit, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- return promise.forget();
-}
-
-void
-Promise::CallInitFunction(const GlobalObject& aGlobal,
- PromiseInit& aInit, ErrorResult& aRv)
-{
- JSContext* cx = aGlobal.Context();
-
- JS::Rooted<JSObject*> resolveFunc(cx,
- CreateFunction(cx, this,
- PromiseCallback::Resolve));
- if (!resolveFunc) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- JS::Rooted<JSObject*> rejectFunc(cx,
- CreateFunction(cx, this,
- PromiseCallback::Reject));
- if (!rejectFunc) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- aInit.Call(resolveFunc, rejectFunc, aRv, "promise initializer",
- CallbackObject::eRethrowExceptions, Compartment());
- aRv.WouldReportJSException();
-
- if (aRv.Failed()) {
- if (aRv.IsUncatchableException()) {
- // Just propagate this to the caller.
- return;
- }
-
- // There are two possibilities here. Either we've got a rethrown exception,
- // or we reported that already and synthesized a generic NS_ERROR_FAILURE on
- // the ErrorResult. In the former case, it doesn't much matter how we get
- // the exception JS::Value from the ErrorResult to us, since we'll just end
- // up wrapping it into the right compartment as needed if we hand it to
- // someone. But in the latter case we have to ensure that the new exception
- // object we create is created in our reflector compartment, not in our
- // current compartment, because in the case when we're a Promise constructor
- // called over Xrays creating it in the current compartment would mean
- // rejecting with a value that can't be accessed by code that can call
- // then() on this Promise.
- //
- // Luckily, MaybeReject(aRv) does exactly what we want here: it enters our
- // reflector compartment before trying to produce a JS::Value from the
- // ErrorResult.
- MaybeReject(aRv);
- }
-}
-
-#define GET_CAPABILITIES_EXECUTOR_RESOLVE_SLOT 0
-#define GET_CAPABILITIES_EXECUTOR_REJECT_SLOT 1
-
-namespace {
-bool
-GetCapabilitiesExecutor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-getcapabilitiesexecutor-functions
- // except we store the [[Resolve]] and [[Reject]] in our own internal slots,
- // not in a PromiseCapability. The PromiseCapability will then read them from
- // us.
- JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
-
- // Step 1 is an assert.
-
- // Step 2 doesn't need to be done, because it's just giving a name to the
- // PromiseCapability record which is supposed to be stored in an internal
- // slot. But we don't store that at all, per the comment above; we just
- // directly store its [[Resolve]] and [[Reject]] members.
-
- // Steps 3 and 4.
- if (!js::GetFunctionNativeReserved(&args.callee(),
- GET_CAPABILITIES_EXECUTOR_RESOLVE_SLOT).isUndefined() ||
- !js::GetFunctionNativeReserved(&args.callee(),
- GET_CAPABILITIES_EXECUTOR_REJECT_SLOT).isUndefined()) {
- ErrorResult rv;
- rv.ThrowTypeError<MSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY>();
- return !rv.MaybeSetPendingException(aCx);
- }
-
- // Step 5.
- js::SetFunctionNativeReserved(&args.callee(),
- GET_CAPABILITIES_EXECUTOR_RESOLVE_SLOT,
- args.get(0));
-
- // Step 6.
- js::SetFunctionNativeReserved(&args.callee(),
- GET_CAPABILITIES_EXECUTOR_REJECT_SLOT,
- args.get(1));
-
- // Step 7.
- args.rval().setUndefined();
- return true;
-}
-} // anonymous namespace
-
-/* static */ void
-Promise::NewPromiseCapability(JSContext* aCx, nsIGlobalObject* aGlobal,
- JS::Handle<JS::Value> aConstructor,
- bool aForceCallbackCreation,
- PromiseCapability& aCapability,
- ErrorResult& aRv)
-{
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-newpromisecapability
-
- if (!aConstructor.isObject() ||
- !JS::IsConstructor(&aConstructor.toObject())) {
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
-
- // Step 2 is a note.
- // Step 3 is already done because we got the PromiseCapability passed in.
-
- // Optimization: Check whether constructor is in fact the canonical
- // Promise constructor for aGlobal.
- JS::Rooted<JSObject*> global(aCx, aGlobal->GetGlobalJSObject());
- {
- // Scope for the JSAutoCompartment, since we need to enter the compartment
- // of global to get constructors from it. Save the compartment we used to
- // be in, though; we'll need it later.
- JS::Rooted<JSObject*> callerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
- JSAutoCompartment ac(aCx, global);
-
- // Now wrap aConstructor into the compartment of aGlobal, so comparing it to
- // the canonical Promise for that compartment actually makes sense.
- JS::Rooted<JS::Value> constructorValue(aCx, aConstructor);
- if (!MaybeWrapObjectValue(aCx, &constructorValue)) {
- aRv.NoteJSContextException(aCx);
- return;
- }
-
- JSObject* defaultCtor = PromiseBinding::GetConstructorObject(aCx);
- if (!defaultCtor) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- if (defaultCtor == &constructorValue.toObject()) {
- // This is the canonical Promise constructor.
- aCapability.mNativePromise = Promise::Create(aGlobal, aRv);
- if (aForceCallbackCreation) {
- // We have to be a bit careful here. We want to create these functions
- // in the compartment in which they would be created if we actually
- // invoked the constructor via JS::Construct below. That means our
- // callerGlobal compartment if aConstructor is an Xray and the reflector
- // compartment of the promise we're creating otherwise. But note that
- // our callerGlobal compartment is precisely the reflector compartment
- // unless the call was done over Xrays, because the reflector
- // compartment comes from xpc::XrayAwareCalleeGlobal. So we really just
- // want to create these functions in the callerGlobal compartment.
- MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(&aConstructor.toObject()) ||
- callerGlobal == global);
- JSAutoCompartment ac2(aCx, callerGlobal);
-
- JSObject* resolveFuncObj =
- CreateFunction(aCx, aCapability.mNativePromise,
- PromiseCallback::Resolve);
- if (!resolveFuncObj) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- aCapability.mResolve.setObject(*resolveFuncObj);
-
- JSObject* rejectFuncObj =
- CreateFunction(aCx, aCapability.mNativePromise,
- PromiseCallback::Reject);
- if (!rejectFuncObj) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- aCapability.mReject.setObject(*rejectFuncObj);
- }
- return;
- }
- }
-
- // Step 4.
- // We can create our get-capabilities function in the calling compartment. It
- // will work just as if we did |new promiseConstructor(function(a,b){}).
- // Notably, if we're called over Xrays that's all fine, because we will end up
- // creating the callbacks in the caller compartment in that case.
- JSFunction* getCapabilitiesFunc =
- js::NewFunctionWithReserved(aCx, GetCapabilitiesExecutor,
- 2 /* nargs */,
- 0 /* flags */,
- nullptr);
- if (!getCapabilitiesFunc) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- JS::Rooted<JSObject*> getCapabilitiesObj(aCx);
- getCapabilitiesObj = JS_GetFunctionObject(getCapabilitiesFunc);
-
- // Step 5 doesn't need to be done, since we're not actually storing a
- // PromiseCapability in the executor; see the comments in
- // GetCapabilitiesExecutor above.
-
- // Step 6 and step 7.
- JS::Rooted<JS::Value> getCapabilities(aCx,
- JS::ObjectValue(*getCapabilitiesObj));
- JS::Rooted<JSObject*> promiseObj(aCx);
- if (!JS::Construct(aCx, aConstructor,
- JS::HandleValueArray(getCapabilities),
- &promiseObj)) {
- aRv.NoteJSContextException(aCx);
- return;
- }
-
- // Step 8 plus copying over the value to the PromiseCapability.
- JS::Rooted<JS::Value> v(aCx);
- v = js::GetFunctionNativeReserved(getCapabilitiesObj,
- GET_CAPABILITIES_EXECUTOR_RESOLVE_SLOT);
- if (!v.isObject() || !JS::IsCallable(&v.toObject())) {
- aRv.ThrowTypeError<MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE>();
- return;
- }
- aCapability.mResolve = v;
-
- // Step 9 plus copying over the value to the PromiseCapability.
- v = js::GetFunctionNativeReserved(getCapabilitiesObj,
- GET_CAPABILITIES_EXECUTOR_REJECT_SLOT);
- if (!v.isObject() || !JS::IsCallable(&v.toObject())) {
- aRv.ThrowTypeError<MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE>();
- return;
- }
- aCapability.mReject = v;
-
- // Step 10.
- aCapability.mPromise = promiseObj;
-
- // Step 11 doesn't need anything, since the PromiseCapability was passed in.
-}
-
-/* static */ void
-Promise::Resolve(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aValue,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)
-{
- // Implementation of
- // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.resolve
-
- JSContext* cx = aGlobal.Context();
-
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- // Steps 1 and 2.
- if (!aThisv.isObject()) {
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
-
- // Step 3. If a Promise was passed and matches our constructor, just return it.
- if (aValue.isObject()) {
- JS::Rooted<JSObject*> valueObj(cx, &aValue.toObject());
- Promise* nextPromise;
- nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
-
- if (NS_SUCCEEDED(rv)) {
- JS::Rooted<JS::Value> constructor(cx);
- if (!JS_GetProperty(cx, valueObj, "constructor", &constructor)) {
- aRv.NoteJSContextException(cx);
- return;
- }
-
- // Cheat instead of calling JS_SameValue, since we know one's an object.
- if (aThisv == constructor) {
- aRetval.setObject(*valueObj);
- return;
- }
- }
- }
-
- // Step 4.
- PromiseCapability capability(cx);
- NewPromiseCapability(cx, global, aThisv, false, capability, aRv);
- // Step 5.
- if (aRv.Failed()) {
- return;
- }
-
- // Step 6.
- Promise* p = capability.mNativePromise;
- if (p) {
- p->MaybeResolveInternal(cx, aValue);
- p->mFullfillmentStack = p->mAllocationStack;
- } else {
- JS::Rooted<JS::Value> value(cx, aValue);
- JS::Rooted<JS::Value> ignored(cx);
- if (!JS::Call(cx, JS::UndefinedHandleValue /* thisVal */,
- capability.mResolve, JS::HandleValueArray(value),
- &ignored)) {
- // Step 7.
- aRv.NoteJSContextException(cx);
- return;
- }
- }
-
- // Step 8.
- aRetval.set(capability.PromiseValue());
-}
-
-/* static */ already_AddRefed<Promise>
-Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
- JS::Handle<JS::Value> aValue, ErrorResult& aRv)
-{
- RefPtr<Promise> promise = Create(aGlobal, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- promise->MaybeResolveInternal(aCx, aValue);
- return promise.forget();
-}
-
-/* static */ void
-Promise::Reject(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aValue,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)
-{
- // Implementation of
- // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.reject
-
- JSContext* cx = aGlobal.Context();
-
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- // Steps 1 and 2.
- if (!aThisv.isObject()) {
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
-
- // Step 3.
- PromiseCapability capability(cx);
- NewPromiseCapability(cx, global, aThisv, false, capability, aRv);
- // Step 4.
- if (aRv.Failed()) {
- return;
- }
-
- // Step 5.
- Promise* p = capability.mNativePromise;
- if (p) {
- p->MaybeRejectInternal(cx, aValue);
- p->mRejectionStack = p->mAllocationStack;
- } else {
- JS::Rooted<JS::Value> value(cx, aValue);
- JS::Rooted<JS::Value> ignored(cx);
- if (!JS::Call(cx, JS::UndefinedHandleValue /* thisVal */,
- capability.mReject, JS::HandleValueArray(value),
- &ignored)) {
- // Step 6.
- aRv.NoteJSContextException(cx);
- return;
- }
- }
-
- // Step 7.
- aRetval.set(capability.PromiseValue());
-}
-
-/* static */ already_AddRefed<Promise>
-Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
- JS::Handle<JS::Value> aValue, ErrorResult& aRv)
-{
- RefPtr<Promise> promise = Create(aGlobal, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- promise->MaybeRejectInternal(aCx, aValue);
- return promise.forget();
-}
-
-namespace {
-void
-SpeciesConstructor(JSContext* aCx,
- JS::Handle<JSObject*> promise,
- JS::Handle<JS::Value> defaultCtor,
- JS::MutableHandle<JS::Value> ctor,
- ErrorResult& aRv)
-{
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-speciesconstructor
-
- // Step 1.
- MOZ_ASSERT(promise);
-
- // Step 2.
- JS::Rooted<JS::Value> constructorVal(aCx);
- if (!JS_GetProperty(aCx, promise, "constructor", &constructorVal)) {
- // Step 3.
- aRv.NoteJSContextException(aCx);
- return;
- }
-
- // Step 4.
- if (constructorVal.isUndefined()) {
- ctor.set(defaultCtor);
- return;
- }
-
- // Step 5.
- if (!constructorVal.isObject()) {
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
-
- // Step 6.
- JS::Rooted<jsid> species(aCx,
- SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::species)));
- JS::Rooted<JS::Value> speciesVal(aCx);
- JS::Rooted<JSObject*> constructorObj(aCx, &constructorVal.toObject());
- if (!JS_GetPropertyById(aCx, constructorObj, species, &speciesVal)) {
- // Step 7.
- aRv.NoteJSContextException(aCx);
- return;
- }
-
- // Step 8.
- if (speciesVal.isNullOrUndefined()) {
- ctor.set(defaultCtor);
- return;
- }
-
- // Step 9.
- if (speciesVal.isObject() && JS::IsConstructor(&speciesVal.toObject())) {
- ctor.set(speciesVal);
- return;
- }
-
- // Step 10.
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
-}
-} // anonymous namespace
-
-void
-Promise::Then(JSContext* aCx, JS::Handle<JSObject*> aCalleeGlobal,
- AnyCallback* aResolveCallback, AnyCallback* aRejectCallback,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.prototype.then
-
- // Step 1.
- JS::Rooted<JS::Value> promiseVal(aCx, JS::ObjectValue(*GetWrapper()));
- if (!MaybeWrapObjectValue(aCx, &promiseVal)) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- JS::Rooted<JSObject*> promiseObj(aCx, &promiseVal.toObject());
- MOZ_ASSERT(promiseObj);
-
- // Step 2 was done by the bindings.
-
- // Step 3. We want to use aCalleeGlobal here because it will do the
- // right thing for us via Xrays (where we won't find @@species on
- // our promise constructor for now).
- JS::Rooted<JS::Value> defaultCtorVal(aCx);
- { // Scope for JSAutoCompartment
- JSAutoCompartment ac(aCx, aCalleeGlobal);
- JSObject* defaultCtor = PromiseBinding::GetConstructorObject(aCx);
- if (!defaultCtor) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- defaultCtorVal.setObject(*defaultCtor);
- }
- if (!MaybeWrapObjectValue(aCx, &defaultCtorVal)) {
- aRv.NoteJSContextException(aCx);
- return;
- }
-
- JS::Rooted<JS::Value> constructor(aCx);
- SpeciesConstructor(aCx, promiseObj, defaultCtorVal, &constructor, aRv);
- if (aRv.Failed()) {
- // Step 4.
- return;
- }
-
- // Step 5.
- GlobalObject globalObj(aCx, GetWrapper());
- if (globalObj.Failed()) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- nsCOMPtr<nsIGlobalObject> globalObject =
- do_QueryInterface(globalObj.GetAsSupports());
- if (!globalObject) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
- PromiseCapability capability(aCx);
- NewPromiseCapability(aCx, globalObject, constructor, false, capability, aRv);
- if (aRv.Failed()) {
- // Step 6.
- return;
- }
-
- // Now step 7: start
- // http://www.ecma-international.org/ecma-262/6.0/#sec-performpromisethen
-
- // Step 1 and step 2 are just assertions.
-
- // Step 3 and step 4 are kinda handled for us already; we use null
- // to represent "Identity" and "Thrower".
-
- // Steps 5 and 6. These branch based on whether we know we have a
- // vanilla Promise or not.
- JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
- if (capability.mNativePromise) {
- Promise* promise = capability.mNativePromise;
-
- RefPtr<PromiseCallback> resolveCb =
- PromiseCallback::Factory(promise, global, aResolveCallback,
- PromiseCallback::Resolve);
-
- RefPtr<PromiseCallback> rejectCb =
- PromiseCallback::Factory(promise, global, aRejectCallback,
- PromiseCallback::Reject);
-
- AppendCallbacks(resolveCb, rejectCb);
- } else {
- JS::Rooted<JSObject*> resolveObj(aCx, &capability.mResolve.toObject());
- RefPtr<AnyCallback> resolveFunc =
- new AnyCallback(aCx, resolveObj, GetIncumbentGlobal());
-
- JS::Rooted<JSObject*> rejectObj(aCx, &capability.mReject.toObject());
- RefPtr<AnyCallback> rejectFunc =
- new AnyCallback(aCx, rejectObj, GetIncumbentGlobal());
-
- if (!capability.mPromise) {
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
- JS::Rooted<JSObject*> newPromiseObj(aCx, capability.mPromise);
- // We want to store the reflector itself.
- newPromiseObj = js::CheckedUnwrap(newPromiseObj);
- if (!newPromiseObj) {
- // Just throw something.
- aRv.ThrowTypeError<MSG_ILLEGAL_PROMISE_CONSTRUCTOR>();
- return;
- }
-
- RefPtr<PromiseCallback> resolveCb;
- if (aResolveCallback) {
- resolveCb = new WrapperPromiseCallback(global, aResolveCallback,
- newPromiseObj,
- resolveFunc, rejectFunc);
- } else {
- resolveCb = new InvokePromiseFuncCallback(global, newPromiseObj,
- resolveFunc);
- }
-
- RefPtr<PromiseCallback> rejectCb;
- if (aRejectCallback) {
- rejectCb = new WrapperPromiseCallback(global, aRejectCallback,
- newPromiseObj,
- resolveFunc, rejectFunc);
- } else {
- rejectCb = new InvokePromiseFuncCallback(global, newPromiseObj,
- rejectFunc);
- }
-
- AppendCallbacks(resolveCb, rejectCb);
- }
-
- aRetval.set(capability.PromiseValue());
-}
-
-void
-Promise::Catch(JSContext* aCx, AnyCallback* aRejectCallback,
- JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.prototype.catch
-
- // We can't call Promise::Then directly, because someone might have
- // overridden Promise.prototype.then.
- JS::Rooted<JS::Value> promiseVal(aCx, JS::ObjectValue(*GetWrapper()));
- if (!MaybeWrapObjectValue(aCx, &promiseVal)) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- JS::Rooted<JSObject*> promiseObj(aCx, &promiseVal.toObject());
- MOZ_ASSERT(promiseObj);
- JS::AutoValueArray<2> callbacks(aCx);
- callbacks[0].setUndefined();
- if (aRejectCallback) {
- callbacks[1].setObject(*aRejectCallback->Callable());
- // It could be in any compartment, so put it in ours.
- if (!MaybeWrapObjectValue(aCx, callbacks[1])) {
- aRv.NoteJSContextException(aCx);
- return;
- }
- } else {
- callbacks[1].setNull();
- }
- if (!JS_CallFunctionName(aCx, promiseObj, "then", callbacks, aRetval)) {
- aRv.NoteJSContextException(aCx);
- }
-}
-
-/**
- * The CountdownHolder class encapsulates Promise.all countdown functions and
- * the countdown holder parts of the Promises spec. It maintains the result
- * array and AllResolveElementFunctions use SetValue() to set the array indices.
- */
-class CountdownHolder final : public nsISupports
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CountdownHolder)
-
- CountdownHolder(const GlobalObject& aGlobal, Promise* aPromise,
- uint32_t aCountdown)
- : mPromise(aPromise), mCountdown(aCountdown)
- {
- MOZ_ASSERT(aCountdown != 0);
- JSContext* cx = aGlobal.Context();
-
- // The only time aGlobal.Context() and aGlobal.Get() are not
- // same-compartment is when we're called via Xrays, and in that situation we
- // in fact want to create the array in the callee compartment
-
- JSAutoCompartment ac(cx, aGlobal.Get());
- mValues = JS_NewArrayObject(cx, aCountdown);
- mozilla::HoldJSObjects(this);
- }
-
-private:
- ~CountdownHolder()
- {
- mozilla::DropJSObjects(this);
- }
-
-public:
- void SetValue(uint32_t index, const JS::Handle<JS::Value> aValue)
- {
- MOZ_ASSERT(mCountdown > 0);
-
- AutoJSAPI jsapi;
- if (!jsapi.Init(mValues)) {
- return;
- }
- JSContext* cx = jsapi.cx();
-
- JS::Rooted<JS::Value> value(cx, aValue);
- JS::Rooted<JSObject*> values(cx, mValues);
- if (!JS_WrapValue(cx, &value) ||
- !JS_DefineElement(cx, values, index, value, JSPROP_ENUMERATE)) {
- MOZ_ASSERT(JS_IsExceptionPending(cx));
- JS::Rooted<JS::Value> exn(cx);
- if (!jsapi.StealException(&exn)) {
- mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
- } else {
- mPromise->MaybeReject(cx, exn);
- }
- }
-
- --mCountdown;
- if (mCountdown == 0) {
- JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*mValues));
- mPromise->MaybeResolve(cx, result);
- }
- }
-
-private:
- RefPtr<Promise> mPromise;
- uint32_t mCountdown;
- JS::Heap<JSObject*> mValues;
-};
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(CountdownHolder)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(CountdownHolder)
-NS_IMPL_CYCLE_COLLECTION_CLASS(CountdownHolder)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CountdownHolder)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CountdownHolder)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mValues)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CountdownHolder)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CountdownHolder)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
- tmp->mValues = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-/**
- * An AllResolveElementFunction is the per-promise
- * part of the Promise.all() algorithm.
- * Every Promise in the handler is handed an instance of this as a resolution
- * handler and it sets the relevant index in the CountdownHolder.
- */
-class AllResolveElementFunction final : public PromiseNativeHandler
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveElementFunction)
-
- AllResolveElementFunction(CountdownHolder* aHolder, uint32_t aIndex)
- : mCountdownHolder(aHolder), mIndex(aIndex)
- {
- MOZ_ASSERT(aHolder);
- }
-
- void
- ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
- {
- mCountdownHolder->SetValue(mIndex, aValue);
- }
-
- void
- RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
- {
- // Should never be attached to Promise as a reject handler.
- MOZ_CRASH("AllResolveElementFunction should never be attached to a Promise's reject handler!");
- }
-
-private:
- ~AllResolveElementFunction()
- {
- }
-
- RefPtr<CountdownHolder> mCountdownHolder;
- uint32_t mIndex;
-};
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveElementFunction)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveElementFunction)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveElementFunction)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION(AllResolveElementFunction, mCountdownHolder)
-
-static const JSClass PromiseAllDataHolderClass = {
- "PromiseAllDataHolder", JSCLASS_HAS_RESERVED_SLOTS(3)
-};
-
-// Slot indices for objects of class PromiseAllDataHolderClass.
-#define DATA_HOLDER_REMAINING_ELEMENTS_SLOT 0
-#define DATA_HOLDER_VALUES_ARRAY_SLOT 1
-#define DATA_HOLDER_RESOLVE_FUNCTION_SLOT 2
-
-// Slot indices for PromiseAllResolveElement.
-// The RESOLVE_ELEMENT_INDEX_SLOT stores our index unless we've already been
-// called. Then it stores INT32_MIN (which is never a valid index value).
-#define RESOLVE_ELEMENT_INDEX_SLOT 0
-// The RESOLVE_ELEMENT_DATA_HOLDER_SLOT slot stores an object of class
-// PromiseAllDataHolderClass.
-#define RESOLVE_ELEMENT_DATA_HOLDER_SLOT 1
-
-static bool
-PromiseAllResolveElement(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- // Implements
- // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.all-resolve-element-functions
- //
- // See the big comment about compartments in Promise::All "Substep 4" that
- // explains what compartments the various stuff here lives in.
- JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
-
- // Step 1.
- int32_t index =
- js::GetFunctionNativeReserved(&args.callee(),
- RESOLVE_ELEMENT_INDEX_SLOT).toInt32();
- // Step 2.
- if (index == INT32_MIN) {
- args.rval().setUndefined();
- return true;
- }
-
- // Step 3.
- js::SetFunctionNativeReserved(&args.callee(),
- RESOLVE_ELEMENT_INDEX_SLOT,
- JS::Int32Value(INT32_MIN));
-
- // Step 4 already done.
-
- // Step 5.
- JS::Rooted<JSObject*> dataHolder(aCx,
- &js::GetFunctionNativeReserved(&args.callee(),
- RESOLVE_ELEMENT_DATA_HOLDER_SLOT).toObject());
-
- JS::Rooted<JS::Value> values(aCx,
- js::GetReservedSlot(dataHolder, DATA_HOLDER_VALUES_ARRAY_SLOT));
-
- // Step 6, effectively.
- JS::Rooted<JS::Value> resolveFunc(aCx,
- js::GetReservedSlot(dataHolder, DATA_HOLDER_RESOLVE_FUNCTION_SLOT));
-
- // Step 7.
- int32_t remainingElements =
- js::GetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT).toInt32();
-
- // Step 8.
- JS::Rooted<JSObject*> valuesObj(aCx, &values.toObject());
- if (!JS_DefineElement(aCx, valuesObj, index, args.get(0), JSPROP_ENUMERATE)) {
- return false;
- }
-
- // Step 9.
- remainingElements -= 1;
- js::SetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT,
- JS::Int32Value(remainingElements));
-
- // Step 10.
- if (remainingElements == 0) {
- return JS::Call(aCx, JS::UndefinedHandleValue, resolveFunc,
- JS::HandleValueArray(values), args.rval());
- }
-
- // Step 11.
- args.rval().setUndefined();
- return true;
-}
-
-
-/* static */ void
-Promise::All(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aIterable,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)
-{
- // Implements http://www.ecma-international.org/ecma-262/6.0/#sec-promise.all
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- JSContext* cx = aGlobal.Context();
-
- // Steps 1-5: nothing to do. Note that the @@species bits got removed in
- // https://github.com/tc39/ecma262/pull/211
-
- // Step 6.
- PromiseCapability capability(cx);
- NewPromiseCapability(cx, global, aThisv, true, capability, aRv);
- // Step 7.
- if (aRv.Failed()) {
- return;
- }
-
- MOZ_ASSERT(aThisv.isObject(), "How did NewPromiseCapability succeed?");
- JS::Rooted<JSObject*> constructorObj(cx, &aThisv.toObject());
-
- // After this point we have a useful promise value in "capability", so just go
- // ahead and put it in our retval now. Every single return path below would
- // want to do that anyway.
- aRetval.set(capability.PromiseValue());
- if (!MaybeWrapValue(cx, aRetval)) {
- aRv.NoteJSContextException(cx);
- return;
- }
-
- // The arguments we're going to be passing to "then" on each loop iteration.
- // The second one we know already; the first one will be created on each
- // iteration of the loop.
- JS::AutoValueArray<2> callbackFunctions(cx);
- callbackFunctions[1].set(capability.mReject);
-
- // Steps 8 and 9.
- JS::ForOfIterator iter(cx);
- if (!iter.init(aIterable, JS::ForOfIterator::AllowNonIterable)) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- if (!iter.valueIsIterable()) {
- ThrowErrorMessage(cx, MSG_PROMISE_ARG_NOT_ITERABLE,
- "Argument of Promise.all");
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step 10 doesn't need to be done, because ForOfIterator handles it
- // for us.
-
- // Now we jump over to
- // http://www.ecma-international.org/ecma-262/6.0/#sec-performpromiseall
- // and do its steps.
-
- // Substep 4. Create our data holder that holds all the things shared across
- // every step of the iterator. In particular, this holds the
- // remainingElementsCount (as an integer reserved slot), the array of values,
- // and the resolve function from our PromiseCapability.
- //
- // We have to be very careful about which compartments we create things in
- // here. In particular, we have to maintain the invariant that anything
- // stored in a reserved slot is same-compartment with the object whose
- // reserved slot it's in. But we want to create the values array in the
- // Promise reflector compartment, because that array can get exposed to code
- // that has access to the Promise reflector (in particular code from that
- // compartment), and that should work, even if the Promise reflector
- // compartment is less-privileged than our caller compartment.
- //
- // So the plan is as follows: Create the values array in the promise reflector
- // compartment. Create the PromiseAllResolveElement function and the data
- // holder in our current compartment. Store a cross-compartment wrapper to
- // the values array in the holder. This should be OK because the only things
- // we hand the PromiseAllResolveElement function to are the "then" calls we do
- // and in the case when the reflector compartment is not the current
- // compartment those are happening over Xrays anyway, which means they get the
- // canonical "then" function and content can't see our
- // PromiseAllResolveElement.
- JS::Rooted<JSObject*> dataHolder(cx);
- dataHolder = JS_NewObjectWithGivenProto(cx, &PromiseAllDataHolderClass,
- nullptr);
- if (!dataHolder) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- JS::Rooted<JSObject*> reflectorGlobal(cx, global->GetGlobalJSObject());
- JS::Rooted<JSObject*> valuesArray(cx);
- { // Scope for JSAutoCompartment.
- JSAutoCompartment ac(cx, reflectorGlobal);
- valuesArray = JS_NewArrayObject(cx, 0);
- }
- if (!valuesArray) {
- // It's important that we've exited the JSAutoCompartment by now, before
- // calling RejectWithException and possibly invoking capability.mReject.
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // The values array as a value we can pass to a function in our current
- // compartment, or store in the holder's reserved slot.
- JS::Rooted<JS::Value> valuesArrayVal(cx, JS::ObjectValue(*valuesArray));
- if (!MaybeWrapObjectValue(cx, &valuesArrayVal)) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- js::SetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT,
- JS::Int32Value(1));
- js::SetReservedSlot(dataHolder, DATA_HOLDER_VALUES_ARRAY_SLOT,
- valuesArrayVal);
- js::SetReservedSlot(dataHolder, DATA_HOLDER_RESOLVE_FUNCTION_SLOT,
- capability.mResolve);
-
- // Substep 5.
- CheckedInt32 index = 0;
-
- // Substep 6.
- JS::Rooted<JS::Value> nextValue(cx);
- while (true) {
- bool done;
- // Steps a, b, c, e, f, g.
- if (!iter.next(&nextValue, &done)) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step d.
- if (done) {
- int32_t remainingCount =
- js::GetReservedSlot(dataHolder,
- DATA_HOLDER_REMAINING_ELEMENTS_SLOT).toInt32();
- remainingCount -= 1;
- if (remainingCount == 0) {
- JS::Rooted<JS::Value> ignored(cx);
- if (!JS::Call(cx, JS::UndefinedHandleValue, capability.mResolve,
- JS::HandleValueArray(valuesArrayVal), &ignored)) {
- capability.RejectWithException(cx, aRv);
- }
- return;
- }
- js::SetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT,
- JS::Int32Value(remainingCount));
- // We're all set for now!
- return;
- }
-
- // Step h.
- { // Scope for the JSAutoCompartment we need to work with valuesArray. We
- // mostly do this for performance; we could go ahead and do the define via
- // a cross-compartment proxy instead...
- JSAutoCompartment ac(cx, valuesArray);
- if (!JS_DefineElement(cx, valuesArray, index.value(),
- JS::UndefinedHandleValue, JSPROP_ENUMERATE)) {
- // Have to go back into the caller compartment before we try to touch
- // capability.mReject. Luckily, capability.mReject is guaranteed to be
- // an object in the right compartment here.
- JSAutoCompartment ac2(cx, &capability.mReject.toObject());
- capability.RejectWithException(cx, aRv);
- return;
- }
- }
-
- // Step i. Sadly, we can't take a shortcut here even if
- // capability.mNativePromise exists, because someone could have overridden
- // "resolve" on the canonical Promise constructor.
- JS::Rooted<JS::Value> nextPromise(cx);
- if (!JS_CallFunctionName(cx, constructorObj, "resolve",
- JS::HandleValueArray(nextValue),
- &nextPromise)) {
- // Step j.
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step k.
- JS::Rooted<JSObject*> resolveElement(cx);
- JSFunction* resolveFunc =
- js::NewFunctionWithReserved(cx, PromiseAllResolveElement,
- 1 /* nargs */, 0 /* flags */, nullptr);
- if (!resolveFunc) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- resolveElement = JS_GetFunctionObject(resolveFunc);
- // Steps l-p.
- js::SetFunctionNativeReserved(resolveElement,
- RESOLVE_ELEMENT_INDEX_SLOT,
- JS::Int32Value(index.value()));
- js::SetFunctionNativeReserved(resolveElement,
- RESOLVE_ELEMENT_DATA_HOLDER_SLOT,
- JS::ObjectValue(*dataHolder));
-
- // Step q.
- int32_t remainingElements =
- js::GetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT).toInt32();
- js::SetReservedSlot(dataHolder, DATA_HOLDER_REMAINING_ELEMENTS_SLOT,
- JS::Int32Value(remainingElements + 1));
-
- // Step r. And now we don't know whether nextPromise has an overridden
- // "then" method, so no shortcuts here either.
- callbackFunctions[0].setObject(*resolveElement);
- JS::Rooted<JSObject*> nextPromiseObj(cx);
- JS::Rooted<JS::Value> ignored(cx);
- if (!JS_ValueToObject(cx, nextPromise, &nextPromiseObj) ||
- !JS_CallFunctionName(cx, nextPromiseObj, "then", callbackFunctions,
- &ignored)) {
- // Step s.
- capability.RejectWithException(cx, aRv);
- }
-
- // Step t.
- index += 1;
- if (!index.isValid()) {
- // Let's just claim OOM.
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- capability.RejectWithException(cx, aRv);
- }
- }
-}
-
-/* static */ already_AddRefed<Promise>
-Promise::All(const GlobalObject& aGlobal,
- const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv)
-{
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- JSContext* cx = aGlobal.Context();
-
- if (aPromiseList.IsEmpty()) {
- JS::Rooted<JSObject*> empty(cx, JS_NewArrayObject(cx, 0));
- if (!empty) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return nullptr;
- }
- JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*empty));
- // We know "value" is not a promise, so call the Resolve function
- // that doesn't have to check for that.
- return Promise::Resolve(global, cx, value, aRv);
- }
-
- RefPtr<Promise> promise = Create(global, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
- RefPtr<CountdownHolder> holder =
- new CountdownHolder(aGlobal, promise, aPromiseList.Length());
-
- JS::Rooted<JSObject*> obj(cx, JS::CurrentGlobalOrNull(cx));
- if (!obj) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- RefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise, obj);
-
- for (uint32_t i = 0; i < aPromiseList.Length(); ++i) {
- RefPtr<PromiseNativeHandler> resolveHandler =
- new AllResolveElementFunction(holder, i);
-
- RefPtr<PromiseCallback> resolveCb =
- new NativePromiseCallback(resolveHandler, Resolved);
-
- // Every promise gets its own resolve callback, which will set the right
- // index in the array to the resolution value.
- aPromiseList[i]->AppendCallbacks(resolveCb, rejectCb);
- }
-
- return promise.forget();
-}
-
-/* static */ void
-Promise::Race(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aIterable, JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv)
-{
- // Implements http://www.ecma-international.org/ecma-262/6.0/#sec-promise.race
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- JSContext* cx = aGlobal.Context();
-
- // Steps 1-5: nothing to do. Note that the @@species bits got removed in
- // https://github.com/tc39/ecma262/pull/211
- PromiseCapability capability(cx);
-
- // Step 6.
- NewPromiseCapability(cx, global, aThisv, true, capability, aRv);
- // Step 7.
- if (aRv.Failed()) {
- return;
- }
-
- MOZ_ASSERT(aThisv.isObject(), "How did NewPromiseCapability succeed?");
- JS::Rooted<JSObject*> constructorObj(cx, &aThisv.toObject());
-
- // After this point we have a useful promise value in "capability", so just go
- // ahead and put it in our retval now. Every single return path below would
- // want to do that anyway.
- aRetval.set(capability.PromiseValue());
- if (!MaybeWrapValue(cx, aRetval)) {
- aRv.NoteJSContextException(cx);
- return;
- }
-
- // The arguments we're going to be passing to "then" on each loop iteration.
- JS::AutoValueArray<2> callbackFunctions(cx);
- callbackFunctions[0].set(capability.mResolve);
- callbackFunctions[1].set(capability.mReject);
-
- // Steps 8 and 9.
- JS::ForOfIterator iter(cx);
- if (!iter.init(aIterable, JS::ForOfIterator::AllowNonIterable)) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- if (!iter.valueIsIterable()) {
- ThrowErrorMessage(cx, MSG_PROMISE_ARG_NOT_ITERABLE,
- "Argument of Promise.race");
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step 10 doesn't need to be done, because ForOfIterator handles it
- // for us.
-
- // Now we jump over to
- // http://www.ecma-international.org/ecma-262/6.0/#sec-performpromiserace
- // and do its steps.
- JS::Rooted<JS::Value> nextValue(cx);
- while (true) {
- bool done;
- // Steps a, b, c, e, f, g.
- if (!iter.next(&nextValue, &done)) {
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step d.
- if (done) {
- // We're all set!
- return;
- }
-
- // Step h. Sadly, we can't take a shortcut here even if
- // capability.mNativePromise exists, because someone could have overridden
- // "resolve" on the canonical Promise constructor.
- JS::Rooted<JS::Value> nextPromise(cx);
- if (!JS_CallFunctionName(cx, constructorObj, "resolve",
- JS::HandleValueArray(nextValue), &nextPromise)) {
- // Step i.
- capability.RejectWithException(cx, aRv);
- return;
- }
-
- // Step j. And now we don't know whether nextPromise has an overridden
- // "then" method, so no shortcuts here either.
- JS::Rooted<JSObject*> nextPromiseObj(cx);
- JS::Rooted<JS::Value> ignored(cx);
- if (!JS_ValueToObject(cx, nextPromise, &nextPromiseObj) ||
- !JS_CallFunctionName(cx, nextPromiseObj, "then", callbackFunctions,
- &ignored)) {
- // Step k.
- capability.RejectWithException(cx, aRv);
- }
- }
-}
-
-/* static */
-bool
-Promise::PromiseSpecies(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
- args.rval().set(args.thisv());
- return true;
-}
-
-void
-Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- RefPtr<PromiseCallback> resolveCb =
- new NativePromiseCallback(aRunnable, Resolved);
-
- RefPtr<PromiseCallback> rejectCb =
- new NativePromiseCallback(aRunnable, Rejected);
-
- AppendCallbacks(resolveCb, rejectCb);
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
JSObject*
Promise::GlobalJSObject() const
{
@@ -2560,382 +644,6 @@ Promise::Compartment() const
return js::GetObjectCompartment(GlobalJSObject());
}
-#ifndef SPIDERMONKEY_PROMISE
-void
-Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
- PromiseCallback* aRejectCallback)
-{
- if (!mGlobal || mGlobal->IsDying()) {
- return;
- }
-
- MOZ_ASSERT(aResolveCallback);
- MOZ_ASSERT(aRejectCallback);
-
- if (mIsLastInChain && mState == PromiseState::Rejected) {
- // This rejection is now consumed.
- PromiseDebugging::AddConsumedRejection(*this);
- // Note that we may not have had the opportunity to call
- // RunResolveTask() yet, so we may never have called
- // `PromiseDebugging:AddUncaughtRejection`.
- }
- mIsLastInChain = false;
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- // Now that there is a callback, we don't need to report anymore.
- mHadRejectCallback = true;
- RemoveWorkerHolder();
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
- mResolveCallbacks.AppendElement(aResolveCallback);
- mRejectCallbacks.AppendElement(aRejectCallback);
-
- // If promise's state is fulfilled, queue a task to process our fulfill
- // callbacks with promise's result. If promise's state is rejected, queue a
- // task to process our reject callbacks with promise's result.
- if (mState != Pending) {
- TriggerPromiseReactions();
- }
-}
-#endif // SPIDERMONKEY_PROMISE
-
-#ifndef SPIDERMONKEY_PROMISE
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
-void
-Promise::MaybeReportRejected()
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- if (mState != Rejected || mHadRejectCallback || mResult.isUndefined()) {
- return;
- }
-
- AutoJSAPI jsapi;
- // We may not have a usable global by now (if it got unlinked
- // already), so don't init with it.
- jsapi.Init();
- JSContext* cx = jsapi.cx();
- JS::Rooted<JSObject*> obj(cx, GetWrapper());
- MOZ_ASSERT(obj); // We preserve our wrapper, so should always have one here.
- JS::Rooted<JS::Value> val(cx, mResult);
-
- JSAutoCompartment ac(cx, obj);
- if (!JS_WrapValue(cx, &val)) {
- JS_ClearPendingException(cx);
- return;
- }
-
- js::ErrorReport report(cx);
- RefPtr<Exception> exp;
- bool isObject = val.isObject();
- if (!isObject || NS_FAILED(UNWRAP_OBJECT(Exception, &val.toObject(), exp))) {
- if (!isObject ||
- NS_FAILED(UNWRAP_OBJECT(DOMException, &val.toObject(), exp))) {
- if (!report.init(cx, val, js::ErrorReport::NoSideEffects)) {
- NS_WARNING("Couldn't convert the unhandled rejected value to an exception.");
- JS_ClearPendingException(cx);
- return;
- }
- }
- }
-
- RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
- bool isMainThread = MOZ_LIKELY(NS_IsMainThread());
- bool isChrome = isMainThread ? nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj))
- : GetCurrentThreadWorkerPrivate()->IsChromeWorker();
- nsGlobalWindow* win = isMainThread ? xpc::WindowGlobalOrNull(obj) : nullptr;
- uint64_t windowID = win ? win->AsInner()->WindowID() : 0;
- if (exp) {
- xpcReport->Init(cx, exp, isChrome, windowID);
- } else {
- xpcReport->Init(report.report(), report.toStringResult(),
- isChrome, windowID);
- }
-
- // Now post an event to do the real reporting async
- // Since Promises preserve their wrapper, it is essential to RefPtr<> the
- // AsyncErrorReporter, otherwise if the call to DispatchToMainThread fails, it
- // will leak. See Bug 958684. So... don't use DispatchToMainThread()
- nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
- if (NS_WARN_IF(!mainThread)) {
- // Would prefer NS_ASSERTION, but that causes failure in xpcshell tests
- NS_WARNING("!!! Trying to report rejected Promise after MainThread shutdown");
- }
- if (mainThread) {
- RefPtr<AsyncErrorReporter> r = new AsyncErrorReporter(xpcReport);
- mainThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
- }
-}
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
-void
-Promise::MaybeResolveInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- if (mResolvePending) {
- return;
- }
-
- ResolveInternal(aCx, aValue);
-}
-
-void
-Promise::MaybeRejectInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- if (mResolvePending) {
- return;
- }
-
- RejectInternal(aCx, aValue);
-}
-
-void
-Promise::HandleException(JSContext* aCx)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- JS::Rooted<JS::Value> exn(aCx);
- if (JS_GetPendingException(aCx, &exn)) {
- JS_ClearPendingException(aCx);
- RejectInternal(aCx, exn);
- }
-}
-
-void
-Promise::ResolveInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
-
- mResolvePending = true;
-
- if (aValue.isObject()) {
- JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
-
- // Thenables.
- JS::Rooted<JS::Value> then(aCx);
- if (!JS_GetProperty(aCx, valueObj, "then", &then)) {
- HandleException(aCx);
- return;
- }
-
- if (then.isObject() && JS::IsCallable(&then.toObject())) {
- // This is the then() function of the thenable aValueObj.
- JS::Rooted<JSObject*> thenObj(aCx, &then.toObject());
-
- // We used to have a fast path here for the case when the following
- // requirements held:
- //
- // 1) valueObj is a Promise.
- // 2) thenObj is a JSFunction backed by our actual Promise::Then
- // implementation.
- //
- // But now that we're doing subclassing in Promise.prototype.then we would
- // also need the following requirements:
- //
- // 3) Getting valueObj.constructor has no side-effects.
- // 4) Getting valueObj.constructor[@@species] has no side-effects.
- // 5) valueObj.constructor[@@species] is a function and calling it has no
- // side-effects (e.g. it's the canonical Promise constructor) and it
- // provides some callback functions to call as arguments to its
- // argument.
- //
- // Ensuring that stuff while not inside SpiderMonkey is painful, so let's
- // drop the fast path for now.
-
- RefPtr<PromiseInit> thenCallback =
- new PromiseInit(nullptr, thenObj, mozilla::dom::GetIncumbentGlobal());
- RefPtr<PromiseResolveThenableJob> task =
- new PromiseResolveThenableJob(this, valueObj, thenCallback);
- context->DispatchToMicroTask(task.forget());
- return;
- }
- }
-
- MaybeSettle(aValue, Resolved);
-}
-
-void
-Promise::RejectInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- mResolvePending = true;
-
- MaybeSettle(aValue, Rejected);
-}
-
-void
-Promise::Settle(JS::Handle<JS::Value> aValue, PromiseState aState)
-{
- MOZ_ASSERT(mGlobal,
- "We really should have a global here. Except we sometimes don't "
- "in the wild for some odd reason");
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- if (!mGlobal || mGlobal->IsDying()) {
- return;
- }
-
- mSettlementTimestamp = TimeStamp::Now();
-
- AutoJSAPI jsapi;
- jsapi.Init();
- JSContext* cx = jsapi.cx();
- JS::RootedObject wrapper(cx, GetWrapper());
- MOZ_ASSERT(wrapper); // We preserved it
- JSAutoCompartment ac(cx, wrapper);
-
- JS::Rooted<JS::Value> value(cx, aValue);
-
- if (!JS_WrapValue(cx, &value)) {
- JS_ClearPendingException(cx);
- value = JS::UndefinedValue();
- }
- SetResult(value);
- SetState(aState);
-
- JS::dbg::onPromiseSettled(cx, wrapper);
-
- if (aState == PromiseState::Rejected &&
- mIsLastInChain) {
- // The Promise has just been rejected, and it is last in chain.
- // We need to inform PromiseDebugging.
- // If the Promise is eventually not the last in chain anymore,
- // we will need to inform PromiseDebugging again.
- PromiseDebugging::AddUncaughtRejection(*this);
- }
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- // If the Promise was rejected, and there is no reject handler already setup,
- // watch for thread shutdown.
- if (aState == PromiseState::Rejected &&
- !mHadRejectCallback &&
- !NS_IsMainThread()) {
- WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
- MOZ_ASSERT(worker);
- worker->AssertIsOnWorkerThread();
-
- mWorkerHolder = new PromiseReportRejectWorkerHolder(this);
- if (NS_WARN_IF(!mWorkerHolder->HoldWorker(worker, Closing))) {
- mWorkerHolder = nullptr;
- // Worker is shutting down, report rejection immediately since it is
- // unlikely that reject callbacks will be added after this point.
- MaybeReportRejectedOnce();
- }
- }
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
- TriggerPromiseReactions();
-}
-
-void
-Promise::MaybeSettle(JS::Handle<JS::Value> aValue,
- PromiseState aState)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- // Promise.all() or Promise.race() implementations will repeatedly call
- // Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
- // from asserting.
- if (mState != Pending) {
- return;
- }
-
- Settle(aValue, aState);
-}
-
-void
-Promise::TriggerPromiseReactions()
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- CycleCollectedJSContext* runtime = CycleCollectedJSContext::Get();
-
- nsTArray<RefPtr<PromiseCallback>> callbacks;
- callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
- : mRejectCallbacks);
- mResolveCallbacks.Clear();
- mRejectCallbacks.Clear();
-
- for (uint32_t i = 0; i < callbacks.Length(); ++i) {
- RefPtr<PromiseReactionJob> task =
- new PromiseReactionJob(this, callbacks[i], mResult);
- runtime->DispatchToMicroTask(task.forget());
- }
-}
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
-void
-Promise::RemoveWorkerHolder()
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- // The DTOR of this WorkerHolder will release the worker for us.
- mWorkerHolder = nullptr;
-}
-
-bool
-PromiseReportRejectWorkerHolder::Notify(Status aStatus)
-{
- MOZ_ASSERT(aStatus > Running);
- mPromise->MaybeReportRejectedOnce();
- // After this point, `this` has been deleted by RemoveWorkerHolder!
- return true;
-}
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
-bool
-Promise::CaptureStack(JSContext* aCx, JS::Heap<JSObject*>& aTarget)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- JS::Rooted<JSObject*> stack(aCx);
- if (!JS::CaptureCurrentStack(aCx, &stack)) {
- return false;
- }
- aTarget = stack;
- return true;
-}
-
-void
-Promise::GetDependentPromises(nsTArray<RefPtr<Promise>>& aPromises)
-{
- NS_ASSERT_OWNINGTHREAD(Promise);
-
- // We want to return promises that correspond to then() calls, Promise.all()
- // calls, and Promise.race() calls.
- //
- // For the then() case, we have both resolve and reject callbacks that know
- // what the next promise is.
- //
- // For the race() case, likewise.
- //
- // For the all() case, our reject callback knows what the next promise is, but
- // our resolve callback just knows it needs to notify some
- // PromiseNativeHandler, which itself only has an indirect relationship to the
- // next promise.
- //
- // So we walk over our _reject_ callbacks and ask each of them what promise
- // its dependent promise is.
- for (size_t i = 0; i < mRejectCallbacks.Length(); ++i) {
- Promise* p = mRejectCallbacks[i]->GetDependentPromise();
- if (p) {
- aPromises.AppendElement(p);
- }
- }
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
// A WorkerRunnable to resolve/reject the Promise on the worker thread.
// Calling thread MUST hold PromiseWorkerProxy's mutex before creating this.
class PromiseWorkerProxyRunnable : public WorkerRunnable
@@ -3223,23 +931,6 @@ void Promise::MaybeRejectBrokenly(const nsAString& aArg) {
MaybeSomething(aArg, &Promise::MaybeReject);
}
-#ifndef SPIDERMONKEY_PROMISE
-uint64_t
-Promise::GetID() {
- if (mID != 0) {
- return mID;
- }
- return mID = ++gIDGenerator;
-}
-#endif // SPIDERMONKEY_PROMISE
-
-#ifndef SPIDERMONKEY_PROMISE
-Promise::PromiseState
-Promise::State() const
-{
- return mState;
-}
-#else // SPIDERMONKEY_PROMISE
Promise::PromiseState
Promise::State() const
{
@@ -3256,7 +947,6 @@ Promise::State() const
return PromiseState::Pending;
}
-#endif // SPIDERMONKEY_PROMISE
} // namespace dom
} // namespace mozilla
diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h
index 642603a11..2fe365c46 100644
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -21,17 +21,6 @@
#include "js/TypeDecls.h"
#include "jspubtd.h"
-// Bug 1083361 introduces a new mechanism for tracking uncaught
-// rejections. This #define serves to track down the parts of code
-// that need to be removed once clients have been put together
-// to take advantage of the new mechanism. New code should not
-// depend on code #ifdefed to this #define.
-#define DOM_PROMISE_DEPRECATED_REPORTING !SPIDERMONKEY_PROMISE
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
-#include "mozilla/dom/workers/bindings/WorkerHolder.h"
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
class nsIGlobalObject;
namespace mozilla {
@@ -40,88 +29,36 @@ namespace dom {
class AnyCallback;
class DOMError;
class MediaStreamError;
-class PromiseCallback;
class PromiseInit;
class PromiseNativeHandler;
class PromiseDebugging;
-class Promise;
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
-class PromiseReportRejectWorkerHolder : public workers::WorkerHolder
-{
- // PromiseReportRejectWorkerHolder is held by an nsAutoPtr on the Promise
- // which means that this object will be destroyed before the Promise is
- // destroyed.
- Promise* MOZ_NON_OWNING_REF mPromise;
-
-public:
- explicit PromiseReportRejectWorkerHolder(Promise* aPromise)
- : mPromise(aPromise)
- {
- MOZ_ASSERT(mPromise);
- }
-
- virtual bool
- Notify(workers::Status aStatus) override;
-};
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
#define NS_PROMISE_IID \
{ 0x1b8d6215, 0x3e67, 0x43ba, \
{ 0x8a, 0xf9, 0x31, 0x5e, 0x8f, 0xce, 0x75, 0x65 } }
class Promise : public nsISupports,
-#ifndef SPIDERMONKEY_PROMISE
- // Only wrappercached when we're not using SpiderMonkey
- // promises, because those don't have a useful object moved
- // hook, which wrappercache needs.
- public nsWrapperCache,
-#endif // SPIDERMONKEY_PROMISE
public SupportsWeakPtr<Promise>
{
- friend class NativePromiseCallback;
- friend class PromiseReactionJob;
- friend class PromiseResolverTask;
friend class PromiseTask;
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- friend class PromiseReportRejectWorkerHolder;
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
friend class PromiseWorkerProxy;
friend class PromiseWorkerProxyRunnable;
- friend class RejectPromiseCallback;
- friend class ResolvePromiseCallback;
- friend class PromiseResolveThenableJob;
- friend class FastPromiseResolveThenableJob;
- friend class WrapperPromiseCallback;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROMISE_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-#ifdef SPIDERMONKEY_PROMISE
- // We're not skippable, since we're not owned from JS to start with.
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
-#else // SPIDERMONKEY_PROMISE
- NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(Promise)
-#endif // SPIDERMONKEY_PROMISE
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Promise)
// Promise creation tries to create a JS reflector for the Promise, so is
// fallible. Furthermore, we don't want to do JS-wrapping on a 0-refcount
// object, so we addref before doing that and return the addrefed pointer
// here.
-#ifdef SPIDERMONKEY_PROMISE
static already_AddRefed<Promise>
Create(nsIGlobalObject* aGlobal, ErrorResult& aRv);
// Reports a rejected Promise by sending an error report.
static void ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise);
-#else
- static already_AddRefed<Promise>
- Create(nsIGlobalObject* aGlobal, ErrorResult& aRv,
- // Passing null for aDesiredProto will use Promise.prototype.
- JS::Handle<JSObject*> aDesiredProto = nullptr);
-#endif // SPIDERMONKEY_PROMISE
typedef void (Promise::*MaybeFunc)(JSContext* aCx,
JS::Handle<JS::Value> aValue);
@@ -183,11 +120,6 @@ public:
return mGlobal;
}
-#ifdef SPIDERMONKEY_PROMISE
- bool
- WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
- JS::MutableHandle<JSObject*> aWrapper);
-
// Do the equivalent of Promise.resolve in the compartment of aGlobal. The
// compartment of aCx is ignored. Errors are reported on the ErrorResult; if
// aRv comes back !Failed(), this function MUST return a non-null value.
@@ -223,95 +155,17 @@ public:
return mPromiseObj;
}
-#else // SPIDERMONKEY_PROMISE
- JSObject* PromiseObj()
- {
- return GetWrapper();
- }
-
- virtual JSObject*
- WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- static already_AddRefed<Promise>
- Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
- ErrorResult& aRv, JS::Handle<JSObject*> aDesiredProto);
-
- static void
- Resolve(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aValue,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);
-
- static already_AddRefed<Promise>
- Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
- JS::Handle<JS::Value> aValue, ErrorResult& aRv);
-
- static void
- Reject(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aValue,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);
-
- static already_AddRefed<Promise>
- Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
- JS::Handle<JS::Value> aValue, ErrorResult& aRv);
-
- void
- Then(JSContext* aCx,
- // aCalleeGlobal may not be in the compartment of aCx, when called over
- // Xrays.
- JS::Handle<JSObject*> aCalleeGlobal,
- AnyCallback* aResolveCallback, AnyCallback* aRejectCallback,
- JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv);
-
- void
- Catch(JSContext* aCx,
- AnyCallback* aRejectCallback,
- JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv);
-
- static void
- All(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aIterable, JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv);
-
- static already_AddRefed<Promise>
- All(const GlobalObject& aGlobal,
- const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv);
-
- static void
- Race(const GlobalObject& aGlobal, JS::Handle<JS::Value> aThisv,
- JS::Handle<JS::Value> aIterable, JS::MutableHandle<JS::Value> aRetval,
- ErrorResult& aRv);
-
- static bool
- PromiseSpecies(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
-#endif // SPIDERMONKEY_PROMISE
-
void AppendNativeHandler(PromiseNativeHandler* aRunnable);
JSObject* GlobalJSObject() const;
JSCompartment* Compartment() const;
-#ifndef SPIDERMONKEY_PROMISE
- // Return a unique-to-the-process identifier for this Promise.
- uint64_t GetID();
-#endif // SPIDERMONKEY_PROMISE
-
-#ifndef SPIDERMONKEY_PROMISE
- enum JSCallbackSlots {
- SLOT_PROMISE = 0,
- SLOT_DATA
- };
-#endif // SPIDERMONKEY_PROMISE
-
-#ifdef SPIDERMONKEY_PROMISE
// Create a dom::Promise from a given SpiderMonkey Promise object.
// aPromiseObj MUST be in the compartment of aGlobal's global JS object.
static already_AddRefed<Promise>
CreateFromExisting(nsIGlobalObject* aGlobal,
JS::Handle<JSObject*> aPromiseObj);
-#endif // SPIDERMONKEY_PROMISE
enum class PromiseState {
Pending,
@@ -335,99 +189,7 @@ protected:
// use the default prototype for the sort of Promise we have.
void CreateWrapper(JS::Handle<JSObject*> aDesiredProto, ErrorResult& aRv);
-#ifndef SPIDERMONKEY_PROMISE
- // Create the JS resolving functions of resolve() and reject(). And provide
- // references to the two functions by calling PromiseInit passed from Promise
- // constructor.
- void CallInitFunction(const GlobalObject& aGlobal, PromiseInit& aInit,
- ErrorResult& aRv);
-
- // The NewPromiseCapability function from
- // <http://www.ecma-international.org/ecma-262/6.0/#sec-newpromisecapability>.
- // Errors are communicated via aRv. If aForceCallbackCreation is
- // true, then this function will ensure that aCapability has a
- // useful mResolve/mReject even if mNativePromise is non-null.
- static void NewPromiseCapability(JSContext* aCx, nsIGlobalObject* aGlobal,
- JS::Handle<JS::Value> aConstructor,
- bool aForceCallbackCreation,
- PromiseCapability& aCapability,
- ErrorResult& aRv);
-
- bool IsPending()
- {
- return mResolvePending;
- }
-
- void GetDependentPromises(nsTArray<RefPtr<Promise>>& aPromises);
-
- bool IsLastInChain() const
- {
- return mIsLastInChain;
- }
-
- void SetNotifiedAsUncaught()
- {
- mWasNotifiedAsUncaught = true;
- }
-
- bool WasNotifiedAsUncaught() const
- {
- return mWasNotifiedAsUncaught;
- }
-#endif // SPIDERMONKEY_PROMISE
-
private:
-#ifndef SPIDERMONKEY_PROMISE
- friend class PromiseDebugging;
-
- void SetState(PromiseState aState)
- {
- MOZ_ASSERT(mState == Pending);
- MOZ_ASSERT(aState != Pending);
- mState = aState;
- }
-
- void SetResult(JS::Handle<JS::Value> aValue)
- {
- mResult = aValue;
- }
-
- // This method enqueues promise's resolve/reject callbacks with promise's
- // result. It's executed when the resolver.resolve() or resolver.reject() is
- // called or when the promise already has a result and new callbacks are
- // appended by then() or catch().
- void TriggerPromiseReactions();
-
- void Settle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
- void MaybeSettle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
-
- void AppendCallbacks(PromiseCallback* aResolveCallback,
- PromiseCallback* aRejectCallback);
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- // If we have been rejected and our mResult is a JS exception,
- // report it to the error console.
- // Use MaybeReportRejectedOnce() for actual calls.
- void MaybeReportRejected();
-
- void MaybeReportRejectedOnce() {
- MaybeReportRejected();
- RemoveWorkerHolder();
- mResult.setUndefined();
- }
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
- void MaybeResolveInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue);
- void MaybeRejectInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue);
-
- void ResolveInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue);
- void RejectInternal(JSContext* aCx,
- JS::Handle<JS::Value> aValue);
-#endif // SPIDERMONKEY_PROMISE
-
template <typename T>
void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
MOZ_ASSERT(PromiseObj()); // It was preserved!
@@ -444,92 +206,11 @@ private:
(this->*aFunc)(cx, val);
}
-#ifndef SPIDERMONKEY_PROMISE
- // Static methods for the PromiseInit functions.
- static bool
- JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
-
- static bool
- ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask,
- unsigned aArgc, JS::Value* aVp);
- static bool
- JSCallbackThenableResolver(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
- static bool
- JSCallbackThenableRejecter(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
-
- static JSObject*
- CreateFunction(JSContext* aCx, Promise* aPromise, int32_t aTask);
-
- static JSObject*
- CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask);
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- void RemoveWorkerHolder();
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
- // Capture the current stack and store it in aTarget. If false is
- // returned, an exception is presumably pending on aCx.
- bool CaptureStack(JSContext* aCx, JS::Heap<JSObject*>& aTarget);
-#endif // SPIDERMONKEY_PROMISE
-
void HandleException(JSContext* aCx);
RefPtr<nsIGlobalObject> mGlobal;
-#ifndef SPIDERMONKEY_PROMISE
- nsTArray<RefPtr<PromiseCallback> > mResolveCallbacks;
- nsTArray<RefPtr<PromiseCallback> > mRejectCallbacks;
-
- JS::Heap<JS::Value> mResult;
- // A stack that shows where this promise was allocated, if there was
- // JS running at the time. Otherwise null.
- JS::Heap<JSObject*> mAllocationStack;
- // mRejectionStack is only set when the promise is rejected directly from
- // script, by calling Promise.reject() or the rejection callback we pass to
- // the PromiseInit function. Promises that are rejected internally do not
- // have a rejection stack.
- JS::Heap<JSObject*> mRejectionStack;
- // mFullfillmentStack is only set when the promise is fulfilled directly from
- // script, by calling Promise.resolve() or the fulfillment callback we pass to
- // the PromiseInit function. Promises that are fulfilled internally do not
- // have a fulfillment stack.
- JS::Heap<JSObject*> mFullfillmentStack;
- PromiseState mState;
-
-#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
- bool mHadRejectCallback;
-
- // If a rejected promise on a worker has no reject callbacks attached, it
- // needs to know when the worker is shutting down, to report the error on the
- // console before the worker's context is deleted. This feature is used for
- // that purpose.
- nsAutoPtr<PromiseReportRejectWorkerHolder> mWorkerHolder;
-#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
-
- bool mTaskPending;
- bool mResolvePending;
-
- // `true` if this Promise is the last in the chain, or `false` if
- // another Promise has been created from this one by a call to
- // `then`, `all`, `race`, etc.
- bool mIsLastInChain;
-
- // `true` if PromiseDebugging has already notified at least one observer that
- // this promise was left uncaught, `false` otherwise.
- bool mWasNotifiedAsUncaught;
-
- // The time when this promise was created.
- TimeStamp mCreationTimestamp;
-
- // The time when this promise transitioned out of the pending state.
- TimeStamp mSettlementTimestamp;
-
- // Once `GetID()` has been called, a unique-to-the-process identifier for this
- // promise. Until then, `0`.
- uint64_t mID;
-#else // SPIDERMONKEY_PROMISE
JS::Heap<JSObject*> mPromiseObj;
-#endif // SPIDERMONKEY_PROMISE
};
NS_DEFINE_STATIC_IID_ACCESSOR(Promise, NS_PROMISE_IID)
diff --git a/dom/promise/PromiseCallback.cpp b/dom/promise/PromiseCallback.cpp
deleted file mode 100644
index 6ecf983b7..000000000
--- a/dom/promise/PromiseCallback.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "PromiseCallback.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/PromiseNativeHandler.h"
-
-#include "jsapi.h"
-#include "jsfriendapi.h"
-#include "jswrapper.h"
-
-namespace mozilla {
-namespace dom {
-
-#ifndef SPIDERMONKEY_PROMISE
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(PromiseCallback)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(PromiseCallback)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PromiseCallback)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_0(PromiseCallback)
-
-PromiseCallback::PromiseCallback()
-{
-}
-
-PromiseCallback::~PromiseCallback()
-{
-}
-
-// ResolvePromiseCallback
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(ResolvePromiseCallback)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ResolvePromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
- tmp->mGlobal = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ResolvePromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ResolvePromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ResolvePromiseCallback)
-NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
-
-NS_IMPL_ADDREF_INHERITED(ResolvePromiseCallback, PromiseCallback)
-NS_IMPL_RELEASE_INHERITED(ResolvePromiseCallback, PromiseCallback)
-
-ResolvePromiseCallback::ResolvePromiseCallback(Promise* aPromise,
- JS::Handle<JSObject*> aGlobal)
- : mPromise(aPromise)
- , mGlobal(aGlobal)
-{
- MOZ_ASSERT(aPromise);
- MOZ_ASSERT(aGlobal);
- HoldJSObjects(this);
-}
-
-ResolvePromiseCallback::~ResolvePromiseCallback()
-{
- DropJSObjects(this);
-}
-
-nsresult
-ResolvePromiseCallback::Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- // Run resolver's algorithm with value and the synchronous flag set.
-
- JS::ExposeValueToActiveJS(aValue);
-
- JSAutoCompartment ac(aCx, mGlobal);
- JS::Rooted<JS::Value> value(aCx, aValue);
- if (!JS_WrapValue(aCx, &value)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- return NS_ERROR_FAILURE;
- }
-
- mPromise->ResolveInternal(aCx, value);
- return NS_OK;
-}
-
-// RejectPromiseCallback
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(RejectPromiseCallback)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(RejectPromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
- tmp->mGlobal = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(RejectPromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(RejectPromiseCallback)
-NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(RejectPromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_ADDREF_INHERITED(RejectPromiseCallback, PromiseCallback)
-NS_IMPL_RELEASE_INHERITED(RejectPromiseCallback, PromiseCallback)
-
-RejectPromiseCallback::RejectPromiseCallback(Promise* aPromise,
- JS::Handle<JSObject*> aGlobal)
- : mPromise(aPromise)
- , mGlobal(aGlobal)
-{
- MOZ_ASSERT(aPromise);
- MOZ_ASSERT(mGlobal);
- HoldJSObjects(this);
-}
-
-RejectPromiseCallback::~RejectPromiseCallback()
-{
- DropJSObjects(this);
-}
-
-nsresult
-RejectPromiseCallback::Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- // Run resolver's algorithm with value and the synchronous flag set.
-
- JS::ExposeValueToActiveJS(aValue);
-
- JSAutoCompartment ac(aCx, mGlobal);
- JS::Rooted<JS::Value> value(aCx, aValue);
- if (!JS_WrapValue(aCx, &value)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- return NS_ERROR_FAILURE;
- }
-
-
- mPromise->RejectInternal(aCx, value);
- return NS_OK;
-}
-
-// InvokePromiseFuncCallback
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(InvokePromiseFuncCallback)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(InvokePromiseFuncCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromiseFunc)
- tmp->mGlobal = nullptr;
- tmp->mNextPromiseObj = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(InvokePromiseFuncCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromiseFunc)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(InvokePromiseFuncCallback)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNextPromiseObj)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(InvokePromiseFuncCallback)
-NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
-
-NS_IMPL_ADDREF_INHERITED(InvokePromiseFuncCallback, PromiseCallback)
-NS_IMPL_RELEASE_INHERITED(InvokePromiseFuncCallback, PromiseCallback)
-
-InvokePromiseFuncCallback::InvokePromiseFuncCallback(JS::Handle<JSObject*> aGlobal,
- JS::Handle<JSObject*> aNextPromiseObj,
- AnyCallback* aPromiseFunc)
- : mGlobal(aGlobal)
- , mNextPromiseObj(aNextPromiseObj)
- , mPromiseFunc(aPromiseFunc)
-{
- MOZ_ASSERT(aGlobal);
- MOZ_ASSERT(aNextPromiseObj);
- MOZ_ASSERT(aPromiseFunc);
- HoldJSObjects(this);
-}
-
-InvokePromiseFuncCallback::~InvokePromiseFuncCallback()
-{
- DropJSObjects(this);
-}
-
-nsresult
-InvokePromiseFuncCallback::Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- // Run resolver's algorithm with value and the synchronous flag set.
-
- JS::ExposeValueToActiveJS(aValue);
-
- JSAutoCompartment ac(aCx, mGlobal);
- JS::Rooted<JS::Value> value(aCx, aValue);
- if (!JS_WrapValue(aCx, &value)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- return NS_ERROR_FAILURE;
- }
-
- ErrorResult rv;
- JS::Rooted<JS::Value> ignored(aCx);
- mPromiseFunc->Call(value, &ignored, rv);
- // Useful exceptions already got reported.
- rv.SuppressException();
- return NS_OK;
-}
-
-Promise*
-InvokePromiseFuncCallback::GetDependentPromise()
-{
- Promise* promise;
- if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) {
- return promise;
- }
-
- // Oh, well.
- return nullptr;
-}
-
-// WrapperPromiseCallback
-NS_IMPL_CYCLE_COLLECTION_CLASS(WrapperPromiseCallback)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WrapperPromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextPromise)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mResolveFunc)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mRejectFunc)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
- tmp->mGlobal = nullptr;
- tmp->mNextPromiseObj = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WrapperPromiseCallback,
- PromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextPromise)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveFunc)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectFunc)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WrapperPromiseCallback)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNextPromiseObj)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WrapperPromiseCallback)
-NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
-
-NS_IMPL_ADDREF_INHERITED(WrapperPromiseCallback, PromiseCallback)
-NS_IMPL_RELEASE_INHERITED(WrapperPromiseCallback, PromiseCallback)
-
-WrapperPromiseCallback::WrapperPromiseCallback(Promise* aNextPromise,
- JS::Handle<JSObject*> aGlobal,
- AnyCallback* aCallback)
- : mNextPromise(aNextPromise)
- , mGlobal(aGlobal)
- , mCallback(aCallback)
-{
- MOZ_ASSERT(aNextPromise);
- MOZ_ASSERT(aGlobal);
- HoldJSObjects(this);
-}
-
-WrapperPromiseCallback::WrapperPromiseCallback(JS::Handle<JSObject*> aGlobal,
- AnyCallback* aCallback,
- JS::Handle<JSObject*> aNextPromiseObj,
- AnyCallback* aResolveFunc,
- AnyCallback* aRejectFunc)
- : mNextPromiseObj(aNextPromiseObj)
- , mResolveFunc(aResolveFunc)
- , mRejectFunc(aRejectFunc)
- , mGlobal(aGlobal)
- , mCallback(aCallback)
-{
- MOZ_ASSERT(mNextPromiseObj);
- MOZ_ASSERT(aResolveFunc);
- MOZ_ASSERT(aRejectFunc);
- MOZ_ASSERT(aGlobal);
- HoldJSObjects(this);
-}
-
-WrapperPromiseCallback::~WrapperPromiseCallback()
-{
- DropJSObjects(this);
-}
-
-nsresult
-WrapperPromiseCallback::Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- JS::ExposeValueToActiveJS(aValue);
-
- JSAutoCompartment ac(aCx, mGlobal);
- JS::Rooted<JS::Value> value(aCx, aValue);
- if (!JS_WrapValue(aCx, &value)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- return NS_ERROR_FAILURE;
- }
-
- ErrorResult rv;
-
- // PromiseReactionTask step 6
- JS::Rooted<JS::Value> retValue(aCx);
- JSCompartment* compartment;
- if (mNextPromise) {
- compartment = mNextPromise->Compartment();
- } else {
- MOZ_ASSERT(mNextPromiseObj);
- compartment = js::GetObjectCompartment(mNextPromiseObj);
- }
- mCallback->Call(value, &retValue, rv, "promise callback",
- CallbackObject::eRethrowExceptions,
- compartment);
-
- rv.WouldReportJSException();
-
- // PromiseReactionTask step 7
- if (rv.Failed()) {
- if (rv.IsUncatchableException()) {
- // We have nothing to resolve/reject the promise with.
- return rv.StealNSResult();
- }
-
- JS::Rooted<JS::Value> value(aCx);
- { // Scope for JSAutoCompartment
- // Convert the ErrorResult to a JS exception object that we can reject
- // ourselves with. This will be exactly the exception that would get
- // thrown from a binding method whose ErrorResult ended up with whatever
- // is on "rv" right now. Do this in the promise reflector compartment.
- Maybe<JSAutoCompartment> ac;
- if (mNextPromise) {
- ac.emplace(aCx, mNextPromise->GlobalJSObject());
- } else {
- ac.emplace(aCx, mNextPromiseObj);
- }
- DebugOnly<bool> conversionResult = ToJSValue(aCx, rv, &value);
- MOZ_ASSERT(conversionResult);
- }
-
- if (mNextPromise) {
- mNextPromise->RejectInternal(aCx, value);
- } else {
- JS::Rooted<JS::Value> ignored(aCx);
- ErrorResult rejectRv;
- mRejectFunc->Call(value, &ignored, rejectRv);
- // This reported any JS exceptions; we just have a pointless exception on
- // there now.
- rejectRv.SuppressException();
- }
- return NS_OK;
- }
-
- // If the return value is the same as the promise itself, throw TypeError.
- if (retValue.isObject()) {
- JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
- valueObj = js::CheckedUnwrap(valueObj);
- JS::Rooted<JSObject*> nextPromiseObj(aCx);
- if (mNextPromise) {
- nextPromiseObj = mNextPromise->GetWrapper();
- } else {
- MOZ_ASSERT(mNextPromiseObj);
- nextPromiseObj = mNextPromiseObj;
- }
- // XXXbz shouldn't this check be over in ResolveInternal anyway?
- if (valueObj == nextPromiseObj) {
- const char* fileName = nullptr;
- uint32_t lineNumber = 0;
-
- // Try to get some information about the callback to report a sane error,
- // but don't try too hard (only deals with scripted functions).
- JS::Rooted<JSObject*> unwrapped(aCx,
- js::CheckedUnwrap(mCallback->Callback()));
-
- if (unwrapped) {
- JSAutoCompartment ac(aCx, unwrapped);
- if (JS_ObjectIsFunction(aCx, unwrapped)) {
- JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
- JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));
-
- MOZ_ASSERT(func);
- JSScript* script = JS_GetFunctionScript(aCx, func);
- if (script) {
- fileName = JS_GetScriptFilename(script);
- lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
- }
- }
- }
-
- // We're back in aValue's compartment here.
- JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
- if (!fn) {
- // Out of memory. Promise will stay unresolved.
- JS_ClearPendingException(aCx);
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- JS::Rooted<JSString*> message(aCx,
- JS_NewStringCopyZ(aCx,
- "then() cannot return same Promise that it resolves."));
- if (!message) {
- // Out of memory. Promise will stay unresolved.
- JS_ClearPendingException(aCx);
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- JS::Rooted<JS::Value> typeError(aCx);
- if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, fn, lineNumber, 0,
- nullptr, message, &typeError)) {
- // Out of memory. Promise will stay unresolved.
- JS_ClearPendingException(aCx);
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- if (mNextPromise) {
- mNextPromise->RejectInternal(aCx, typeError);
- } else {
- JS::Rooted<JS::Value> ignored(aCx);
- ErrorResult rejectRv;
- mRejectFunc->Call(typeError, &ignored, rejectRv);
- // This reported any JS exceptions; we just have a pointless exception
- // on there now.
- rejectRv.SuppressException();
- }
- return NS_OK;
- }
- }
-
- // Otherwise, run resolver's resolve with value.
- if (!JS_WrapValue(aCx, &retValue)) {
- NS_WARNING("Failed to wrap value into the right compartment.");
- return NS_ERROR_FAILURE;
- }
-
- if (mNextPromise) {
- mNextPromise->ResolveInternal(aCx, retValue);
- } else {
- JS::Rooted<JS::Value> ignored(aCx);
- ErrorResult resolveRv;
- mResolveFunc->Call(retValue, &ignored, resolveRv);
- // This reported any JS exceptions; we just have a pointless exception
- // on there now.
- resolveRv.SuppressException();
- }
-
- return NS_OK;
-}
-
-Promise*
-WrapperPromiseCallback::GetDependentPromise()
-{
- // Per spec, various algorithms like all() and race() are actually implemented
- // in terms of calling then() but passing it the resolve/reject functions that
- // are passed as arguments to function passed to the Promise constructor.
- // That will cause the promise in question to hold on to a
- // WrapperPromiseCallback, but the dependent promise should really be the one
- // whose constructor those functions came from, not the about-to-be-ignored
- // return value of "then". So try to determine whether we're in that case and
- // if so go ahead and dig the dependent promise out of the function we have.
- JSObject* callable = mCallback->Callable();
- // Unwrap it, in case it's a cross-compartment wrapper. Our caller here is
- // system, so it's really ok to just go and unwrap.
- callable = js::UncheckedUnwrap(callable);
- if (JS_IsNativeFunction(callable, Promise::JSCallback)) {
- JS::Value promiseVal =
- js::GetFunctionNativeReserved(callable, Promise::SLOT_PROMISE);
- Promise* promise;
- UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise);
- return promise;
- }
-
- if (mNextPromise) {
- return mNextPromise;
- }
-
- Promise* promise;
- if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) {
- return promise;
- }
-
- // Oh, well.
- return nullptr;
-}
-
-// NativePromiseCallback
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(NativePromiseCallback,
- PromiseCallback, mHandler)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(NativePromiseCallback)
-NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
-
-NS_IMPL_ADDREF_INHERITED(NativePromiseCallback, PromiseCallback)
-NS_IMPL_RELEASE_INHERITED(NativePromiseCallback, PromiseCallback)
-
-NativePromiseCallback::NativePromiseCallback(PromiseNativeHandler* aHandler,
- Promise::PromiseState aState)
- : mHandler(aHandler)
- , mState(aState)
-{
- MOZ_ASSERT(aHandler);
-}
-
-NativePromiseCallback::~NativePromiseCallback()
-{
-}
-
-nsresult
-NativePromiseCallback::Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- JS::ExposeValueToActiveJS(aValue);
-
- if (mState == Promise::Resolved) {
- mHandler->ResolvedCallback(aCx, aValue);
- return NS_OK;
- }
-
- if (mState == Promise::Rejected) {
- mHandler->RejectedCallback(aCx, aValue);
- return NS_OK;
- }
-
- NS_NOTREACHED("huh?");
- return NS_ERROR_FAILURE;
-}
-
-/* static */ PromiseCallback*
-PromiseCallback::Factory(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
- AnyCallback* aCallback, Task aTask)
-{
- MOZ_ASSERT(aNextPromise);
-
- // If we have a callback and a next resolver, we have to exec the callback and
- // then propagate the return value to the next resolver->resolve().
- if (aCallback) {
- return new WrapperPromiseCallback(aNextPromise, aGlobal, aCallback);
- }
-
- if (aTask == Resolve) {
- return new ResolvePromiseCallback(aNextPromise, aGlobal);
- }
-
- if (aTask == Reject) {
- return new RejectPromiseCallback(aNextPromise, aGlobal);
- }
-
- MOZ_ASSERT(false, "This should not happen");
- return nullptr;
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/promise/PromiseCallback.h b/dom/promise/PromiseCallback.h
deleted file mode 100644
index 9f55e03d0..000000000
--- a/dom/promise/PromiseCallback.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_PromiseCallback_h
-#define mozilla_dom_PromiseCallback_h
-
-#include "mozilla/dom/Promise.h"
-#include "nsCycleCollectionParticipant.h"
-
-namespace mozilla {
-namespace dom {
-
-#ifndef SPIDERMONKEY_PROMISE
-// This is the base class for any PromiseCallback.
-// It's a logical step in the promise chain of callbacks.
-class PromiseCallback : public nsISupports
-{
-protected:
- virtual ~PromiseCallback();
-
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS(PromiseCallback)
-
- PromiseCallback();
-
- virtual nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) = 0;
-
- // Return the Promise that this callback will end up resolving or
- // rejecting, if any.
- virtual Promise* GetDependentPromise() = 0;
-
- enum Task {
- Resolve,
- Reject
- };
-
- // This factory returns a PromiseCallback object with refcount of 0.
- static PromiseCallback*
- Factory(Promise* aNextPromise, JS::Handle<JSObject*> aObject,
- AnyCallback* aCallback, Task aTask);
-};
-
-// WrapperPromiseCallback execs a JS Callback with a value, and then the return
-// value is sent to either:
-// a) If aNextPromise is non-null, the aNextPromise->ResolveFunction() or to
-// aNextPromise->RejectFunction() if the JS Callback throws.
-// or
-// b) If aNextPromise is null, in which case aResolveFunc and aRejectFunc must
-// be non-null, then to aResolveFunc, unless aCallback threw, in which case
-// aRejectFunc.
-class WrapperPromiseCallback final : public PromiseCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WrapperPromiseCallback,
- PromiseCallback)
-
- nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) override;
-
- Promise* GetDependentPromise() override;
-
- // Constructor for when we know we have a vanilla Promise.
- WrapperPromiseCallback(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
- AnyCallback* aCallback);
-
- // Constructor for when all we have to work with are resolve/reject functions.
- WrapperPromiseCallback(JS::Handle<JSObject*> aGlobal,
- AnyCallback* aCallback,
- JS::Handle<JSObject*> mNextPromiseObj,
- AnyCallback* aResolveFunc,
- AnyCallback* aRejectFunc);
-
-private:
- ~WrapperPromiseCallback();
-
- // Either mNextPromise is non-null or all three of mNextPromiseObj,
- // mResolveFund and mRejectFunc must are non-null.
- RefPtr<Promise> mNextPromise;
- // mNextPromiseObj is the reflector itself; it may not be in the
- // same compartment as anything else we have.
- JS::Heap<JSObject*> mNextPromiseObj;
- RefPtr<AnyCallback> mResolveFunc;
- RefPtr<AnyCallback> mRejectFunc;
- JS::Heap<JSObject*> mGlobal;
- RefPtr<AnyCallback> mCallback;
-};
-
-// ResolvePromiseCallback calls aPromise->ResolveFunction() with the value
-// received by Call().
-class ResolvePromiseCallback final : public PromiseCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ResolvePromiseCallback,
- PromiseCallback)
-
- nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) override;
-
- Promise* GetDependentPromise() override
- {
- return mPromise;
- }
-
- ResolvePromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
-
-private:
- ~ResolvePromiseCallback();
-
- RefPtr<Promise> mPromise;
- JS::Heap<JSObject*> mGlobal;
-};
-
-// RejectPromiseCallback calls aPromise->RejectFunction() with the value
-// received by Call().
-class RejectPromiseCallback final : public PromiseCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(RejectPromiseCallback,
- PromiseCallback)
-
- nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) override;
-
- Promise* GetDependentPromise() override
- {
- return mPromise;
- }
-
- RejectPromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
-
-private:
- ~RejectPromiseCallback();
-
- RefPtr<Promise> mPromise;
- JS::Heap<JSObject*> mGlobal;
-};
-
-// InvokePromiseFuncCallback calls the given function with the value
-// received by Call().
-class InvokePromiseFuncCallback final : public PromiseCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(InvokePromiseFuncCallback,
- PromiseCallback)
-
- nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) override;
-
- Promise* GetDependentPromise() override;
-
- InvokePromiseFuncCallback(JS::Handle<JSObject*> aGlobal,
- JS::Handle<JSObject*> aNextPromiseObj,
- AnyCallback* aPromiseFunc);
-
-private:
- ~InvokePromiseFuncCallback();
-
- JS::Heap<JSObject*> mGlobal;
- JS::Heap<JSObject*> mNextPromiseObj;
- RefPtr<AnyCallback> mPromiseFunc;
-};
-
-// NativePromiseCallback wraps a PromiseNativeHandler.
-class NativePromiseCallback final : public PromiseCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NativePromiseCallback,
- PromiseCallback)
-
- nsresult Call(JSContext* aCx,
- JS::Handle<JS::Value> aValue) override;
-
- Promise* GetDependentPromise() override
- {
- return nullptr;
- }
-
- NativePromiseCallback(PromiseNativeHandler* aHandler,
- Promise::PromiseState aState);
-
-private:
- ~NativePromiseCallback();
-
- RefPtr<PromiseNativeHandler> mHandler;
- Promise::PromiseState mState;
-};
-
-#endif // SPIDERMONKEY_PROMISE
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PromiseCallback_h
diff --git a/dom/promise/PromiseDebugging.cpp b/dom/promise/PromiseDebugging.cpp
index fc0942ee4..f3ec33e8b 100644
--- a/dom/promise/PromiseDebugging.cpp
+++ b/dom/promise/PromiseDebugging.cpp
@@ -66,20 +66,6 @@ private:
/* static */ MOZ_THREAD_LOCAL(bool)
FlushRejections::sDispatched;
-#ifndef SPIDERMONKEY_PROMISE
-static Promise*
-UnwrapPromise(JS::Handle<JSObject*> aPromise, ErrorResult& aRv)
-{
- Promise* promise;
- if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Promise, aPromise, promise)))) {
- aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING("Argument"));
- return nullptr;
- }
- return promise;
-}
-#endif // SPIDERMONKEY_PROMISE
-
-#ifdef SPIDERMONKEY_PROMISE
/* static */ void
PromiseDebugging::GetState(GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
@@ -173,34 +159,6 @@ PromiseDebugging::GetFullfillmentStack(GlobalObject& aGlobal,
aStack.set(JS::GetPromiseResolutionSite(obj));
}
-#else
-
-/* static */ void
-PromiseDebugging::GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
- PromiseDebuggingStateHolder& aState,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- switch (promise->mState) {
- case Promise::Pending:
- aState.mState = PromiseDebuggingState::Pending;
- break;
- case Promise::Resolved:
- aState.mState = PromiseDebuggingState::Fulfilled;
- aState.mValue = promise->mResult;
- break;
- case Promise::Rejected:
- aState.mState = PromiseDebuggingState::Rejected;
- aState.mReason = promise->mResult;
- break;
- }
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
/*static */ nsString
PromiseDebugging::sIDPrefix;
@@ -232,86 +190,6 @@ PromiseDebugging::FlushUncaughtRejections()
FlushRejections::FlushSync();
}
-#ifndef SPIDERMONKEY_PROMISE
-
-/* static */ void
-PromiseDebugging::GetAllocationStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
- JS::MutableHandle<JSObject*> aStack,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- aStack.set(promise->mAllocationStack);
-}
-
-/* static */ void
-PromiseDebugging::GetRejectionStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
- JS::MutableHandle<JSObject*> aStack,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- aStack.set(promise->mRejectionStack);
-}
-
-/* static */ void
-PromiseDebugging::GetFullfillmentStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
- JS::MutableHandle<JSObject*> aStack,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- aStack.set(promise->mFullfillmentStack);
-}
-
-/* static */ void
-PromiseDebugging::GetDependentPromises(GlobalObject&, JS::Handle<JSObject*> aPromise,
- nsTArray<RefPtr<Promise>>& aPromises,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- promise->GetDependentPromises(aPromises);
-}
-
-/* static */ double
-PromiseDebugging::GetPromiseLifetime(GlobalObject&,
- JS::Handle<JSObject*> aPromise,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return 0;
- }
- return (TimeStamp::Now() - promise->mCreationTimestamp).ToMilliseconds();
-}
-
-/* static */ double
-PromiseDebugging::GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return 0;
- }
- if (promise->mState == Promise::Pending) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return 0;
- }
- return (promise->mSettlementTimestamp -
- promise->mCreationTimestamp).ToMilliseconds();
-}
-
-#endif // SPIDERMONKEY_PROMISE
-
/* static */ void
PromiseDebugging::AddUncaughtRejectionObserver(GlobalObject&,
UncaughtRejectionObserver& aObserver)
@@ -337,8 +215,6 @@ PromiseDebugging::RemoveUncaughtRejectionObserver(GlobalObject&,
return false;
}
-#ifdef SPIDERMONKEY_PROMISE
-
/* static */ void
PromiseDebugging::AddUncaughtRejection(JS::HandleObject aPromise)
{
@@ -420,102 +296,5 @@ PromiseDebugging::FlushUncaughtRejectionsInternal()
storage->mConsumedRejections.clear();
}
-#else
-
-/* static */ void
-PromiseDebugging::AddUncaughtRejection(Promise& aPromise)
-{
- CycleCollectedJSContext::Get()->mUncaughtRejections.AppendElement(&aPromise);
- FlushRejections::DispatchNeeded();
-}
-
-/* void */ void
-PromiseDebugging::AddConsumedRejection(Promise& aPromise)
-{
- CycleCollectedJSContext::Get()->mConsumedRejections.AppendElement(&aPromise);
- FlushRejections::DispatchNeeded();
-}
-
-/* static */ void
-PromiseDebugging::GetPromiseID(GlobalObject&,
- JS::Handle<JSObject*> aPromise,
- nsString& aID,
- ErrorResult& aRv)
-{
- Promise* promise = UnwrapPromise(aPromise, aRv);
- if (aRv.Failed()) {
- return;
- }
- uint64_t promiseID = promise->GetID();
- aID = sIDPrefix;
- aID.AppendInt(promiseID);
-}
-
-/* static */ void
-PromiseDebugging::FlushUncaughtRejectionsInternal()
-{
- CycleCollectedJSContext* storage = CycleCollectedJSContext::Get();
-
- // The Promise that have been left uncaught (rejected and last in
- // their chain) since the last call to this function.
- nsTArray<nsCOMPtr<nsISupports>> uncaught;
- storage->mUncaughtRejections.SwapElements(uncaught);
-
- // The Promise that have been left uncaught at some point, but that
- // have eventually had their `then` method called.
- nsTArray<nsCOMPtr<nsISupports>> consumed;
- storage->mConsumedRejections.SwapElements(consumed);
-
- nsTArray<nsCOMPtr<nsISupports>>& observers = storage->mUncaughtRejectionObservers;
-
- nsresult rv;
- // Notify observers of uncaught Promise.
-
- for (size_t i = 0; i < uncaught.Length(); ++i) {
- nsCOMPtr<Promise> promise = do_QueryInterface(uncaught[i], &rv);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- if (!promise->IsLastInChain()) {
- // This promise is not the last in the chain anymore,
- // so the error has been caught at some point.
- continue;
- }
-
- // For the moment, the Promise is still at the end of the
- // chain. Let's inform observers, so that they may decide whether
- // to report it.
- for (size_t j = 0; j < observers.Length(); ++j) {
- ErrorResult err;
- RefPtr<UncaughtRejectionObserver> obs =
- static_cast<UncaughtRejectionObserver*>(observers[j].get());
-
- obs->OnLeftUncaught(*promise, err); // Ignore errors
- }
-
- promise->SetNotifiedAsUncaught();
- }
-
- // Notify observers of consumed Promise.
-
- for (size_t i = 0; i < consumed.Length(); ++i) {
- nsCOMPtr<Promise> promise = do_QueryInterface(consumed[i], &rv);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- if (!promise->WasNotifiedAsUncaught()) {
- continue;
- }
-
- MOZ_ASSERT(!promise->IsLastInChain());
- for (size_t j = 0; j < observers.Length(); ++j) {
- ErrorResult err;
- RefPtr<UncaughtRejectionObserver> obs =
- static_cast<UncaughtRejectionObserver*>(observers[j].get());
-
- obs->OnConsumed(*promise, err); // Ignore errors
- }
- }
-}
-#endif // SPIDERMONKEY_PROMISE
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/promise/PromiseDebugging.h b/dom/promise/PromiseDebugging.h
index 218a64c2e..77397b841 100644
--- a/dom/promise/PromiseDebugging.h
+++ b/dom/promise/PromiseDebugging.h
@@ -52,37 +52,17 @@ public:
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
-#ifndef SPIDERMONKEY_PROMISE
- static void GetDependentPromises(GlobalObject&,
- JS::Handle<JSObject*> aPromise,
- nsTArray<RefPtr<Promise>>& aPromises,
- ErrorResult& aRv);
- static double GetPromiseLifetime(GlobalObject&,
- JS::Handle<JSObject*> aPromise,
- ErrorResult& aRv);
- static double GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
- ErrorResult& aRv);
-#endif // SPIDERMONKEY_PROMISE
-
// Mechanism for watching uncaught instances of Promise.
static void AddUncaughtRejectionObserver(GlobalObject&,
UncaughtRejectionObserver& aObserver);
static bool RemoveUncaughtRejectionObserver(GlobalObject&,
UncaughtRejectionObserver& aObserver);
-#ifdef SPIDERMONKEY_PROMISE
// Mark a Promise as having been left uncaught at script completion.
static void AddUncaughtRejection(JS::HandleObject);
// Mark a Promise previously added with `AddUncaughtRejection` as
// eventually consumed.
static void AddConsumedRejection(JS::HandleObject);
-#else
- // Mark a Promise as having been left uncaught at script completion.
- static void AddUncaughtRejection(Promise&);
- // Mark a Promise previously added with `AddUncaughtRejection` as
- // eventually consumed.
- static void AddConsumedRejection(Promise&);
-#endif // SPIDERMONKEY_PROMISE
// Propagate the informations from AddUncaughtRejection
// and AddConsumedRejection to observers.
static void FlushUncaughtRejections();
diff --git a/dom/promise/moz.build b/dom/promise/moz.build
index 11d2a7496..c0e3d79a7 100644
--- a/dom/promise/moz.build
+++ b/dom/promise/moz.build
@@ -11,9 +11,8 @@ EXPORTS.mozilla.dom += [
'PromiseWorkerProxy.h',
]
-UNIFIED_SOURCES += [
+SOURCES += [
'Promise.cpp',
- 'PromiseCallback.cpp',
'PromiseDebugging.cpp',
]
diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
index 65be02809..56a119e1a 100644
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -513,8 +513,19 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
bool allowed =
mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
- mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
- mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
+ mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated);
+
+ // If the inlined script or style is allowed by either unsafe-inline or the
+ // nonce, go ahead and shortcut this loop.
+ if (allowed) {
+ continue;
+ }
+
+ // Check if the csp-hash matches against the hash of the script.
+ // If we don't have any content to check, block the script.
+ if (!aContent.IsEmpty()) {
+ allowed = mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
+ }
if (!allowed) {
// policy is violoated: deny the load unless policy is report only and
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index 71c8e3433..d07ad7945 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -641,13 +641,22 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// just a specific scheme, the parser should generate a nsCSPSchemeSource.
NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string");
+ // Before we can check if the host matches, we have to
+ // extract the host part from aUri.
+ nsAutoCString uriHost;
+ nsresult rv = aUri->GetAsciiHost(uriHost);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsString decodedUriHost;
+ CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
+
// 2) host matching: Enforce a single *
if (mHost.EqualsASCII("*")) {
// The single ASTERISK character (*) does not match a URI's scheme of a type
// designating a globally unique identifier (such as blob:, data:, or filesystem:)
- // At the moment firefox does not support filesystem; but for future compatibility
+ // At the moment UXP does not support "filesystem:" but for future compatibility
// we support it in CSP according to the spec, see: 4.2.2 Matching Source Expressions
- // Note, that whitelisting any of these schemes would call nsCSPSchemeSrc::permits().
+ // Note: whitelisting any of these schemes would call nsCSPSchemeSrc::permits().
bool isBlobScheme =
(NS_SUCCEEDED(aUri->SchemeIs("blob", &isBlobScheme)) && isBlobScheme);
bool isDataScheme =
@@ -658,20 +667,15 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
if (isBlobScheme || isDataScheme || isFileScheme) {
return false;
}
- return true;
- }
-
- // Before we can check if the host matches, we have to
- // extract the host part from aUri.
- nsAutoCString uriHost;
- nsresult rv = aUri->GetAsciiHost(uriHost);
- NS_ENSURE_SUCCESS(rv, false);
-
- nsString decodedUriHost;
- CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
+ // If no scheme is present there also won't be a port and folder to check
+ // which means we can return early.
+ if (mScheme.IsEmpty()) {
+ return true;
+ }
+ }
// 4.5) host matching: Check if the allowed host starts with a wilcard.
- if (mHost.First() == '*') {
+ else if (mHost.First() == '*') {
NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
// Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index 08fd9afd9..5c6701992 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -10,6 +10,7 @@
#include "nsIStreamListener.h"
#include "nsCDefaultURIFixup.h"
#include "nsIURIFixup.h"
+#include "nsIImageLoadingContent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabChild.h"
@@ -123,7 +124,7 @@ nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel)
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
- NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_SUCCESS(rv, rv);
if (!uri) {
return NS_OK;
}
@@ -801,6 +802,8 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel)
// within nsCorsListenerProxy
rv = DoCheckLoadURIChecks(uri, loadInfo);
NS_ENSURE_SUCCESS(rv, rv);
+ // TODO: Bug 1371237
+ // consider calling SetBlockedRequest in nsContentSecurityManager::CheckChannel
}
return NS_OK;
diff --git a/dom/smil/nsSMILCSSProperty.cpp b/dom/smil/nsSMILCSSProperty.cpp
index 53f3e0fbf..e74512443 100644
--- a/dom/smil/nsSMILCSSProperty.cpp
+++ b/dom/smil/nsSMILCSSProperty.cpp
@@ -38,14 +38,8 @@ GetCSSComputedValue(Element* aElem,
return false;
}
- nsIPresShell* shell = doc->GetShell();
- if (!shell) {
- NS_WARNING("Unable to look up computed style -- no pres shell");
- return false;
- }
-
RefPtr<nsComputedDOMStyle> computedStyle =
- NS_NewComputedDOMStyle(aElem, EmptyString(), shell);
+ NS_NewComputedDOMStyle(aElem, EmptyString(), doc);
computedStyle->GetPropertyValue(aPropID, aResult);
return true;
diff --git a/dom/storage/DOMStorageCache.cpp b/dom/storage/DOMStorageCache.cpp
index a2b5a6f73..ee9a22e96 100644
--- a/dom/storage/DOMStorageCache.cpp
+++ b/dom/storage/DOMStorageCache.cpp
@@ -205,11 +205,6 @@ DOMStorageCache::ProcessUsageDelta(const DOMStorage* aStorage, int64_t aDelta)
bool
DOMStorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta)
{
- // Check if we are in a low disk space situation
- if (aDelta > 0 && mManager && mManager->IsLowDiskSpace()) {
- return false;
- }
-
// Check limit per this origin
Data& data = mData[aGetDataSetIndex];
uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta;
diff --git a/dom/storage/DOMStorageIPC.cpp b/dom/storage/DOMStorageIPC.cpp
index a8cd745f1..9d87a5788 100644
--- a/dom/storage/DOMStorageIPC.cpp
+++ b/dom/storage/DOMStorageIPC.cpp
@@ -11,7 +11,6 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Unused.h"
-#include "nsIDiskSpaceWatcher.h"
#include "nsThreadUtils.h"
namespace mozilla {
@@ -321,22 +320,6 @@ private:
mozilla::Unused << mParent->SendOriginsHavingData(scopes);
}
- // We need to check if the device is in a low disk space situation, so
- // we can forbid in that case any write in localStorage.
- nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher =
- do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
- if (!diskSpaceWatcher) {
- return NS_OK;
- }
-
- bool lowDiskSpace = false;
- diskSpaceWatcher->GetIsDiskFull(&lowDiskSpace);
-
- if (lowDiskSpace) {
- mozilla::Unused << mParent->SendObserve(
- nsDependentCString("low-disk-space"), EmptyString(), EmptyCString());
- }
-
return NS_OK;
}
diff --git a/dom/storage/DOMStorageManager.cpp b/dom/storage/DOMStorageManager.cpp
index 156e846ba..8f50fcfb4 100644
--- a/dom/storage/DOMStorageManager.cpp
+++ b/dom/storage/DOMStorageManager.cpp
@@ -103,7 +103,6 @@ NS_IMPL_ISUPPORTS(DOMStorageManager,
DOMStorageManager::DOMStorageManager(DOMStorage::StorageType aType)
: mCaches(8)
, mType(aType)
- , mLowDiskSpace(false)
{
DOMStorageObserver* observer = DOMStorageObserver::Self();
NS_ASSERTION(observer, "No DOMStorageObserver, cannot observe private data delete notifications!");
@@ -566,22 +565,6 @@ DOMStorageManager::Observe(const char* aTopic,
return NS_OK;
}
- if (!strcmp(aTopic, "low-disk-space")) {
- if (mType == LocalStorage) {
- mLowDiskSpace = true;
- }
-
- return NS_OK;
- }
-
- if (!strcmp(aTopic, "no-low-disk-space")) {
- if (mType == LocalStorage) {
- mLowDiskSpace = false;
- }
-
- return NS_OK;
- }
-
#ifdef DOM_STORAGE_TESTS
if (!strcmp(aTopic, "test-reload")) {
if (mType != LocalStorage) {
diff --git a/dom/storage/DOMStorageManager.h b/dom/storage/DOMStorageManager.h
index 666e16a6f..0bfd21975 100644
--- a/dom/storage/DOMStorageManager.h
+++ b/dom/storage/DOMStorageManager.h
@@ -102,12 +102,6 @@ private:
const DOMStorage::StorageType mType;
- // If mLowDiskSpace is true it indicates a low device storage situation and
- // so no localStorage writes are allowed. sessionStorage writes are still
- // allowed.
- bool mLowDiskSpace;
- bool IsLowDiskSpace() const { return mLowDiskSpace; };
-
void ClearCaches(uint32_t aUnloadFlags,
const OriginAttributesPattern& aPattern,
const nsACString& aKeyPrefix);
diff --git a/dom/storage/DOMStorageObserver.cpp b/dom/storage/DOMStorageObserver.cpp
index a2b3f1da8..fbbab8e54 100644
--- a/dom/storage/DOMStorageObserver.cpp
+++ b/dom/storage/DOMStorageObserver.cpp
@@ -70,9 +70,6 @@ DOMStorageObserver::Init()
obs->AddObserver(sSelf, "profile-before-change", true);
obs->AddObserver(sSelf, "xpcom-shutdown", true);
- // Observe low device storage notifications.
- obs->AddObserver(sSelf, "disk-space-watcher", true);
-
#ifdef DOM_STORAGE_TESTS
// Testing
obs->AddObserver(sSelf, "domstorage-test-flush-force", true);
@@ -313,16 +310,6 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
return NS_OK;
}
- if (!strcmp(aTopic, "disk-space-watcher")) {
- if (NS_LITERAL_STRING("full").Equals(aData)) {
- Notify("low-disk-space");
- } else if (NS_LITERAL_STRING("free").Equals(aData)) {
- Notify("no-low-disk-space");
- }
-
- return NS_OK;
- }
-
#ifdef DOM_STORAGE_TESTS
if (!strcmp(aTopic, "domstorage-test-flush-force")) {
DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
diff --git a/dom/svg/crashtests/880544-1.svg b/dom/svg/crashtests/880544-1.svg
deleted file mode 100644
index 9052d2396..000000000
--- a/dom/svg/crashtests/880544-1.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("p").transform.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <path id="p" transform="scale(1)" />
-
-</svg>
diff --git a/dom/svg/crashtests/880544-2.svg b/dom/svg/crashtests/880544-2.svg
deleted file mode 100644
index 7570c7cbf..000000000
--- a/dom/svg/crashtests/880544-2.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").x.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <text id="e" x="10">foo</text>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-3.svg b/dom/svg/crashtests/880544-3.svg
deleted file mode 100644
index 5791b8ec6..000000000
--- a/dom/svg/crashtests/880544-3.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").rotate.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <text id="e" rotate="10">foo</text>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-4.svg b/dom/svg/crashtests/880544-4.svg
deleted file mode 100644
index 7bdb80f47..000000000
--- a/dom/svg/crashtests/880544-4.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").pathSegList.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <path id="e" d="M0,0"/>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-5.svg b/dom/svg/crashtests/880544-5.svg
deleted file mode 100644
index ef7f468f8..000000000
--- a/dom/svg/crashtests/880544-5.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").points.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <polygon id="e" points="0,0"/>
-
-</svg>
diff --git a/dom/svg/crashtests/crashtests.list b/dom/svg/crashtests/crashtests.list
index 147838bbe..b2e920152 100644
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -66,11 +66,6 @@ load 837450-1.svg
load 842463-1.html
load 847138-1.svg
load 864509.svg
-load 880544-1.svg
-load 880544-2.svg
-load 880544-3.svg
-load 880544-4.svg
-load 880544-5.svg
load 898915-1.svg
load 1035248-1.svg
load 1035248-2.svg
diff --git a/dom/tests/mochitest/ajax/offline/mochitest.ini b/dom/tests/mochitest/ajax/offline/mochitest.ini
index 961b143b6..45909e94e 100644
--- a/dom/tests/mochitest/ajax/offline/mochitest.ini
+++ b/dom/tests/mochitest/ajax/offline/mochitest.ini
@@ -79,8 +79,6 @@ support-files =
[test_fallback.html]
[test_foreign.html]
[test_identicalManifest.html]
-[test_lowDeviceStorage.html]
-[test_lowDeviceStorageDuringUpdate.html]
[test_missingFile.html]
[test_missingManifest.html]
[test_noManifest.html]
diff --git a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html b/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html
deleted file mode 100644
index d03ef5a12..000000000
--- a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title>Low device storage</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/**
- * This test checks that an offline cache update scheduled *after* a low device
- * storage situation appears is canceled. It basically does:
- *
- * 1. Notifies to the offline cache update service about a fake
- * low device storage situation.
- * 2. Schedules an update and observes for its notifications.
- * 3. We are supposed to receive an error event notifying about the cancelation
- * of the update because of the low storage situation.
- * 4. Notifies to the offline cache update service that we've recovered from
- * the low storage situation.
- */
-
-var updateService = SpecialPowers.Cc['@mozilla.org/offlinecacheupdate-service;1']
- .getService(Ci.nsIOfflineCacheUpdateService);
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-var errorReceived = false;
-
-var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
-
-function finish() {
- obs.notifyObservers(updateService, "disk-space-watcher", "free");
-
- OfflineTest.teardownAndFinish();
-}
-
-if (OfflineTest.setup()) {
- obs.notifyObservers(updateService, "disk-space-watcher", "full");
-
- var updateObserver = {
- updateStateChanged: function (aUpdate, aState) {
- switch(aState) {
- case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
- errorReceived = true;
- OfflineTest.ok(true, "Expected error. Update canceled");
- break;
- case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
- aUpdate.removeObserver(this);
- OfflineTest.ok(errorReceived,
- "Finished after receiving the expected error");
- finish();
- break;
- case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
- aUpdate.removeObserver(this);
- OfflineTest.ok(false, "No update");
- finish();
- break;
- case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
- case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
- case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
- aUpdate.removeObserver(this);
- OfflineTest.ok(false, "The update was supposed to be canceled");
- finish();
- break;
- }
- },
- applicationCacheAvailable: function() {}
- };
-
- var manifest = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest";
- var ioService = Cc["@mozilla.org/network/io-service;1"]
- .getService(Ci.nsIIOService);
- var manifestURI = ioService.newURI(manifest, null, null);
- var documentURI = ioService.newURI(document.documentURI, null, null);
- var update = updateService.scheduleUpdate(manifestURI, documentURI, systemPrincipal, window);
- update.addObserver(updateObserver, false);
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body>
-
-</body>
-</html>
diff --git a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html b/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html
deleted file mode 100644
index 88a0b4eae..000000000
--- a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest">
-<head>
-<title>Low device storage during update</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/**
- * This test checks that an offline cache update is canceled when a low device
- * storage condition is detected during the update.
- */
-
-var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
- .getService(Ci.nsIOfflineCacheUpdateService);
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function finish() {
- obs.notifyObservers(updateService, "disk-space-watcher", "free");
-
- OfflineTest.teardownAndFinish();
-}
-
-function onError() {
- OfflineTest.ok(true, "Expected error: Update canceled");
- finish();
-}
-
-function onUnexpectedEvent() {
- OfflineTest.ok(false, "The update was supposed to be canceled");
- finish();
-}
-
-function onChecking() {
- obs.notifyObservers(updateService, "disk-space-watcher", "full");
-}
-
-if (OfflineTest.setup()) {
- applicationCache.onerror = OfflineTest.priv(onError);
- applicationCache.onprogress = OfflineTest.priv(onUnexpectedEvent);
- applicationCache.oncached = OfflineTest.priv(onUnexpectedEvent);
- applicationCache.onchecking = OfflineTest.priv(onChecking);
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body>
-
-</body>
-</html>
diff --git a/dom/tests/mochitest/bugs/iframe_bug38959-1.html b/dom/tests/mochitest/bugs/iframe_bug38959-1.html
deleted file mode 100644
index d4c16c47a..000000000
--- a/dom/tests/mochitest/bugs/iframe_bug38959-1.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-<head>
- <title>Iframe test for bug 38959</title>
-</head>
-<body">
-<script>
-
-x = false;
-window.opener.postMessage(1, "http://mochi.test:8888");
-window.close();
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/bugs/iframe_bug38959-2.html b/dom/tests/mochitest/bugs/iframe_bug38959-2.html
deleted file mode 100644
index 36cd0c156..000000000
--- a/dom/tests/mochitest/bugs/iframe_bug38959-2.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-<head>
- <title>Iframe test for bug 38959</title>
-</head>
-<body">
-<script>
-
-x = true;
-window.opener.postMessage(2, "http://mochi.test:8888");
-window.close();
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini
index e0c71f857..309aab6e0 100644
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -23,8 +23,6 @@ support-files =
grandchild_bug260264.html
iframe_bug304459-1.html
iframe_bug304459-2.html
- iframe_bug38959-1.html
- iframe_bug38959-2.html
iframe_bug430276-2.html
iframe_bug430276.html
iframe_bug440572.html
@@ -64,7 +62,6 @@ skip-if = toolkit == 'android' #TIMED_OUT
[test_bug377539.html]
[test_bug384122.html]
[test_bug389366.html]
-[test_bug38959.html]
[test_bug393974.html]
[test_bug394769.html]
[test_bug396843.html]
diff --git a/dom/tests/mochitest/bugs/test_bug38959.html b/dom/tests/mochitest/bugs/test_bug38959.html
deleted file mode 100644
index a8d07d1a6..000000000
--- a/dom/tests/mochitest/bugs/test_bug38959.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=38959
--->
-<head>
- <title>Test for Bug 38959</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=38959">Mozilla Bug 38959</a>
-<p id="display"></p>
-<div id="content" style="display: none">
- <iframe id="frame"></iframe>
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 38959 **/
-
-var newValue;
-
-function watcher(id, ol, ne)
-{
- newValue = ne;
- return ne;
-}
-
-function openWindow(url, crossOrigin)
-{
- newValue = true;
- var w = window.open(url);
- w.watch("x", watcher);
-}
-
-function receiveMessage(evt)
-{
- ok(newValue, "Watchpoints only allowed same-origin.");
- if (evt.data == 1) {
- openWindow("/tests/dom/tests/mochitest/bugs/iframe_bug38959-2.html");
- }
- else {
- SimpleTest.finish();
- }
-}
-
-SimpleTest.waitForExplicitFinish();
-
-window.addEventListener("message", receiveMessage, false);
-
-openWindow("http://example.org/tests/dom/tests/mochitest/bugs/iframe_bug38959-1.html");
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/tests/mochitest/chrome/queryCaretRectWin.html b/dom/tests/mochitest/chrome/queryCaretRectWin.html
index cd5a8ec64..cb2fe78a1 100644
--- a/dom/tests/mochitest/chrome/queryCaretRectWin.html
+++ b/dom/tests/mochitest/chrome/queryCaretRectWin.html
@@ -20,7 +20,7 @@
left: 0em;
top: 0em;
font-size: 10pt;
- font-family: monospace;
+ font-family: 'Courier New';
line-height: 20px;
letter-spacing: 0px;
margin-top:-1px; /* nix the text area border */
diff --git a/dom/tests/mochitest/chrome/selectAtPoint.html b/dom/tests/mochitest/chrome/selectAtPoint.html
index 8c625e6f7..6326b500f 100644
--- a/dom/tests/mochitest/chrome/selectAtPoint.html
+++ b/dom/tests/mochitest/chrome/selectAtPoint.html
@@ -127,13 +127,7 @@
targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
yPos: rect.top + (charDims.height / 2) };
setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
- if (isLinux || isMac) {
- // XXX I think this is a bug, the right hand selection is 4.5 characters over with a
- // monspaced font. what we want: t(te)s(ts)election1 what we get: t(te)st(se)lection1
- checkSelection(document, "split selection", "tese");
- } else if (isWindows) {
- checkSelection(document, "split selection", "tets");
- }
+ checkSelection(document, "split selection", "tets");
// Trying to select where there's no text, should fail but not throw
let result = dwu.selectAtPoint(rect.left - 20, rect.top - 20, Ci.nsIDOMWindowUtils.SELECT_CHARACTER, false);
@@ -228,7 +222,7 @@
<style type="text/css">
body {
- font-family: monospace;
+ font-family: 'Courier New';
margin-left: 40px;
margin-top: 40px;
padding: 0;
@@ -267,7 +261,7 @@ body {
<br />
-<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
+<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: \'Courier New\';' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
<br/>
diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini
index 5242bf9b1..30b90664a 100644
--- a/dom/tests/mochitest/localstorage/mochitest.ini
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -47,6 +47,5 @@ skip-if = toolkit == 'android' #TIMED_OUT
skip-if = toolkit == 'android' #TIMED_OUT
[test_localStorageReplace.html]
skip-if = toolkit == 'android'
-[test_lowDeviceStorage.html]
[test_storageConstructor.html]
[test_localStorageSessionPrefOverride.html]
diff --git a/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html b/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html
deleted file mode 100644
index 046587150..000000000
--- a/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title>Test localStorage usage while in a low device storage situation</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="text/javascript" src="localStorageCommon.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/*
-This test does the following:
-- Stores an item in localStorage.
-- Checks the stored value.
-- Emulates a low device storage situation.
-- Gets the stored item again.
-- Removes the stored item.
-- Fails storing a new value.
-- Emulates recovering from a low device storage situation.
-- Stores a new value.
-- Checks the stored value.
-*/
-
-function lowDeviceStorage(lowStorage) {
- var data = lowStorage ? "full" : "free";
- os().notifyObservers(null, "disk-space-watcher", data);
-}
-
-function startTest() {
- // Add a test item.
- localStorage.setItem("item", "value");
- is(localStorage.getItem("item"), "value", "getItem()");
-
- // Emulates a low device storage situation.
- lowDeviceStorage(true);
-
- // Checks that we can still access to the stored item.
- is(localStorage.getItem("item"), "value",
- "getItem() during a device storage situation");
-
- // Removes the stored item.
- localStorage.removeItem("item");
- is(localStorage.getItem("item"), null,
- "getItem() after removing the item");
-
- // Fails storing a new item.
- try {
- localStorage.setItem("newItem", "value");
- ok(false, "Storing a new item is expected to fail");
- } catch(e) {
- ok(true, "Got an expected exception " + e);
- } finally {
- is(localStorage.getItem("newItem"), null,
- "setItem while device storage is low");
- }
-
- // Emulates recovering from a low device storage situation.
- lowDeviceStorage(false);
-
- // Add a test item after recovering from the low device storage situation.
- localStorage.setItem("newItem", "value");
- is(localStorage.getItem("newItem"), "value",
- "getItem() with available storage");
-
- SimpleTest.finish();
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body onload="startTest();">
-</body>
-</html>
diff --git a/dom/webidl/CSSStyleSheet.webidl b/dom/webidl/CSSStyleSheet.webidl
index 48fb89db1..15c110b8b 100644
--- a/dom/webidl/CSSStyleSheet.webidl
+++ b/dom/webidl/CSSStyleSheet.webidl
@@ -23,7 +23,7 @@ interface CSSStyleSheet : StyleSheet {
[ChromeOnly, BinaryName="parsingModeDOM"]
readonly attribute CSSStyleSheetParsingMode parsingMode;
[Throws, NeedsSubjectPrincipal]
- unsigned long insertRule(DOMString rule, unsigned long index);
+ unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
[Throws, NeedsSubjectPrincipal]
void deleteRule(unsigned long index);
};
diff --git a/dom/webidl/HTMLScriptElement.webidl b/dom/webidl/HTMLScriptElement.webidl
index 377056366..5b64c42d7 100644
--- a/dom/webidl/HTMLScriptElement.webidl
+++ b/dom/webidl/HTMLScriptElement.webidl
@@ -13,6 +13,8 @@ interface HTMLScriptElement : HTMLElement {
attribute DOMString src;
[SetterThrows]
attribute DOMString type;
+ [SetterThrows, Pref="dom.moduleScripts.enabled"]
+ attribute boolean noModule;
[SetterThrows]
attribute DOMString charset;
[SetterThrows]
diff --git a/dom/webidl/Promise.webidl b/dom/webidl/Promise.webidl
index 4dcb7d43e..a296553df 100644
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -3,75 +3,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
- * The origin of this IDL file is
- * http://dom.spec.whatwg.org/#promises
+ * This IDL file contains utilities to help connect JS promises to our
+ * Web IDL infrastructure.
*/
-// TODO We use object instead Function. There is an open issue on WebIDL to
-// have different types for "platform-provided function" and "user-provided
-// function"; for now, we just use "object".
-callback PromiseInit = void (object resolve, object reject);
-
callback PromiseJobCallback = void();
[TreatNonCallableAsNull]
callback AnyCallback = any (any value);
-// When using SpiderMonkey promises, we don't want to define all this stuff;
-// just define a tiny interface to make codegen of Promise arguments and return
-// values work.
-#ifndef SPIDERMONKEY_PROMISE
-[Constructor(PromiseInit init),
- Exposed=(Window,Worker,WorkerDebugger,System)]
-// Need to escape "Promise" so it's treated as an identifier.
-interface _Promise {
- // Have to use "any" (or "object", but "any" is simpler) as the type to
- // support the subclassing behavior, since nothing actually requires the
- // return value of PromiseSubclass.resolve/reject to be a Promise object.
- [NewObject, Throws]
- static any resolve(optional any value);
- [NewObject, Throws]
- static any reject(optional any value);
-
- // The [TreatNonCallableAsNull] annotation is required since then() should do
- // nothing instead of throwing errors when non-callable arguments are passed.
- // Have to use "any" (or "object", but "any" is simpler) as the type to
- // support the subclassing behavior, since nothing actually requires the
- // return value of PromiseSubclass.then/catch to be a Promise object.
- [NewObject, Throws]
- any then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
- [TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
-
- [NewObject, Throws]
- any catch([TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
-
- // Have to use "any" (or "object", but "any" is simpler) as the type to
- // support the subclassing behavior, since nothing actually requires the
- // return value of PromiseSubclass.all to be a Promise object. As a result,
- // we also have to do our argument conversion manually, because we want to
- // convert its exceptions into rejections.
- [NewObject, Throws]
- static any all(optional any iterable);
-
- // Have to use "any" (or "object", but "any" is simpler) as the type to
- // support the subclassing behavior, since nothing actually requires the
- // return value of PromiseSubclass.race to be a Promise object. As a result,
- // we also have to do our argument conversion manually, because we want to
- // convert its exceptions into rejections.
- [NewObject, Throws]
- static any race(optional any iterable);
-};
-#else // SPIDERMONKEY_PROMISE
-[NoInterfaceObject,
- Exposed=(Window,Worker,WorkerDebugger,System)]
-// Need to escape "Promise" so it's treated as an identifier.
-interface _Promise {
-};
-
// Hack to allow us to have JS owning and properly tracing/CCing/etc a
// PromiseNativeHandler.
[NoInterfaceObject,
Exposed=(Window,Worker,System)]
interface PromiseNativeHandler {
};
-#endif // SPIDERMONKEY_PROMISE
diff --git a/dom/webidl/PromiseDebugging.webidl b/dom/webidl/PromiseDebugging.webidl
index 107b8bc65..1a5c1aa32 100644
--- a/dom/webidl/PromiseDebugging.webidl
+++ b/dom/webidl/PromiseDebugging.webidl
@@ -38,11 +38,7 @@ callback interface UncaughtRejectionObserver {
* caught, i.e. if its `then` callback is called, `onConsumed` will
* be called.
*/
-#ifdef SPIDERMONKEY_PROMISE
void onLeftUncaught(object p);
-#else
- void onLeftUncaught(Promise<any> p);
-#endif SPIDERMONKEY_PROMISE
/**
* A Promise previously left uncaught is not the last in its
@@ -51,11 +47,7 @@ callback interface UncaughtRejectionObserver {
* @param p A Promise that was previously left in uncaught state is
* now caught, i.e. it is not the last in its chain anymore.
*/
-#ifdef SPIDERMONKEY_PROMISE
void onConsumed(object p);
-#else
- void onConsumed(Promise<any> p);
-#endif SPIDERMONKEY_PROMISE
};
[ChromeOnly, Exposed=(Window,System)]
@@ -105,42 +97,6 @@ interface PromiseDebugging {
[Throws]
static object? getFullfillmentStack(object p);
-#ifndef SPIDERMONKEY_PROMISE
- /**
- * Get the promises directly depending on a given promise. These are:
- *
- * 1) Return values of then() calls on the promise
- * 2) Return values of Promise.all() if the given promise was passed in as one
- * of the arguments.
- * 3) Return values of Promise.race() if the given promise was passed in as
- * one of the arguments.
- *
- * Once a promise is settled, it will generally notify its dependent promises
- * and forget about them, so this is most useful on unsettled promises.
- *
- * Note that this function only returns the promises that directly depend on
- * p. It does not recursively return promises that depend on promises that
- * depend on p.
- */
- [Throws]
- static sequence<Promise<any>> getDependentPromises(object p);
-
- /**
- * Get the number of milliseconds elapsed since the given promise was created.
- */
- [Throws]
- static DOMHighResTimeStamp getPromiseLifetime(object p);
-
- /*
- * Get the number of milliseconds elapsed between the promise being created
- * and being settled. Throws NS_ERROR_UNEXPECTED if the promise has not
- * settled.
- */
- [Throws]
- static DOMHighResTimeStamp getTimeToSettle(object p);
-
-#endif // SPIDERMONKEY_PROMISE
-
/**
* Watching uncaught rejections on the current thread.
*
diff --git a/dom/webidl/TestInterfaceJS.webidl b/dom/webidl/TestInterfaceJS.webidl
index 2cf8d701a..2757745f0 100644
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -70,7 +70,7 @@ interface TestInterfaceJS : EventTarget {
// Tests for promise-rejection behavior
Promise<void> testPromiseWithThrowingChromePromiseInit();
- Promise<void> testPromiseWithThrowingContentPromiseInit(PromiseInit func);
+ Promise<void> testPromiseWithThrowingContentPromiseInit(Function func);
Promise<void> testPromiseWithDOMExceptionThrowingPromiseInit();
Promise<void> testPromiseWithThrowingChromeThenFunction();
Promise<void> testPromiseWithThrowingContentThenFunction(AnyCallback func);
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 0fe10eff9..172895f97 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -12,8 +12,6 @@ PREPROCESSED_WEBIDL_FILES = [
'HTMLMediaElement.webidl',
'Navigator.webidl',
'Node.webidl',
- 'Promise.webidl',
- 'PromiseDebugging.webidl',
'Window.webidl',
]
@@ -371,6 +369,8 @@ WEBIDL_FILES = [
'PresentationRequest.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
+ 'Promise.webidl',
+ 'PromiseDebugging.webidl',
'PushEvent.webidl',
'PushManager.webidl',
'PushManager.webidl',
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 27eb570e9..c6ef21f2c 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2543,6 +2543,12 @@ WorkerPrivateParent<Derived>::DisableDebugger()
WorkerPrivate* self = ParentAsWorkerPrivate();
+ // RegisterDebugger might have been dispatched but not completed.
+ // Wait for its execution to complete before unregistering.
+ if (!NS_IsMainThread()) {
+ self->WaitForIsDebuggerRegistered(true);
+ }
+
if (NS_FAILED(UnregisterWorkerDebugger(self))) {
NS_WARNING("Failed to unregister worker debugger!");
}