diff options
Diffstat (limited to 'dom/canvas')
25 files changed, 255 insertions, 231 deletions
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 18af28e9f..111519c71 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -783,6 +783,15 @@ public: : mCanvas(aCanvas) {} + void OnShutdown() { + if(!mCanvas) { + return; + } + + mCanvas = nullptr; + nsContentUtils::UnregisterShutdownObserver(this); + } + NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER private: @@ -800,7 +809,7 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, { if (mCanvas && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { mCanvas->OnShutdown(); - nsContentUtils::UnregisterShutdownObserver(this); + OnShutdown(); } return NS_OK; @@ -1038,7 +1047,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CanvasRenderingContext2D) ImplCycleCollectionTraverse(cb, info.mElement, "Hit region fallback element"); } } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(CanvasRenderingContext2D) @@ -1097,6 +1105,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompos , mIsCapturedFrameInvalid(false) , mPathTransformWillUpdate(false) , mInvalidateCount(0) + , mWriteOnly(false) // == !origin-clean { sNumLivingContexts++; @@ -1218,7 +1227,7 @@ void CanvasRenderingContext2D::RemoveShutdownObserver() { if (mShutdownObserver) { - nsContentUtils::UnregisterShutdownObserver(mShutdownObserver); + mShutdownObserver->OnShutdown(); mShutdownObserver = nullptr; } } @@ -2554,7 +2563,8 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource, // 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(); } @@ -4209,6 +4219,12 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess if (state->gradientStyles[style]) { // Gradient pattern = GetGradientFor(style); } else if (state->patternStyles[style]) { // Pattern + if (mCtx->mCanvasElement) { + CanvasUtils::DoDrawImageSecurityCheck( + mCtx->mCanvasElement, state->patternStyles[style]->mPrincipal, + state->patternStyles[style]->mForceWriteOnly, + state->patternStyles[style]->mCORSUsed); + } pattern = GetPatternFor(style); } else { MOZ_ASSERT(false, "Should never reach here."); @@ -4944,6 +4960,10 @@ 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); @@ -4952,6 +4972,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } + if (imageBitmap.IsWriteOnly()) { + SetWriteOnly(); + } + imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); } else { @@ -5666,9 +5690,8 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx, // 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() && - !nsContentUtils::IsCallerChrome()) - { + if (IsWriteOnly() || + (mCanvasElement && mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome())) { // XXX ERRMSG we need to report an error to developers here! (bug 329026) aError.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; @@ -6312,6 +6335,13 @@ CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager* aManager) 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 848b3ee08..d4f295a03 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -40,6 +40,7 @@ class SourceSurface; namespace dom { class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap; typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource; +class ImageBitmap; class ImageData; class StringOrCanvasGradientOrCanvasPattern; class OwningStringOrCanvasGradientOrCanvasPattern; @@ -1151,6 +1152,17 @@ protected: friend struct CanvasBidiProcessor; friend class CanvasDrawObserver; + friend class ImageBitmap; + + // For the origin-clean algorithm (mWriteOnly == !origin-clean) + // See https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html + void SetWriteOnly(); + + bool IsWriteOnly() const { + return mWriteOnly; + } + + bool mWriteOnly; }; } // namespace dom diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp index 3000e59bd..61317fb51 100644 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -7,7 +7,6 @@ #include "ImageBitmapRenderingContext.h" #include "ImageEncoder.h" #include "mozilla/dom/CanvasRenderingContext2D.h" -#include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" #include "nsContentUtils.h" #include "nsDOMJSUtils.h" @@ -138,13 +137,10 @@ CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType break; case CanvasContextType::Canvas2D: - Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); ret = new CanvasRenderingContext2D(aCompositorBackend); break; case CanvasContextType::WebGL1: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - ret = WebGL1Context::Create(); if (!ret) return nullptr; @@ -152,8 +148,6 @@ CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType break; case CanvasContextType::WebGL2: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - ret = WebGL2Context::Create(); if (!ret) return nullptr; @@ -205,16 +199,8 @@ CanvasRenderingContextHelper::GetContext(JSContext* aCx, // See bug 645792 and bug 1215072. // We want to throw only if dictionary initialization fails, // so only in case aRv has been set to some error value. - if (contextType == CanvasContextType::WebGL1) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0); - else if (contextType == CanvasContextType::WebGL2) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0); return nullptr; } - if (contextType == CanvasContextType::WebGL1) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1); - else if (contextType == CanvasContextType::WebGL2) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1); } else { // We already have a context of some type. if (contextType != mCurrentContextType) diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index e45cdfc6f..6efe1b318 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -351,29 +351,27 @@ CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes */ template<class HTMLElementType> static already_AddRefed<SourceSurface> -GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv) +GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, + bool* aWriteOnly, ErrorResult& aRv) { nsLayoutUtils::SurfaceFromElementResult res = 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(); if (NS_WARN_IF(!surface)) { - aRv.Throw(NS_ERROR_NOT_AVAILABLE); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } + + // Check origin-clean and pass back + *aWriteOnly = !CheckSecurityForHTMLElements(res); return surface.forget(); } /* - * The specification doesn't allow to create an ImegeBitmap from a vector image. + * The specification doesn't allow to create an ImageBitmap from a vector image. * This function is used to check if the given HTMLImageElement contains a * raster image. */ @@ -398,7 +396,7 @@ HasRasterImage(HTMLImageElement& aImageEl) } ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, - bool aIsPremultipliedAlpha /* = true */) + bool aWriteOnly, bool aIsPremultipliedAlpha /* = true */) : mParent(aGlobal) , mData(aData) , mSurface(nullptr) @@ -406,6 +404,7 @@ ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height) , mIsPremultipliedAlpha(aIsPremultipliedAlpha) , mIsCroppingAreaOutSideOfSourceImage(false) + , mWriteOnly(aWriteOnly) { MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor."); } @@ -698,6 +697,7 @@ ImageBitmap::ToCloneData() const RefPtr<SourceSurface> surface = mData->GetAsSourceSurface(); result->mSurface = surface->GetDataSurface(); MOZ_ASSERT(result->mSurface); + result->mWriteOnly = mWriteOnly; return Move(result); } @@ -708,7 +708,7 @@ ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal, { RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface); - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mIsPremultipliedAlpha); ret->mIsCroppingAreaOutSideOfSourceImage = @@ -724,11 +724,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas, ErrorResult& aRv) { - // Check origin-clean. - if (aOffscreenCanvas.IsWriteOnly()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + // Check origin-clean + bool writeOnly = aOffscreenCanvas.IsWriteOnly(); nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, @@ -744,7 +741,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); return ret.forget(); } @@ -757,16 +754,19 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } - + // Check if the image element is a bitmap (e.g. it's a vector graphic) or not. if (!HasRasterImage(aImageEl)) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 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; @@ -780,7 +780,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl 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()) { @@ -812,13 +812,13 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl return nullptr; } + bool writeOnly = true; + // 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; - } + + writeOnly = !CheckSecurityForHTMLElements(false, CORSUsed, principal); // Create ImageBitmap. ImageContainer *container = aVideoEl.GetImageContainer(); @@ -834,7 +834,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl 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()) { @@ -856,12 +856,18 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas 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()); @@ -874,8 +880,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas aCropRect.isSome()) { // The _surface_ must be a DataSourceSurface. MOZ_ASSERT(surface->GetType() == SurfaceType::DATA, - "The snapshot SourceSurface from WebGL rendering contest is not \ - DataSourceSurface."); + "The snapshot SourceSurface from WebGL rendering contest is not DataSourceSurface."); RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect); cropRect.MoveTo(0, 0); @@ -897,7 +902,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas 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()) { @@ -958,9 +963,12 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, return nullptr; } - // Create an ImageBimtap. + // Create an ImageBitmap. // ImageData's underlying data is not alpha-premultiplied. - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, + data, + false /* write-only */, + false /* alpha-premult */); // The cropping information has been handled in the CreateImageFromRawData() // function. @@ -975,11 +983,8 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, 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 origin-clean + bool writeOnly = aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly(); RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot(); @@ -1001,7 +1006,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& 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()) { @@ -1024,7 +1029,10 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap, } RefPtr<layers::Image> data = aImageBitmap.mData; - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mIsPremultipliedAlpha); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, + data, + aImageBitmap.mWriteOnly, + aImageBitmap.mIsPremultipliedAlpha); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -1295,7 +1303,7 @@ private: } // Create ImageBitmap object. - RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1391,7 +1399,7 @@ private: } // Create ImageBitmap object. - RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1486,14 +1494,19 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, uint32_t picRectHeight_; uint32_t isPremultipliedAlpha_; uint32_t isCroppingAreaOutSideOfSourceImage_; + uint32_t writeOnly; + uint32_t dummy; if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) || !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) || !JS_ReadUint32Pair(aReader, &isPremultipliedAlpha_, - &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_); @@ -1512,7 +1525,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, { RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]); RefPtr<ImageBitmap> imageBitmap = - new ImageBitmap(aParent, img, isPremultipliedAlpha_); + new ImageBitmap(aParent, img, !!writeOnly, isPremultipliedAlpha_); imageBitmap->mIsCroppingAreaOutSideOfSourceImage = isCroppingAreaOutSideOfSourceImage_; @@ -1547,6 +1560,7 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, const uint32_t picRectHeight = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.height); const uint32_t isPremultipliedAlpha = aImageBitmap->mIsPremultipliedAlpha ? 1 : 0; const uint32_t isCroppingAreaOutSideOfSourceImage = aImageBitmap->mIsCroppingAreaOutSideOfSourceImage ? 1 : 0; + const uint32_t isWriteOnly = aImageBitmap->mWriteOnly ? 1 : 0; // Indexing the cloned surfaces and send the index to the receiver. uint32_t index = aClonedSurfaces.Length(); @@ -1555,7 +1569,8 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isPremultipliedAlpha, - isCroppingAreaOutSideOfSourceImage))) { + isCroppingAreaOutSideOfSourceImage)) || + NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isWriteOnly, 0))) { return false; } diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index 2119c6bda..25084b6ac 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -65,6 +65,7 @@ struct ImageBitmapCloneData final gfx::IntRect mPictureRect; bool mIsPremultipliedAlpha; bool mIsCroppingAreaOutSideOfSourceImage; + bool mWriteOnly; }; /* @@ -161,6 +162,10 @@ public: template<typename T> friend class MapDataIntoBufferSource; + bool IsWriteOnly() const { + return mWriteOnly; + } + // Mozilla Extensions ImageBitmapFormat FindOptimalFormat(const Optional<Sequence<ImageBitmapFormat>>& aPossibleFormats, @@ -197,6 +202,7 @@ protected: * CreateInternal(from ImageData) method. */ ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, + bool aWriteOnly, bool aIsPremultipliedAlpha = true); virtual ~ImageBitmap(); @@ -280,6 +286,12 @@ protected: */ bool mIsCroppingAreaOutSideOfSourceImage; + /* + * 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 8f5074554..ad313906a 100644 --- a/dom/canvas/ImageBitmapRenderingContext.cpp +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -63,6 +63,11 @@ ImageBitmapRenderingContext::TransferFromImageBitmap(ImageBitmap& aImageBitmap) if (!mImage) { return; } + + // Check if ImageBitmap is tainted, and if so flag the canvas tainted too. + if (aImageBitmap.IsWriteOnly() && mCanvasElement) { + mCanvasElement->SetWriteOnly(); + } Redraw(gfxRect(0, 0, mWidth, mHeight)); } diff --git a/dom/canvas/ImageData.cpp b/dom/canvas/ImageData.cpp index b201fa279..d24fbca95 100644 --- a/dom/canvas/ImageData.cpp +++ b/dom/canvas/ImageData.cpp @@ -29,7 +29,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ImageData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ImageData) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ImageData) diff --git a/dom/canvas/WebGL1Context.cpp b/dom/canvas/WebGL1Context.cpp index c1818a3f9..e82cafbe5 100644 --- a/dom/canvas/WebGL1Context.cpp +++ b/dom/canvas/WebGL1Context.cpp @@ -6,7 +6,6 @@ #include "WebGL1Context.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" -#include "mozilla/Telemetry.h" #include "WebGLFormats.h" namespace mozilla { @@ -43,8 +42,6 @@ WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result) { - mozilla::Telemetry::Accumulate(mozilla::Telemetry::CANVAS_WEBGL_USED, 1); - nsIDOMWebGLRenderingContext* ctx = mozilla::WebGL1Context::Create(); NS_ADDREF(*out_result = ctx); diff --git a/dom/canvas/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp index f202c9950..02a8f649f 100644 --- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -115,7 +115,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa const ScopedLazyBind lazyBind(gl, target, this); mContext->InvalidateBufferFetching(); -#ifdef XP_MACOSX +#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) // bug 790879 if (gl->WorkAroundDriverBugs() && size > INT32_MAX) @@ -134,6 +134,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa if (error) { MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error); + mByteLength = 0; return; } } else { diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 32eed6354..e2e05e5fd 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -47,7 +47,6 @@ #include "nsSVGEffects.h" #include "prenv.h" #include "ScopedGLHelpers.h" -#include "VRManagerChild.h" #include "mozilla/layers/TextureClientSharedSurface.h" // Local @@ -825,10 +824,6 @@ NS_IMETHODIMP WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) { if (signedWidth < 0 || signedHeight < 0) { - if (!gl) { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, - NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SIZE")); - } GenerateWarning("Canvas size is too large (seems like a negative value wrapped)"); return NS_ERROR_OUT_OF_MEMORY; } @@ -884,12 +879,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) return NS_OK; } - nsCString failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_UNKOWN"); - auto autoTelemetry = mozilla::MakeScopeExit([&] { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, - failureId); - }); - // End of early return cases. // At this point we know that we're not just resizing an existing context, // we are initializing a new context. @@ -911,7 +900,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) // resource handles created from older context generations. if (!(mGeneration + 1).isValid()) { // exit without changing the value of mGeneration - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY"); const nsLiteralCString text("Too many WebGL contexts created this run."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -928,11 +916,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) disabled |= gfxPlatform::InSafeMode(); if (disabled) { - if (gfxPlatform::InSafeMode()) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SAFEMODE"); - } else { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED"); - } const nsLiteralCString text("WebGL is currently disabled."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -945,7 +928,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) if (mOptions.failIfMajorPerformanceCaveat) { nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); if (!HasAcceleratedLayers(gfxInfo)) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT"); const nsLiteralCString text("failIfMajorPerformanceCaveat: Compositor is not" " hardware-accelerated."); ThrowEvent_WebGLContextCreationError(text); @@ -961,12 +943,9 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) if (!CreateAndInitGL(forceEnabled, &failReasons)) { nsCString text("WebGL creation failed: "); for (const auto& cur : failReasons) { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key); - text.AppendASCII("\n* "); text.Append(cur.info); } - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON"); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; } @@ -978,7 +957,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) DestroyResourcesAndContext(); MOZ_ASSERT(!gl); - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_WARP"); const nsLiteralCString text("failIfMajorPerformanceCaveat: Driver is not" " hardware-accelerated."); ThrowEvent_WebGLContextCreationError(text); @@ -992,7 +970,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) DestroyResourcesAndContext(); MOZ_ASSERT(!gl); - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DXGL_INTEROP2"); const nsLiteralCString text("Caveat: WGL without DXGLInterop2."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -1001,7 +978,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) } if (!ResizeBackbuffer(width, height)) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER"); const nsLiteralCString text("Initializing WebGL backbuffer failed."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -1085,7 +1061,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) ////// - failureId = NS_LITERAL_CSTRING("SUCCESS"); return NS_OK; } @@ -2263,84 +2238,6 @@ WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height, return totalBytes; } -already_AddRefed<layers::SharedSurfaceTextureClient> -WebGLContext::GetVRFrame() -{ - if (!mLayerIsMirror) { - /** - * Do not allow VR frame submission until a mirroring canvas layer has - * been returned by GetCanvasLayer - */ - return nullptr; - } - - VRManagerChild* vrmc = VRManagerChild::Get(); - if (!vrmc) { - return nullptr; - } - - /** - * Swap buffers as though composition has occurred. - * We will then share the resulting front buffer to be submitted to the VR - * compositor. - */ - BeginComposition(); - EndComposition(); - - gl::GLScreenBuffer* screen = gl->Screen(); - if (!screen) { - return nullptr; - } - - RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front(); - if (!sharedSurface) { - return nullptr; - } - - if (sharedSurface && sharedSurface->GetAllocator() != vrmc) { - RefPtr<SharedSurfaceTextureClient> dest = - screen->Factory()->NewTexClient(sharedSurface->GetSize()); - if (!dest) { - return nullptr; - } - gl::SharedSurface* destSurf = dest->Surf(); - destSurf->ProducerAcquire(); - SharedSurface::ProdCopy(sharedSurface->Surf(), dest->Surf(), - screen->Factory()); - destSurf->ProducerRelease(); - - return dest.forget(); - } - - return sharedSurface.forget(); -} - -bool -WebGLContext::StartVRPresentation() -{ - VRManagerChild* vrmc = VRManagerChild::Get(); - if (!vrmc) { - return false; - } - gl::GLScreenBuffer* screen = gl->Screen(); - if (!screen) { - return false; - } - gl::SurfaceCaps caps = screen->mCaps; - - UniquePtr<gl::SurfaceFactory> factory = - gl::GLScreenBuffer::CreateFactory(gl, - caps, - vrmc, - vrmc->GetBackendType(), - TextureFlags::ORIGIN_BOTTOM_LEFT); - - if (factory) { - screen->Morph(Move(factory)); - } - return true; -} - //////////////////////////////////////////////////////////////////////////////// static inline size_t diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index b4d416a33..0510e6898 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -20,6 +20,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/LinkedList.h" #include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" #include "nsCycleCollectionNoteChild.h" #include "nsICanvasRenderingContextInternal.h" #include "nsLayoutUtils.h" @@ -275,8 +276,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*) { @@ -298,6 +300,7 @@ class WebGLContext , public WebGLContextUnchecked , public WebGLRectangleObject , public nsWrapperCache + , public SupportsWeakPtr<WebGLContext> { friend class ScopedDrawHelper; friend class ScopedDrawWithTransformFeedback; @@ -341,6 +344,7 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext, nsIDOMWebGLRenderingContext) + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContext) virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0; @@ -656,9 +660,6 @@ public: void PixelStorei(GLenum pname, GLint param); void PolygonOffset(GLfloat factor, GLfloat units); - already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame(); - bool StartVRPresentation(); - //// webgl::PackingInfo diff --git a/dom/canvas/WebGLContextBuffers.cpp b/dom/canvas/WebGLContextBuffers.cpp index af506c01c..f53f9d7d7 100644 --- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -9,6 +9,8 @@ #include "WebGLBuffer.h" #include "WebGLVertexArray.h" +#include "mozilla/CheckedInt.h" + namespace mozilla { WebGLRefPtr<WebGLBuffer>* @@ -345,6 +347,16 @@ WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) //// + const auto checkedSize = CheckedInt<size_t>(size); + if (!checkedSize.isValid()) + return ErrorOutOfMemory("%s: Size too large for platform.", funcName); + +#if defined(XP_MACOSX) + if (gl->WorkAroundDriverBugs() && size > 1200000000) { + return ErrorOutOfMemory("Allocations larger than 1200000000 fail on MacOS."); + } +#endif + const UniqueBuffer zeroBuffer(calloc(size, 1)); if (!zeroBuffer) return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName); diff --git a/dom/canvas/WebGLExtensionDebugShaders.cpp b/dom/canvas/WebGLExtensionDebugShaders.cpp index 75880465e..8399aeb95 100644 --- a/dom/canvas/WebGLExtensionDebugShaders.cpp +++ b/dom/canvas/WebGLExtensionDebugShaders.cpp @@ -29,15 +29,10 @@ WebGLExtensionDebugShaders::GetTranslatedShaderSource(const WebGLShader& shader, { retval.SetIsVoid(true); - if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "getTranslatedShaderSource"); + if (mIsLost || !mContext) { return; } - if (mContext->IsContextLost()) - return; - if (!mContext->ValidateObject("getShaderTranslatedSource: shader", shader)) return; diff --git a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp index e2e34f14e..da76eeb2d 100644 --- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp +++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp @@ -40,8 +40,10 @@ void WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLQuery* query) const { const char funcName[] = "deleteQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->DeleteQuery(query, funcName); } @@ -50,8 +52,10 @@ bool WebGLExtensionDisjointTimerQuery::IsQueryEXT(const WebGLQuery* query) const { const char funcName[] = "isQueryEXT"; - if (mIsLost) - return false; + + if (mIsLost || !mContext) { + return false; + } return mContext->IsQuery(query, funcName); } @@ -60,8 +64,10 @@ void WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery& query) const { const char funcName[] = "beginQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->BeginQuery(target, query, funcName); } @@ -70,8 +76,10 @@ void WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) const { const char funcName[] = "endQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->EndQuery(target, funcName); } @@ -80,8 +88,10 @@ void WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery& query, GLenum target) const { const char funcName[] = "queryCounterEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } if (!mContext->ValidateObject(funcName, query)) return; @@ -95,8 +105,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLen { const char funcName[] = "getQueryEXT"; retval.setNull(); - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->GetQuery(cx, target, pname, retval, funcName); } @@ -108,8 +120,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx, { const char funcName[] = "getQueryObjectEXT"; retval.setNull(); - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->GetQueryParameter(cx, query, pname, retval, funcName); } diff --git a/dom/canvas/WebGLExtensionDrawBuffers.cpp b/dom/canvas/WebGLExtensionDrawBuffers.cpp index 27aa76cc7..6f386621f 100644 --- a/dom/canvas/WebGLExtensionDrawBuffers.cpp +++ b/dom/canvas/WebGLExtensionDrawBuffers.cpp @@ -36,7 +36,9 @@ void WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers) { if (mIsLost) { - mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost."); + if (mContext) { + mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost."); + } return; } diff --git a/dom/canvas/WebGLExtensionInstancedArrays.cpp b/dom/canvas/WebGLExtensionInstancedArrays.cpp index 10d0533fe..22b3ec12c 100644 --- a/dom/canvas/WebGLExtensionInstancedArrays.cpp +++ b/dom/canvas/WebGLExtensionInstancedArrays.cpp @@ -28,8 +28,10 @@ WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode, GLsizei primcount) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "drawArraysInstancedANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "drawArraysInstancedANGLE"); + } return; } @@ -44,8 +46,10 @@ WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode, GLsizei primcount) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "drawElementsInstancedANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "drawElementsInstancedANGLE"); + } return; } @@ -57,8 +61,10 @@ WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index, GLuint divisor) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "vertexAttribDivisorANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "vertexAttribDivisorANGLE"); + } return; } diff --git a/dom/canvas/WebGLExtensionLoseContext.cpp b/dom/canvas/WebGLExtensionLoseContext.cpp index 020731e63..41f1633d8 100644 --- a/dom/canvas/WebGLExtensionLoseContext.cpp +++ b/dom/canvas/WebGLExtensionLoseContext.cpp @@ -22,12 +22,14 @@ WebGLExtensionLoseContext::~WebGLExtensionLoseContext() void WebGLExtensionLoseContext::LoseContext() { + if (!mContext) return; mContext->LoseContext(); } void WebGLExtensionLoseContext::RestoreContext() { + if (!mContext) return; mContext->RestoreContext(); } diff --git a/dom/canvas/WebGLExtensionVertexArray.cpp b/dom/canvas/WebGLExtensionVertexArray.cpp index 0984582f5..39aa96801 100644 --- a/dom/canvas/WebGLExtensionVertexArray.cpp +++ b/dom/canvas/WebGLExtensionVertexArray.cpp @@ -25,7 +25,7 @@ WebGLExtensionVertexArray::~WebGLExtensionVertexArray() already_AddRefed<WebGLVertexArray> WebGLExtensionVertexArray::CreateVertexArrayOES() { - if (mIsLost) + if (mIsLost || !mContext) return nullptr; return mContext->CreateVertexArray(); @@ -34,7 +34,7 @@ WebGLExtensionVertexArray::CreateVertexArrayOES() void WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return; mContext->DeleteVertexArray(array); @@ -43,7 +43,7 @@ WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array) bool WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return false; return mContext->IsVertexArray(array); @@ -52,7 +52,7 @@ WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array) void WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return; mContext->BindVertexArray(array); diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h index b18b790c0..6371c7b03 100644 --- a/dom/canvas/WebGLObjectModel.h +++ b/dom/canvas/WebGLObjectModel.h @@ -6,8 +6,8 @@ #ifndef WEBGLOBJECTMODEL_H_ #define WEBGLOBJECTMODEL_H_ +#include "mozilla/WeakPtr.h" #include "nsCycleCollectionNoteChild.h" - #include "WebGLTypes.h" namespace mozilla { @@ -24,7 +24,7 @@ class WebGLContext; class WebGLContextBoundObject { public: - WebGLContext* const mContext; + const WeakPtr<WebGLContext> mContext; private: const uint32_t mContextGeneration; diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp index ec076fdbb..32397dd1a 100644 --- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -215,6 +215,16 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples, if (error) { const char* errorName = mContext->ErrorName(error); mContext->GenerateWarning("%s generated error %s", funcName, errorName); + if (error == LOCAL_GL_OUT_OF_MEMORY) { + // Truncate. + mSamples = 0; + mFormat = nullptr; + mWidth = 0; + mHeight = 0; + mImageDataStatus = WebGLImageDataStatus::NoImageData; + + InvalidateStatusOfAttachedFBs(); + } return; } diff --git a/dom/canvas/WebGLShader.cpp b/dom/canvas/WebGLShader.cpp index 37380f1e0..69ca03fc4 100644 --- a/dom/canvas/WebGLShader.cpp +++ b/dom/canvas/WebGLShader.cpp @@ -168,16 +168,6 @@ WebGLShader::ShaderSource(const nsAString& source) // 7-bit ASCII range, so we can skip the NS_IsAscii() check. const NS_LossyConvertUTF16toASCII sourceCString(cleanSource); - if (mContext->gl->WorkAroundDriverBugs()) { - const size_t maxSourceLength = 0x3ffff; - if (sourceCString.Length() > maxSourceLength) { - mContext->ErrorInvalidValue("shaderSource: Source has more than %d" - " characters. (Driver workaround)", - maxSourceLength); - return; - } - } - if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) { printf_stderr("////////////////////////////////////////\n"); printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n"); diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 767ff610a..65bb71153 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -51,8 +51,6 @@ WebGLTexture::ImageInfo::Clear() WebGLTexture::ImageInfo& WebGLTexture::ImageInfo::operator =(const ImageInfo& a) { - MOZ_ASSERT(a.IsDefined()); - Mutable(mFormat) = a.mFormat; Mutable(mWidth) = a.mWidth; Mutable(mHeight) = a.mHeight; @@ -1216,6 +1214,12 @@ WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f); } +void WebGLTexture::Truncate() { + for (auto& cur : mImageInfoArr) { + SetImageInfo(&cur, ImageInfo()); + } +} + //////////////////////////////////////////////////////////////////////////////// NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture) diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index 66e781f23..8d3024590 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -386,6 +386,7 @@ public: bool* const out_initFailed); bool IsMipmapCubeComplete() const; + void Truncate(); bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); } diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 612d5889d..ae60d2a2b 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" @@ -214,9 +215,18 @@ FromPboOffset(WebGLContext* webgl, const char* funcName, TexImageTarget target, 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()); + if (!cloneData) { + return nullptr; + } + const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface; //// @@ -293,6 +303,14 @@ WebGLContext::FromDomElem(const char* funcName, TexImageTarget target, uint32_t 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;
+ }
+ }
+ uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE | nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR; @@ -412,7 +430,7 @@ WebGLContext::From(const char* funcName, TexImageTarget target, GLsizei rawWidth if (src.mImageBitmap) { return FromImageBitmap(this, funcName, target, width, height, depth, - *(src.mImageBitmap)); + *(src.mImageBitmap), src.mOut_error); } if (src.mImageData) { @@ -1160,6 +1178,7 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels, if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during texture allocation.", funcName); + Truncate(); return; } if (error) { @@ -1292,6 +1311,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level, if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1380,6 +1400,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1496,6 +1517,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL blob->mAvailBytes, blob->mPtr); if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName); + Truncate(); return; } if (error) { @@ -1646,6 +1668,7 @@ WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target, blob->mAvailBytes, blob->mPtr); if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName); + Truncate(); return; } if (error) { @@ -1974,7 +1997,7 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev static bool DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, - const WebGLTexture* tex, TexImageTarget target, GLint level, + WebGLTexture* tex, TexImageTarget target, GLint level, GLint xWithinSrc, GLint yWithinSrc, uint32_t srcTotalWidth, uint32_t srcTotalHeight, const webgl::FormatUsageInfo* srcUsage, @@ -2051,6 +2074,7 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, if (error == LOCAL_GL_OUT_OF_MEMORY) { webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName); + tex->Truncate(); return false; } diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html index b3d3c08ad..3b74970ac 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([ |