closes #557: M1502799 (M1526218, M1528909, M1540221, partial M1484980 with future expansion
This commit is contained in:
parent
612f0f7c3c
commit
695f6a162d
|
@ -966,6 +966,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||||
, mIsCapturedFrameInvalid(false)
|
, mIsCapturedFrameInvalid(false)
|
||||||
, mPathTransformWillUpdate(false)
|
, mPathTransformWillUpdate(false)
|
||||||
, mInvalidateCount(0)
|
, mInvalidateCount(0)
|
||||||
|
, mWriteOnly(false)
|
||||||
{
|
{
|
||||||
sNumLivingContexts++;
|
sNumLivingContexts++;
|
||||||
|
|
||||||
|
@ -1998,7 +1999,11 @@ CanvasRenderingContext2D::SetStyleFromUnion(const StringOrCanvasGradientOrCanvas
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.IsCanvasPattern()) {
|
if (value.IsCanvasPattern()) {
|
||||||
SetStyleFromPattern(value.GetAsCanvasPattern(), whichStyle);
|
CanvasPattern& pattern = value.GetAsCanvasPattern();
|
||||||
|
SetStyleFromPattern(pattern, whichStyle);
|
||||||
|
if (pattern.mForceWriteOnly) {
|
||||||
|
SetWriteOnly();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2121,7 +2126,7 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& source,
|
||||||
// nullptr and set CORSUsed to true for passing the security check in
|
// nullptr and set CORSUsed to true for passing the security check in
|
||||||
// CanvasUtils::DoDrawImageSecurityCheck().
|
// CanvasUtils::DoDrawImageSecurityCheck().
|
||||||
RefPtr<CanvasPattern> pat =
|
RefPtr<CanvasPattern> pat =
|
||||||
new CanvasPattern(this, srcSurf, repeatMode, nullptr, false, true);
|
new CanvasPattern(this, srcSurf, repeatMode, nullptr, imgBitmap.IsWriteOnly(), true);
|
||||||
|
|
||||||
return pat.forget();
|
return pat.forget();
|
||||||
}
|
}
|
||||||
|
@ -2134,12 +2139,13 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& source,
|
||||||
nsLayoutUtils::SurfaceFromElement(htmlElement,
|
nsLayoutUtils::SurfaceFromElement(htmlElement,
|
||||||
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
|
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
|
||||||
|
|
||||||
if (!res.GetSourceSurface()) {
|
RefPtr<SourceSurface> surface = res.GetSourceSurface();
|
||||||
|
if (!surface) {
|
||||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<CanvasPattern> pat = new CanvasPattern(this, res.GetSourceSurface(), repeatMode,
|
RefPtr<CanvasPattern> pat = new CanvasPattern(this, surface, repeatMode,
|
||||||
res.mPrincipal, res.mIsWriteOnly,
|
res.mPrincipal, res.mIsWriteOnly,
|
||||||
res.mCORSUsed);
|
res.mCORSUsed);
|
||||||
return pat.forget();
|
return pat.forget();
|
||||||
|
@ -4370,8 +4376,8 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement)
|
||||||
|
|
||||||
res.mSize = res.mSourceSurface->GetSize();
|
res.mSize = res.mSourceSurface->GetSize();
|
||||||
res.mPrincipal = principal.forget();
|
res.mPrincipal = principal.forget();
|
||||||
res.mIsWriteOnly = false;
|
|
||||||
res.mImageRequest = imgRequest.forget();
|
res.mImageRequest = imgRequest.forget();
|
||||||
|
res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -4446,6 +4452,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
|
||||||
error.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
error.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canvas->IsWriteOnly()) {
|
||||||
|
SetWriteOnly();
|
||||||
|
}
|
||||||
} else if (image.IsImageBitmap()) {
|
} else if (image.IsImageBitmap()) {
|
||||||
ImageBitmap& imageBitmap = image.GetAsImageBitmap();
|
ImageBitmap& imageBitmap = image.GetAsImageBitmap();
|
||||||
srcSurf = imageBitmap.PrepareForDrawTarget(mTarget);
|
srcSurf = imageBitmap.PrepareForDrawTarget(mTarget);
|
||||||
|
@ -4454,6 +4464,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imageBitmap.IsWriteOnly()) {
|
||||||
|
SetWriteOnly();
|
||||||
|
}
|
||||||
|
|
||||||
imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
|
imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -5146,9 +5160,8 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
|
||||||
|
|
||||||
// Check only if we have a canvas element; if we were created with a docshell,
|
// Check only if we have a canvas element; if we were created with a docshell,
|
||||||
// then it's special internal use.
|
// then it's special internal use.
|
||||||
if (mCanvasElement && mCanvasElement->IsWriteOnly() &&
|
if (IsWriteOnly() ||
|
||||||
!nsContentUtils::IsCallerChrome())
|
(mCanvasElement && !mCanvasElement->CallerCanRead(aCx))) {
|
||||||
{
|
|
||||||
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
|
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
|
||||||
error.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
error.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -5754,6 +5767,13 @@ CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager *aManager)
|
||||||
return !aManager->CanUseCanvasLayerForSize(IntSize(mWidth, mHeight));
|
return !aManager->CanUseCanvasLayerForSize(IntSize(mWidth, mHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanvasRenderingContext2D::SetWriteOnly() {
|
||||||
|
mWriteOnly = true;
|
||||||
|
if (mCanvasElement) {
|
||||||
|
mCanvasElement->SetWriteOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ class SourceSurface;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
|
class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
|
||||||
typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
|
typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
|
||||||
|
class ImageBitmap;
|
||||||
class ImageData;
|
class ImageData;
|
||||||
class StringOrCanvasGradientOrCanvasPattern;
|
class StringOrCanvasGradientOrCanvasPattern;
|
||||||
class OwningStringOrCanvasGradientOrCanvasPattern;
|
class OwningStringOrCanvasGradientOrCanvasPattern;
|
||||||
|
@ -1081,6 +1082,16 @@ protected:
|
||||||
|
|
||||||
friend struct CanvasBidiProcessor;
|
friend struct CanvasBidiProcessor;
|
||||||
friend class CanvasDrawObserver;
|
friend class CanvasDrawObserver;
|
||||||
|
friend class ImageBitmap;
|
||||||
|
|
||||||
|
void SetWriteOnly();
|
||||||
|
|
||||||
|
bool IsWriteOnly() const
|
||||||
|
{
|
||||||
|
return mWriteOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mWriteOnly;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -83,8 +83,9 @@ DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aCanvasElement->IsWriteOnly())
|
if (aCanvasElement->IsWriteOnly() && !aCanvasElement->mExpandedReader) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we explicitly set WriteOnly just do it and get out
|
// If we explicitly set WriteOnly just do it and get out
|
||||||
if (forceWriteOnly) {
|
if (forceWriteOnly) {
|
||||||
|
@ -103,6 +104,11 @@ DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX: Bug 1502799 implements an expanded reader flag to allow extensions
|
||||||
|
// to look at canvas data under defined conditions. However, we don't
|
||||||
|
// really have a need for this because our old XUL add-ons are chrome
|
||||||
|
// anyway, or do we? See the check above against mExpandedReader.
|
||||||
|
|
||||||
aCanvasElement->SetWriteOnly();
|
aCanvasElement->SetWriteOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,5 +127,25 @@ CoerceDouble(JS::Value v, double* d)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 CanvasUtils
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/dom/ToJSValue.h"
|
#include "mozilla/dom/ToJSValue.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
|
#include "nsLayoutUtils.h"
|
||||||
|
|
||||||
class nsIPrincipal;
|
class nsIPrincipal;
|
||||||
|
|
||||||
|
@ -155,6 +156,10 @@ DashArrayToJSVal(nsTArray<T>& dashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 CanvasUtils
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -312,53 +312,18 @@ private:
|
||||||
const Maybe<IntRect>& mCropRect;
|
const Maybe<IntRect>& mCropRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
|
||||||
CheckSecurityForHTMLElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aPrincipal);
|
|
||||||
|
|
||||||
if (aIsWriteOnly) {
|
|
||||||
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
|
* A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
|
||||||
* security checking.
|
* security checking.
|
||||||
*/
|
*/
|
||||||
template<class HTMLElementType>
|
template<class ElementType>
|
||||||
static already_AddRefed<SourceSurface>
|
static already_AddRefed<SourceSurface>
|
||||||
GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv)
|
GetSurfaceFromElement(nsIGlobalObject* aGlobal, ElementType& aElement,
|
||||||
|
bool* aWriteOnly, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsLayoutUtils::SurfaceFromElementResult res =
|
nsLayoutUtils::SurfaceFromElementResult res =
|
||||||
nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME);
|
nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME);
|
||||||
|
|
||||||
// check origin-clean
|
|
||||||
if (!CheckSecurityForHTMLElements(res)) {
|
|
||||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SourceSurface> surface = res.GetSourceSurface();
|
RefPtr<SourceSurface> surface = res.GetSourceSurface();
|
||||||
|
|
||||||
if (NS_WARN_IF(!surface)) {
|
if (NS_WARN_IF(!surface)) {
|
||||||
|
@ -366,6 +331,8 @@ GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, Error
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*aWriteOnly = res.mIsWriteOnly;
|
||||||
|
|
||||||
return surface.forget();
|
return surface.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,11 +361,13 @@ HasRasterImage(HTMLImageElement& aImageEl)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData)
|
ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
|
||||||
|
bool aWriteOnly)
|
||||||
: mParent(aGlobal)
|
: mParent(aGlobal)
|
||||||
, mData(aData)
|
, mData(aData)
|
||||||
, mSurface(nullptr)
|
, mSurface(nullptr)
|
||||||
, mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
|
, mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
|
||||||
|
, mWriteOnly(aWriteOnly)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
|
MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
|
||||||
}
|
}
|
||||||
|
@ -514,9 +483,12 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool writeOnly = true;
|
||||||
|
|
||||||
// Get the SourceSurface out from the image element and then do security
|
// Get the SourceSurface out from the image element and then do security
|
||||||
// checking.
|
// checking.
|
||||||
RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
|
RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl,
|
||||||
|
&writeOnly, aRv);
|
||||||
|
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -530,7 +502,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
|
||||||
|
|
||||||
// Set the picture rectangle.
|
// Set the picture rectangle.
|
||||||
if (ret && aCropRect.isSome()) {
|
if (ret && aCropRect.isSome()) {
|
||||||
|
@ -560,10 +532,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl
|
||||||
// Check security.
|
// Check security.
|
||||||
nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentPrincipal();
|
nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentPrincipal();
|
||||||
bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
|
bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
|
||||||
if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
|
bool writeOnly = CheckWriteOnlySecurity(CORSUsed, principal);
|
||||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ImageBitmap.
|
// Create ImageBitmap.
|
||||||
ImageContainer *container = aVideoEl.GetImageContainer();
|
ImageContainer *container = aVideoEl.GetImageContainer();
|
||||||
|
@ -575,7 +544,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl
|
||||||
|
|
||||||
AutoLockImage lockImage(container);
|
AutoLockImage lockImage(container);
|
||||||
layers::Image* data = lockImage.GetImage();
|
layers::Image* data = lockImage.GetImage();
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
|
||||||
|
|
||||||
// Set the picture rectangle.
|
// Set the picture rectangle.
|
||||||
if (ret && aCropRect.isSome()) {
|
if (ret && aCropRect.isSome()) {
|
||||||
|
@ -594,12 +563,18 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas
|
||||||
return nullptr;
|
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())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!writeOnly) {
|
||||||
|
writeOnly = aCanvasEl.IsWriteOnly();
|
||||||
|
}
|
||||||
|
|
||||||
// Crop the source surface if needed.
|
// Crop the source surface if needed.
|
||||||
RefPtr<SourceSurface> croppedSurface;
|
RefPtr<SourceSurface> croppedSurface;
|
||||||
IntRect cropRect = aCropRect.valueOr(IntRect());
|
IntRect cropRect = aCropRect.valueOr(IntRect());
|
||||||
|
@ -635,7 +610,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
|
||||||
|
|
||||||
// Set the picture rectangle.
|
// Set the picture rectangle.
|
||||||
if (ret && aCropRect.isSome()) {
|
if (ret && aCropRect.isSome()) {
|
||||||
|
@ -694,7 +669,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an ImageBimtap.
|
// Create an ImageBimtap.
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false /* write-only */);
|
||||||
|
|
||||||
// The cropping information has been handled in the CreateImageFromRawData()
|
// The cropping information has been handled in the CreateImageFromRawData()
|
||||||
// function.
|
// function.
|
||||||
|
@ -706,11 +681,9 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
|
||||||
ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
|
ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
|
||||||
const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
|
const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
// Check origin-clean.
|
// Check write-only mode.
|
||||||
if (aCanvasCtx.GetCanvas()->IsWriteOnly()) {
|
bool writeOnly =
|
||||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
|
RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
|
||||||
|
|
||||||
|
@ -732,7 +705,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D&
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
|
||||||
|
|
||||||
// Set the picture rectangle.
|
// Set the picture rectangle.
|
||||||
if (ret && aCropRect.isSome()) {
|
if (ret && aCropRect.isSome()) {
|
||||||
|
@ -752,7 +725,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<layers::Image> data = aImageBitmap.mData;
|
RefPtr<layers::Image> data = aImageBitmap.mData;
|
||||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mWriteOnly);
|
||||||
|
|
||||||
// Set the picture rectangle.
|
// Set the picture rectangle.
|
||||||
if (ret && aCropRect.isSome()) {
|
if (ret && aCropRect.isSome()) {
|
||||||
|
@ -1001,7 +974,9 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ImageBitmap object.
|
// Create ImageBitmap object.
|
||||||
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
|
// Ass-U-me that if this is a blob object, the promise to resolve it
|
||||||
|
// would not have been kicked off without a permissions check.
|
||||||
|
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */);
|
||||||
return imageBitmap.forget();
|
return imageBitmap.forget();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1081,7 +1056,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ImageBitmap object.
|
// Create ImageBitmap object.
|
||||||
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
|
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data,
|
||||||
|
false /* write-only */);
|
||||||
return imageBitmap.forget();
|
return imageBitmap.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1170,12 +1146,17 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx,
|
||||||
uint32_t picRectY_;
|
uint32_t picRectY_;
|
||||||
uint32_t picRectWidth_;
|
uint32_t picRectWidth_;
|
||||||
uint32_t picRectHeight_;
|
uint32_t picRectHeight_;
|
||||||
|
uint32_t writeOnly;
|
||||||
|
uint32_t dummy;
|
||||||
|
|
||||||
if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
|
if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
|
||||||
!JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_)) {
|
!JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
|
||||||
|
!JS_ReadUint32Pair(aReader, &writeOnly, &dummy)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(dummy == 0);
|
||||||
|
|
||||||
int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
|
int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
|
||||||
int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
|
int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
|
||||||
int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
|
int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
|
||||||
|
@ -1193,7 +1174,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx,
|
||||||
JS::Rooted<JS::Value> value(aCx);
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
{
|
{
|
||||||
RefPtr<ImageBitmap> imageBitmap =
|
RefPtr<ImageBitmap> imageBitmap =
|
||||||
new ImageBitmap(aParent, aClonedImages[aIndex]);
|
new ImageBitmap(aParent, aClonedImages[aIndex], !!writeOnly);
|
||||||
|
|
||||||
ErrorResult error;
|
ErrorResult error;
|
||||||
imageBitmap->SetPictureRect(IntRect(picRectX, picRectY,
|
imageBitmap->SetPictureRect(IntRect(picRectX, picRectY,
|
||||||
|
@ -1229,7 +1210,8 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
|
||||||
|
|
||||||
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
|
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
|
||||||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
|
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
|
||||||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight))) {
|
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
|
||||||
|
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, aImageBitmap->mWriteOnly, 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,9 +110,14 @@ public:
|
||||||
friend CreateImageBitmapFromBlobTask;
|
friend CreateImageBitmapFromBlobTask;
|
||||||
friend CreateImageBitmapFromBlobWorkerTask;
|
friend CreateImageBitmapFromBlobWorkerTask;
|
||||||
|
|
||||||
|
bool IsWriteOnly() const
|
||||||
|
{
|
||||||
|
return mWriteOnly;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData);
|
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, bool aWriteOnly);
|
||||||
|
|
||||||
virtual ~ImageBitmap();
|
virtual ~ImageBitmap();
|
||||||
|
|
||||||
|
@ -173,6 +178,13 @@ protected:
|
||||||
* to draw this ImageBitmap into a HTMLCanvasElement.
|
* to draw this ImageBitmap into a HTMLCanvasElement.
|
||||||
*/
|
*/
|
||||||
gfx::IntRect mPictureRect;
|
gfx::IntRect mPictureRect;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
} // namespace dom
|
||||||
|
|
|
@ -621,8 +621,8 @@ NS_IMETHODIMP
|
||||||
HTMLCanvasElement::ToDataURL(const nsAString& aType, JS::Handle<JS::Value> aParams,
|
HTMLCanvasElement::ToDataURL(const nsAString& aType, JS::Handle<JS::Value> aParams,
|
||||||
JSContext* aCx, nsAString& aDataURL)
|
JSContext* aCx, nsAString& aDataURL)
|
||||||
{
|
{
|
||||||
// do a trust check if this is a write-only canvas
|
// mWriteOnly check is redundant, but optimizes for the common case.
|
||||||
if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
|
if (mWriteOnly && !CallerCanRead(aCx)) {
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,8 +751,8 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||||
JS::Handle<JS::Value> aParams,
|
JS::Handle<JS::Value> aParams,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
// do a trust check if this is a write-only canvas
|
// mWriteOnly check is redundant, but optimizes for the common case.
|
||||||
if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
|
if (mWriteOnly && !CallerCanRead(aCx)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -935,17 +935,47 @@ HTMLCanvasElement::GetSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
HTMLCanvasElement::IsWriteOnly()
|
HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; }
|
||||||
{
|
|
||||||
return mWriteOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
HTMLCanvasElement::SetWriteOnly()
|
HTMLCanvasElement::SetWriteOnly()
|
||||||
{
|
{
|
||||||
|
mExpandedReader = nullptr;
|
||||||
mWriteOnly = true;
|
mWriteOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLCanvasElement::SetWriteOnly(nsIPrincipal* aExpandedReader)
|
||||||
|
{
|
||||||
|
mExpandedReader = aExpandedReader;
|
||||||
|
mWriteOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
HTMLCanvasElement::CallerCanRead(JSContext* aCx)
|
||||||
|
{
|
||||||
|
if (!mWriteOnly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: We don't implement expanded readers yet, and may not need them.
|
||||||
|
#if(0)
|
||||||
|
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);
|
||||||
|
#else
|
||||||
|
// This is essentially what we did before, modulo the write-only check.
|
||||||
|
return nsContentUtils::IsCallerChrome();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
|
HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
|
||||||
{
|
{
|
||||||
|
|
|
@ -222,13 +222,19 @@ public:
|
||||||
/**
|
/**
|
||||||
* Determine whether the canvas is write-only.
|
* Determine whether the canvas is write-only.
|
||||||
*/
|
*/
|
||||||
bool IsWriteOnly();
|
bool IsWriteOnly() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force the canvas to be write-only.
|
* Force the canvas to be write-only.
|
||||||
*/
|
*/
|
||||||
void SetWriteOnly();
|
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
|
* Notify that some canvas content has changed and the window may
|
||||||
* need to be updated. aDamageRect is in canvas coordinates.
|
* need to be updated. aDamageRect is in canvas coordinates.
|
||||||
|
@ -381,6 +387,13 @@ public:
|
||||||
// is itself write-only.
|
// is itself write-only.
|
||||||
bool mWriteOnly;
|
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();
|
bool IsPrintCallbackDone();
|
||||||
|
|
||||||
void HandlePrintCallback(nsPresContext::nsPresContextType aType);
|
void HandlePrintCallback(nsPresContext::nsPresContextType aType);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/BasicEvents.h"
|
#include "mozilla/BasicEvents.h"
|
||||||
|
#include "mozilla/dom/CanvasUtils.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/EffectCompositor.h"
|
#include "mozilla/EffectCompositor.h"
|
||||||
#include "mozilla/EffectSet.h"
|
#include "mozilla/EffectSet.h"
|
||||||
|
@ -7147,9 +7148,9 @@ nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement,
|
||||||
|
|
||||||
result.mSize = IntSize(imgWidth, imgHeight);
|
result.mSize = IntSize(imgWidth, imgHeight);
|
||||||
result.mPrincipal = principal.forget();
|
result.mPrincipal = principal.forget();
|
||||||
// no images, including SVG images, can load content from another domain.
|
|
||||||
result.mIsWriteOnly = false;
|
|
||||||
result.mImageRequest = imgRequest.forget();
|
result.mImageRequest = imgRequest.forget();
|
||||||
|
result.mIsWriteOnly =
|
||||||
|
CanvasUtils::CheckWriteOnlySecurity(result.mCORSUsed, result.mPrincipal);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -7261,7 +7262,8 @@ nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
|
||||||
result.mHasSize = true;
|
result.mHasSize = true;
|
||||||
result.mSize = result.mLayersImage->GetSize();
|
result.mSize = result.mLayersImage->GetSize();
|
||||||
result.mPrincipal = principal.forget();
|
result.mPrincipal = principal.forget();
|
||||||
result.mIsWriteOnly = false;
|
result.mIsWriteOnly =
|
||||||
|
CanvasUtils::CheckWriteOnlySecurity(result.mCORSUsed, result.mPrincipal);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue