summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/bindings/CallbackObject.h3
-rw-r--r--dom/bindings/Codegen.py45
-rw-r--r--dom/bindings/Record.h15
-rw-r--r--dom/canvas/CanvasRenderingContext2D.cpp44
-rw-r--r--dom/canvas/CanvasRenderingContext2D.h11
-rw-r--r--dom/canvas/CanvasUtils.cpp43
-rw-r--r--dom/canvas/CanvasUtils.h5
-rw-r--r--dom/canvas/ImageBitmap.cpp118
-rw-r--r--dom/canvas/ImageBitmap.h14
-rw-r--r--dom/canvas/ImageBitmapRenderingContext.cpp4
-rw-r--r--dom/canvas/WebGLBuffer.cpp2
-rw-r--r--dom/canvas/WebGLContext.h3
-rw-r--r--dom/canvas/WebGLTextureUpload.cpp18
-rw-r--r--dom/canvas/test/test_imagebitmap.html23
-rw-r--r--dom/events/DataTransfer.cpp12
-rw-r--r--dom/fetch/Fetch.cpp4
-rw-r--r--dom/html/HTMLCanvasElement.cpp43
-rw-r--r--dom/html/HTMLCanvasElement.h17
-rw-r--r--dom/indexedDB/ActorsParent.cpp46
-rw-r--r--dom/ipc/ContentParent.cpp3
-rw-r--r--dom/media/AudioConverter.cpp103
-rw-r--r--dom/media/MediaPrefs.h1
-rw-r--r--dom/media/eme/CDMProxy.h4
-rw-r--r--dom/media/eme/MediaKeys.cpp2
-rw-r--r--dom/media/eme/MediaKeys.h2
-rw-r--r--dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp2
-rw-r--r--dom/media/eme/mediadrm/MediaDrmCDMProxy.h3
-rw-r--r--dom/media/gmp/ChromiumCDMParent.cpp5
-rw-r--r--dom/media/gmp/ChromiumCDMParent.h3
-rw-r--r--dom/media/gmp/ChromiumCDMProxy.cpp72
-rw-r--r--dom/media/gmp/ChromiumCDMProxy.h9
-rw-r--r--dom/media/ipc/VideoDecoderParent.cpp5
-rw-r--r--dom/media/platforms/PDMFactory.cpp3
-rw-r--r--dom/media/platforms/PDMFactory.h3
-rw-r--r--dom/media/platforms/wmf/WMFDecoderModule.cpp79
-rw-r--r--dom/tests/mochitest/general/test_clipboard_disallowed.html15
-rw-r--r--dom/u2f/U2F.cpp2
-rw-r--r--dom/webauthn/WebAuthnManager.cpp2
38 files changed, 525 insertions, 263 deletions
diff --git a/dom/bindings/CallbackObject.h b/dom/bindings/CallbackObject.h
index e995d44..141e725 100644
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -479,8 +479,9 @@ class CallbackObjectHolder : CallbackObjectHolderBase {
void UnlinkSelf() {
// NS_IF_RELEASE because we might have been unlinked before
nsISupports* ptr = GetISupports();
- NS_IF_RELEASE(ptr);
+ // Clear mPtrBits before the release to prevent reentrance.
mPtrBits = 0;
+ NS_IF_RELEASE(ptr);
}
uintptr_t mPtrBits;
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 9415c0b..f5c1a0e 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4642,6 +4642,22 @@ def recordKeyDeclType(recordType):
return CGGeneric(recordKeyType(recordType))
+def initializerForType(type):
+ """
+ Get the right initializer for the given type for a data location where we
+ plan to then initialize it from a JS::Value. Some types need to always be
+ initialized even before we start the JS::Value-to-IDL-value conversion.
+
+ Returns a string or None if no initialization is needed.
+ """
+ if type.isObject():
+ return "nullptr"
+ # We could probably return CGDictionary.getNonInitializingCtorArg() for the
+ # dictionary case, but code outside DictionaryBase subclasses can't use
+ # that, so we can't do it across the board.
+ return None
+
+
# If this function is modified, modify CGNativeMember.getArg and
# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
# and holdertype we end up using, because it needs to be able to return the code
@@ -4949,6 +4965,12 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"passedToJSImpl": "${passedToJSImpl}"
})
+ elementInitializer = initializerForType(elementType)
+ if elementInitializer is None:
+ elementInitializer = ""
+ else:
+ elementInitializer = elementInitializer + ", "
+
# NOTE: Keep this in sync with variadic conversions as needed
templateBody = fill(
"""
@@ -4969,7 +4991,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if (done${nestingLevel}) {
break;
}
- ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(mozilla::fallible);
+ ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(${elementInitializer}mozilla::fallible);
if (!slotPtr${nestingLevel}) {
JS_ReportOutOfMemory(cx);
$*{exceptionCode}
@@ -4984,6 +5006,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
arrayRef=arrayRef,
elementType=elementInfo.declType.define(),
elementConversion=elementConversion,
+ elementInitializer=elementInitializer,
nestingLevel=str(nestingLevel))
templateBody = wrapObjectTemplate(templateBody, type,
@@ -6528,6 +6551,8 @@ class CGArgumentConverter(CGThing):
rooterDecl = ""
replacer["elemType"] = typeConversion.declType.define()
+ replacer["elementInitializer"] = initializerForType(self.argument.type) or ""
+
# NOTE: Keep this in sync with sequence conversions as needed
variadicConversion = string.Template(
"${seqType} ${declName};\n" +
@@ -6539,7 +6564,8 @@ class CGArgumentConverter(CGThing):
return false;
}
for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
- ${elemType}& slot = *${declName}.AppendElement(mozilla::fallible);
+ // OK to do infallible append here, since we ensured capacity already.
+ ${elemType}& slot = *${declName}.AppendElement(${elementInitializer});
""")
).substitute(replacer)
@@ -13689,8 +13715,9 @@ class CGDictionary(CGThing):
def getMemberInitializer(self, memberInfo):
"""
Get the right initializer for the member. Most members don't need one,
- but we need to pre-initialize 'any' and 'object' that have a default
- value, so they're safe to trace at all times.
+ but we need to pre-initialize 'object' that have a default value or are
+ required (and hence are not inside Optional), so they're safe to trace
+ at all times. And we can optimize a bit for dictionary-typed members.
"""
member, _ = memberInfo
if member.canHaveMissingValue():
@@ -13699,17 +13726,13 @@ class CGDictionary(CGThing):
# up.
return None
type = member.type
- if type.isAny():
- return "JS::UndefinedValue()"
- if type.isObject():
- return "nullptr"
if type.isDictionary():
# When we construct ourselves, we don't want to init our member
# dictionaries. Either we're being constructed-but-not-initialized
# ourselves (and then we don't want to init them) or we're about to
# init ourselves and then we'll init them anyway.
return CGDictionary.getNonInitializingCtorArg()
- return None
+ return initializerForType(type)
def getMemberSourceDescription(self, member):
return ("'%s' member of %s" %
@@ -16324,7 +16347,7 @@ class CallbackMethod(CallbackMember):
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
def getRvalDecl(self):
- return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
+ return "JS::Rooted<JS::Value> rval(cx);\n"
def getCall(self):
if self.argCount > 0:
@@ -16480,7 +16503,7 @@ class CallbackGetter(CallbackAccessor):
spiderMonkeyInterfacesAreStructs)
def getRvalDecl(self):
- return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
+ return "JS::Rooted<JS::Value> rval(cx);\n"
def getCall(self):
return fill(
diff --git a/dom/bindings/Record.h b/dom/bindings/Record.h
index 277f40f..c3827af 100644
--- a/dom/bindings/Record.h
+++ b/dom/bindings/Record.h
@@ -35,6 +35,21 @@ class RecordEntry {
ValueType mValue;
};
+// Specialize for a JSObject* ValueType and initialize it on construction, so we
+// don't need to worry about un-initialized JSObject* floating around.
+template <typename KeyType>
+class RecordEntry<KeyType, JSObject*> {
+ public:
+ RecordEntry() : mValue(nullptr) {}
+
+ // Move constructor so we can do Records of Records.
+ RecordEntry(RecordEntry<KeyType, JSObject*>&& aOther)
+ : mKey(std::move(aOther.mKey)), mValue(std::move(aOther.mValue)) {}
+
+ KeyType mKey;
+ JSObject* mValue;
+};
+
} // namespace binding_detail
template <typename KeyType, typename ValueType>
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index eee73e5..73cd347 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1080,7 +1080,8 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(
mPredictManyRedrawCalls(false),
mIsCapturedFrameInvalid(false),
mPathTransformWillUpdate(false),
- mInvalidateCount(0) {
+ mInvalidateCount(0),
+ mWriteOnly(false) {
if (!sMaxContextsInitialized) {
sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
sMaxContextsInitialized = true;
@@ -2346,7 +2347,11 @@ void CanvasRenderingContext2D::SetStyleFromUnion(
}
if (aValue.IsCanvasPattern()) {
- SetStyleFromPattern(aValue.GetAsCanvasPattern(), aWhichStyle);
+ CanvasPattern& pattern = aValue.GetAsCanvasPattern();
+ SetStyleFromPattern(pattern, aWhichStyle);
+ if (pattern.mForceWriteOnly) {
+ SetWriteOnly();
+ }
return;
}
@@ -2497,7 +2502,7 @@ already_AddRefed<CanvasPattern> CanvasRenderingContext2D::CreatePattern(
// nullptr and set CORSUsed to true for passing the security check in
// CanvasUtils::DoDrawImageSecurityCheck().
RefPtr<CanvasPattern> pat =
- new CanvasPattern(this, srcSurf, repeatMode, nullptr, false, true);
+ new CanvasPattern(this, srcSurf, repeatMode, nullptr, imgBitmap.IsWriteOnly(), true);
return pat.forget();
}
@@ -2514,13 +2519,14 @@ already_AddRefed<CanvasPattern> CanvasRenderingContext2D::CreatePattern(
nsLayoutUtils::SurfaceFromElement(
element, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE, mTarget);
- if (!res.GetSourceSurface()) {
+ RefPtr<SourceSurface> surface = res.GetSourceSurface();
+ if (!surface) {
return nullptr;
}
RefPtr<CanvasPattern> pat =
- new CanvasPattern(this, res.GetSourceSurface(), repeatMode,
- res.mPrincipal, res.mIsWriteOnly, res.mCORSUsed);
+ new CanvasPattern(this, surface, repeatMode, res.mPrincipal,
+ res.mIsWriteOnly, res.mCORSUsed);
return pat.forget();
}
@@ -4848,8 +4854,8 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
res.mSize = res.mSourceSurface->GetSize();
res.mPrincipal = principal.forget();
- res.mIsWriteOnly = false;
res.mImageRequest = imgRequest.forget();
+ res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal);
return res;
}
@@ -4908,6 +4914,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
+
+ if (canvas->IsWriteOnly()) {
+ SetWriteOnly();
+ }
} else if (aImage.IsImageBitmap()) {
ImageBitmap& imageBitmap = aImage.GetAsImageBitmap();
srcSurf = imageBitmap.PrepareForDrawTarget(mTarget);
@@ -4916,6 +4926,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
return;
}
+ if (imageBitmap.IsWriteOnly()) {
+ SetWriteOnly();
+ }
+
imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
} else {
if (aImage.IsHTMLImageElement()) {
@@ -5421,13 +5435,8 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
// Check only if we have a canvas element; if we were created with a docshell,
// then it's special internal use.
- if (mCanvasElement && mCanvasElement->IsWriteOnly() &&
- // We could ask bindings for the caller type, but they already hand us a
- // JSContext, and we're at least _somewhat_ perf-sensitive (so may not
- // want to compute the caller type in the common non-write-only case), so
- // let's just use what we have.
- !nsContentUtils::CallerHasPermission(aCx,
- nsGkAtoms::all_urlsPermission)) {
+ if (IsWriteOnly() ||
+ (mCanvasElement && !mCanvasElement->CallerCanRead(aCx))) {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
@@ -6029,6 +6038,13 @@ bool CanvasRenderingContext2D::ShouldForceInactiveLayer(
return !aManager->CanUseCanvasLayerForSize(GetSize());
}
+void CanvasRenderingContext2D::SetWriteOnly() {
+ mWriteOnly = true;
+ if (mCanvasElement) {
+ mCanvasElement->SetWriteOnly();
+ }
+}
+
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h
index c436d36..693daf2 100644
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -43,6 +43,7 @@ class
HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
CanvasImageSource;
+class ImageBitmap;
class ImageData;
class StringOrCanvasGradientOrCanvasPattern;
class OwningStringOrCanvasGradientOrCanvasPattern;
@@ -1091,6 +1092,16 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
friend struct CanvasBidiProcessor;
friend class CanvasDrawObserver;
+ friend class ImageBitmap;
+
+ void SetWriteOnly();
+
+ bool IsWriteOnly() const
+ {
+ return mWriteOnly;
+ }
+
+ bool mWriteOnly;
};
size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D* aContext);
diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp
index 5ab2aa7..a76885b 100644
--- a/dom/canvas/CanvasUtils.cpp
+++ b/dom/canvas/CanvasUtils.cpp
@@ -236,7 +236,9 @@ void DoDrawImageSecurityCheck(dom::HTMLCanvasElement* aCanvasElement,
return;
}
- if (aCanvasElement->IsWriteOnly()) return;
+ if (aCanvasElement->IsWriteOnly() && !aCanvasElement->mExpandedReader) {
+ return;
+ }
// If we explicitly set WriteOnly just do it and get out
if (forceWriteOnly) {
@@ -254,6 +256,25 @@ void DoDrawImageSecurityCheck(dom::HTMLCanvasElement* aCanvasElement,
return;
}
+ if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
+ // This is a resource from an extension content script principal.
+
+ if (aCanvasElement->mExpandedReader &&
+ aCanvasElement->mExpandedReader->Subsumes(aPrincipal)) {
+ // This canvas already allows reading from this principal.
+ return;
+ }
+
+ if (!aCanvasElement->mExpandedReader) {
+ // Allow future reads from this same princial only.
+ aCanvasElement->SetWriteOnly(aPrincipal);
+ return;
+ }
+
+ // If we got here, this must be the *second* extension tainting
+ // the canvas. Fall through to mark it WriteOnly for everyone.
+ }
+
aCanvasElement->SetWriteOnly();
}
@@ -275,5 +296,25 @@ bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* /* unused */) {
nsGkAtoms::all_urlsPermission);
}
+bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal) {
+ if (!aPrincipal) {
+ return true;
+ }
+
+ if (!aCORSUsed) {
+ nsIGlobalObject* incumbentSettingsObject = dom::GetIncumbentGlobal();
+ if (NS_WARN_IF(!incumbentSettingsObject)) {
+ return true;
+ }
+
+ nsIPrincipal* principal = incumbentSettingsObject->PrincipalOrNull();
+ if (NS_WARN_IF(!principal) || !(principal->Subsumes(aPrincipal))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace CanvasUtils
} // namespace mozilla
diff --git a/dom/canvas/CanvasUtils.h b/dom/canvas/CanvasUtils.h
index f87a5af..fa5c497 100644
--- a/dom/canvas/CanvasUtils.h
+++ b/dom/canvas/CanvasUtils.h
@@ -11,6 +11,7 @@
#include "mozilla/dom/ToJSValue.h"
#include "jsapi.h"
#include "mozilla/FloatingPoint.h"
+#include "nsLayoutUtils.h"
class nsIPrincipal;
@@ -172,6 +173,10 @@ void DashArrayToJSVal(nsTArray<T>& dashes, JSContext* cx,
}
}
+// returns true if write-only mode must used for this principal based on
+// the incumbent global.
+bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal);
+
} // namespace CanvasUtils
} // namespace mozilla
diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp
index e74df2e..6e579dc 100644
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -407,50 +407,18 @@ class CreateImageFromRawDataInMainThreadSyncTask final
const Maybe<IntRect>& mCropRect;
};
-static bool CheckSecurityForHTMLElements(bool aIsWriteOnly, bool aCORSUsed,
- nsIPrincipal* aPrincipal) {
- if (aIsWriteOnly || !aPrincipal) {
- return false;
- }
-
- if (!aCORSUsed) {
- nsIGlobalObject* incumbentSettingsObject = GetIncumbentGlobal();
- if (NS_WARN_IF(!incumbentSettingsObject)) {
- return false;
- }
-
- nsIPrincipal* principal = incumbentSettingsObject->PrincipalOrNull();
- if (NS_WARN_IF(!principal) || !(principal->Subsumes(aPrincipal))) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool CheckSecurityForHTMLElements(
- const nsLayoutUtils::SurfaceFromElementResult& aRes) {
- return CheckSecurityForHTMLElements(aRes.mIsWriteOnly, aRes.mCORSUsed,
- aRes.mPrincipal);
-}
-
/*
* A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
* security checking.
*/
-template <class HTMLElementType>
+template <class ElementType>
static already_AddRefed<SourceSurface> GetSurfaceFromElement(
- nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv) {
+ nsIGlobalObject* aGlobal, ElementType& aElement, bool* aWriteOnly,
+ ErrorResult& aRv) {
nsLayoutUtils::SurfaceFromElementResult res =
nsLayoutUtils::SurfaceFromElement(
&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
- // check origin-clean
- if (!CheckSecurityForHTMLElements(res)) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return nullptr;
- }
-
RefPtr<SourceSurface> surface = res.GetSourceSurface();
if (NS_WARN_IF(!surface)) {
@@ -458,6 +426,8 @@ static already_AddRefed<SourceSurface> GetSurfaceFromElement(
return nullptr;
}
+ *aWriteOnly = res.mIsWriteOnly;
+
return surface.forget();
}
@@ -485,7 +455,7 @@ static bool HasRasterImage(HTMLImageElement& aImageEl) {
}
ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
- gfxAlphaType aAlphaType)
+ bool aWriteOnly, gfxAlphaType aAlphaType)
: mParent(aGlobal),
mData(aData),
mSurface(nullptr),
@@ -493,7 +463,8 @@ ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height),
mAlphaType(aAlphaType),
mIsCroppingAreaOutSideOfSourceImage(false),
- mAllocatedImageData(false) {
+ mAllocatedImageData(false),
+ mWriteOnly(aWriteOnly) {
MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
mShutdownObserver = new ImageBitmapShutdownObserver(this);
@@ -751,6 +722,7 @@ UniquePtr<ImageBitmapCloneData> ImageBitmap::ToCloneData() const {
RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
result->mSurface = surface->GetDataSurface();
MOZ_ASSERT(result->mSurface);
+ result->mWriteOnly = mWriteOnly;
return Move(result);
}
@@ -759,7 +731,8 @@ UniquePtr<ImageBitmapCloneData> ImageBitmap::ToCloneData() const {
nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData) {
RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mAlphaType);
+ RefPtr<ImageBitmap> ret =
+ new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mAlphaType);
ret->mAllocatedImageData = true;
@@ -775,11 +748,8 @@ UniquePtr<ImageBitmapCloneData> ImageBitmap::ToCloneData() const {
ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
OffscreenCanvas& aOffscreenCanvas,
ErrorResult& aRv) {
- // Check origin-clean.
- if (aOffscreenCanvas.IsWriteOnly()) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return nullptr;
- }
+ // Check write-only mode.
+ bool writeOnly = aOffscreenCanvas.IsWriteOnly();
nsLayoutUtils::SurfaceFromElementResult res =
nsLayoutUtils::SurfaceFromOffscreenCanvas(
@@ -794,7 +764,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
RefPtr<layers::Image> data = CreateImageFromSurface(surface);
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+ RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
ret->mAllocatedImageData = true;
@@ -816,9 +786,12 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
return nullptr;
}
+ bool writeOnly = true;
+
// Get the SourceSurface out from the image element and then do security
// checking.
- RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
+ RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl,
+ &writeOnly, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -832,7 +805,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
return nullptr;
}
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+ RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
// Set the picture rectangle.
if (ret && aCropRect.isSome()) {
@@ -868,10 +841,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
// Check security.
nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
- if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return nullptr;
- }
+ bool writeOnly = CheckWriteOnlySecurity(CORSUsed, principal);
// Create ImageBitmap.
RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
@@ -879,7 +849,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+ RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
// Set the picture rectangle.
if (ret && aCropRect.isSome()) {
@@ -900,13 +870,18 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
return nullptr;
}
- RefPtr<SourceSurface> surface =
- GetSurfaceFromElement(aGlobal, aCanvasEl, aRv);
+ bool writeOnly = true;
+ RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl,
+ &writeOnly, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
+ if (!writeOnly) {
+ writeOnly = aCanvasEl.IsWriteOnly();
+ }
+
// Crop the source surface if needed.
RefPtr<SourceSurface> croppedSurface;
IntRect cropRect = aCropRect.valueOr(IntRect());
@@ -939,7 +914,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
return nullptr;
}
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+ RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
if (needToReportMemoryAllocation) {
ret->mAllocatedImageData = true;
@@ -1001,7 +976,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
}
// Create an ImageBimtap.
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, alphaType);
+ RefPtr<ImageBitmap> ret =
+ new ImageBitmap(aGlobal, data, false /* write-only */, alphaType);
ret->mAllocatedImageData = true;
@@ -1017,11 +993,9 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
/* static */ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
const Maybe<IntRect>& aCropRect, ErrorResult& aRv) {
- // Check origin-clean.
- if (aCanvasCtx.GetCanvas()->IsWriteOnly()) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return nullptr;
- }
+ // Check write-only mode.
+ bool writeOnly =
+ aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly();
RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
@@ -1043,7 +1017,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
return nullptr;
}
- RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+ RefPtr<ImageBitmap> ret =
+ new ImageBitmap(aGlobal, data, writeOnly);
ret->mAllocatedImageData = true;
@@ -1068,7 +1043,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
RefPtr<layers::Image> data = aImageBitmap.mData;
RefPtr<ImageBitmap> ret =
- new ImageBitmap(aGlobal, data, aImageBitmap.mAlphaType);
+ new ImageBitmap(aGlobal, data, aImageBitmap.mWriteOnly,
+ aImageBitmap.mAlphaType);
// Set the picture rectangle.
if (ret && aCropRect.isSome()) {
@@ -1384,14 +1360,19 @@ static void AsyncCreateImageBitmapFromBlob(Promise* aPromise,
uint32_t picRectHeight_;
uint32_t alphaType_;
uint32_t isCroppingAreaOutSideOfSourceImage_;
+ uint32_t writeOnly;
+ uint32_t dummy;
if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
!JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
!JS_ReadUint32Pair(aReader, &alphaType_,
- &isCroppingAreaOutSideOfSourceImage_)) {
+ &isCroppingAreaOutSideOfSourceImage_) ||
+ !JS_ReadUint32Pair(aReader, &writeOnly, &dummy)) {
return nullptr;
}
+ MOZ_ASSERT(dummy == 0);
+
int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
@@ -1415,7 +1396,7 @@ static void AsyncCreateImageBitmapFromBlob(Promise* aPromise,
}
#endif
RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
- RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aParent, img, alphaType);
+ RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aParent, img, !!writeOnly, alphaType);
imageBitmap->mIsCroppingAreaOutSideOfSourceImage =
isCroppingAreaOutSideOfSourceImage_;
@@ -1462,7 +1443,8 @@ static void AsyncCreateImageBitmapFromBlob(Promise* aPromise,
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, alphaType,
- isCroppingAreaOutSideOfSourceImage))) {
+ isCroppingAreaOutSideOfSourceImage)) ||
+ NS_WARN_IF(!JS_WriteUint32Pair(aWriter, aImageBitmap->mWriteOnly, 0))) {
return false;
}
@@ -2003,7 +1985,8 @@ class CreateImageFromBufferSourceRawDataInMainThreadSyncTask final
// Create an ImageBimtap.
// Assume the data from an external buffer is not alpha-premultiplied.
RefPtr<ImageBitmap> imageBitmap =
- new ImageBitmap(aGlobal, data, gfxAlphaType::NonPremult);
+ new ImageBitmap(aGlobal, data, false /* write-only */,
+ gfxAlphaType::NonPremult);
imageBitmap->mAllocatedImageData = true;
@@ -2239,7 +2222,8 @@ void CreateImageBitmapFromBlob::DecodeAndCropBlobCompletedOwningThread(
}
// Create ImageBitmap object.
- RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, aImage);
+ RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, aImage,
+ false /* write-only */);
// Set mIsCroppingAreaOutSideOfSourceImage.
imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(mSourceSize,
diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h
index 1612296..8b4bd12 100644
--- a/dom/canvas/ImageBitmap.h
+++ b/dom/canvas/ImageBitmap.h
@@ -63,6 +63,7 @@ struct ImageBitmapCloneData final {
gfx::IntRect mPictureRect;
gfxAlphaType mAlphaType;
bool mIsCroppingAreaOutSideOfSourceImage;
+ bool mWriteOnly;
};
/*
@@ -160,6 +161,11 @@ class ImageBitmap final : public nsISupports, public nsWrapperCache {
void OnShutdown();
+ bool IsWriteOnly() const
+ {
+ return mWriteOnly;
+ }
+
protected:
/*
* The default value of aIsPremultipliedAlpha is TRUE because that the
@@ -181,6 +187,7 @@ class ImageBitmap final : public nsISupports, public nsWrapperCache {
* CreateInternal(from ImageData) method.
*/
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
+ bool aWriteOnly,
gfxAlphaType aAlphaType = gfxAlphaType::Premult);
virtual ~ImageBitmap();
@@ -271,6 +278,13 @@ class ImageBitmap final : public nsISupports, public nsWrapperCache {
* Whether this object allocated allocated and owns the image data.
*/
bool mAllocatedImageData;
+
+ /*
+ * Write-Only flag is set to true if this image has been generated from a
+ * cross-origin source. This is the opposite of what is called 'origin-clean'
+ * in the spec.
+ */
+ bool mWriteOnly;
};
} // namespace dom
diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp
index 01ce541..1761acc 100644
--- a/dom/canvas/ImageBitmapRenderingContext.cpp
+++ b/dom/canvas/ImageBitmapRenderingContext.cpp
@@ -60,6 +60,10 @@ void ImageBitmapRenderingContext::TransferFromImageBitmap(
return;
}
+ if (aImageBitmap.IsWriteOnly() && mCanvasElement) {
+ mCanvasElement->SetWriteOnly();
+ }
+
Redraw(gfxRect(0, 0, mWidth, mHeight));
}
diff --git a/dom/canvas/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp
index 657ad78..63dbbc0 100644
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -96,7 +96,7 @@ void WebGLBuffer::BufferData(GLenum target, size_t size, const void* data,
if (!ValidateBufferUsageEnum(mContext, funcName, usage)) return;
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
// bug 790879
if (mContext->gl->WorkAroundDriverBugs() && size > INT32_MAX) {
mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h
index 1bfde2f..bc2cab7 100644
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -241,8 +241,9 @@ struct TexImageSourceAdapter final : public TexImageSource {
mPboOffset = pboOffset;
}
- TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult*) {
+ TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult* out_error) {
mImageBitmap = imageBitmap;
+ mOut_error = out_error;
}
TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) {
diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp
index ef29d18..7170fc1 100644
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -12,6 +12,7 @@
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "mozilla/gfx/2D.h"
+#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageData.h"
@@ -222,7 +223,12 @@ static UniquePtr<webgl::TexUnpackBytes> FromPboOffset(
static UniquePtr<webgl::TexUnpackBlob> FromImageBitmap(
WebGLContext* webgl, const char* funcName, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
- const dom::ImageBitmap& imageBitmap) {
+ const dom::ImageBitmap& imageBitmap, ErrorResult* aRv) {
+ if (imageBitmap.IsWriteOnly()) {
+ aRv->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+
UniquePtr<dom::ImageBitmapCloneData> cloneData =
Move(imageBitmap.ToCloneData());
const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
@@ -294,6 +300,14 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
const char* funcName, TexImageTarget target, uint32_t width,
uint32_t height, uint32_t depth, const dom::Element& elem,
ErrorResult* const out_error) {
+ if (elem.IsHTMLElement(nsGkAtoms::canvas)) {
+ const dom::HTMLCanvasElement* canvas = static_cast<const dom::HTMLCanvasElement*>(&elem);
+ if (canvas->IsWriteOnly()) {
+ out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+ }
+
// The canvas spec says that drawImage should draw the first frame of
// animated images. The webgl spec doesn't mention the issue, so we do the
// same as drawImage.
@@ -414,7 +428,7 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::From(
if (src.mImageBitmap) {
return FromImageBitmap(this, funcName, target, width, height, depth,
- *(src.mImageBitmap));
+ *(src.mImageBitmap), src.mOut_error);
}
if (src.mImageData) {
diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html
index 17f050e..81360d2 100644
--- a/dom/canvas/test/test_imagebitmap.html
+++ b/dom/canvas/test/test_imagebitmap.html
@@ -270,13 +270,22 @@ function testSecurityErrors() {
}
function checkPromiseFailedWithSecurityError(p) {
- return p.then( function(reason) { ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); },
- function(reason) { if (reason == "SecurityError: The operation is insecure.") {
- ok(true, reason);
- }
- else {
- ok(false, "Did not get SecurityError with unclean source. Error Message: " + reason);
- }});
+ return p.then(imageBitmap => {
+ ok(!!imageBitmap, "ImageBitmaps are always created");
+ const context = document.createElement("canvas").getContext("2d");
+ context.drawImage(imageBitmap, 0, 0);
+ try {
+ context.getImageData(0, 0, 1, 1);
+ ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully.");
+ } catch (ex) {
+ if (ex == "SecurityError: The operation is insecure.") {
+ ok(true, ex);
+ }
+ else {
+ ok(false, "Did not get SecurityError with unclean source. Error Message: " + ex);
+ }
+ }
+ });
}
return Promise.all([
diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp
index cbb606b..e1a4690 100644
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -39,6 +39,7 @@
#include "mozilla/dom/OSFileSystem.h"
#include "mozilla/dom/Promise.h"
#include "nsNetUtil.h"
+#include "nsReadableUtils.h"
namespace mozilla {
namespace dom {
@@ -644,7 +645,18 @@ void DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
"DataTransfer");
return false;
}
+
+ // Disallow content from creating x-moz-place flavors, so that it cannot
+ // create fake Places smart queries exposing user data, but give a free
+ // pass to WebExtensions.
+ auto principal = BasePrincipal::Cast(aPrincipal);
+ if (!principal->AddonPolicy() &&
+ StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-place"))) {
+ NS_WARNING("Disallowing adding moz-place types to DataTransfer");
+ return false;
+ }
}
+
return true;
}
diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp
index 4b000fa..40e83bc 100644
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -1023,6 +1023,8 @@ void FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv) {
// If we already have a ReadableStreamBody and it has been created by DOM, we
// have to lock it now because it can have been shared with other objects.
if (mReadableStreamBody) {
+ JSAutoCompartment ac(aCx, mOwner->GetGlobalJSObject());
+
JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
if (JS::ReadableStreamGetMode(readableStreamObj) ==
JS::ReadableStreamMode::ExternalSource) {
@@ -1232,6 +1234,8 @@ void FetchBody<Derived>::MaybeTeeReadableStreamBody(
return;
}
+ JSAutoCompartment ac(aCx, mOwner->GetGlobalJSObject());
+
JS::Rooted<JSObject*> stream(aCx, mReadableStreamBody);
// If this is a ReadableStream with an external source, this has been
diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp
index 0417a30..3a4d67a 100644
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -586,9 +586,8 @@ bool HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
void HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
JS::Handle<JS::Value> aParams,
nsAString& aDataURL, ErrorResult& aRv) {
- // do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::CallerHasPermission(
- aCx, nsGkAtoms::all_urlsPermission)) {
+ // mWriteOnly check is redundant, but optimizes for the common case.
+ if (mWriteOnly && !CallerCanRead(aCx)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -761,9 +760,8 @@ void HTMLCanvasElement::ToBlob(JSContext* aCx, BlobCallback& aCallback,
const nsAString& aType,
JS::Handle<JS::Value> aParams,
ErrorResult& aRv) {
- // do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::CallerHasPermission(
- aCx, nsGkAtoms::all_urlsPermission)) {
+ // mWriteOnly check is redundant, but optimizes for the common case.
+ if (mWriteOnly && !CallerCanRead(aCx)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -939,9 +937,38 @@ already_AddRefed<nsISupports> HTMLCanvasElement::MozGetIPCContext(
nsIntSize HTMLCanvasElement::GetSize() { return GetWidthHeight(); }
-bool HTMLCanvasElement::IsWriteOnly() { return mWriteOnly; }
+bool HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; }
+
+void HTMLCanvasElement::SetWriteOnly() {
+ mExpandedReader = nullptr;
+ mWriteOnly = true;
+}
+
+void
+HTMLCanvasElement::SetWriteOnly(nsIPrincipal* aExpandedReader)
+{
+ mExpandedReader = aExpandedReader;
+ mWriteOnly = true;
+}
+
+bool
+HTMLCanvasElement::CallerCanRead(JSContext* aCx)
+{
+ if (!mWriteOnly) {
+ return true;
+ }
-void HTMLCanvasElement::SetWriteOnly() { mWriteOnly = true; }
+ nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx);
+
+ // If mExpandedReader is set, this canvas was tainted only by
+ // mExpandedReader's resources. So allow reading if the subject
+ // principal subsumes mExpandedReader.
+ if (mExpandedReader && prin->Subsumes(mExpandedReader)) {
+ return true;
+ }
+
+ return nsContentUtils::PrincipalHasPermission(prin, nsGkAtoms::all_urlsPermission);
+}
void HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect) {
// We don't need to flush anything here; if there's no frame or if
diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h
index 76c1cbf..99b9be8 100644
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -201,7 +201,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
/**
* Determine whether the canvas is write-only.
*/
- bool IsWriteOnly();
+ bool IsWriteOnly() const;
/**
* Force the canvas to be write-only.
@@ -209,6 +209,12 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
void SetWriteOnly();
/**
+ * Force the canvas to be write-only, except for readers from
+ * a specific extension's content script expanded principal.
+ */
+ void SetWriteOnly(nsIPrincipal* aExpandedReader);
+
+ /**
* Notify that some canvas content has changed and the window may
* need to be updated. aDamageRect is in canvas coordinates.
*/
@@ -369,7 +375,14 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
// We also transitively set it when script paints a canvas which
// is itself write-only.
bool mWriteOnly;
-
+
+ // When this canvas is (only) tainted by an image from an extension
+ // content script, allow reads from the same extension afterwards.
+ RefPtr<nsIPrincipal> mExpandedReader;
+
+ // Determines if the caller should be able to read the content.
+ bool CallerCanRead(JSContext* aCx);
+
bool IsPrintCallbackDone();
void HandlePrintCallback(nsPresContext::nsPresContextType aType);
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index c64e117..d71da6b 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -21275,32 +21275,38 @@ void TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
MOZ_ASSERT(mTransaction);
if (NS_WARN_IF(IsActorDestroyed())) {
- // Don't send any notifications if the actor was destroyed already.
+ // Normally we wouldn't need to send any notifications if the actor was
+ // already destroyed, but this can be a VersionChangeOp which needs to
+ // notify its parent operation (OpenDatabaseOp) about the failure.
+ // So SendFailureResult needs to be called even when the actor was
+ // destroyed. Normal operations redundantly check if the actor was
+ // destroyed in SendSuccessResult and SendFailureResult, therefore it's
+ // ok to call it in all cases here.
if (NS_SUCCEEDED(mResultCode)) {
IDB_REPORT_INTERNAL_ERR();
mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
- } else {
- if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) {
- // Aborted transactions always see their requests fail with ABORT_ERR,
- // even if the request succeeded or failed with another error.
- mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
- } else if (NS_SUCCEEDED(mResultCode)) {
- if (aSendPreprocessInfo) {
- // This should not release the IPDL reference.
- mResultCode = SendPreprocessInfo();
- } else {
- // This may release the IPDL reference.
- mResultCode = SendSuccessResult();
- }
+ } else if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) {
+ // Aborted transactions always see their requests fail with ABORT_ERR,
+ // even if the request succeeded or failed with another error.
+ mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
+ }
+
+ if (NS_SUCCEEDED(mResultCode)) {
+ if (aSendPreprocessInfo) {
+ // This should not release the IPDL reference.
+ mResultCode = SendPreprocessInfo();
+ } else {
+ // This may release the IPDL reference.
+ mResultCode = SendSuccessResult();
}
+ }
- if (NS_FAILED(mResultCode)) {
- // This should definitely release the IPDL reference.
- if (!SendFailureResult(mResultCode)) {
- // Abort the transaction.
- mTransaction->Abort(mResultCode, /* aForce */ false);
- }
+ if (NS_FAILED(mResultCode)) {
+ // This should definitely release the IPDL reference.
+ if (!SendFailureResult(mResultCode)) {
+ // Abort the transaction.
+ mTransaction->Abort(mResultCode, /* aForce */ false);
}
}
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index d979d15..ae164c7 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4505,6 +4505,9 @@ mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
case gfx::CrashGuardType::D3D11Video:
guard = MakeUnique<gfx::D3D11VideoCrashGuard>(this);
break;
+ case gfx::CrashGuardType::WMFVPXVideo:
+ guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
+ break;
default:
MOZ_ASSERT_UNREACHABLE("unknown crash guard type");
return IPC_FAIL_NO_REASON(this);
diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp
index 32a5e9a..50e2bb9 100644
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -5,8 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioConverter.h"
-#include <string.h>
#include <speex/speex_resampler.h>
+#include <string.h>
#include <cmath>
/*
@@ -131,24 +131,26 @@ static inline int16_t clipTo15(int32_t aX) {
size_t AudioConverter::DownmixAudio(void* aOut, const void* aIn,
size_t aFrames) const {
- MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
- mIn.Format() == AudioConfig::FORMAT_FLT);
- MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
- MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
- "Can only downmix input data in SMPTE layout");
- MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
- mOut.Layout() == AudioConfig::ChannelLayout(1));
+ MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
+ mIn.Format() == AudioConfig::FORMAT_FLT);
+ MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() >= mOut.Channels());
+ MOZ_DIAGNOSTIC_ASSERT(
+ mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
+ "Can only downmix input data in SMPTE layout");
+ MOZ_DIAGNOSTIC_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
+ mOut.Layout() == AudioConfig::ChannelLayout(1));
- uint32_t channels = mIn.Channels();
+ uint32_t inChannels = mIn.Channels();
+ uint32_t outChannels = mOut.Channels();
- if (channels == 1 && mOut.Channels() == 1) {
+ if (inChannels == outChannels) {
if (aOut != aIn) {
memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
return aFrames;
}
- if (channels > 2) {
+ if (inChannels > 2) {
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
// Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows
// 5-8.
@@ -193,14 +195,16 @@ size_t AudioConverter::DownmixAudio(void* aOut, const void* aIn,
for (uint32_t i = 0; i < aFrames; i++) {
float sampL = 0.0;
float sampR = 0.0;
- for (uint32_t j = 0; j < channels; j++) {
- sampL +=
- in[i * mIn.Channels() + j] * dmatrix[mIn.Channels() - 3][j][0];
- sampR +=
- in[i * mIn.Channels() + j] * dmatrix[mIn.Channels() - 3][j][1];
+ for (uint32_t j = 0; j < inChannels; j++) {
+ sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0];
+ sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1];
+ }
+ if (outChannels == 2) {
+ *out++ = sampL;
+ *out++ = sampR;
+ } else {
+ *out++ = (sampL + sampR) * 0.5;
}
- *out++ = sampL;
- *out++ = sampR;
}
} else if (mIn.Format() == AudioConfig::FORMAT_S16) {
// Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows
@@ -240,45 +244,46 @@ size_t AudioConverter::DownmixAudio(void* aOut, const void* aIn,
for (uint32_t i = 0; i < aFrames; i++) {
int32_t sampL = 0;
int32_t sampR = 0;
- for (uint32_t j = 0; j < channels; j++) {
- sampL += in[i * channels + j] * dmatrix[channels - 3][j][0];
- sampR += in[i * channels + j] * dmatrix[channels - 3][j][1];
+ for (uint32_t j = 0; j < inChannels; j++) {
+ sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0];
+ sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1];
+ }
+ sampL = clipTo15((sampL + 8192) >> 14);
+ sampR = clipTo15((sampR + 8192) >> 14);
+ if (outChannels == 2) {
+ *out++ = sampL;
+ *out++ = sampR;
+ } else {
+ *out++ = (sampL + sampR) * 0.5;
}
- *out++ = clipTo15((sampL + 8192) >> 14);
- *out++ = clipTo15((sampR + 8192) >> 14);
}
} else {
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
}
-
- // If we are to continue downmixing to mono, start working on the output
- // buffer.
- aIn = aOut;
- channels = 2;
+ return aFrames;
}
- if (mOut.Channels() == 1) {
- if (mIn.Format() == AudioConfig::FORMAT_FLT) {
- const float* in = static_cast<const float*>(aIn);
- float* out = static_cast<float*>(aOut);
- for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
- float sample = 0.0;
- // The sample of the buffer would be interleaved.
- sample = (in[fIdx * channels] + in[fIdx * channels + 1]) * 0.5;
- *out++ = sample;
- }
- } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
- const int16_t* in = static_cast<const int16_t*>(aIn);
- int16_t* out = static_cast<int16_t*>(aOut);
- for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
- int32_t sample = 0.0;
- // The sample of the buffer would be interleaved.
- sample = (in[fIdx * channels] + in[fIdx * channels + 1]) * 0.5;
- *out++ = sample;
- }
- } else {
- MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
+ MOZ_DIAGNOSTIC_ASSERT(inChannels == 2 && outChannels == 1);
+ if (mIn.Format() == AudioConfig::FORMAT_FLT) {
+ const float* in = static_cast<const float*>(aIn);
+ float* out = static_cast<float*>(aOut);
+ for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
+ float sample = 0.0;
+ // The sample of the buffer would be interleaved.
+ sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5;
+ *out++ = sample;
}
+ } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
+ const int16_t* in = static_cast<const int16_t*>(aIn);
+ int16_t* out = static_cast<int16_t*>(aOut);
+ for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) {
+ int32_t sample = 0.0;
+ // The sample of the buffer would be interleaved.
+ sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5;
+ *out++ = sample;
+ }
+ } else {
+ MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
}
return aFrames;
}
diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h
index 7f8191c..01db78a 100644
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -154,7 +154,6 @@ class MediaPrefs final {
DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false);
DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure",
DecoderDoctorWMFDisabledIsFailure, bool, false);
- DECL_MEDIA_PREF("media.wmf.vp9.enabled", PDMWMFVP9DecoderEnabled, bool, true);
#endif
DECL_MEDIA_PREF("media.decoder.recycle.enabled", MediaDecoderCheckRecycling,
bool, false);
diff --git a/dom/media/eme/CDMProxy.h b/dom/media/eme/CDMProxy.h
index 53e3a37..d0f7181 100644
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -82,7 +82,7 @@ class CDMProxy {
// Main thread only.
CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
bool aDistinctiveIdentifierRequired, bool aPersistentStateRequired,
- nsIEventTarget* aMainThread)
+ nsISerialEventTarget* aMainThread)
: mKeys(aKeys),
mKeySystem(aKeySystem),
mCapabilites("CDMProxy::mCDMCaps"),
@@ -272,7 +272,7 @@ class CDMProxy {
const bool mPersistentStateRequired;
// The main thread associated with the root document.
- const nsCOMPtr<nsIEventTarget> mMainThread;
+ const nsCOMPtr<nsISerialEventTarget> mMainThread;
};
} // namespace mozilla
diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp
index 0434418..de2953a 100644
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -307,7 +307,7 @@ class MediaKeysGMPCrashHelper : public GMPCrashHelper {
};
already_AddRefed<CDMProxy> MediaKeys::CreateCDMProxy(
- nsIEventTarget* aMainThread) {
+ nsISerialEventTarget* aMainThread) {
RefPtr<CDMProxy> proxy;
#ifdef MOZ_WIDGET_ANDROID
if (IsWidevineKeySystem(mKeySystem)) {
diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h
index 8661d54..128c968 100644
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -148,7 +148,7 @@ class MediaKeys final : public nsISupports,
// Instantiate CDMProxy instance.
// It could be MediaDrmCDMProxy (Widevine on Fennec) or ChromiumCDMProxy (the
// rest).
- already_AddRefed<CDMProxy> CreateCDMProxy(nsIEventTarget* aMainThread);
+ already_AddRefed<CDMProxy> CreateCDMProxy(nsISerialEventTarget* aMainThread);
// Removes promise from mPromises, and returns it.
already_AddRefed<DetailedPromise> RetrievePromise(PromiseId aId);
diff --git a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
index f8a81e8..3bb8678 100644
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
@@ -28,7 +28,7 @@ MediaDrmCDMProxy::MediaDrmCDMProxy(dom::MediaKeys* aKeys,
const nsAString& aKeySystem,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired,
- nsIEventTarget* aMainThread)
+ nsISerialEventTarget* aMainThread)
: CDMProxy(aKeys, aKeySystem, aDistinctiveIdentifierRequired,
aPersistentStateRequired, aMainThread),
mCDM(nullptr),
diff --git a/dom/media/eme/mediadrm/MediaDrmCDMProxy.h b/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
index cc0d4f2..92463ed 100644
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
@@ -31,7 +31,8 @@ class MediaDrmCDMProxy : public CDMProxy {
MediaDrmCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
bool aDistinctiveIdentifierRequired,
- bool aPersistentStateRequired, nsIEventTarget* aMainThread);
+ bool aPersistentStateRequired,
+ nsISerialEventTarget* aMainThread);
void Init(PromiseId aPromiseId, const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
diff --git a/dom/media/gmp/ChromiumCDMParent.cpp b/dom/media/gmp/ChromiumCDMParent.cpp
index 5d4534f..5d8a3e2 100644
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -61,8 +61,6 @@ RefPtr<ChromiumCDMParent::InitPromise> ChromiumCDMParent::Init(
!aMainThread ? "true" : "false")),
__func__);
}
- mCDMCallback = aCDMCallback;
- mMainThread = aMainThread;
RefPtr<ChromiumCDMParent::InitPromise> promise =
mInitPromise.Ensure(__func__);
@@ -70,7 +68,7 @@ RefPtr<ChromiumCDMParent::InitPromise> ChromiumCDMParent::Init(
SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState)
->Then(
AbstractThread::GetCurrent(), __func__,
- [self](bool aSuccess) {
+ [self, aCDMCallback](bool aSuccess) {
if (!aSuccess) {
GMP_LOG(
"ChromiumCDMParent::Init() failed with callback from "
@@ -84,6 +82,7 @@ RefPtr<ChromiumCDMParent::InitPromise> ChromiumCDMParent::Init(
}
GMP_LOG(
"ChromiumCDMParent::Init() succeeded with callback from child");
+ self->mCDMCallback = aCDMCallback;
self->mInitPromise.ResolveIfExists(true /* unused */, __func__);
},
[self](ResponseRejectReason aReason) {
diff --git a/dom/media/gmp/ChromiumCDMParent.h b/dom/media/gmp/ChromiumCDMParent.h
index fd7dcc2..61dfc92 100644
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -179,9 +179,6 @@ class ChromiumCDMParent final : public PChromiumCDMParent,
// life time of this object, but never more than one active at once.
uint32_t mMaxRefFrames = 0;
ReorderQueue mReorderQueue;
-
- // The main thread associated with the root document. Must be set in Init().
- nsCOMPtr<nsIEventTarget> mMainThread;
};
} // namespace gmp
diff --git a/dom/media/gmp/ChromiumCDMProxy.cpp b/dom/media/gmp/ChromiumCDMProxy.cpp
index f00b4bc..4af9473 100644
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -22,17 +22,18 @@ ChromiumCDMProxy::ChromiumCDMProxy(dom::MediaKeys* aKeys,
GMPCrashHelper* aCrashHelper,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired,
- nsIEventTarget* aMainThread)
+ nsISerialEventTarget* aMainThread)
: CDMProxy(aKeys, aKeySystem, aDistinctiveIdentifierRequired,
aPersistentStateRequired, aMainThread),
mCrashHelper(aCrashHelper),
mCDMMutex("ChromiumCDMProxy"),
mGMPThread(GetGMPAbstractThread()) {
MOZ_ASSERT(NS_IsMainThread());
- MOZ_COUNT_CTOR(ChromiumCDMProxy);
}
-ChromiumCDMProxy::~ChromiumCDMProxy() { MOZ_COUNT_DTOR(ChromiumCDMProxy); }
+ChromiumCDMProxy::~ChromiumCDMProxy() {
+ EME_LOG("ChromiumCDMProxy::~ChromiumCDMProxy(this=%p)", this);
+}
void ChromiumCDMProxy::Init(PromiseId aPromiseId, const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
@@ -90,13 +91,25 @@ void ChromiumCDMProxy::Init(PromiseId aPromiseId, const nsAString& aOrigin,
cdm->Init(self->mCallback.get(),
self->mDistinctiveIdentifierRequired,
self->mPersistentStateRequired, self->mMainThread)
- ->Then(thread, __func__,
+ ->Then(self->mMainThread, __func__,
[self, aPromiseId, cdm](bool /* unused */) {
// CDM init succeeded
{
MutexAutoLock lock(self->mCDMMutex);
self->mCDM = cdm;
}
+ if (self->mIsShutdown) {
+ self->RejectPromise(
+ aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING(
+ "ChromiumCDMProxy shutdown during "
+ "ChromiumCDMProxy::Init"));
+ // If shutdown happened while waiting to init, we
+ // need to explicitly shutdown the CDM to avoid it
+ // referencing this proxy which is on its way out.
+ self->ShutdownCDMIfExists();
+ return;
+ }
self->OnCDMCreated(aPromiseId);
},
[self, aPromiseId](MediaResult aResult) {
@@ -118,13 +131,6 @@ void ChromiumCDMProxy::OnCDMCreated(uint32_t aPromiseId) {
EME_LOG("ChromiumCDMProxy::OnCDMCreated(pid=%u) isMainThread=%d this=%p",
aPromiseId, NS_IsMainThread(), this);
- if (!NS_IsMainThread()) {
- mMainThread->Dispatch(NewRunnableMethod<PromiseId>(
- "ChromiumCDMProxy::OnCDMCreated", this,
- &ChromiumCDMProxy::OnCDMCreated, aPromiseId),
- NS_DISPATCH_NORMAL);
- return;
- }
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
@@ -141,6 +147,29 @@ void ChromiumCDMProxy::OnCDMCreated(uint32_t aPromiseId) {
}
}
+void ChromiumCDMProxy::ShutdownCDMIfExists() {
+ EME_LOG(
+ "ChromiumCDMProxy::ShutdownCDMIfExists(this=%p) mCDM=%p, mIsShutdown=%s",
+ this, mCDM.get(), mIsShutdown ? "true" : "false");
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mGMPThread);
+ MOZ_ASSERT(mIsShutdown,
+ "Should only shutdown the CDM if the proxy is shutting down");
+ RefPtr<gmp::ChromiumCDMParent> cdm;
+ {
+ MutexAutoLock lock(mCDMMutex);
+ cdm.swap(mCDM);
+ }
+ if (cdm) {
+ // We need to keep this proxy alive until the parent has finished its
+ // Shutdown (as it may still try to use the proxy until then).
+ RefPtr<ChromiumCDMProxy> self(this);
+ nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
+ "ChromiumCDMProxy::Shutdown", [self, cdm]() { cdm->Shutdown(); });
+ mGMPThread->Dispatch(task.forget());
+ }
+}
+
#ifdef DEBUG
bool ChromiumCDMProxy::IsOnOwnerThread() {
return mGMPThread->IsCurrentThreadIn();
@@ -294,21 +323,14 @@ void ChromiumCDMProxy::RemoveSession(const nsAString& aSessionId,
void ChromiumCDMProxy::Shutdown() {
MOZ_ASSERT(NS_IsMainThread());
- EME_LOG("ChromiumCDMProxy::Shutdown()");
- mKeys.Clear();
- RefPtr<gmp::ChromiumCDMParent> cdm;
- {
- MutexAutoLock lock(mCDMMutex);
- cdm.swap(mCDM);
- }
- if (cdm) {
- // We need to keep this proxy alive until the parent has finished its
- // Shutdown (as it may still try to use the proxy until then).
- RefPtr<ChromiumCDMProxy> self(this);
- nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
- "ChromiumCDMProxy::Shutdown", [self, cdm]() { cdm->Shutdown(); });
- mGMPThread->Dispatch(task.forget());
+ EME_LOG("ChromiumCDMProxy::Shutdown(this=%p) mCDM=%p, mIsShutdown=%s", this,
+ mCDM.get(), mIsShutdown ? "true" : "false");
+ if (mIsShutdown) {
+ return;
}
+ mIsShutdown = true;
+ mKeys.Clear();
+ ShutdownCDMIfExists();
}
void ChromiumCDMProxy::RejectPromise(PromiseId aId, nsresult aCode,
diff --git a/dom/media/gmp/ChromiumCDMProxy.h b/dom/media/gmp/ChromiumCDMProxy.h
index 13fa28b..9200969 100644
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -7,8 +7,8 @@
#ifndef ChromiumCDMProxy_h_
#define ChromiumCDMProxy_h_
-#include "mozilla/CDMProxy.h"
#include "mozilla/AbstractThread.h"
+#include "mozilla/CDMProxy.h"
#include "ChromiumCDMParent.h"
namespace mozilla {
@@ -23,7 +23,7 @@ class ChromiumCDMProxy : public CDMProxy {
ChromiumCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
GMPCrashHelper* aCrashHelper,
bool aAllowDistinctiveIdentifier, bool aAllowPersistentState,
- nsIEventTarget* aMainThread);
+ nsISerialEventTarget* aMainThread);
void Init(PromiseId aPromiseId, const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
@@ -108,9 +108,14 @@ class ChromiumCDMProxy : public CDMProxy {
private:
void OnCDMCreated(uint32_t aPromiseId);
+ void ShutdownCDMIfExists();
~ChromiumCDMProxy();
+ // True if Shutdown() has been called. Should only be read and written on
+ // main thread.
+ bool mIsShutdown = false;
+
GMPCrashHelper* mCrashHelper;
Mutex mCDMMutex;
diff --git a/dom/media/ipc/VideoDecoderParent.cpp b/dom/media/ipc/VideoDecoderParent.cpp
index 6c95f31..24eb234 100644
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -11,6 +11,7 @@
#include "mozilla/layers/VideoBridgeChild.h"
#include "mozilla/layers/ImageClient.h"
#include "MediaInfo.h"
+#include "PDMFactory.h"
#include "VideoDecoderManagerParent.h"
#ifdef XP_WIN
#include "WMFDecoderModule.h"
@@ -61,9 +62,11 @@ VideoDecoderParent::VideoDecoderParent(
mKnowsCompositor->IdentifyTextureHost(aIdentifier);
#ifdef XP_WIN
+ // Ensure everything is properly initialized on the right thread.
+ PDMFactory::EnsureInit();
+
// TODO: Ideally we wouldn't hardcode the WMF PDM, and we'd use the normal PDM
// factory logic for picking a decoder.
- WMFDecoderModule::Init();
RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
pdm->Startup();
diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp
index 2211a1a..c8e7df2 100644
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -152,7 +152,8 @@ PDMFactory::PDMFactory() {
PDMFactory::~PDMFactory() {}
-void PDMFactory::EnsureInit() const {
+/* static */
+void PDMFactory::EnsureInit() {
{
StaticMutexAutoLock mon(sMonitor);
if (sInstance) {
diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h
index fb6065b..fcd89dc 100644
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -45,6 +45,8 @@ class PDMFactory final {
// This is called on the decode task queue.
void SetCDMProxy(CDMProxy* aProxy);
+ static void EnsureInit();
+
static constexpr int kYUV400 = 0;
static constexpr int kYUV420 = 1;
static constexpr int kYUV422 = 2;
@@ -72,7 +74,6 @@ class PDMFactory final {
bool mFFmpegFailedToLoad = false;
bool mGMPPDMFailedToStartup = false;
- void EnsureInit() const;
template <class T>
friend class StaticAutoPtr;
static StaticAutoPtr<PDMFactoryImpl> sInstance;
diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp
index 8db98b4..98b70b0 100644
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -5,6 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WMFDecoderModule.h"
+#include <algorithm>
+#include <vector>
+#include "DriverCrashGuard.h"
#include "GfxDriverInfo.h"
#include "MFTDecoder.h"
#include "MP4Decoder.h"
@@ -22,22 +25,23 @@
#include "mozilla/StaticMutex.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/mscom/EnsureMTA.h"
#include "nsAutoPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIGfxInfo.h"
#include "nsIWindowsRegKey.h"
+#include "nsIXULRuntime.h"
#include "nsServiceManagerUtils.h"
#include "nsWindowsHelpers.h"
#include "prsystem.h"
#include "nsIXULRuntime.h"
-#include "mozilla/mscom/EnsureMTA.h"
extern const GUID CLSID_WebmMfVpxDec;
-extern const GUID CLSID_AMDWebmMfVp9Dec;
namespace mozilla {
static Atomic<bool> sDXVAEnabled(false);
+static Atomic<bool> sUsableVPXMFT(false);
WMFDecoderModule::~WMFDecoderModule() {
if (mWMFInitialized) {
@@ -46,22 +50,54 @@ WMFDecoderModule::~WMFDecoderModule() {
}
}
+static bool CanCreateMFTDecoder(const GUID& aGuid) {
+ // The IMFTransform interface used by MFTDecoder is documented to require to
+ // run on an MTA thread.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
+ // Note: our normal SharedThreadPool task queues are initialized to MTA, but
+ // the main thread (which calls in here from our CanPlayType implementation)
+ // is not.
+ bool canCreateDecoder = false;
+ mozilla::mscom::EnsureMTA([&]() -> void {
+ if (FAILED(wmf::MFStartup())) {
+ return;
+ }
+ RefPtr<MFTDecoder> decoder(new MFTDecoder());
+ canCreateDecoder = SUCCEEDED(decoder->Create(aGuid));
+ wmf::MFShutdown();
+ });
+ return canCreateDecoder;
+}
+
/* static */
void WMFDecoderModule::Init() {
+ MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
+ bool testForVPx;
if (XRE_IsContentProcess()) {
// If we're in the content process and the UseGPUDecoder pref is set, it
// means that we've given up on the GPU process (it's been crashing) so we
// should disable DXVA
sDXVAEnabled = !MediaPrefs::PDMUseGPUDecoder();
+ // We need to test for VPX in the content process as the GPUDecoderModule
+ // directly calls WMFDecoderModule::Supports in the content process.
+ // This unnecessary requirement will be fixed in bug 1534815.
+ testForVPx = true;
} else if (XRE_IsGPUProcess()) {
// Always allow DXVA in the GPU process.
- sDXVAEnabled = true;
+ testForVPx = sDXVAEnabled = true;
} else {
// Only allow DXVA in the UI process if we aren't in e10s Firefox
- sDXVAEnabled = !mozilla::BrowserTabsRemoteAutostart();
+ testForVPx = sDXVAEnabled = !mozilla::BrowserTabsRemoteAutostart();
}
sDXVAEnabled = sDXVAEnabled && gfx::gfxVars::CanUseHardwareVideoDecoding();
+ testForVPx = testForVPx && gfx::gfxVars::CanUseHardwareVideoDecoding();
+ if (testForVPx && gfxPrefs::PDMWMFVP9DecoderEnabled()) {
+ gfx::WMFVPXVideoCrashGuard guard;
+ if (!guard.Crashed()) {
+ sUsableVPXMFT = CanCreateMFTDecoder(CLSID_WebmMfVpxDec);
+ }
+ }
}
/* static */
@@ -122,25 +158,6 @@ already_AddRefed<MediaDataDecoder> WMFDecoderModule::CreateAudioDecoder(
return decoder.forget();
}
-static bool CanCreateMFTDecoder(const GUID& aGuid) {
- // The IMFTransform interface used by MFTDecoder is documented to require to
- // run on an MTA thread.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
- // Note: our normal SharedThreadPool task queues are initialized to MTA, but
- // the main thread (which calls in here from our CanPlayType implementation)
- // is not.
- bool canCreateDecoder = false;
- mozilla::mscom::EnsureMTA([&]() -> void {
- if (FAILED(wmf::MFStartup())) {
- return;
- }
- RefPtr<MFTDecoder> decoder(new MFTDecoder());
- canCreateDecoder = SUCCEEDED(decoder->Create(aGuid));
- wmf::MFShutdown();
- });
- return canCreateDecoder;
-}
-
template <const GUID& aGuid>
static bool CanCreateWMFDecoder() {
static StaticMutex sMutex;
@@ -188,18 +205,12 @@ bool WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>()) {
return true;
}
- if (MediaPrefs::PDMWMFVP9DecoderEnabled()) {
+ if (sUsableVPXMFT) {
static const uint32_t VP8_USABLE_BUILD = 16287;
- if (VPXDecoder::IsVP8(aTrackInfo.mMimeType) &&
- IsWindowsBuildOrLater(VP8_USABLE_BUILD) &&
- CanCreateWMFDecoder<CLSID_WebmMfVpxDec>()) {
- return true;
- }
- if (VPXDecoder::IsVP9(aTrackInfo.mMimeType) &&
- ((gfxPrefs::PDMWMFAMDVP9DecoderEnabled() &&
- CanCreateWMFDecoder<CLSID_AMDWebmMfVp9Dec>()) ||
- CanCreateWMFDecoder<CLSID_WebmMfVpxDec>())) {
- return true;
+ if ((VPXDecoder::IsVP8(aTrackInfo.mMimeType) &&
+ IsWindowsBuildOrLater(VP8_USABLE_BUILD)) ||
+ VPXDecoder::IsVP9(aTrackInfo.mMimeType)) {
+ return CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
}
}
diff --git a/dom/tests/mochitest/general/test_clipboard_disallowed.html b/dom/tests/mochitest/general/test_clipboard_disallowed.html
index 71ba09d..0b5422d 100644
--- a/dom/tests/mochitest/general/test_clipboard_disallowed.html
+++ b/dom/tests/mochitest/general/test_clipboard_disallowed.html
@@ -48,6 +48,21 @@ function checkAllowed(event)
exception = null;
try {
+ clipboardData.mozSetDataAt("text/x-moz-place", "Test", 0);
+ } catch(ex) {
+ exception = ex;
+ }
+ is(String(exception).indexOf("SecurityError"), 0, "Cannot set place");
+ exception = null;
+ try {
+ clipboardData.mozSetDataAt("text/x-moz-place-container", "Test", 0);
+ } catch(ex) {
+ exception = ex;
+ }
+ is(String(exception).indexOf("SecurityError"), 0, "Cannot set place container");
+
+ exception = null;
+ try {
clipboardData.mozSetDataAt("application/something", "This is data", 0);
} catch(ex) {
exception = ex;
diff --git a/dom/u2f/U2F.cpp b/dom/u2f/U2F.cpp
index abc0a9b..478c48b 100644
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -184,7 +184,7 @@ U2F::~U2F() {
MOZ_ASSERT(NS_IsMainThread());
if (mTransaction.isSome()) {
- RejectTransaction(NS_ERROR_ABORT);
+ ClearTransaction();
}
if (mChild) {
diff --git a/dom/webauthn/WebAuthnManager.cpp b/dom/webauthn/WebAuthnManager.cpp
index aa0b294..0dcfa51 100644
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -192,7 +192,7 @@ WebAuthnManager::~WebAuthnManager() {
MOZ_ASSERT(NS_IsMainThread());
if (mTransaction.isSome()) {
- RejectTransaction(NS_ERROR_ABORT);
+ ClearTransaction();
}
if (mChild) {