Bug 1500768 - Implement SVGImageElement support for createImageBitmap, r=jwatt
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 25 Oct 2018 14:55:06 +0200
changeset 491277 e81ad7034716854a48a3d04a0b53b4b63956b77d
parent 491276 feb8571f288e22049912d64e3daa133578c8d55b
child 491278 2e9cdd9ff7b6bdc6e7add0ae187166f59d9ad177
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjwatt
bugs1500768
milestone65.0a1
Bug 1500768 - Implement SVGImageElement support for createImageBitmap, r=jwatt
dom/canvas/ImageBitmap.cpp
dom/canvas/ImageBitmap.h
dom/canvas/ImageBitmapSource.h
dom/webidl/ImageBitmap.webidl
testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-drawImage.html.ini
testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini
testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-transfer.html.ini
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -433,17 +433,17 @@ private:
   uint32_t mBufferLength;
   uint32_t mStride;
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   const Maybe<IntRect>& mCropRect;
 };
 
 static bool
-CheckSecurityForHTMLElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
+CheckSecurityForElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
 {
   if (aIsWriteOnly || !aPrincipal) {
     return false;
   }
 
   if (!aCORSUsed) {
     nsIGlobalObject* incumbentSettingsObject = GetIncumbentGlobal();
     if (NS_WARN_IF(!incumbentSettingsObject)) {
@@ -455,55 +455,56 @@ CheckSecurityForHTMLElements(bool aIsWri
       return false;
     }
   }
 
   return true;
 }
 
 static bool
-CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes)
+CheckSecurityForElements(const nsLayoutUtils::SurfaceFromElementResult& aRes)
 {
-  return CheckSecurityForHTMLElements(aRes.mIsWriteOnly, aRes.mCORSUsed, aRes.mPrincipal);
+  return CheckSecurityForElements(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)
+GetSurfaceFromElement(nsIGlobalObject* aGlobal, ElementType& aElement, ErrorResult& aRv)
 {
   nsLayoutUtils::SurfaceFromElementResult res =
     nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
 
   // check origin-clean
-  if (!CheckSecurityForHTMLElements(res)) {
+  if (!CheckSecurityForElements(res)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   RefPtr<SourceSurface> surface = res.GetSourceSurface();
 
   if (NS_WARN_IF(!surface)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   return surface.forget();
 }
 
 /*
  * The specification doesn't allow to create an ImegeBitmap from a vector image.
- * This function is used to check if the given HTMLImageElement contains a
+ * This function is used to check if the given Image Element contains a
  * raster image.
  */
+template<class ElementType>
 static bool
-HasRasterImage(HTMLImageElement& aImageEl)
+HasRasterImage(ElementType& aImageEl)
 {
   nsresult rv;
 
   nsCOMPtr<imgIRequest> imgRequest;
   rv = aImageEl.GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                            getter_AddRefs(imgRequest));
   if (NS_SUCCEEDED(rv) && imgRequest) {
     nsCOMPtr<imgIContainer> imgContainer;
@@ -888,16 +889,46 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
+ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
+                            const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
+{
+  // Get the SourceSurface out from the image element and then do security
+  // checking.
+  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
+
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  // Create ImageBitmap.
+  RefPtr<layers::Image> data = CreateImageFromSurface(surface);
+
+  if (NS_WARN_IF(!data)) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return nullptr;
+  }
+
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+
+  // Set the picture rectangle.
+  if (ret && aCropRect.isSome()) {
+    ret->SetPictureRect(aCropRect.ref(), aRv);
+  }
+
+  return ret.forget();
+}
+
+/* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
   aVideoEl.MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_IMAGEBITMAP);
 
   // Check network state.
   if (aVideoEl.NetworkState() == NETWORK_EMPTY) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -909,17 +940,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   if (aVideoEl.ReadyState() <= HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check security.
   nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
   bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
-  if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
+  if (!CheckSecurityForElements(false, CORSUsed, principal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Create ImageBitmap.
   RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
   if (!data) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
@@ -1368,16 +1399,20 @@ ImageBitmap::Create(nsIGlobalObject* aGl
   }
 
   RefPtr<ImageBitmap> imageBitmap;
 
   if (aSrc.IsHTMLImageElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLImageElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLImageElement(), aCropRect, aRv);
+  } else if (aSrc.IsSVGImageElement()) {
+    MOZ_ASSERT(NS_IsMainThread(),
+               "Creating ImageBitmap from SVGImageElement off the main thread.");
+    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsSVGImageElement(), aCropRect, aRv);
   } else if (aSrc.IsHTMLVideoElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLVideoElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLVideoElement(), aCropRect, aRv);
   } else if (aSrc.IsHTMLCanvasElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLCanvasElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLCanvasElement(), aCropRect, aRv);
--- a/dom/canvas/ImageBitmap.h
+++ b/dom/canvas/ImageBitmap.h
@@ -43,22 +43,22 @@ class ArrayBufferViewOrArrayBuffer;
 class CanvasRenderingContext2D;
 class CreateImageBitmapFromBlob;
 class CreateImageBitmapFromBlobTask;
 class CreateImageBitmapFromBlobWorkerTask;
 class File;
 class HTMLCanvasElement;
 class HTMLImageElement;
 class HTMLVideoElement;
-enum class ImageBitmapFormat : uint8_t;
+class ImageBitmapShutdownObserver;
 class ImageData;
 class ImageUtils;
 class Promise;
 class PostMessageEvent; // For StructuredClone between windows.
-class ImageBitmapShutdownObserver;
+class SVGImageElement;
 
 struct ImageBitmapCloneData final
 {
   RefPtr<gfx::DataSourceSurface> mSurface;
   gfx::IntRect mPictureRect;
   gfxAlphaType mAlphaType;
 };
 
@@ -180,16 +180,20 @@ protected:
 
   void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
+  CreateInternal(nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
+                 const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
+
+  static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
--- a/dom/canvas/ImageBitmapSource.h
+++ b/dom/canvas/ImageBitmapSource.h
@@ -6,15 +6,15 @@
 
 #ifndef mozilla_dom_ImageBitmapSource_h
 #define mozilla_dom_ImageBitmapSource_h
 
 namespace mozilla {
 namespace dom {
 
 // So we don't have to forward declare this elsewhere.
-class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData;
-typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData ImageBitmapSource;
+class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData;
+typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData ImageBitmapSource;
 
 }
 }
 
 #endif
--- a/dom/webidl/ImageBitmap.webidl
+++ b/dom/webidl/ImageBitmap.webidl
@@ -5,24 +5,17 @@
  *
  * The origin of this IDL file is
  * https://html.spec.whatwg.org/multipage/webappapis.html#images
  *
  * The origin of the extended IDL file is
  * http://w3c.github.io/mediacapture-worker/#imagebitmap-extensions
  */
 
-// This is needed because we don't support SVG element as canvas image source.
-// See bug 1500768.
-typedef (HTMLImageElement or
-         HTMLCanvasElement or
-         HTMLVideoElement or
-         ImageBitmap) CanvasImageSourceExcludedSVG;
-
-typedef (CanvasImageSourceExcludedSVG or
+typedef (CanvasImageSource or
          Blob or
          CanvasRenderingContext2D or // This is out of spec.
          ImageData) ImageBitmapSource;
 
 [Exposed=(Window,Worker)]
 interface ImageBitmap {
   [Constant]
   readonly attribute unsigned long width;
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-drawImage.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-drawImage.html.ini
@@ -9,22 +9,16 @@
     expected: FAIL
 
   [createImageBitmap from a vector HTMLImageElement, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from a vector HTMLImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
     expected: FAIL
 
-  [createImageBitmap from a bitmap SVGImageElement, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a bitmap SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
   [createImageBitmap from a vector SVGImageElement, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from a vector SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from an HTMLCanvasElement scaled down, and drawImage on the created ImageBitmap]
     expected: FAIL
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini
@@ -11,29 +11,11 @@
   [createImageBitmap with an invalid OffscreenCanvas source.]
     expected: FAIL
 
   [createImageBitmap with a broken image source.]
     expected: FAIL
 
   [createImageBitmap with an available but undecodable image source.]
     expected: FAIL
-
-  [createImageBitmap with a bitmap SVGImageElement source and sw set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a bitmap SVGImageElement source and sh set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a vector SVGImageElement source and sw set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a vector SVGImageElement source and sh set to 0]
-    expected: FAIL
-
   [createImageBitmap with CanvasRenderingContext2D image source.]
     expected: FAIL
 
-  [createImageBitmap with a bitmap SVGImageElement source and oversized (unallocatable) crop region]
-    expected: FAIL
-
-  [createImageBitmap with a vector SVGImageElement source and oversized (unallocatable) crop region]
-    expected: FAIL
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-transfer.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-transfer.html.ini
@@ -1,13 +1,10 @@
 [createImageBitmap-transfer.html]
   [Transfer ImageBitmap created from a vector HTMLImageElement]
     expected: FAIL
 
-  [Transfer ImageBitmap created from a bitmap SVGImageElement]
-    expected: FAIL
-
   [Transfer ImageBitmap created from a vector SVGImageElement]
     expected: FAIL
 
   [Transfer ImageBitmap created from an OffscreenCanvas]
     expected: FAIL