summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/base/nsContentPolicy.cpp21
-rw-r--r--dom/base/nsContentUtils.cpp9
-rw-r--r--dom/base/nsDocument.cpp25
-rw-r--r--dom/base/nsDocument.h6
-rw-r--r--dom/base/nsGlobalWindow.cpp7
-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.cpp6
-rw-r--r--dom/base/nsWindowMemoryReporter.cpp9
-rw-r--r--dom/base/nsWindowMemoryReporter.h1
-rw-r--r--dom/bindings/BindingUtils.cpp8
-rw-r--r--dom/bindings/BindingUtils.h3
-rw-r--r--dom/bindings/Codegen.py15
-rw-r--r--dom/bindings/moz.build8
-rw-r--r--dom/bindings/nsIScriptError.idl135
-rw-r--r--dom/bindings/nsScriptError.cpp438
-rw-r--r--dom/bindings/nsScriptError.h109
-rw-r--r--dom/bindings/nsScriptErrorWithStack.cpp120
-rw-r--r--dom/canvas/WebGLBuffer.cpp1
-rw-r--r--dom/canvas/WebGLContext.h3
-rw-r--r--dom/canvas/WebGLExtensionDebugShaders.cpp7
-rw-r--r--dom/canvas/WebGLExtensionDisjointTimerQuery.cpp42
-rw-r--r--dom/canvas/WebGLExtensionDrawBuffers.cpp4
-rw-r--r--dom/canvas/WebGLExtensionInstancedArrays.cpp18
-rw-r--r--dom/canvas/WebGLExtensionLoseContext.cpp2
-rw-r--r--dom/canvas/WebGLExtensionVertexArray.cpp8
-rw-r--r--dom/canvas/WebGLObjectModel.h4
-rw-r--r--dom/canvas/WebGLRenderbuffer.cpp10
-rw-r--r--dom/canvas/WebGLShader.cpp10
-rw-r--r--dom/canvas/WebGLTexture.cpp8
-rw-r--r--dom/canvas/WebGLTexture.h1
-rw-r--r--dom/canvas/WebGLTextureUpload.cpp8
-rw-r--r--dom/indexedDB/ActorsChild.cpp7
-rw-r--r--dom/ipc/ContentParent.cpp17
-rw-r--r--dom/media/MediaResource.cpp2
-rw-r--r--dom/media/fmp4/MP4Decoder.cpp3
-rw-r--r--dom/media/mediasource/ContainerParser.cpp3
-rw-r--r--dom/media/mediasource/MediaSource.cpp6
-rw-r--r--dom/media/mediasource/TrackBuffersManager.cpp2
-rw-r--r--dom/media/webm/WebMDecoder.cpp16
-rw-r--r--dom/media/webm/WebMDemuxer.cpp26
-rw-r--r--dom/network/UDPSocketChild.cpp23
-rw-r--r--dom/plugins/base/nsPluginStreamListenerPeer.cpp4
-rw-r--r--dom/security/nsContentSecurityManager.cpp30
-rw-r--r--dom/workers/RuntimeService.cpp2
-rw-r--r--dom/workers/WorkerPrivate.cpp226
-rw-r--r--dom/workers/WorkerPrivate.h46
-rw-r--r--dom/workers/moz.build1
-rw-r--r--dom/workers/test/test_sharedWorker.html2
51 files changed, 1295 insertions, 304 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/nsDocument.cpp b/dom/base/nsDocument.cpp
index a6ed419df..6b8e11db0 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -9222,19 +9222,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 +9256,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 +9266,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 +9290,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 +9307,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
@@ -11943,7 +11949,8 @@ nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
&aWindowSizes->mLayoutPresShellSize,
&aWindowSizes->mLayoutStyleSetsSize,
&aWindowSizes->mLayoutTextRunsSize,
- &aWindowSizes->mLayoutPresContextSize);
+ &aWindowSizes->mLayoutPresContextSize,
+ &aWindowSizes->mLayoutFramePropertiesSize);
}
aWindowSizes->mPropertyTablesSize +=
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 95fd57545..2b29b98fa 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -948,11 +948,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/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index f9126f4da..afaa24f09 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2504,8 +2504,7 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument* aNewDocument)
}
bool equal;
- if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
- &equal)) &&
+ if (NS_SUCCEEDED(mDoc->NodePrincipal()->EqualsConsideringDomain(aNewDocument->NodePrincipal(), &equal)) &&
equal) {
// The origin is the same.
return true;
@@ -9335,7 +9334,7 @@ nsGlobalWindow::EnterModalState()
topWin->mSuspendedDoc = topDoc;
if (topDoc) {
- topDoc->SuppressEventHandling(nsIDocument::eEvents);
+ topDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
}
nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
@@ -9372,7 +9371,7 @@ nsGlobalWindow::LeaveModalState()
if (topWin->mSuspendedDoc) {
nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
- topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
+ topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
currentDoc == topWin->mSuspendedDoc);
topWin->mSuspendedDoc = nullptr;
}
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 c1b732258..3c850c4cd 100644
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -715,11 +715,13 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
/// would keep the docshell around, but trash the frameloader
UnloadObject();
}
- nsIDocument* doc = thisContent->GetComposedDoc();
- if (doc && doc->IsActive()) {
+ 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);
+ }
}
}
diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp
index acec4acfb..8f4bf6b11 100644
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -400,6 +400,12 @@ CollectWindowReports(nsGlobalWindow *aWindow,
aWindowTotalSizes->mLayoutPresContextSize +=
windowSizes.mLayoutPresContextSize;
+ REPORT_SIZE("/layout/frame-properties", windowSizes.mLayoutFramePropertiesSize,
+ "Memory used for frame properties attached to frames "
+ "within a window.");
+ aWindowTotalSizes->mLayoutFramePropertiesSize +=
+ windowSizes.mLayoutFramePropertiesSize;
+
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
@@ -563,6 +569,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize,
"This is the sum of all windows' 'layout/pres-contexts' numbers.");
+ REPORT("window-objects/layout/frame-properties", windowTotalSizes.mLayoutFramePropertiesSize,
+ "This is the sum of all windows' 'layout/frame-properties' numbers.");
+
size_t frameTotal = 0;
#define FRAME_ID(classname) \
frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname);
diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h
index b9e986959..5d40dc9f5 100644
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -33,6 +33,7 @@ class nsWindowSizes {
macro(Style, mLayoutStyleSetsSize) \
macro(Other, mLayoutTextRunsSize) \
macro(Other, mLayoutPresContextSize) \
+ macro(Other, mLayoutFramePropertiesSize) \
macro(Other, mPropertyTablesSize) \
public:
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 8d2bdaac6..a26fc4422 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1184,14 +1184,6 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
}
bool
-UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp)
-{
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- args.rval().set(args.thisv());
- return true;
-}
-
-bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
{
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index a3ec70f47..5cab835b3 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2045,9 +2045,6 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
}
bool
-UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
bool
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 74acb5918..d7d700a96 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2390,11 +2390,10 @@ class MethodDefiner(PropertyDefiner):
# Synthesize our valueOf method
self.regular.append({
"name": 'valueOf',
- "nativeName": "UnforgeableValueOf",
+ "selfHostedName": "Object_valueOf",
"methodInfo": False,
"length": 0,
- "flags": "JSPROP_ENUMERATE", # readonly/permanent added
- # automatically.
+ "flags": "0", # readonly/permanent added automatically.
"condition": MemberCondition()
})
@@ -3456,19 +3455,15 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
"nsContentUtils::ThreadsafeIsCallerChrome()"))
if descriptor.interface.getExtendedAttribute("Unforgeable"):
- # We do our undefined toJSON and toPrimitive here, not as a regular
- # property because we don't have a concept of value props anywhere in
- # IDL.
+ # We do our undefined toPrimitive here, not as a regular property
+ # because we don't have a concept of value props anywhere in IDL.
unforgeables.append(CGGeneric(fill(
"""
JS::RootedId toPrimitive(aCx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
JS::UndefinedHandleValue,
- JSPROP_READONLY | JSPROP_PERMANENT) ||
- !JS_DefineProperty(aCx, ${holderName}, "toJSON",
- JS::UndefinedHandleValue,
- JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
$*{failureCode}
}
""",
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index 043b3c494..ed8a4d37e 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -6,6 +6,12 @@
TEST_DIRS += ['test']
+XPIDL_SOURCES += [
+ 'nsIScriptError.idl'
+]
+
+XPIDL_MODULE = 'dom_bindings'
+
EXPORTS.ipc += [
'ErrorIPCUtils.h',
]
@@ -91,6 +97,8 @@ UNIFIED_SOURCES += [
'DOMJSProxyHandler.cpp',
'Exceptions.cpp',
'IterableIterator.cpp',
+ 'nsScriptError.cpp',
+ 'nsScriptErrorWithStack.cpp',
'SimpleGlobalObject.cpp',
'ToJSValue.cpp',
'WebIDLGlobalNameHash.cpp',
diff --git a/dom/bindings/nsIScriptError.idl b/dom/bindings/nsIScriptError.idl
new file mode 100644
index 000000000..8436361a8
--- /dev/null
+++ b/dom/bindings/nsIScriptError.idl
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsIConsoleMessage subclass for representing JavaScript errors and warnings.
+ */
+
+
+#include "nsISupports.idl"
+#include "nsIArray.idl"
+#include "nsIConsoleMessage.idl"
+
+%{C++
+#include "nsStringGlue.h" // for nsDependentCString
+%}
+
+[scriptable, uuid(e8933fc9-c302-4e12-a55b-4f88611d9c6c)]
+interface nsIScriptErrorNote : nsISupports
+{
+ readonly attribute AString errorMessage;
+ readonly attribute AString sourceName;
+ readonly attribute uint32_t lineNumber;
+ readonly attribute uint32_t columnNumber;
+
+ AUTF8String toString();
+};
+
+[scriptable, uuid(63eb4d3e-7d99-4150-b4f3-11314f9d82a9)]
+interface nsIScriptError : nsIConsoleMessage
+{
+ /** pseudo-flag for default case */
+ const unsigned long errorFlag = 0x0;
+
+ /** message is warning */
+ const unsigned long warningFlag = 0x1;
+
+ /** exception was thrown for this case - exception-aware hosts can ignore */
+ const unsigned long exceptionFlag = 0x2;
+
+ // XXX check how strict is implemented these days.
+ /** error or warning is due to strict option */
+ const unsigned long strictFlag = 0x4;
+
+ /** just a log message */
+ const unsigned long infoFlag = 0x8;
+
+ /**
+ * The error message without any context/line number information.
+ *
+ * @note nsIConsoleMessage.message will return the error formatted
+ * with file/line information.
+ */
+ readonly attribute AString errorMessage;
+
+ readonly attribute AString sourceName;
+ readonly attribute AString sourceLine;
+ readonly attribute uint32_t lineNumber;
+ readonly attribute uint32_t columnNumber;
+ readonly attribute uint32_t flags;
+
+ /**
+ * Categories I know about -
+ * XUL javascript
+ * content javascript (both of these from nsDocShell, currently)
+ * system javascript (errors in JS components and other system JS)
+ */
+ readonly attribute string category;
+
+ /* Get the window id this was initialized with. Zero will be
+ returned if init() was used instead of initWithWindowID(). */
+ readonly attribute unsigned long long outerWindowID;
+
+ /* Get the inner window id this was initialized with. Zero will be
+ returned if init() was used instead of initWithWindowID(). */
+ readonly attribute unsigned long long innerWindowID;
+
+ readonly attribute boolean isFromPrivateWindow;
+
+ attribute jsval stack;
+
+ /**
+ * The name of a template string, as found in js.msg, associated with the
+ * error message.
+ */
+ attribute AString errorMessageName;
+
+ readonly attribute nsIArray notes;
+
+ void init(in AString message,
+ in AString sourceName,
+ in AString sourceLine,
+ in uint32_t lineNumber,
+ in uint32_t columnNumber,
+ in uint32_t flags,
+ in string category);
+
+ /* This should be called instead of nsIScriptError.init to
+ initialize with a window id. The window id should be for the
+ inner window associated with this error. */
+ void initWithWindowID(in AString message,
+ in AString sourceName,
+ in AString sourceLine,
+ in uint32_t lineNumber,
+ in uint32_t columnNumber,
+ in uint32_t flags,
+ in ACString category,
+ in unsigned long long innerWindowID);
+%{C++
+ // This overload allows passing a literal string for category.
+ template<uint32_t N>
+ nsresult InitWithWindowID(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char (&c)[N],
+ uint64_t aInnerWindowID)
+ {
+ nsDependentCString category(c, N - 1);
+ return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
+ columnNumber, flags, category, aInnerWindowID);
+ }
+%}
+
+};
+
+%{ C++
+#define NS_SCRIPTERROR_CID \
+{ 0x1950539a, 0x90f0, 0x4d22, { 0xb5, 0xaf, 0x71, 0x32, 0x9c, 0x68, 0xfa, 0x35 }}
+
+#define NS_SCRIPTERROR_CONTRACTID "@mozilla.org/scripterror;1"
+%}
diff --git a/dom/bindings/nsScriptError.cpp b/dom/bindings/nsScriptError.cpp
new file mode 100644
index 000000000..9248d1a31
--- /dev/null
+++ b/dom/bindings/nsScriptError.cpp
@@ -0,0 +1,438 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* 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/. */
+
+/*
+ * nsIScriptError implementation.
+ */
+
+#include "nsScriptError.h"
+#include "jsprf.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "nsGlobalWindow.h"
+#include "nsNetUtil.h"
+#include "nsPIDOMWindow.h"
+#include "nsILoadContext.h"
+#include "nsIDocShell.h"
+#include "nsIMutableArray.h"
+#include "nsIScriptError.h"
+#include "nsISensitiveInfoHiddenURI.h"
+
+static_assert(nsIScriptError::errorFlag == JSREPORT_ERROR &&
+ nsIScriptError::warningFlag == JSREPORT_WARNING &&
+ nsIScriptError::exceptionFlag == JSREPORT_EXCEPTION &&
+ nsIScriptError::strictFlag == JSREPORT_STRICT &&
+ nsIScriptError::infoFlag == JSREPORT_USER_1,
+ "flags should be consistent");
+
+nsScriptErrorBase::nsScriptErrorBase()
+ : mMessage(),
+ mMessageName(),
+ mSourceName(),
+ mLineNumber(0),
+ mSourceLine(),
+ mColumnNumber(0),
+ mFlags(0),
+ mCategory(),
+ mOuterWindowID(0),
+ mInnerWindowID(0),
+ mTimeStamp(0),
+ mInitializedOnMainThread(false),
+ mIsFromPrivateWindow(false)
+{
+}
+
+nsScriptErrorBase::~nsScriptErrorBase() {}
+
+void
+nsScriptErrorBase::AddNote(nsIScriptErrorNote* note)
+{
+ mNotes.AppendObject(note);
+}
+
+void
+nsScriptErrorBase::InitializeOnMainThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!mInitializedOnMainThread);
+
+ if (mInnerWindowID) {
+ nsGlobalWindow* window =
+ nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
+ if (window) {
+ nsPIDOMWindowOuter* outer = window->GetOuterWindow();
+ if (outer)
+ mOuterWindowID = outer->WindowID();
+
+ nsIDocShell* docShell = window->GetDocShell();
+ nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+
+ if (loadContext) {
+ // Never mark exceptions from chrome windows as having come from
+ // private windows, since we always want them to be reported.
+ nsIPrincipal* winPrincipal = window->GetPrincipal();
+ mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
+ !nsContentUtils::IsSystemPrincipal(winPrincipal);
+ }
+ }
+ }
+
+ mInitializedOnMainThread = true;
+}
+
+// nsIConsoleMessage methods
+NS_IMETHODIMP
+nsScriptErrorBase::GetMessageMoz(char16_t** result) {
+ nsresult rv;
+
+ nsAutoCString message;
+ rv = ToString(message);
+ if (NS_FAILED(rv))
+ return rv;
+
+ *result = UTF8ToNewUnicode(message);
+ if (!*result)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel)
+{
+ if (mFlags & (uint32_t)nsIScriptError::infoFlag) {
+ *aLogLevel = nsIConsoleMessage::info;
+ } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) {
+ *aLogLevel = nsIConsoleMessage::warn;
+ } else {
+ *aLogLevel = nsIConsoleMessage::error;
+ }
+ return NS_OK;
+}
+
+// nsIScriptError methods
+NS_IMETHODIMP
+nsScriptErrorBase::GetErrorMessage(nsAString& aResult) {
+ aResult.Assign(mMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetSourceName(nsAString& aResult) {
+ aResult.Assign(mSourceName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetSourceLine(nsAString& aResult) {
+ aResult.Assign(mSourceLine);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetLineNumber(uint32_t* result) {
+ *result = mLineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetColumnNumber(uint32_t* result) {
+ *result = mColumnNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetFlags(uint32_t* result) {
+ *result = mFlags;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetCategory(char** result) {
+ *result = ToNewCString(mCategory);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetStack(JS::MutableHandleValue aStack) {
+ aStack.setUndefined();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::SetStack(JS::HandleValue aStack) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) {
+ aErrorMessageName = mMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
+ mMessageName = aErrorMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category)
+{
+ return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
+ columnNumber, flags,
+ category ? nsDependentCString(category)
+ : EmptyCString(),
+ 0);
+}
+
+static void
+AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc)
+{
+ if (aSourceNameSrc.IsEmpty())
+ return;
+
+ aSourceNameDest.Assign(aSourceNameSrc);
+
+ nsCOMPtr<nsIURI> uri;
+ nsAutoCString pass;
+ if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) &&
+ NS_SUCCEEDED(uri->GetPassword(pass)) &&
+ !pass.IsEmpty())
+ {
+ nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri);
+
+ nsAutoCString loc;
+ if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc)))
+ aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc));
+ }
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::InitWithWindowID(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const nsACString& category,
+ uint64_t aInnerWindowID)
+{
+ mMessage.Assign(message);
+ AssignSourceNameHelper(mSourceName, sourceName);
+ mLineNumber = lineNumber;
+ mSourceLine.Assign(sourceLine);
+ mColumnNumber = columnNumber;
+ mFlags = flags;
+ mCategory = category;
+ mTimeStamp = JS_Now() / 1000;
+ mInnerWindowID = aInnerWindowID;
+
+ if (aInnerWindowID && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ return NS_OK;
+}
+
+static nsresult
+ToStringHelper(const char* aSeverity, const nsString& aMessage,
+ const nsString& aSourceName, const nsString* aSourceLine,
+ uint32_t aLineNumber, uint32_t aColumnNumber,
+ nsACString& /*UTF8*/ aResult)
+{
+ static const char format0[] =
+ "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
+ static const char format1[] =
+ "[%s: \"%s\" {file: \"%s\" line: %d}]";
+ static const char format2[] =
+ "[%s: \"%s\"]";
+
+ char* temp;
+ char* tempMessage = nullptr;
+ char* tempSourceName = nullptr;
+ char* tempSourceLine = nullptr;
+
+ if (!aMessage.IsEmpty())
+ tempMessage = ToNewUTF8String(aMessage);
+ if (!aSourceName.IsEmpty())
+ // Use at most 512 characters from mSourceName.
+ tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512));
+ if (aSourceLine && !aSourceLine->IsEmpty())
+ // Use at most 512 characters from mSourceLine.
+ tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512));
+
+ if (nullptr != tempSourceName && nullptr != tempSourceLine) {
+ temp = JS_smprintf(format0,
+ aSeverity,
+ tempMessage,
+ tempSourceName,
+ aLineNumber,
+ aColumnNumber,
+ tempSourceLine);
+ } else if (!aSourceName.IsEmpty()) {
+ temp = JS_smprintf(format1,
+ aSeverity,
+ tempMessage,
+ tempSourceName,
+ aLineNumber);
+ } else {
+ temp = JS_smprintf(format2,
+ aSeverity,
+ tempMessage);
+ }
+
+ if (nullptr != tempMessage)
+ free(tempMessage);
+ if (nullptr != tempSourceName)
+ free(tempSourceName);
+ if (nullptr != tempSourceLine)
+ free(tempSourceLine);
+
+ if (!temp)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ aResult.Assign(temp);
+ JS_smprintf_free(temp);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
+{
+ static const char error[] = "JavaScript Error";
+ static const char warning[] = "JavaScript Warning";
+
+ const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
+
+ return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine,
+ mLineNumber, mColumnNumber, aResult);
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID)
+{
+ NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
+ "This can't be safely determined off the main thread, "
+ "returning an inaccurate value!");
+
+ if (!mInitializedOnMainThread && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ *aOuterWindowID = mOuterWindowID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID)
+{
+ *aInnerWindowID = mInnerWindowID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp)
+{
+ *aTimeStamp = mTimeStamp;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow)
+{
+ NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
+ "This can't be safely determined off the main thread, "
+ "returning an inaccurate value!");
+
+ if (!mInitializedOnMainThread && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ *aIsFromPrivateWindow = mIsFromPrivateWindow;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetNotes(nsIArray** aNotes)
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIMutableArray> array =
+ do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t len = mNotes.Length();
+ for (uint32_t i = 0; i < len; i++)
+ array->AppendElement(mNotes[i], false);
+ array.forget(aNotes);
+
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
+
+nsScriptErrorNote::nsScriptErrorNote()
+ : mMessage(),
+ mSourceName(),
+ mLineNumber(0),
+ mColumnNumber(0)
+{
+}
+
+nsScriptErrorNote::~nsScriptErrorNote() {}
+
+void
+nsScriptErrorNote::Init(const nsAString& message,
+ const nsAString& sourceName,
+ uint32_t lineNumber,
+ uint32_t columnNumber)
+{
+ mMessage.Assign(message);
+ AssignSourceNameHelper(mSourceName, sourceName);
+ mLineNumber = lineNumber;
+ mColumnNumber = columnNumber;
+}
+
+// nsIScriptErrorNote methods
+NS_IMETHODIMP
+nsScriptErrorNote::GetErrorMessage(nsAString& aResult) {
+ aResult.Assign(mMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetSourceName(nsAString& aResult) {
+ aResult.Assign(mSourceName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetLineNumber(uint32_t* result) {
+ *result = mLineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetColumnNumber(uint32_t* result) {
+ *result = mColumnNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult)
+{
+ return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr,
+ mLineNumber, mColumnNumber, aResult);
+}
+
+NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)
diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h
new file mode 100644
index 000000000..b8049d0a0
--- /dev/null
+++ b/dom/bindings/nsScriptError.h
@@ -0,0 +1,109 @@
+/* -*- 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_nsScriptError_h
+#define mozilla_dom_nsScriptError_h
+
+#include "mozilla/Atomics.h"
+
+#include <stdint.h>
+
+#include "jsapi.h"
+#include "js/RootingAPI.h"
+
+#include "nsIScriptError.h"
+#include "nsString.h"
+
+class nsScriptErrorNote final : public nsIScriptErrorNote {
+ public:
+ nsScriptErrorNote();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSISCRIPTERRORNOTE
+
+ void Init(const nsAString& message, const nsAString& sourceName,
+ uint32_t lineNumber, uint32_t columnNumber);
+
+ private:
+ virtual ~nsScriptErrorNote();
+
+ nsString mMessage;
+ nsString mSourceName;
+ nsString mSourceLine;
+ uint32_t mLineNumber;
+ uint32_t mColumnNumber;
+};
+
+// Definition of nsScriptError..
+class nsScriptErrorBase : public nsIScriptError {
+public:
+ nsScriptErrorBase();
+
+ NS_DECL_NSICONSOLEMESSAGE
+ NS_DECL_NSISCRIPTERROR
+
+ void AddNote(nsIScriptErrorNote* note);
+
+protected:
+ virtual ~nsScriptErrorBase();
+
+ void
+ InitializeOnMainThread();
+
+ nsCOMArray<nsIScriptErrorNote> mNotes;
+ nsString mMessage;
+ nsString mMessageName;
+ nsString mSourceName;
+ uint32_t mLineNumber;
+ nsString mSourceLine;
+ uint32_t mColumnNumber;
+ uint32_t mFlags;
+ nsCString mCategory;
+ // mOuterWindowID is set on the main thread from InitializeOnMainThread().
+ uint64_t mOuterWindowID;
+ uint64_t mInnerWindowID;
+ int64_t mTimeStamp;
+ // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
+ // thread from InitializeOnMainThread().
+ mozilla::Atomic<bool> mInitializedOnMainThread;
+ bool mIsFromPrivateWindow;
+};
+
+class nsScriptError final : public nsScriptErrorBase {
+public:
+ nsScriptError() {}
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+ virtual ~nsScriptError() {}
+};
+
+class nsScriptErrorWithStack : public nsScriptErrorBase {
+public:
+ explicit nsScriptErrorWithStack(JS::HandleObject);
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack)
+
+ NS_IMETHOD Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category) override;
+
+ NS_IMETHOD GetStack(JS::MutableHandleValue) override;
+ NS_IMETHOD ToString(nsACString& aResult) override;
+
+private:
+ virtual ~nsScriptErrorWithStack();
+ // Complete stackframe where the error happened.
+ // Must be SavedFrame object.
+ JS::Heap<JSObject*> mStack;
+};
+
+#endif /* mozilla_dom_nsScriptError_h */
diff --git a/dom/bindings/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp
new file mode 100644
index 000000000..74c00999f
--- /dev/null
+++ b/dom/bindings/nsScriptErrorWithStack.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* 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/. */
+
+/*
+ * nsScriptErrorWithStack implementation.
+ * a main-thread-only, cycle-collected subclass of nsScriptErrorBase
+ * that can store a SavedFrame stack trace object.
+ */
+
+#include "nsScriptError.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "nsGlobalWindow.h"
+#include "nsCycleCollectionParticipant.h"
+
+using namespace mozilla::dom;
+
+namespace {
+
+static nsCString
+FormatStackString(JSContext* cx, HandleObject aStack) {
+ JS::RootedString formattedStack(cx);
+
+ if (!JS::BuildStackString(cx, aStack, &formattedStack)) {
+ return nsCString();
+ }
+
+ nsAutoJSString stackJSString;
+ if (!stackJSString.init(cx, formattedStack)) {
+ return nsCString();
+ }
+
+ return NS_ConvertUTF16toUTF8(stackJSString.get());
+}
+
+}
+
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptErrorWithStack)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptErrorWithStack)
+ tmp->mStack = nullptr;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptErrorWithStack)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsScriptErrorWithStack)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptErrorWithStack)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptErrorWithStack)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptErrorWithStack)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsIConsoleMessage)
+ NS_INTERFACE_MAP_ENTRY(nsIScriptError)
+NS_INTERFACE_MAP_END
+
+nsScriptErrorWithStack::nsScriptErrorWithStack(JS::HandleObject aStack)
+ : mStack(aStack)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "You can't use this class on workers.");
+ mozilla::HoldJSObjects(this);
+}
+
+nsScriptErrorWithStack::~nsScriptErrorWithStack() {
+ mozilla::DropJSObjects(this);
+}
+
+NS_IMETHODIMP
+nsScriptErrorWithStack::Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category)
+{
+ MOZ_CRASH("nsScriptErrorWithStack requires to be initialized with a document, by using InitWithWindowID");
+}
+
+NS_IMETHODIMP
+nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) {
+ aStack.setObjectOrNull(mStack);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCString message;
+ nsresult rv = nsScriptErrorBase::ToString(message);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!mStack) {
+ aResult.Assign(message);
+ return NS_OK;
+ }
+
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(mStack)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ JSContext* cx = jsapi.cx();
+ RootedObject stack(cx, mStack);
+ nsCString stackString = FormatStackString(cx, stack);
+ nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString;
+ aResult.Assign(combined);
+
+ return NS_OK;
+}
diff --git a/dom/canvas/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp
index 1eaf37ac4..02a8f649f 100644
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -134,6 +134,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa
if (error) {
MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
+ mByteLength = 0;
return;
}
} else {
diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h
index 8a20237ff..0510e6898 100644
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -20,6 +20,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/LinkedList.h"
#include "mozilla/UniquePtr.h"
+#include "mozilla/WeakPtr.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsICanvasRenderingContextInternal.h"
#include "nsLayoutUtils.h"
@@ -299,6 +300,7 @@ class WebGLContext
, public WebGLContextUnchecked
, public WebGLRectangleObject
, public nsWrapperCache
+ , public SupportsWeakPtr<WebGLContext>
{
friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback;
@@ -342,6 +344,7 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
nsIDOMWebGLRenderingContext)
+ MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContext)
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0;
diff --git a/dom/canvas/WebGLExtensionDebugShaders.cpp b/dom/canvas/WebGLExtensionDebugShaders.cpp
index 75880465e..8399aeb95 100644
--- a/dom/canvas/WebGLExtensionDebugShaders.cpp
+++ b/dom/canvas/WebGLExtensionDebugShaders.cpp
@@ -29,15 +29,10 @@ WebGLExtensionDebugShaders::GetTranslatedShaderSource(const WebGLShader& shader,
{
retval.SetIsVoid(true);
- if (mIsLost) {
- mContext->ErrorInvalidOperation("%s: Extension is lost.",
- "getTranslatedShaderSource");
+ if (mIsLost || !mContext) {
return;
}
- if (mContext->IsContextLost())
- return;
-
if (!mContext->ValidateObject("getShaderTranslatedSource: shader", shader))
return;
diff --git a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
index e2e34f14e..da76eeb2d 100644
--- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
+++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
@@ -40,8 +40,10 @@ void
WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLQuery* query) const
{
const char funcName[] = "deleteQueryEXT";
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
mContext->DeleteQuery(query, funcName);
}
@@ -50,8 +52,10 @@ bool
WebGLExtensionDisjointTimerQuery::IsQueryEXT(const WebGLQuery* query) const
{
const char funcName[] = "isQueryEXT";
- if (mIsLost)
- return false;
+
+ if (mIsLost || !mContext) {
+ return false;
+ }
return mContext->IsQuery(query, funcName);
}
@@ -60,8 +64,10 @@ void
WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery& query) const
{
const char funcName[] = "beginQueryEXT";
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
mContext->BeginQuery(target, query, funcName);
}
@@ -70,8 +76,10 @@ void
WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) const
{
const char funcName[] = "endQueryEXT";
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
mContext->EndQuery(target, funcName);
}
@@ -80,8 +88,10 @@ void
WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery& query, GLenum target) const
{
const char funcName[] = "queryCounterEXT";
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
if (!mContext->ValidateObject(funcName, query))
return;
@@ -95,8 +105,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLen
{
const char funcName[] = "getQueryEXT";
retval.setNull();
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
mContext->GetQuery(cx, target, pname, retval, funcName);
}
@@ -108,8 +120,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx,
{
const char funcName[] = "getQueryObjectEXT";
retval.setNull();
- if (mIsLost)
- return;
+
+ if (mIsLost || !mContext) {
+ return;
+ }
mContext->GetQueryParameter(cx, query, pname, retval, funcName);
}
diff --git a/dom/canvas/WebGLExtensionDrawBuffers.cpp b/dom/canvas/WebGLExtensionDrawBuffers.cpp
index 27aa76cc7..6f386621f 100644
--- a/dom/canvas/WebGLExtensionDrawBuffers.cpp
+++ b/dom/canvas/WebGLExtensionDrawBuffers.cpp
@@ -36,7 +36,9 @@ void
WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers)
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost.");
+ if (mContext) {
+ mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost.");
+ }
return;
}
diff --git a/dom/canvas/WebGLExtensionInstancedArrays.cpp b/dom/canvas/WebGLExtensionInstancedArrays.cpp
index 10d0533fe..22b3ec12c 100644
--- a/dom/canvas/WebGLExtensionInstancedArrays.cpp
+++ b/dom/canvas/WebGLExtensionInstancedArrays.cpp
@@ -28,8 +28,10 @@ WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode,
GLsizei primcount)
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("%s: Extension is lost.",
- "drawArraysInstancedANGLE");
+ if (mContext) {
+ mContext->ErrorInvalidOperation("%s: Extension is lost.",
+ "drawArraysInstancedANGLE");
+ }
return;
}
@@ -44,8 +46,10 @@ WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode,
GLsizei primcount)
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("%s: Extension is lost.",
- "drawElementsInstancedANGLE");
+ if (mContext) {
+ mContext->ErrorInvalidOperation("%s: Extension is lost.",
+ "drawElementsInstancedANGLE");
+ }
return;
}
@@ -57,8 +61,10 @@ WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index,
GLuint divisor)
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("%s: Extension is lost.",
- "vertexAttribDivisorANGLE");
+ if (mContext) {
+ mContext->ErrorInvalidOperation("%s: Extension is lost.",
+ "vertexAttribDivisorANGLE");
+ }
return;
}
diff --git a/dom/canvas/WebGLExtensionLoseContext.cpp b/dom/canvas/WebGLExtensionLoseContext.cpp
index 020731e63..41f1633d8 100644
--- a/dom/canvas/WebGLExtensionLoseContext.cpp
+++ b/dom/canvas/WebGLExtensionLoseContext.cpp
@@ -22,12 +22,14 @@ WebGLExtensionLoseContext::~WebGLExtensionLoseContext()
void
WebGLExtensionLoseContext::LoseContext()
{
+ if (!mContext) return;
mContext->LoseContext();
}
void
WebGLExtensionLoseContext::RestoreContext()
{
+ if (!mContext) return;
mContext->RestoreContext();
}
diff --git a/dom/canvas/WebGLExtensionVertexArray.cpp b/dom/canvas/WebGLExtensionVertexArray.cpp
index 0984582f5..39aa96801 100644
--- a/dom/canvas/WebGLExtensionVertexArray.cpp
+++ b/dom/canvas/WebGLExtensionVertexArray.cpp
@@ -25,7 +25,7 @@ WebGLExtensionVertexArray::~WebGLExtensionVertexArray()
already_AddRefed<WebGLVertexArray>
WebGLExtensionVertexArray::CreateVertexArrayOES()
{
- if (mIsLost)
+ if (mIsLost || !mContext)
return nullptr;
return mContext->CreateVertexArray();
@@ -34,7 +34,7 @@ WebGLExtensionVertexArray::CreateVertexArrayOES()
void
WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array)
{
- if (mIsLost)
+ if (mIsLost || !mContext)
return;
mContext->DeleteVertexArray(array);
@@ -43,7 +43,7 @@ WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array)
bool
WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array)
{
- if (mIsLost)
+ if (mIsLost || !mContext)
return false;
return mContext->IsVertexArray(array);
@@ -52,7 +52,7 @@ WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array)
void
WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array)
{
- if (mIsLost)
+ if (mIsLost || !mContext)
return;
mContext->BindVertexArray(array);
diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h
index b18b790c0..6371c7b03 100644
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -6,8 +6,8 @@
#ifndef WEBGLOBJECTMODEL_H_
#define WEBGLOBJECTMODEL_H_
+#include "mozilla/WeakPtr.h"
#include "nsCycleCollectionNoteChild.h"
-
#include "WebGLTypes.h"
namespace mozilla {
@@ -24,7 +24,7 @@ class WebGLContext;
class WebGLContextBoundObject
{
public:
- WebGLContext* const mContext;
+ const WeakPtr<WebGLContext> mContext;
private:
const uint32_t mContextGeneration;
diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp
index ec076fdbb..32397dd1a 100644
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -215,6 +215,16 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
if (error) {
const char* errorName = mContext->ErrorName(error);
mContext->GenerateWarning("%s generated error %s", funcName, errorName);
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ // Truncate.
+ mSamples = 0;
+ mFormat = nullptr;
+ mWidth = 0;
+ mHeight = 0;
+ mImageDataStatus = WebGLImageDataStatus::NoImageData;
+
+ InvalidateStatusOfAttachedFBs();
+ }
return;
}
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/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp
index 767ff610a..65bb71153 100644
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -51,8 +51,6 @@ WebGLTexture::ImageInfo::Clear()
WebGLTexture::ImageInfo&
WebGLTexture::ImageInfo::operator =(const ImageInfo& a)
{
- MOZ_ASSERT(a.IsDefined());
-
Mutable(mFormat) = a.mFormat;
Mutable(mWidth) = a.mWidth;
Mutable(mHeight) = a.mHeight;
@@ -1216,6 +1214,12 @@ WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt&
mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f);
}
+void WebGLTexture::Truncate() {
+ for (auto& cur : mImageInfoArr) {
+ SetImageInfo(&cur, ImageInfo());
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h
index 66e781f23..8d3024590 100644
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -386,6 +386,7 @@ public:
bool* const out_initFailed);
bool IsMipmapCubeComplete() const;
+ void Truncate();
bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp
index 3839b5d5e..ae60d2a2b 100644
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1178,6 +1178,7 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
if (error == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Ran out of memory during texture allocation.",
funcName);
+ Truncate();
return;
}
if (error) {
@@ -1310,6 +1311,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
if (glError == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
funcName);
+ Truncate();
return;
}
@@ -1398,6 +1400,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
if (glError == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
funcName);
+ Truncate();
return;
}
@@ -1514,6 +1517,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL
blob->mAvailBytes, blob->mPtr);
if (error == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
+ Truncate();
return;
}
if (error) {
@@ -1664,6 +1668,7 @@ WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target,
blob->mAvailBytes, blob->mPtr);
if (error == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
+ Truncate();
return;
}
if (error) {
@@ -1992,7 +1997,7 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev
static bool
DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage,
- const WebGLTexture* tex, TexImageTarget target, GLint level,
+ WebGLTexture* tex, TexImageTarget target, GLint level,
GLint xWithinSrc, GLint yWithinSrc,
uint32_t srcTotalWidth, uint32_t srcTotalHeight,
const webgl::FormatUsageInfo* srcUsage,
@@ -2069,6 +2074,7 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage,
if (error == LOCAL_GL_OUT_OF_MEMORY) {
webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName);
+ tex->Truncate();
return false;
}
diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp
index c4fcceb90..30dc9b6da 100644
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -2385,9 +2385,14 @@ BackgroundVersionChangeTransactionChild::RecvComplete(const nsresult& aResult)
database->Close();
}
+ RefPtr<IDBOpenDBRequest> request = mOpenDBRequest;
+ MOZ_ASSERT(request);
+
mTransaction->FireCompleteOrAbortEvents(aResult);
- mOpenDBRequest->SetTransaction(nullptr);
+ request->SetTransaction(nullptr);
+ request = nullptr;
+
mOpenDBRequest = nullptr;
NoteComplete();
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 79446151c..97e3a4880 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -229,11 +229,6 @@
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
-#if defined(XP_WIN)
-// e10s forced enable pref, defined in nsAppRunner.cpp
-extern const char* kForceEnableE10sPref;
-#endif
-
using base::ChildPrivileges;
using base::KillProcess;
@@ -1275,12 +1270,6 @@ ContentParent::Init()
if (nsIPresShell::IsAccessibilityActive()) {
#if !defined(XP_WIN)
Unused << SendActivateA11y(0);
-#else
- // On Windows we currently only enable a11y in the content process
- // for testing purposes.
- if (Preferences::GetBool(kForceEnableE10sPref, false)) {
- Unused << SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
- }
#endif
}
#endif
@@ -2573,12 +2562,6 @@ ContentParent::Observe(nsISupports* aSubject,
// accessibility gets initiated in chrome process.
#if !defined(XP_WIN)
Unused << SendActivateA11y(0);
-#else
- // On Windows we currently only enable a11y in the content process
- // for testing purposes.
- if (Preferences::GetBool(kForceEnableE10sPref, false)) {
- Unused << SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
- }
#endif
} else {
// If possible, shut down accessibility in content process when
diff --git a/dom/media/MediaResource.cpp b/dom/media/MediaResource.cpp
index d36783be7..84a8d67fd 100644
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -1525,7 +1525,7 @@ void BaseMediaResource::SetLoadInBackground(bool aLoadInBackground) {
NS_WARNING("Null owner in MediaResource::SetLoadInBackground()");
return;
}
- dom::HTMLMediaElement* element = owner->GetMediaElement();
+ RefPtr<dom::HTMLMediaElement> element = owner->GetMediaElement();
if (!element) {
NS_WARNING("Null element in MediaResource::SetLoadInBackground()");
return;
diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp
index 6954e9757..b293c251b 100644
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -172,7 +172,8 @@ bool
MP4Decoder::IsH264(const nsACString& aMimeType)
{
return aMimeType.EqualsLiteral("video/mp4") ||
- aMimeType.EqualsLiteral("video/avc");
+ aMimeType.EqualsLiteral("video/avc") ||
+ aMimeType.EqualsLiteral("video/webm; codecs=avc1");
}
/* static */
diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp
index 4ae37d7e9..b4dcfde8a 100644
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -697,6 +697,9 @@ ContainerParser::CreateForMIMEType(const nsACString& aType)
if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
return new WebMContainerParser(aType);
}
+ if (aType.LowerCaseEqualsLiteral("video/x-matroska") || aType.LowerCaseEqualsLiteral("audio/x-matroska")) {
+ return new WebMContainerParser(aType);
+ }
#ifdef MOZ_FMP4
if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) {
diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp
index 152c0085a..1c276cdc1 100644
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -110,14 +110,16 @@ MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* a
}
return NS_OK;
}
- if (mimeType.EqualsASCII("video/webm")) {
+ if (mimeType.EqualsASCII("video/webm") ||
+ mimeType.EqualsASCII("video/x-matroska")) {
if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
IsWebMForced(aDiagnostics))) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
return NS_OK;
}
- if (mimeType.EqualsASCII("audio/webm")) {
+ if (mimeType.EqualsASCII("audio/webm") ||
+ mimeType.EqualsASCII("audio/x-matroska")) {
if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp
index ac6d82411..21fb158b5 100644
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -814,6 +814,8 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
ShutdownDemuxers();
if (mType.LowerCaseEqualsLiteral("video/webm") ||
+ mType.LowerCaseEqualsLiteral("video/x-matroska") ||
+ mType.LowerCaseEqualsLiteral("audio/x-matroska") ||
mType.LowerCaseEqualsLiteral("audio/webm")) {
mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ );
return;
diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp
index 9575d6e42..cbe9ffdb7 100644
--- a/dom/media/webm/WebMDecoder.cpp
+++ b/dom/media/webm/WebMDecoder.cpp
@@ -42,7 +42,10 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
const bool isWebMAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/webm");
const bool isWebMVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/webm");
- if (!isWebMAudio && !isWebMVideo) {
+ const bool isMatroskaAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/x-matroska") ;
+ const bool isMatroskaVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/x-matroska") ;
+
+ if (!isWebMAudio && !isWebMVideo && !isMatroskaAudio && !isMatroskaVideo) {
return false;
}
@@ -63,7 +66,7 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
}
// Note: Only accept VP8/VP9 in a video content type, not in an audio
// content type.
- if (isWebMVideo &&
+ if ((isWebMVideo || isMatroskaVideo) &&
(codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") ||
codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) {
@@ -74,6 +77,15 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
continue;
}
#endif
+
+ if (IsH264CodecString(codec)) {
+ continue;
+ }
+
+ if (IsAACCodecString(codec)) {
+ continue;
+ }
+
// Some unsupported codec.
return false;
}
diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp
index 013da9b2c..84b4b506e 100644
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -326,6 +326,20 @@ WebMDemuxer::ReadMetadata()
case NESTEGG_CODEC_AV1:
mInfo.mVideo.mMimeType = "video/webm; codecs=av1";
break;
+ case NESTEGG_CODEC_AVC1: {
+ mInfo.mVideo.mMimeType = "video/webm; codecs=avc1";
+
+ unsigned char* data = 0;
+ size_t length = 0;
+ r = nestegg_track_codec_data(context, track, 0, &data, &length);
+ if (r == -1) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mInfo.mVideo.mExtraData = new MediaByteBuffer(length);
+ mInfo.mVideo.mExtraData->AppendElements(data, length);
+ break;
+ }
default:
NS_WARNING("Unknown WebM video codec");
return NS_ERROR_FAILURE;
@@ -408,6 +422,8 @@ WebMDemuxer::ReadMetadata()
mInfo.mAudio.mMimeType = "audio/opus";
OpusDataDecoder::AppendCodecDelay(mInfo.mAudio.mCodecSpecificConfig,
media::TimeUnit::FromNanoseconds(params.codec_delay).ToMicroseconds());
+ } else if (mAudioCodec == NESTEGG_CODEC_AAC) {
+ mInfo.mAudio.mMimeType = "audio/mp4a-latm";
}
mSeekPreroll = params.seek_preroll;
mInfo.mAudio.mRate = params.rate;
@@ -662,6 +678,9 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
isKeyframe = AOMDecoder::IsKeyframe(sample);
break;
#endif
+ case NESTEGG_CODEC_AVC1:
+ isKeyframe = nestegg_packet_has_keyframe(holder->Packet());
+ break;
default:
NS_WARNING("Cannot detect keyframes in unknown WebM video codec");
return NS_ERROR_FAILURE;
@@ -682,7 +701,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
dimensions = AOMDecoder::GetFrameSize(sample);
break;
#endif
- }
+ }
if (mLastSeenFrameSize.isSome()
&& (dimensions != mLastSeenFrameSize.value())) {
mInfo.mVideo.mDisplay = dimensions;
@@ -749,6 +768,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
if (aType == TrackInfo::kVideoTrack) {
sample->mTrackInfo = mSharedVideoTrackInfo;
}
+
+ if (mVideoCodec == NESTEGG_CODEC_AVC1) {
+ sample->mExtraData = mInfo.mVideo.mExtraData;
+ }
+
aSamples->Push(sample);
}
return NS_OK;
diff --git a/dom/network/UDPSocketChild.cpp b/dom/network/UDPSocketChild.cpp
index 6e374ce31..d205e7e8a 100644
--- a/dom/network/UDPSocketChild.cpp
+++ b/dom/network/UDPSocketChild.cpp
@@ -172,19 +172,28 @@ UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
NS_ENSURE_ARG(aSocket);
- mSocket = aSocket;
- AddIPDLReference();
+ if (NS_IsMainThread()) {
+ if (!gNeckoChild->SendPUDPSocketConstructor(
+ this, IPC::Principal(aPrincipal), mFilterName)) {
+ return NS_ERROR_FAILURE;
+ }
+ } else {
+ if (!mBackgroundManager) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
- if (mBackgroundManager) {
// If we want to support a passed-in principal here we'd need to
// convert it to a PrincipalInfo
MOZ_ASSERT(!aPrincipal);
- mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName);
- } else {
- gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
- mFilterName);
+ if (!mBackgroundManager->SendPUDPSocketConstructor(
+ this, void_t(), mFilterName)) {
+ return NS_ERROR_FAILURE;
+ }
}
+ mSocket = aSocket;
+ AddIPDLReference();
+
SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback,
recvBufferSize, sendBufferSize);
return NS_OK;
diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
index 665e11ec1..0476315d5 100644
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -1381,7 +1381,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
return NS_ERROR_FAILURE;
}
- // Don't allow cross-origin 307 POST redirects.
+ // Don't allow cross-origin 307/308 POST redirects.
nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
if (oldHttpChannel) {
uint32_t responseStatus;
@@ -1389,7 +1389,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
if (NS_FAILED(rv)) {
return rv;
}
- if (responseStatus == 307) {
+ if (responseStatus == 307 || responseStatus == 308) {
nsAutoCString method;
rv = oldHttpChannel->GetRequestMethod(method);
if (NS_FAILED(rv)) {
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index f2cbc8fcf..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"
@@ -95,9 +96,14 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
/* static */ nsresult
nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel)
{
- // We dissallow using FTP resources as a subresource everywhere.
+ // We dissallow using FTP resources as a subresource almost everywhere.
// The only valid way to use FTP resources is loading it as
// a top level document.
+
+ // Override blocking if the pref is set to allow.
+ if (!mozilla::net::nsIOService::BlockFTPSubresources()) {
+ return NS_OK;
+ }
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (!loadInfo) {
@@ -105,22 +111,40 @@ nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel)
}
nsContentPolicyType type = loadInfo->GetExternalContentPolicyType();
+
+ // Allow save-as download of FTP files on HTTP pages.
+ if (type == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD) {
+ return NS_OK;
+ }
+
+ // Allow direct document requests
if (type == nsIContentPolicy::TYPE_DOCUMENT) {
return NS_OK;
}
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;
}
+ // Allow if it's not the FTP protocol
bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI);
if (!isFtpURI) {
return NS_OK;
}
+ // Allow loading FTP subresources in top-level FTP documents.
+ nsIPrincipal* triggeringPrincipal = loadInfo->TriggeringPrincipal();
+ nsCOMPtr<nsIURI> tURI;
+ triggeringPrincipal->GetURI(getter_AddRefs(tURI));
+ bool isTrigFtpURI = (NS_SUCCEEDED(tURI->SchemeIs("ftp", &isTrigFtpURI)) && isTrigFtpURI);
+ if (isTrigFtpURI) {
+ return NS_OK;
+ }
+
+ // If we get here, the request is blocked and should be reported.
nsCOMPtr<nsIDocument> doc;
if (nsINode* node = loadInfo->LoadingNode()) {
doc = node->OwnerDoc();
@@ -778,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/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 21f6d8ddf..19c4ded2a 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -988,7 +988,7 @@ Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
}
if (existing) {
- js::Wrapper::Renew(cx, existing, obj, wrapper);
+ js::Wrapper::Renew(existing, obj, wrapper);
}
return js::Wrapper::New(cx, obj, wrapper);
}
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 6bc5c4f96..27eb570e9 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -87,6 +87,7 @@
#include "nsProxyRelease.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
+#include "nsScriptError.h"
#include "nsUTF8Utils.h"
#include "prthread.h"
#include "xpcpublic.h"
@@ -281,27 +282,34 @@ struct WindowAction
};
void
-LogErrorToConsole(const nsAString& aMessage,
- const nsAString& aFilename,
- const nsAString& aLine,
- uint32_t aLineNumber,
- uint32_t aColumnNumber,
- uint32_t aFlags,
- uint64_t aInnerWindowId)
+LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId)
{
AssertIsOnMainThread();
- nsCOMPtr<nsIScriptError> scriptError =
- do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+ RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
if (scriptError) {
- if (NS_FAILED(scriptError->InitWithWindowID(aMessage, aFilename, aLine,
- aLineNumber, aColumnNumber,
- aFlags, "Web Worker",
+ nsAutoCString category("Web Worker");
+ if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage,
+ aReport.mFilename,
+ aReport.mLine,
+ aReport.mLineNumber,
+ aReport.mColumnNumber,
+ aReport.mFlags,
+ category,
aInnerWindowId))) {
NS_WARNING("Failed to init script error!");
scriptError = nullptr;
+
+ for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
+ const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
+
+ nsScriptErrorNote* noteObject = new nsScriptErrorNote();
+ noteObject->Init(note.mMessage, note.mFilename,
+ note.mLineNumber, note.mColumnNumber);
+ scriptError->AddNote(noteObject);
+ }
}
}
@@ -316,23 +324,23 @@ LogErrorToConsole(const nsAString& aMessage,
}
NS_WARNING("LogMessage failed!");
} else if (NS_SUCCEEDED(consoleService->LogStringMessage(
- aMessage.BeginReading()))) {
+ aReport.mMessage.BeginReading()))) {
return;
}
NS_WARNING("LogStringMessage failed!");
}
- NS_ConvertUTF16toUTF8 msg(aMessage);
- NS_ConvertUTF16toUTF8 filename(aFilename);
+ NS_ConvertUTF16toUTF8 msg(aReport.mMessage);
+ NS_ConvertUTF16toUTF8 filename(aReport.mFilename);
static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]";
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(),
- filename.get(), aLineNumber);
+ filename.get(), aReport.mLineNumber);
#endif
- fprintf(stderr, kErrorString, msg.get(), filename.get(), aLineNumber);
+ fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber);
fflush(stderr);
}
@@ -536,10 +544,7 @@ private:
}
if (aWorkerPrivate->IsSharedWorker()) {
- aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(),
- EmptyString(),
- EmptyString(), 0, 0,
- JSREPORT_ERROR,
+ aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr,
/* isErrorEvent */ false);
return true;
}
@@ -1060,15 +1065,7 @@ private:
class ReportErrorRunnable final : public WorkerRunnable
{
- nsString mMessage;
- nsString mFilename;
- nsString mLine;
- uint32_t mLineNumber;
- uint32_t mColumnNumber;
- uint32_t mFlags;
- uint32_t mErrorNumber;
- JSExnType mExnType;
- bool mMutedError;
+ WorkerErrorReport mReport;
public:
// aWorkerPrivate is the worker thread we're on (or the main thread, if null)
@@ -1077,11 +1074,7 @@ public:
static void
ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aFireAtScope, WorkerPrivate* aTarget,
- const nsString& aMessage, const nsString& aFilename,
- const nsString& aLine, uint32_t aLineNumber,
- uint32_t aColumnNumber, uint32_t aFlags,
- uint32_t aErrorNumber, JSExnType aExnType,
- bool aMutedError, uint64_t aInnerWindowId,
+ const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
JS::Handle<JS::Value> aException = JS::NullHandleValue)
{
if (aWorkerPrivate) {
@@ -1092,16 +1085,16 @@ public:
// We should not fire error events for warnings but instead make sure that
// they show up in the error console.
- if (!JSREPORT_IS_WARNING(aFlags)) {
+ if (!JSREPORT_IS_WARNING(aReport.mFlags)) {
// First fire an ErrorEvent at the worker.
RootedDictionary<ErrorEventInit> init(aCx);
- if (aMutedError) {
+ if (aReport.mMutedError) {
init.mMessage.AssignLiteral("Script error.");
} else {
- init.mMessage = aMessage;
- init.mFilename = aFilename;
- init.mLineno = aLineNumber;
+ init.mMessage = aReport.mMessage;
+ init.mFilename = aReport.mFilename;
+ init.mLineno = aReport.mLineNumber;
init.mError = aException;
}
@@ -1128,7 +1121,8 @@ public:
// into an error event on our parent worker!
// https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this
// better.
- if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) {
+ if (aFireAtScope &&
+ (aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) {
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
NS_ASSERTION(global, "This should never be null!");
@@ -1145,8 +1139,8 @@ public:
MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global);
if (globalScope || IsDebuggerSandbox(global)) {
- aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber,
- aMessage);
+ aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber,
+ aReport.mMessage);
return;
}
@@ -1193,28 +1187,20 @@ public:
// Now fire a runnable to do the same on the parent's thread if we can.
if (aWorkerPrivate) {
RefPtr<ReportErrorRunnable> runnable =
- new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine,
- aLineNumber, aColumnNumber, aFlags,
- aErrorNumber, aExnType, aMutedError);
+ new ReportErrorRunnable(aWorkerPrivate, aReport);
runnable->Dispatch();
return;
}
// Otherwise log an error to the error console.
- LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
- aFlags, aInnerWindowId);
+ LogErrorToConsole(aReport, aInnerWindowId);
}
private:
- ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage,
- const nsString& aFilename, const nsString& aLine,
- uint32_t aLineNumber, uint32_t aColumnNumber,
- uint32_t aFlags, uint32_t aErrorNumber,
- JSExnType aExnType, bool aMutedError)
+ ReportErrorRunnable(WorkerPrivate* aWorkerPrivate,
+ const WorkerErrorReport& aReport)
: WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
- mMessage(aMessage), mFilename(aFilename), mLine(aLine),
- mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags),
- mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError)
+ mReport(aReport)
{ }
virtual void
@@ -1251,9 +1237,7 @@ private:
}
if (aWorkerPrivate->IsSharedWorker()) {
- aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename,
- mLine, mLineNumber,
- mColumnNumber, mFlags,
+ aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport,
/* isErrorEvent */ true);
return true;
}
@@ -1267,9 +1251,10 @@ private:
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->WorkerName(),
aWorkerPrivate->ScriptURL(),
- mMessage,
- mFilename, mLine, mLineNumber,
- mColumnNumber, mFlags, mExnType);
+ mReport.mMessage,
+ mReport.mFilename, mReport.mLine, mReport.mLineNumber,
+ mReport.mColumnNumber, mReport.mFlags,
+ mReport.mExnType);
}
return true;
}
@@ -1289,9 +1274,8 @@ private:
return true;
}
- ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage,
- mFilename, mLine, mLineNumber, mColumnNumber, mFlags,
- mErrorNumber, mExnType, mMutedError, innerWindowId);
+ ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport,
+ innerWindowId);
return true;
}
};
@@ -3314,21 +3298,16 @@ template <class Derived>
void
WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
JSContext* aCx,
- const nsAString& aMessage,
- const nsAString& aFilename,
- const nsAString& aLine,
- uint32_t aLineNumber,
- uint32_t aColumnNumber,
- uint32_t aFlags,
+ const WorkerErrorReport* aReport,
bool aIsErrorEvent)
{
AssertIsOnMainThread();
- if (JSREPORT_IS_WARNING(aFlags)) {
+ if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) {
// Don't fire any events anywhere. Just log to console.
// XXXbz should we log to all the consoles of all the relevant windows?
- LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
- aFlags, 0);
+ MOZ_ASSERT(aReport);
+ LogErrorToConsole(*aReport, 0);
return;
}
@@ -3357,10 +3336,10 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
RootedDictionary<ErrorEventInit> errorInit(aCx);
errorInit.mBubbles = false;
errorInit.mCancelable = true;
- errorInit.mMessage = aMessage;
- errorInit.mFilename = aFilename;
- errorInit.mLineno = aLineNumber;
- errorInit.mColno = aColumnNumber;
+ errorInit.mMessage = aReport->mMessage;
+ errorInit.mFilename = aReport->mFilename;
+ errorInit.mLineno = aReport->mLineNumber;
+ errorInit.mColno = aReport->mColumnNumber;
event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
errorInit);
@@ -3426,9 +3405,9 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
MOZ_ASSERT(NS_IsMainThread());
RootedDictionary<ErrorEventInit> init(aCx);
- init.mLineno = aLineNumber;
- init.mFilename = aFilename;
- init.mMessage = aMessage;
+ init.mLineno = aReport->mLineNumber;
+ init.mFilename = aReport->mFilename;
+ init.mMessage = aReport->mMessage;
init.mCancelable = true;
init.mBubbles = true;
@@ -3446,8 +3425,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
// Finally log a warning in the console if no window tried to prevent it.
if (shouldLogErrorToConsole) {
- LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
- aFlags, 0);
+ MOZ_ASSERT(aReport);
+ LogErrorToConsole(*aReport, 0);
}
}
@@ -4120,7 +4099,10 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
listeners[index]->OnError(aFilename, aLineno, aMessage);
}
- LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0);
+ WorkerErrorReport report;
+ report.mMessage = aMessage;
+ report.mFilename = aFilename;
+ LogErrorToConsole(report, 0);
}
WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
@@ -5926,6 +5908,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
}
void
+WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport)
+{
+ mFilename = NS_ConvertUTF8toUTF16(aReport->filename);
+ mLineNumber = aReport->lineno;
+ mColumnNumber = aReport->column;
+ mErrorNumber = aReport->errorNumber;
+}
+
+void
+WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote)
+{
+ WorkerErrorBase::AssignErrorBase(aNote);
+ xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage);
+}
+
+void
+WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport)
+{
+ WorkerErrorBase::AssignErrorBase(aReport);
+ xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage);
+
+ mLine.Assign(aReport->linebuf(), aReport->linebufLength());
+ mFlags = aReport->flags;
+ MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT);
+ mExnType = JSExnType(aReport->exnType);
+ mMutedError = aReport->isMuted;
+
+ if (aReport->notes) {
+ if (!mNotes.SetLength(aReport->notes->length(), fallible)) {
+ return;
+ }
+
+ size_t i = 0;
+ for (auto&& note : *aReport->notes) {
+ mNotes.ElementAt(i).AssignErrorNote(note.get());
+ i++;
+ }
+ }
+}
+
+void
WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
JSErrorReport* aReport)
{
@@ -5947,32 +5970,17 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
}
JS_ClearPendingException(aCx);
- nsString message, filename, line;
- uint32_t lineNumber, columnNumber, flags, errorNumber;
- JSExnType exnType = JSEXN_ERR;
- bool mutedError = aReport && aReport->isMuted;
-
+ WorkerErrorReport report;
if (aReport) {
- // We want the same behavior here as xpc::ErrorReport::init here.
- xpc::ErrorReport::ErrorReportToMessageString(aReport, message);
-
- filename = NS_ConvertUTF8toUTF16(aReport->filename);
- line.Assign(aReport->linebuf(), aReport->linebufLength());
- lineNumber = aReport->lineno;
- columnNumber = aReport->tokenOffset();
- flags = aReport->flags;
- errorNumber = aReport->errorNumber;
- MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT);
- exnType = JSExnType(aReport->exnType);
+ report.AssignErrorReport(aReport);
}
else {
- lineNumber = columnNumber = errorNumber = 0;
- flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
+ report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
}
- if (message.IsEmpty() && aToStringResult) {
+ if (report.mMessage.IsEmpty() && aToStringResult) {
nsDependentCString toStringResult(aToStringResult.c_str());
- if (!AppendUTF8toUTF16(toStringResult, message, mozilla::fallible)) {
+ if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) {
// Try again, with only a 1 KB string. Do this infallibly this time.
// If the user doesn't have 1 KB to spare we're done anyways.
uint32_t index = std::min(uint32_t(1024), toStringResult.Length());
@@ -5982,7 +5990,7 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
nsDependentCString truncatedToStringResult(aToStringResult.c_str(),
index);
- AppendUTF8toUTF16(truncatedToStringResult, message);
+ AppendUTF8toUTF16(truncatedToStringResult, report.mMessage);
}
}
@@ -5991,13 +5999,11 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
// Don't want to run the scope's error handler if this is a recursive error or
// if we ran out of memory.
bool fireAtScope = mErrorHandlerRecursionCount == 1 &&
- errorNumber != JSMSG_OUT_OF_MEMORY &&
+ report.mErrorNumber != JSMSG_OUT_OF_MEMORY &&
JS::CurrentGlobalOrNull(aCx);
- ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
- filename, line, lineNumber,
- columnNumber, flags, errorNumber, exnType,
- mutedError, 0, exn);
+ ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0,
+ exn);
mErrorHandlerRecursionCount--;
}
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 20a530205..885abccd5 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -140,6 +140,45 @@ public:
}
};
+class WorkerErrorBase {
+public:
+ nsString mMessage;
+ nsString mFilename;
+ uint32_t mLineNumber;
+ uint32_t mColumnNumber;
+ uint32_t mErrorNumber;
+
+ WorkerErrorBase()
+ : mLineNumber(0),
+ mColumnNumber(0),
+ mErrorNumber(0)
+ { }
+
+ void AssignErrorBase(JSErrorBase* aReport);
+};
+
+class WorkerErrorNote : public WorkerErrorBase {
+public:
+ void AssignErrorNote(JSErrorNotes::Note* aNote);
+};
+
+class WorkerErrorReport : public WorkerErrorBase {
+public:
+ nsString mLine;
+ uint32_t mFlags;
+ JSExnType mExnType;
+ bool mMutedError;
+ nsTArray<WorkerErrorNote> mNotes;
+
+ WorkerErrorReport()
+ : mFlags(0),
+ mExnType(JSEXN_ERR),
+ mMutedError(false)
+ { }
+
+ void AssignErrorReport(JSErrorReport* aReport);
+};
+
template <class Derived>
class WorkerPrivateParent : public DOMEventTargetHelper
{
@@ -401,12 +440,7 @@ public:
void
BroadcastErrorToSharedWorkers(JSContext* aCx,
- const nsAString& aMessage,
- const nsAString& aFilename,
- const nsAString& aLine,
- uint32_t aLineNumber,
- uint32_t aColumnNumber,
- uint32_t aFlags,
+ const WorkerErrorReport* aReport,
bool aIsErrorEvent);
void
diff --git a/dom/workers/moz.build b/dom/workers/moz.build
index 4f4b52e4a..9fea84193 100644
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
'../base',
'../system',
'/dom/base',
+ '/dom/bindings',
'/xpcom/build',
'/xpcom/threads',
]
diff --git a/dom/workers/test/test_sharedWorker.html b/dom/workers/test/test_sharedWorker.html
index 3d3d4e2c6..c00c4e586 100644
--- a/dom/workers/test/test_sharedWorker.html
+++ b/dom/workers/test/test_sharedWorker.html
@@ -23,7 +23,7 @@
const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) +
filename;
const errorLine = 91;
- const errorColumn = 0;
+ const errorColumn = 11;
var worker = new SharedWorker(filename);