LCOV - code coverage report
Current view: top level - dom/canvas - ImageBitmap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 928 0.5 %
Date: 2017-07-14 16:53:18 Functions: 1 115 0.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/ImageBitmap.h"
       8             : #include "mozilla/CheckedInt.h"
       9             : #include "mozilla/dom/ImageBitmapBinding.h"
      10             : #include "mozilla/dom/Promise.h"
      11             : #include "mozilla/dom/StructuredCloneTags.h"
      12             : #include "mozilla/dom/WorkerPrivate.h"
      13             : #include "mozilla/dom/WorkerRunnable.h"
      14             : #include "mozilla/gfx/2D.h"
      15             : #include "mozilla/gfx/Swizzle.h"
      16             : #include "ImageBitmapColorUtils.h"
      17             : #include "ImageBitmapUtils.h"
      18             : #include "ImageUtils.h"
      19             : #include "imgTools.h"
      20             : 
      21             : using namespace mozilla::gfx;
      22             : using namespace mozilla::layers;
      23             : 
      24             : namespace mozilla {
      25             : namespace dom {
      26             : 
      27             : using namespace workers;
      28             : 
      29           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmap, mParent)
      30           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmap)
      31           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmap)
      32           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmap)
      33           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      34           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      35           0 : NS_INTERFACE_MAP_END
      36             : 
      37             : /*
      38             :  * This helper function is used to notify DOM that aBytes memory is allocated
      39             :  * here so that we could trigger GC appropriately.
      40             :  */
      41             : static void
      42           0 : RegisterAllocation(nsIGlobalObject* aGlobal, size_t aBytes)
      43             : {
      44           0 :   AutoJSAPI jsapi;
      45           0 :   if (jsapi.Init(aGlobal)) {
      46           0 :     JS_updateMallocCounter(jsapi.cx(), aBytes);
      47             :   }
      48           0 : }
      49             : 
      50             : static void
      51           0 : RegisterAllocation(nsIGlobalObject* aGlobal, SourceSurface* aSurface)
      52             : {
      53             :   // Calculate how many bytes are used.
      54           0 :   const int bytesPerPixel = BytesPerPixel(aSurface->GetFormat());
      55             :   const size_t bytes =
      56           0 :     aSurface->GetSize().height * aSurface->GetSize().width * bytesPerPixel;
      57             : 
      58             :   // Register.
      59           0 :   RegisterAllocation(aGlobal, bytes);
      60           0 : }
      61             : 
      62             : static void
      63           0 : RegisterAllocation(nsIGlobalObject* aGlobal, layers::Image* aImage)
      64             : {
      65             :   // Calculate how many bytes are used.
      66           0 :   if (aImage->GetFormat() == mozilla::ImageFormat::PLANAR_YCBCR) {
      67           0 :     RegisterAllocation(aGlobal, aImage->AsPlanarYCbCrImage()->GetDataSize());
      68           0 :   } else if (aImage->GetFormat() == mozilla::ImageFormat::NV_IMAGE) {
      69           0 :     RegisterAllocation(aGlobal, aImage->AsNVImage()->GetBufferSize());
      70             :   } else {
      71           0 :     RefPtr<SourceSurface> surface = aImage->GetAsSourceSurface();
      72           0 :     RegisterAllocation(aGlobal, surface);
      73             :   }
      74           0 : }
      75             : 
      76             : /*
      77             :  * If either aRect.width or aRect.height are negative, then return a new IntRect
      78             :  * which represents the same rectangle as the aRect does but with positive width
      79             :  * and height.
      80             :  */
      81             : static IntRect
      82           0 : FixUpNegativeDimension(const IntRect& aRect, ErrorResult& aRv)
      83             : {
      84           0 :   gfx::IntRect rect = aRect;
      85             : 
      86             :   // fix up negative dimensions
      87           0 :   if (rect.width < 0) {
      88           0 :     CheckedInt32 checkedX = CheckedInt32(rect.x) + rect.width;
      89             : 
      90           0 :     if (!checkedX.isValid()) {
      91           0 :       aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
      92           0 :       return rect;
      93             :     }
      94             : 
      95           0 :     rect.x = checkedX.value();
      96           0 :     rect.width = -(rect.width);
      97             :   }
      98             : 
      99           0 :   if (rect.height < 0) {
     100           0 :     CheckedInt32 checkedY = CheckedInt32(rect.y) + rect.height;
     101             : 
     102           0 :     if (!checkedY.isValid()) {
     103           0 :       aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     104           0 :       return rect;
     105             :     }
     106             : 
     107           0 :     rect.y = checkedY.value();
     108           0 :     rect.height = -(rect.height);
     109             :   }
     110             : 
     111           0 :   return rect;
     112             : }
     113             : 
     114             : /*
     115             :  * This helper function copies the data of the given DataSourceSurface,
     116             :  *  _aSurface_, in the given area, _aCropRect_, into a new DataSourceSurface.
     117             :  * This might return null if it can not create a new SourceSurface or it cannot
     118             :  * read data from the given _aSurface_.
     119             :  *
     120             :  * Warning: Even though the area of _aCropRect_ is just the same as the size of
     121             :  *          _aSurface_, this function still copy data into a new
     122             :  *          DataSourceSurface.
     123             :  */
     124             : static already_AddRefed<DataSourceSurface>
     125           0 : CropAndCopyDataSourceSurface(DataSourceSurface* aSurface, const IntRect& aCropRect)
     126             : {
     127           0 :   MOZ_ASSERT(aSurface);
     128             : 
     129             :   // Check the aCropRect
     130           0 :   ErrorResult error;
     131           0 :   const IntRect positiveCropRect = FixUpNegativeDimension(aCropRect, error);
     132           0 :   if (NS_WARN_IF(error.Failed())) {
     133           0 :     error.SuppressException();
     134           0 :     return nullptr;
     135             :   }
     136             : 
     137             :   // Calculate the size of the new SourceSurface.
     138             :   // We cannot keep using aSurface->GetFormat() to create new DataSourceSurface,
     139             :   // since it might be SurfaceFormat::B8G8R8X8 which does not handle opacity,
     140             :   // however the specification explicitly define that "If any of the pixels on
     141             :   // this rectangle are outside the area where the input bitmap was placed, then
     142             :   // they will be transparent black in output."
     143             :   // So, instead, we force the output format to be SurfaceFormat::B8G8R8A8.
     144           0 :   const SurfaceFormat format = SurfaceFormat::B8G8R8A8;
     145           0 :   const int bytesPerPixel = BytesPerPixel(format);
     146           0 :   const IntSize dstSize = IntSize(positiveCropRect.width,
     147           0 :                                   positiveCropRect.height);
     148           0 :   const uint32_t dstStride = dstSize.width * bytesPerPixel;
     149             : 
     150             :   // Create a new SourceSurface.
     151             :   RefPtr<DataSourceSurface> dstDataSurface =
     152           0 :     Factory::CreateDataSourceSurfaceWithStride(dstSize, format, dstStride, true);
     153             : 
     154           0 :   if (NS_WARN_IF(!dstDataSurface)) {
     155           0 :     return nullptr;
     156             :   }
     157             : 
     158             :   // Only do copying and cropping when the positiveCropRect intersects with
     159             :   // the size of aSurface.
     160           0 :   const IntRect surfRect(IntPoint(0, 0), aSurface->GetSize());
     161           0 :   if (surfRect.Intersects(positiveCropRect)) {
     162           0 :     const IntRect surfPortion = surfRect.Intersect(positiveCropRect);
     163           0 :     const IntPoint dest(std::max(0, surfPortion.X() - positiveCropRect.X()),
     164           0 :                         std::max(0, surfPortion.Y() - positiveCropRect.Y()));
     165             : 
     166             :     // Copy the raw data into the newly created DataSourceSurface.
     167           0 :     DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ);
     168           0 :     DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE);
     169           0 :     if (NS_WARN_IF(!srcMap.IsMapped()) ||
     170           0 :         NS_WARN_IF(!dstMap.IsMapped())) {
     171           0 :       return nullptr;
     172             :     }
     173             : 
     174           0 :     uint8_t* srcBufferPtr = srcMap.GetData() + surfPortion.y * srcMap.GetStride()
     175           0 :                                              + surfPortion.x * bytesPerPixel;
     176           0 :     uint8_t* dstBufferPtr = dstMap.GetData() + dest.y * dstMap.GetStride()
     177           0 :                                              + dest.x * bytesPerPixel;
     178             :     CheckedInt<uint32_t> copiedBytesPerRaw =
     179           0 :       CheckedInt<uint32_t>(surfPortion.width) * bytesPerPixel;
     180           0 :     if (!copiedBytesPerRaw.isValid()) {
     181           0 :       return nullptr;
     182             :     }
     183             : 
     184           0 :     for (int i = 0; i < surfPortion.height; ++i) {
     185           0 :       memcpy(dstBufferPtr, srcBufferPtr, copiedBytesPerRaw.value());
     186           0 :       srcBufferPtr += srcMap.GetStride();
     187           0 :       dstBufferPtr += dstMap.GetStride();
     188             :     }
     189             :   }
     190             : 
     191           0 :   return dstDataSurface.forget();
     192             : }
     193             : 
     194             : /*
     195             :  * Encapsulate the given _aSurface_ into a layers::SourceSurfaceImage.
     196             :  */
     197             : static already_AddRefed<layers::Image>
     198           0 : CreateImageFromSurface(SourceSurface* aSurface)
     199             : {
     200           0 :   MOZ_ASSERT(aSurface);
     201             :   RefPtr<layers::SourceSurfaceImage> image =
     202           0 :     new layers::SourceSurfaceImage(aSurface->GetSize(), aSurface);
     203           0 :   return image.forget();
     204             : }
     205             : 
     206             : /*
     207             :  * CreateImageFromRawData(), CreateSurfaceFromRawData() and
     208             :  * CreateImageFromRawDataInMainThreadSyncTask are helpers for
     209             :  * create-from-ImageData case
     210             :  */
     211             : static already_AddRefed<SourceSurface>
     212           0 : CreateSurfaceFromRawData(const gfx::IntSize& aSize,
     213             :                          uint32_t aStride,
     214             :                          gfx::SurfaceFormat aFormat,
     215             :                          uint8_t* aBuffer,
     216             :                          uint32_t aBufferLength,
     217             :                          const Maybe<IntRect>& aCropRect)
     218             : {
     219           0 :   MOZ_ASSERT(!aSize.IsEmpty());
     220           0 :   MOZ_ASSERT(aBuffer);
     221             : 
     222             :   // Wrap the source buffer into a SourceSurface.
     223             :   RefPtr<DataSourceSurface> dataSurface =
     224           0 :     Factory::CreateWrappingDataSourceSurface(aBuffer, aStride, aSize, aFormat);
     225             : 
     226           0 :   if (NS_WARN_IF(!dataSurface)) {
     227           0 :     return nullptr;
     228             :   }
     229             : 
     230             :   // The temporary cropRect variable is equal to the size of source buffer if we
     231             :   // do not need to crop, or it equals to the given cropping size.
     232           0 :   const IntRect cropRect = aCropRect.valueOr(IntRect(0, 0, aSize.width, aSize.height));
     233             : 
     234             :   // Copy the source buffer in the _cropRect_ area into a new SourceSurface.
     235           0 :   RefPtr<DataSourceSurface> result = CropAndCopyDataSourceSurface(dataSurface, cropRect);
     236             : 
     237           0 :   if (NS_WARN_IF(!result)) {
     238           0 :     return nullptr;
     239             :   }
     240             : 
     241           0 :   return result.forget();
     242             : }
     243             : 
     244             : static already_AddRefed<layers::Image>
     245           0 : CreateImageFromRawData(const gfx::IntSize& aSize,
     246             :                        uint32_t aStride,
     247             :                        gfx::SurfaceFormat aFormat,
     248             :                        uint8_t* aBuffer,
     249             :                        uint32_t aBufferLength,
     250             :                        const Maybe<IntRect>& aCropRect)
     251             : {
     252           0 :   MOZ_ASSERT(NS_IsMainThread());
     253             : 
     254             :   // Copy and crop the source buffer into a SourceSurface.
     255             :   RefPtr<SourceSurface> rgbaSurface =
     256           0 :     CreateSurfaceFromRawData(aSize, aStride, aFormat,
     257             :                              aBuffer, aBufferLength,
     258           0 :                              aCropRect);
     259             : 
     260           0 :   if (NS_WARN_IF(!rgbaSurface)) {
     261           0 :     return nullptr;
     262             :   }
     263             : 
     264             :   // Convert RGBA to BGRA
     265           0 :   RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface();
     266             :   RefPtr<DataSourceSurface> bgraDataSurface =
     267           0 :     Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(),
     268             :                                                SurfaceFormat::B8G8R8A8,
     269           0 :                                                rgbaDataSurface->Stride());
     270             : 
     271             :   DataSourceSurface::MappedSurface rgbaMap;
     272             :   DataSourceSurface::MappedSurface bgraMap;
     273             : 
     274           0 :   if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap)) ||
     275           0 :       NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) {
     276           0 :     return nullptr;
     277             :   }
     278             : 
     279           0 :   SwizzleData(rgbaMap.mData, rgbaMap.mStride, SurfaceFormat::R8G8B8A8,
     280             :               bgraMap.mData, bgraMap.mStride, SurfaceFormat::B8G8R8A8,
     281           0 :               bgraDataSurface->GetSize());
     282             : 
     283           0 :   rgbaDataSurface->Unmap();
     284           0 :   bgraDataSurface->Unmap();
     285             : 
     286             :   // Create an Image from the BGRA SourceSurface.
     287           0 :   RefPtr<layers::Image> image = CreateImageFromSurface(bgraDataSurface);
     288             : 
     289           0 :   if (NS_WARN_IF(!image)) {
     290           0 :     return nullptr;
     291             :   }
     292             : 
     293           0 :   return image.forget();
     294             : }
     295             : 
     296             : /*
     297             :  * This is a synchronous task.
     298             :  * This class is used to create a layers::SourceSurfaceImage from raw data in the main
     299             :  * thread. While creating an ImageBitmap from an ImageData, we need to create
     300             :  * a SouceSurface from the ImageData's raw data and then set the SourceSurface
     301             :  * into a layers::SourceSurfaceImage. However, the layers::SourceSurfaceImage asserts the
     302             :  * setting operation in the main thread, so if we are going to create an
     303             :  * ImageBitmap from an ImageData off the main thread, we post an event to the
     304             :  * main thread to create a layers::SourceSurfaceImage from an ImageData's raw data.
     305             :  */
     306           0 : class CreateImageFromRawDataInMainThreadSyncTask final :
     307             :   public WorkerMainThreadRunnable
     308             : {
     309             : public:
     310           0 :   CreateImageFromRawDataInMainThreadSyncTask(uint8_t* aBuffer,
     311             :                                              uint32_t aBufferLength,
     312             :                                              uint32_t aStride,
     313             :                                              gfx::SurfaceFormat aFormat,
     314             :                                              const gfx::IntSize& aSize,
     315             :                                              const Maybe<IntRect>& aCropRect,
     316             :                                              layers::Image** aImage)
     317           0 :   : WorkerMainThreadRunnable(GetCurrentThreadWorkerPrivate(),
     318           0 :                                NS_LITERAL_CSTRING("ImageBitmap :: Create Image from Raw Data"))
     319             :   , mImage(aImage)
     320             :   , mBuffer(aBuffer)
     321             :   , mBufferLength(aBufferLength)
     322             :   , mStride(aStride)
     323             :   , mFormat(aFormat)
     324             :   , mSize(aSize)
     325           0 :   , mCropRect(aCropRect)
     326             :   {
     327           0 :     MOZ_ASSERT(!(*aImage), "Don't pass an existing Image into CreateImageFromRawDataInMainThreadSyncTask.");
     328           0 :   }
     329             : 
     330           0 :   bool MainThreadRun() override
     331             :   {
     332             :     RefPtr<layers::Image> image =
     333           0 :       CreateImageFromRawData(mSize, mStride, mFormat,
     334             :                              mBuffer, mBufferLength,
     335           0 :                              mCropRect);
     336             : 
     337           0 :     if (NS_WARN_IF(!image)) {
     338           0 :       return false;
     339             :     }
     340             : 
     341           0 :     image.forget(mImage);
     342             : 
     343           0 :     return true;
     344             :   }
     345             : 
     346             : private:
     347             :   layers::Image** mImage;
     348             :   uint8_t* mBuffer;
     349             :   uint32_t mBufferLength;
     350             :   uint32_t mStride;
     351             :   gfx::SurfaceFormat mFormat;
     352             :   gfx::IntSize mSize;
     353             :   const Maybe<IntRect>& mCropRect;
     354             : };
     355             : 
     356             : static bool
     357           0 : CheckSecurityForHTMLElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
     358             : {
     359           0 :   MOZ_ASSERT(aPrincipal);
     360             : 
     361           0 :   if (aIsWriteOnly) {
     362           0 :     return false;
     363             :   }
     364             : 
     365           0 :   if (!aCORSUsed) {
     366           0 :     nsIGlobalObject* incumbentSettingsObject = GetIncumbentGlobal();
     367           0 :     if (NS_WARN_IF(!incumbentSettingsObject)) {
     368           0 :       return false;
     369             :     }
     370             : 
     371           0 :     nsIPrincipal* principal = incumbentSettingsObject->PrincipalOrNull();
     372           0 :     if (NS_WARN_IF(!principal) || !(principal->Subsumes(aPrincipal))) {
     373           0 :       return false;
     374             :     }
     375             :   }
     376             : 
     377           0 :   return true;
     378             : }
     379             : 
     380             : static bool
     381           0 : CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes)
     382             : {
     383           0 :   return CheckSecurityForHTMLElements(aRes.mIsWriteOnly, aRes.mCORSUsed, aRes.mPrincipal);
     384             : }
     385             : 
     386             : /*
     387             :  * A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
     388             :  * security checking.
     389             :  */
     390             : template<class HTMLElementType>
     391             : static already_AddRefed<SourceSurface>
     392           0 : GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv)
     393             : {
     394             :   nsLayoutUtils::SurfaceFromElementResult res =
     395           0 :     nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
     396             : 
     397             :   // check origin-clean
     398           0 :   if (!CheckSecurityForHTMLElements(res)) {
     399           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     400           0 :     return nullptr;
     401             :   }
     402             : 
     403           0 :   RefPtr<SourceSurface> surface = res.GetSourceSurface();
     404             : 
     405           0 :   if (NS_WARN_IF(!surface)) {
     406           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     407           0 :     return nullptr;
     408             :   }
     409             : 
     410           0 :   return surface.forget();
     411             : }
     412             : 
     413             : /*
     414             :  * The specification doesn't allow to create an ImegeBitmap from a vector image.
     415             :  * This function is used to check if the given HTMLImageElement contains a
     416             :  * raster image.
     417             :  */
     418             : static bool
     419           0 : HasRasterImage(HTMLImageElement& aImageEl)
     420             : {
     421             :   nsresult rv;
     422             : 
     423           0 :   nsCOMPtr<imgIRequest> imgRequest;
     424           0 :   rv = aImageEl.GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     425           0 :                            getter_AddRefs(imgRequest));
     426           0 :   if (NS_SUCCEEDED(rv) && imgRequest) {
     427           0 :     nsCOMPtr<imgIContainer> imgContainer;
     428           0 :     rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
     429           0 :     if (NS_SUCCEEDED(rv) && imgContainer &&
     430           0 :         imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
     431           0 :       return true;
     432             :     }
     433             :   }
     434             : 
     435           0 :   return false;
     436             : }
     437             : 
     438           0 : ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
     439           0 :                          gfxAlphaType aAlphaType)
     440             :   : mParent(aGlobal)
     441             :   , mData(aData)
     442             :   , mSurface(nullptr)
     443           0 :   , mDataWrapper(new ImageUtils(mData))
     444           0 :   , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
     445             :   , mAlphaType(aAlphaType)
     446           0 :   , mIsCroppingAreaOutSideOfSourceImage(false)
     447             : {
     448           0 :   MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
     449           0 : }
     450             : 
     451           0 : ImageBitmap::~ImageBitmap()
     452             : {
     453           0 : }
     454             : 
     455             : JSObject*
     456           0 : ImageBitmap::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     457             : {
     458           0 :   return ImageBitmapBinding::Wrap(aCx, this, aGivenProto);
     459             : }
     460             : 
     461             : void
     462           0 : ImageBitmap::Close()
     463             : {
     464           0 :   mData = nullptr;
     465           0 :   mSurface = nullptr;
     466           0 :   mPictureRect.SetEmpty();
     467           0 : }
     468             : 
     469             : void
     470           0 : ImageBitmap::SetPictureRect(const IntRect& aRect, ErrorResult& aRv)
     471             : {
     472           0 :   mPictureRect = FixUpNegativeDimension(aRect, aRv);
     473           0 : }
     474             : 
     475             : void
     476           0 : ImageBitmap::SetIsCroppingAreaOutSideOfSourceImage(const IntSize& aSourceSize,
     477             :                                                    const Maybe<IntRect>& aCroppingRect)
     478             : {
     479             :   // No cropping at all.
     480           0 :   if (aCroppingRect.isNothing()) {
     481           0 :     mIsCroppingAreaOutSideOfSourceImage = false;
     482           0 :     return;
     483             :   }
     484             : 
     485           0 :   if (aCroppingRect->X() < 0 || aCroppingRect->Y() < 0 ||
     486           0 :       aCroppingRect->Width() > aSourceSize.width ||
     487           0 :       aCroppingRect->Height() > aSourceSize.height) {
     488           0 :     mIsCroppingAreaOutSideOfSourceImage = true;
     489             :   }
     490             : }
     491             : 
     492             : static already_AddRefed<SourceSurface>
     493           0 : ConvertColorFormatIfNeeded(RefPtr<SourceSurface> aSurface)
     494             : {
     495           0 :   const SurfaceFormat srcFormat = aSurface->GetFormat();
     496           0 :   if (srcFormat == SurfaceFormat::R8G8B8A8 ||
     497           0 :       srcFormat == SurfaceFormat::B8G8R8A8 ||
     498           0 :       srcFormat == SurfaceFormat::R8G8B8X8 ||
     499           0 :       srcFormat == SurfaceFormat::B8G8R8X8 ||
     500           0 :       srcFormat == SurfaceFormat::A8R8G8B8 ||
     501             :       srcFormat == SurfaceFormat::X8R8G8B8) {
     502           0 :     return aSurface.forget();
     503             :   }
     504             : 
     505           0 :   if (srcFormat == SurfaceFormat::A8 ||
     506             :       srcFormat == SurfaceFormat::Depth) {
     507           0 :     return nullptr;
     508             :   }
     509             : 
     510           0 :   const int bytesPerPixel = BytesPerPixel(SurfaceFormat::B8G8R8A8);
     511           0 :   const IntSize dstSize = aSurface->GetSize();
     512           0 :   const uint32_t dstStride = dstSize.width * bytesPerPixel;
     513             : 
     514             :   RefPtr<DataSourceSurface> dstDataSurface =
     515           0 :     Factory::CreateDataSourceSurfaceWithStride(dstSize,
     516             :                                                SurfaceFormat::B8G8R8A8,
     517           0 :                                                dstStride);
     518             : 
     519           0 :   RefPtr<DataSourceSurface> srcDataSurface = aSurface->GetDataSurface();
     520           0 :   if (NS_WARN_IF(!srcDataSurface)) {
     521           0 :     return nullptr;
     522             :   }
     523             : 
     524           0 :   DataSourceSurface::ScopedMap srcMap(srcDataSurface, DataSourceSurface::READ);
     525           0 :   DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE);
     526           0 :   if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
     527           0 :     return nullptr;
     528             :   }
     529             : 
     530           0 :   int rv = 0;
     531           0 :   if (srcFormat == SurfaceFormat::R8G8B8) {
     532           0 :     rv = RGB24ToBGRA32(srcMap.GetData(), srcMap.GetStride(),
     533             :                        dstMap.GetData(), dstMap.GetStride(),
     534           0 :                        dstSize.width, dstSize.height);
     535           0 :   } else if (srcFormat == SurfaceFormat::B8G8R8) {
     536           0 :     rv = BGR24ToBGRA32(srcMap.GetData(), srcMap.GetStride(),
     537             :                        dstMap.GetData(), dstMap.GetStride(),
     538           0 :                        dstSize.width, dstSize.height);
     539           0 :   } else if (srcFormat == SurfaceFormat::HSV) {
     540           0 :     rv = HSVToBGRA32((const float*)srcMap.GetData(), srcMap.GetStride(),
     541             :                      dstMap.GetData(), dstMap.GetStride(),
     542           0 :                      dstSize.width, dstSize.height);
     543           0 :   } else if (srcFormat == SurfaceFormat::Lab) {
     544           0 :     rv = LabToBGRA32((const float*)srcMap.GetData(), srcMap.GetStride(),
     545             :                      dstMap.GetData(), dstMap.GetStride(),
     546           0 :                      dstSize.width, dstSize.height);
     547             :   }
     548             : 
     549           0 :   if (NS_WARN_IF(rv != 0)) {
     550           0 :     return nullptr;
     551             :   }
     552             : 
     553           0 :   return dstDataSurface.forget();
     554             : }
     555             : 
     556             : /*
     557             :  * The functionality of PrepareForDrawTarget method:
     558             :  * (1) Get a SourceSurface from the mData (which is a layers::Image).
     559             :  * (2) Convert the SourceSurface to format B8G8R8A8 if the original format is
     560             :  *     R8G8B8, B8G8R8, HSV or Lab.
     561             :  *     Note: if the original format is A8 or Depth, then return null directly.
     562             :  * (3) Do cropping if the size of SourceSurface does not equal to the
     563             :  *     mPictureRect.
     564             :  * (4) Pre-multiply alpha if needed.
     565             :  */
     566             : already_AddRefed<SourceSurface>
     567           0 : ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget)
     568             : {
     569           0 :   MOZ_ASSERT(aTarget);
     570             : 
     571           0 :   if (!mData) {
     572           0 :     return nullptr;
     573             :   }
     574             : 
     575           0 :   if (!mSurface) {
     576           0 :     mSurface = mData->GetAsSourceSurface();
     577             : 
     578           0 :     if (!mSurface) {
     579           0 :       return nullptr;
     580             :     }
     581             :   }
     582             : 
     583             :   // Check if we need to convert the format.
     584             :   // Convert R8G8B8/B8G8R8/HSV/Lab to B8G8R8A8.
     585             :   // Return null if the original format is A8 or Depth.
     586           0 :   mSurface = ConvertColorFormatIfNeeded(mSurface);
     587           0 :   if (NS_WARN_IF(!mSurface)) {
     588           0 :     return nullptr;
     589             :   }
     590             : 
     591           0 :   RefPtr<DrawTarget> target = aTarget;
     592           0 :   IntRect surfRect(0, 0, mSurface->GetSize().width, mSurface->GetSize().height);
     593             : 
     594             :   // Check if we still need to crop our surface
     595           0 :   if (!mPictureRect.IsEqualEdges(surfRect)) {
     596             : 
     597           0 :     IntRect surfPortion = surfRect.Intersect(mPictureRect);
     598             : 
     599             :     // the crop lies entirely outside the surface area, nothing to draw
     600           0 :     if (surfPortion.IsEmpty()) {
     601           0 :       mSurface = nullptr;
     602           0 :       RefPtr<gfx::SourceSurface> surface(mSurface);
     603           0 :       return surface.forget();
     604             :     }
     605             : 
     606           0 :     IntPoint dest(std::max(0, surfPortion.X() - mPictureRect.X()),
     607           0 :                   std::max(0, surfPortion.Y() - mPictureRect.Y()));
     608             : 
     609             :     // We must initialize this target with mPictureRect.Size() because the
     610             :     // specification states that if the cropping area is given, then return an
     611             :     // ImageBitmap with the size equals to the cropping area.
     612           0 :     target = target->CreateSimilarDrawTarget(mPictureRect.Size(),
     613           0 :                                              target->GetFormat());
     614             : 
     615           0 :     if (!target) {
     616           0 :       mSurface = nullptr;
     617           0 :       RefPtr<gfx::SourceSurface> surface(mSurface);
     618           0 :       return surface.forget();
     619             :     }
     620             : 
     621           0 :     target->CopySurface(mSurface, surfPortion, dest);
     622           0 :     mSurface = target->Snapshot();
     623             : 
     624             :     // Make mCropRect match new surface we've cropped to
     625           0 :     mPictureRect.MoveTo(0, 0);
     626             :   }
     627             : 
     628             :   // Pre-multiply alpha here.
     629             :   // Ignore this step if the source surface does not have alpha channel; this
     630             :   // kind of source surfaces might come form layers::PlanarYCbCrImage.
     631           0 :   if (mAlphaType == gfxAlphaType::NonPremult &&
     632           0 :       !IsOpaque(mSurface->GetFormat()))
     633             :   {
     634           0 :     MOZ_ASSERT(mSurface->GetFormat() == SurfaceFormat::R8G8B8A8 ||
     635             :                mSurface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
     636             :                mSurface->GetFormat() == SurfaceFormat::A8R8G8B8);
     637             : 
     638           0 :     RefPtr<DataSourceSurface> dstSurface = mSurface->GetDataSurface();
     639           0 :     MOZ_ASSERT(dstSurface);
     640             : 
     641           0 :     RefPtr<DataSourceSurface> srcSurface;
     642             :     DataSourceSurface::MappedSurface srcMap;
     643             :     DataSourceSurface::MappedSurface dstMap;
     644             : 
     645           0 :     if (dstSurface->Map(DataSourceSurface::MapType::READ_WRITE, &dstMap)) {
     646           0 :       srcMap = dstMap;
     647             :     } else {
     648           0 :       srcSurface = dstSurface;
     649           0 :       if (!srcSurface->Map(DataSourceSurface::READ, &srcMap)) {
     650           0 :         gfxCriticalError() << "Failed to map source surface for premultiplying alpha.";
     651           0 :         return nullptr;
     652             :       }
     653             : 
     654           0 :       dstSurface = Factory::CreateDataSourceSurface(srcSurface->GetSize(), srcSurface->GetFormat());
     655             : 
     656           0 :       if (!dstSurface || !dstSurface->Map(DataSourceSurface::MapType::WRITE, &dstMap)) {
     657           0 :         gfxCriticalError() << "Failed to map destination surface for premultiplying alpha.";
     658           0 :         srcSurface->Unmap();
     659           0 :         return nullptr;
     660             :       }
     661             :     }
     662             : 
     663           0 :     PremultiplyData(srcMap.mData, srcMap.mStride, mSurface->GetFormat(),
     664           0 :                     dstMap.mData, dstMap.mStride, mSurface->GetFormat(),
     665           0 :                     dstSurface->GetSize());
     666             : 
     667           0 :     dstSurface->Unmap();
     668           0 :     if (srcSurface) {
     669           0 :       srcSurface->Unmap();
     670             :     }
     671             : 
     672           0 :     mSurface = dstSurface;
     673             :   }
     674             : 
     675             :   // Replace our surface with one optimized for the target we're about to draw
     676             :   // to, under the assumption it'll likely be drawn again to that target.
     677             :   // This call should be a no-op for already-optimized surfaces
     678           0 :   mSurface = target->OptimizeSourceSurface(mSurface);
     679             : 
     680           0 :   RefPtr<gfx::SourceSurface> surface(mSurface);
     681           0 :   return surface.forget();
     682             : }
     683             : 
     684             : already_AddRefed<layers::Image>
     685           0 : ImageBitmap::TransferAsImage()
     686             : {
     687           0 :   RefPtr<layers::Image> image = mData;
     688           0 :   Close();
     689           0 :   return image.forget();
     690             : }
     691             : 
     692             : UniquePtr<ImageBitmapCloneData>
     693           0 : ImageBitmap::ToCloneData() const
     694             : {
     695           0 :   UniquePtr<ImageBitmapCloneData> result(new ImageBitmapCloneData());
     696           0 :   result->mPictureRect = mPictureRect;
     697           0 :   result->mAlphaType = mAlphaType;
     698           0 :   result->mIsCroppingAreaOutSideOfSourceImage = mIsCroppingAreaOutSideOfSourceImage;
     699           0 :   RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
     700           0 :   result->mSurface = surface->GetDataSurface();
     701           0 :   MOZ_ASSERT(result->mSurface);
     702             : 
     703           0 :   return Move(result);
     704             : }
     705             : 
     706             : /* static */ already_AddRefed<ImageBitmap>
     707           0 : ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
     708             :                                  ImageBitmapCloneData* aData)
     709             : {
     710           0 :   RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
     711             : 
     712           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mAlphaType);
     713             : 
     714             :   // Report memory allocation.
     715           0 :   RegisterAllocation(aGlobal, aData->mSurface);
     716             : 
     717           0 :   ret->mIsCroppingAreaOutSideOfSourceImage =
     718           0 :     aData->mIsCroppingAreaOutSideOfSourceImage;
     719             : 
     720           0 :   ErrorResult rv;
     721           0 :   ret->SetPictureRect(aData->mPictureRect, rv);
     722           0 :   return ret.forget();
     723             : }
     724             : 
     725             : /* static */ already_AddRefed<ImageBitmap>
     726           0 : ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
     727             :                                        OffscreenCanvas& aOffscreenCanvas,
     728             :                                        ErrorResult& aRv)
     729             : {
     730             :   // Check origin-clean.
     731           0 :   if (aOffscreenCanvas.IsWriteOnly()) {
     732           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     733           0 :     return nullptr;
     734             :   }
     735             : 
     736             :   nsLayoutUtils::SurfaceFromElementResult res =
     737             :     nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas,
     738           0 :                                               nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
     739             : 
     740           0 :   RefPtr<SourceSurface> surface = res.GetSourceSurface();
     741             : 
     742           0 :   if (NS_WARN_IF(!surface)) {
     743           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     744           0 :     return nullptr;
     745             :   }
     746             : 
     747             :   RefPtr<layers::Image> data =
     748           0 :     CreateImageFromSurface(surface);
     749             : 
     750           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
     751             : 
     752             :   // Report memory allocation.
     753           0 :   RegisterAllocation(aGlobal, surface);
     754             : 
     755           0 :   return ret.forget();
     756             : }
     757             : 
     758             : /* static */ already_AddRefed<ImageBitmap>
     759           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
     760             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
     761             : {
     762             :   // Check if the image element is completely available or not.
     763           0 :   if (!aImageEl.Complete()) {
     764           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     765           0 :     return nullptr;
     766             :   }
     767             : 
     768             :   // Check if the image element is a bitmap (e.g. it's a vector graphic) or not.
     769           0 :   if (!HasRasterImage(aImageEl)) {
     770           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     771           0 :     return nullptr;
     772             :   }
     773             : 
     774             :   // Get the SourceSurface out from the image element and then do security
     775             :   // checking.
     776           0 :   RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
     777             : 
     778           0 :   if (NS_WARN_IF(aRv.Failed())) {
     779           0 :     return nullptr;
     780             :   }
     781             : 
     782             :   // Create ImageBitmap.
     783           0 :   RefPtr<layers::Image> data = CreateImageFromSurface(surface);
     784             : 
     785           0 :   if (NS_WARN_IF(!data)) {
     786           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     787           0 :     return nullptr;
     788             :   }
     789             : 
     790           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
     791             : 
     792             :   // Set the picture rectangle.
     793           0 :   if (ret && aCropRect.isSome()) {
     794           0 :     ret->SetPictureRect(aCropRect.ref(), aRv);
     795             :   }
     796             : 
     797             :   // Set mIsCroppingAreaOutSideOfSourceImage.
     798           0 :   ret->SetIsCroppingAreaOutSideOfSourceImage(surface->GetSize(), aCropRect);
     799             : 
     800           0 :   return ret.forget();
     801             : }
     802             : 
     803             : /* static */ already_AddRefed<ImageBitmap>
     804           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
     805             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
     806             : {
     807           0 :   aVideoEl.MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_IMAGEBITMAP);
     808             : 
     809             :   // Check network state.
     810           0 :   if (aVideoEl.NetworkState() == HTMLMediaElement::NETWORK_EMPTY) {
     811           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     812           0 :     return nullptr;
     813             :   }
     814             : 
     815             :   // Check ready state.
     816             :   // Cannot be HTMLMediaElement::HAVE_NOTHING or HTMLMediaElement::HAVE_METADATA.
     817           0 :   if (aVideoEl.ReadyState() <= HTMLMediaElement::HAVE_METADATA) {
     818           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     819           0 :     return nullptr;
     820             :   }
     821             : 
     822             :   // Check security.
     823           0 :   nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
     824           0 :   bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
     825           0 :   if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
     826           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     827           0 :     return nullptr;
     828             :   }
     829             : 
     830             :   // Create ImageBitmap.
     831           0 :   RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
     832           0 :   if (!data) {
     833           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     834           0 :     return nullptr;
     835             :   }
     836           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
     837             : 
     838             :   // Set the picture rectangle.
     839           0 :   if (ret && aCropRect.isSome()) {
     840           0 :     ret->SetPictureRect(aCropRect.ref(), aRv);
     841             :   }
     842             : 
     843             :   // Set mIsCroppingAreaOutSideOfSourceImage.
     844           0 :   ret->SetIsCroppingAreaOutSideOfSourceImage(data->GetSize(), aCropRect);
     845             : 
     846           0 :   return ret.forget();
     847             : }
     848             : 
     849             : /* static */ already_AddRefed<ImageBitmap>
     850           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
     851             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
     852             : {
     853           0 :   if (aCanvasEl.Width() == 0 || aCanvasEl.Height() == 0) {
     854           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     855           0 :     return nullptr;
     856             :   }
     857             : 
     858           0 :   RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv);
     859             : 
     860           0 :   if (NS_WARN_IF(aRv.Failed())) {
     861           0 :     return nullptr;
     862             :   }
     863             : 
     864             :   // Crop the source surface if needed.
     865           0 :   RefPtr<SourceSurface> croppedSurface;
     866           0 :   IntRect cropRect = aCropRect.valueOr(IntRect());
     867             : 
     868             :   // If the HTMLCanvasElement's rendering context is WebGL, then the snapshot
     869             :   // we got from the HTMLCanvasElement is a DataSourceSurface which is a copy
     870             :   // of the rendering context. We handle cropping in this case.
     871           0 :   bool needToReportMemoryAllocation = false;
     872           0 :   if ((aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL1 ||
     873           0 :        aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2) &&
     874           0 :       aCropRect.isSome()) {
     875           0 :     RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
     876           0 :     croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect);
     877           0 :     cropRect.MoveTo(0, 0);
     878           0 :     needToReportMemoryAllocation = true;
     879             :   }
     880             :   else {
     881           0 :     croppedSurface = surface;
     882             :   }
     883             : 
     884           0 :   if (NS_WARN_IF(!croppedSurface)) {
     885           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     886           0 :     return nullptr;
     887             :   }
     888             : 
     889             :   // Create an Image from the SourceSurface.
     890           0 :   RefPtr<layers::Image> data = CreateImageFromSurface(croppedSurface);
     891             : 
     892           0 :   if (NS_WARN_IF(!data)) {
     893           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     894           0 :     return nullptr;
     895             :   }
     896             : 
     897           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
     898             : 
     899             :   // Report memory allocation if needed.
     900           0 :   if (needToReportMemoryAllocation) {
     901           0 :     RegisterAllocation(aGlobal, croppedSurface);
     902             :   }
     903             : 
     904             :   // Set the picture rectangle.
     905           0 :   if (ret && aCropRect.isSome()) {
     906           0 :     ret->SetPictureRect(cropRect, aRv);
     907             :   }
     908             : 
     909             :   // Set mIsCroppingAreaOutSideOfSourceImage.
     910           0 :   ret->SetIsCroppingAreaOutSideOfSourceImage(surface->GetSize(), aCropRect);
     911             : 
     912           0 :   return ret.forget();
     913             : }
     914             : 
     915             : /* static */ already_AddRefed<ImageBitmap>
     916           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
     917             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
     918             : {
     919             :   // Copy data into SourceSurface.
     920           0 :   dom::Uint8ClampedArray array;
     921           0 :   DebugOnly<bool> inited = array.Init(aImageData.GetDataObject());
     922           0 :   MOZ_ASSERT(inited);
     923             : 
     924           0 :   array.ComputeLengthAndData();
     925           0 :   const SurfaceFormat FORMAT = SurfaceFormat::R8G8B8A8;
     926             :   // ImageData's underlying data is not alpha-premultiplied.
     927           0 :   const auto alphaType = gfxAlphaType::NonPremult;
     928           0 :   const uint32_t BYTES_PER_PIXEL = BytesPerPixel(FORMAT);
     929           0 :   const uint32_t imageWidth = aImageData.Width();
     930           0 :   const uint32_t imageHeight = aImageData.Height();
     931           0 :   const uint32_t imageStride = imageWidth * BYTES_PER_PIXEL;
     932           0 :   const uint32_t dataLength = array.Length();
     933           0 :   const gfx::IntSize imageSize(imageWidth, imageHeight);
     934             : 
     935             :   // Check the ImageData is neutered or not.
     936           0 :   if (imageWidth == 0 || imageHeight == 0 ||
     937           0 :       (imageWidth * imageHeight * BYTES_PER_PIXEL) != dataLength) {
     938           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     939           0 :     return nullptr;
     940             :   }
     941             : 
     942             :   // Create and Crop the raw data into a layers::Image
     943           0 :   RefPtr<layers::Image> data;
     944           0 :   if (NS_IsMainThread()) {
     945           0 :     data = CreateImageFromRawData(imageSize, imageStride, FORMAT,
     946             :                                   array.Data(), dataLength,
     947           0 :                                   aCropRect);
     948             :   } else {
     949             :     RefPtr<CreateImageFromRawDataInMainThreadSyncTask> task
     950           0 :       = new CreateImageFromRawDataInMainThreadSyncTask(array.Data(),
     951             :                                                        dataLength,
     952             :                                                        imageStride,
     953             :                                                        FORMAT,
     954             :                                                        imageSize,
     955             :                                                        aCropRect,
     956           0 :                                                        getter_AddRefs(data));
     957           0 :     task->Dispatch(Terminating, aRv);
     958             :   }
     959             : 
     960           0 :   if (NS_WARN_IF(!data)) {
     961           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     962           0 :     return nullptr;
     963             :   }
     964             : 
     965             :   // Create an ImageBimtap.
     966           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, alphaType);
     967             : 
     968             :   // Report memory allocation.
     969           0 :   RegisterAllocation(aGlobal, data);
     970             : 
     971             :   // The cropping information has been handled in the CreateImageFromRawData()
     972             :   // function.
     973             : 
     974             :   // Set mIsCroppingAreaOutSideOfSourceImage.
     975           0 :   ret->SetIsCroppingAreaOutSideOfSourceImage(imageSize, aCropRect);
     976             : 
     977           0 :   return ret.forget();
     978             : }
     979             : 
     980             : /* static */ already_AddRefed<ImageBitmap>
     981           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
     982             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
     983             : {
     984             :   // Check origin-clean.
     985           0 :   if (aCanvasCtx.GetCanvas()->IsWriteOnly()) {
     986           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     987           0 :     return nullptr;
     988             :   }
     989             : 
     990           0 :   RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
     991             : 
     992           0 :   if (NS_WARN_IF(!surface)) {
     993           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     994           0 :     return nullptr;
     995             :   }
     996             : 
     997           0 :   const IntSize surfaceSize = surface->GetSize();
     998           0 :   if (surfaceSize.width == 0 || surfaceSize.height == 0) {
     999           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    1000           0 :     return nullptr;
    1001             :   }
    1002             : 
    1003           0 :   RefPtr<layers::Image> data = CreateImageFromSurface(surface);
    1004             : 
    1005           0 :   if (NS_WARN_IF(!data)) {
    1006           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    1007           0 :     return nullptr;
    1008             :   }
    1009             : 
    1010           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
    1011             : 
    1012             :   // Report memory allocation.
    1013           0 :   RegisterAllocation(aGlobal, surface);
    1014             : 
    1015             :   // Set the picture rectangle.
    1016           0 :   if (ret && aCropRect.isSome()) {
    1017           0 :     ret->SetPictureRect(aCropRect.ref(), aRv);
    1018             :   }
    1019             : 
    1020             :   // Set mIsCroppingAreaOutSideOfSourceImage.
    1021           0 :   ret->SetIsCroppingAreaOutSideOfSourceImage(surface->GetSize(), aCropRect);
    1022             : 
    1023           0 :   return ret.forget();
    1024             : }
    1025             : 
    1026             : /* static */ already_AddRefed<ImageBitmap>
    1027           0 : ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
    1028             :                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
    1029             : {
    1030           0 :   if (!aImageBitmap.mData) {
    1031           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    1032           0 :     return nullptr;
    1033             :   }
    1034             : 
    1035           0 :   RefPtr<layers::Image> data = aImageBitmap.mData;
    1036           0 :   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mAlphaType);
    1037             : 
    1038             :   // Set the picture rectangle.
    1039           0 :   if (ret && aCropRect.isSome()) {
    1040           0 :     ret->SetPictureRect(aCropRect.ref(), aRv);
    1041             :   }
    1042             : 
    1043             :   // Set mIsCroppingAreaOutSideOfSourceImage.
    1044           0 :   if (aImageBitmap.mIsCroppingAreaOutSideOfSourceImage == true) {
    1045           0 :     ret->mIsCroppingAreaOutSideOfSourceImage = true;
    1046             :   } else {
    1047           0 :     ret->SetIsCroppingAreaOutSideOfSourceImage(aImageBitmap.mPictureRect.Size(),
    1048           0 :                                                aCropRect);
    1049             :   }
    1050             : 
    1051           0 :   return ret.forget();
    1052             : }
    1053             : 
    1054           0 : class FulfillImageBitmapPromise
    1055             : {
    1056             : protected:
    1057           0 :   FulfillImageBitmapPromise(Promise* aPromise, ImageBitmap* aImageBitmap)
    1058           0 :   : mPromise(aPromise)
    1059           0 :   , mImageBitmap(aImageBitmap)
    1060             :   {
    1061           0 :     MOZ_ASSERT(aPromise);
    1062           0 :   }
    1063             : 
    1064           0 :   void DoFulfillImageBitmapPromise()
    1065             :   {
    1066           0 :     mPromise->MaybeResolve(mImageBitmap);
    1067           0 :   }
    1068             : 
    1069             : private:
    1070             :   RefPtr<Promise> mPromise;
    1071             :   RefPtr<ImageBitmap> mImageBitmap;
    1072             : };
    1073             : 
    1074           0 : class FulfillImageBitmapPromiseTask final : public Runnable,
    1075             :                                             public FulfillImageBitmapPromise
    1076             : {
    1077             : public:
    1078           0 :   FulfillImageBitmapPromiseTask(Promise* aPromise, ImageBitmap* aImageBitmap)
    1079           0 :     : Runnable("dom::FulfillImageBitmapPromiseTask")
    1080           0 :     , FulfillImageBitmapPromise(aPromise, aImageBitmap)
    1081             :   {
    1082           0 :   }
    1083             : 
    1084           0 :   NS_IMETHOD Run() override
    1085             :   {
    1086           0 :     DoFulfillImageBitmapPromise();
    1087           0 :     return NS_OK;
    1088             :   }
    1089             : };
    1090             : 
    1091           0 : class FulfillImageBitmapPromiseWorkerTask final : public WorkerSameThreadRunnable,
    1092             :                                                   public FulfillImageBitmapPromise
    1093             : {
    1094             : public:
    1095           0 :   FulfillImageBitmapPromiseWorkerTask(Promise* aPromise, ImageBitmap* aImageBitmap)
    1096           0 :   : WorkerSameThreadRunnable(GetCurrentThreadWorkerPrivate()),
    1097           0 :     FulfillImageBitmapPromise(aPromise, aImageBitmap)
    1098             :   {
    1099           0 :   }
    1100             : 
    1101           0 :   bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1102             :   {
    1103           0 :     DoFulfillImageBitmapPromise();
    1104           0 :     return true;
    1105             :   }
    1106             : };
    1107             : 
    1108             : static void
    1109           0 : AsyncFulfillImageBitmapPromise(Promise* aPromise, ImageBitmap* aImageBitmap)
    1110             : {
    1111           0 :   if (NS_IsMainThread()) {
    1112             :     nsCOMPtr<nsIRunnable> task =
    1113           0 :       new FulfillImageBitmapPromiseTask(aPromise, aImageBitmap);
    1114           0 :     NS_DispatchToCurrentThread(task); // Actually, to the main-thread.
    1115             :   } else {
    1116             :     RefPtr<FulfillImageBitmapPromiseWorkerTask> task =
    1117           0 :       new FulfillImageBitmapPromiseWorkerTask(aPromise, aImageBitmap);
    1118           0 :     task->Dispatch(); // Actually, to the current worker-thread.
    1119             :   }
    1120           0 : }
    1121             : 
    1122             : static already_AddRefed<SourceSurface>
    1123           0 : DecodeBlob(Blob& aBlob)
    1124             : {
    1125             :   // Get the internal stream of the blob.
    1126           0 :   nsCOMPtr<nsIInputStream> stream;
    1127           0 :   ErrorResult error;
    1128           0 :   aBlob.Impl()->GetInternalStream(getter_AddRefs(stream), error);
    1129           0 :   if (NS_WARN_IF(error.Failed())) {
    1130           0 :     error.SuppressException();
    1131           0 :     return nullptr;
    1132             :   }
    1133             : 
    1134             :   // Get the MIME type string of the blob.
    1135             :   // The type will be checked in the DecodeImage() method.
    1136           0 :   nsAutoString mimeTypeUTF16;
    1137           0 :   aBlob.GetType(mimeTypeUTF16);
    1138             : 
    1139             :   // Get the Component object.
    1140           0 :   nsCOMPtr<imgITools> imgtool = do_GetService(NS_IMGTOOLS_CID);
    1141           0 :   if (NS_WARN_IF(!imgtool)) {
    1142           0 :     return nullptr;
    1143             :   }
    1144             : 
    1145             :   // Decode image.
    1146           0 :   NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeTypeUTF16); // NS_ConvertUTF16toUTF8 ---|> nsAutoCString
    1147           0 :   nsCOMPtr<imgIContainer> imgContainer;
    1148           0 :   nsresult rv = imgtool->DecodeImage(stream, mimeTypeUTF8, getter_AddRefs(imgContainer));
    1149           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1150           0 :     return nullptr;
    1151             :   }
    1152             : 
    1153             :   // Get the surface out.
    1154           0 :   uint32_t frameFlags = imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_WANT_DATA_SURFACE;
    1155           0 :   uint32_t whichFrame = imgIContainer::FRAME_FIRST;
    1156           0 :   RefPtr<SourceSurface> surface = imgContainer->GetFrame(whichFrame, frameFlags);
    1157             : 
    1158           0 :   if (NS_WARN_IF(!surface)) {
    1159           0 :     return nullptr;
    1160             :   }
    1161             : 
    1162           0 :   return surface.forget();
    1163             : }
    1164             : 
    1165             : static already_AddRefed<layers::Image>
    1166           0 : DecodeAndCropBlob(Blob& aBlob, Maybe<IntRect>& aCropRect,
    1167             :                   /*Output*/ IntSize& sourceSize)
    1168             : {
    1169             :   // Decode the blob into a SourceSurface.
    1170           0 :   RefPtr<SourceSurface> surface = DecodeBlob(aBlob);
    1171             : 
    1172           0 :   if (NS_WARN_IF(!surface)) {
    1173           0 :     return nullptr;
    1174             :   }
    1175             : 
    1176             :   // Set the _sourceSize_ output parameter.
    1177           0 :   sourceSize = surface->GetSize();
    1178             : 
    1179             :   // Crop the source surface if needed.
    1180           0 :   RefPtr<SourceSurface> croppedSurface = surface;
    1181             : 
    1182           0 :   if (aCropRect.isSome()) {
    1183             :     // The blob is just decoded into a RasterImage and not optimized yet, so the
    1184             :     // _surface_ we get is a DataSourceSurface which wraps the RasterImage's
    1185             :     // raw buffer.
    1186             :     //
    1187             :     // The _surface_ might already be optimized so that its type is not
    1188             :     // SurfaceType::DATA. However, we could keep using the generic cropping and
    1189             :     // copying since the decoded buffer is only used in this ImageBitmap so we
    1190             :     // should crop it to save memory usage.
    1191             :     //
    1192             :     // TODO: Bug1189632 is going to refactor this create-from-blob part to
    1193             :     //       decode the blob off the main thread. Re-check if we should do
    1194             :     //       cropping at this moment again there.
    1195           0 :     RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
    1196           0 :     croppedSurface = CropAndCopyDataSourceSurface(dataSurface, aCropRect.ref());
    1197           0 :     aCropRect->MoveTo(0, 0);
    1198             :   }
    1199             : 
    1200           0 :   if (NS_WARN_IF(!croppedSurface)) {
    1201           0 :     return nullptr;
    1202             :   }
    1203             : 
    1204             :   // Create an Image from the source surface.
    1205           0 :   RefPtr<layers::Image> image = CreateImageFromSurface(croppedSurface);
    1206             : 
    1207           0 :   if (NS_WARN_IF(!image)) {
    1208           0 :     return nullptr;
    1209             :   }
    1210             : 
    1211           0 :   return image.forget();
    1212             : }
    1213             : 
    1214             : class CreateImageBitmapFromBlob
    1215             : {
    1216             : protected:
    1217           0 :   CreateImageBitmapFromBlob(Promise* aPromise,
    1218             :                             nsIGlobalObject* aGlobal,
    1219             :                             Blob& aBlob,
    1220             :                             const Maybe<IntRect>& aCropRect)
    1221           0 :   : mPromise(aPromise),
    1222             :     mGlobalObject(aGlobal),
    1223             :     mBlob(&aBlob),
    1224           0 :     mCropRect(aCropRect)
    1225             :   {
    1226           0 :   }
    1227             : 
    1228           0 :   virtual ~CreateImageBitmapFromBlob()
    1229           0 :   {
    1230           0 :   }
    1231             : 
    1232             :   // Returns true on success, false on failure.
    1233           0 :   bool DoCreateImageBitmapFromBlob()
    1234             :   {
    1235           0 :     RefPtr<ImageBitmap> imageBitmap = CreateImageBitmap();
    1236             : 
    1237             :     // handle errors while creating ImageBitmap
    1238             :     // (1) error occurs during reading of the object
    1239             :     // (2) the image data is not in a supported file format
    1240             :     // (3) the image data is corrupted
    1241             :     // All these three cases should reject the promise with "InvalidStateError"
    1242             :     // DOMException
    1243           0 :     if (!imageBitmap) {
    1244           0 :       return false;
    1245             :     }
    1246             : 
    1247           0 :     if (imageBitmap && mCropRect.isSome()) {
    1248           0 :       ErrorResult rv;
    1249           0 :       imageBitmap->SetPictureRect(mCropRect.ref(), rv);
    1250             : 
    1251           0 :       if (rv.Failed()) {
    1252           0 :         mPromise->MaybeReject(rv);
    1253           0 :         return false;
    1254             :       }
    1255             :     }
    1256             : 
    1257             :     // Report memory allocation.
    1258           0 :     RegisterAllocation(mGlobalObject, imageBitmap->mData);
    1259             : 
    1260           0 :     mPromise->MaybeResolve(imageBitmap);
    1261           0 :     return true;
    1262             :   }
    1263             : 
    1264             :   // Will return null on failure.  In that case, mPromise will already
    1265             :   // be rejected with the right thing.
    1266             :   virtual already_AddRefed<ImageBitmap> CreateImageBitmap() = 0;
    1267             : 
    1268             :   RefPtr<Promise> mPromise;
    1269             :   nsCOMPtr<nsIGlobalObject> mGlobalObject;
    1270             :   RefPtr<mozilla::dom::Blob> mBlob;
    1271             :   Maybe<IntRect> mCropRect;
    1272             : };
    1273             : 
    1274           0 : class CreateImageBitmapFromBlobTask final : public Runnable,
    1275             :                                             public CreateImageBitmapFromBlob
    1276             : {
    1277             : public:
    1278           0 :   CreateImageBitmapFromBlobTask(Promise* aPromise,
    1279             :                                 nsIGlobalObject* aGlobal,
    1280             :                                 Blob& aBlob,
    1281             :                                 const Maybe<IntRect>& aCropRect)
    1282           0 :     : Runnable("dom::CreateImageBitmapFromBlobTask")
    1283           0 :     , CreateImageBitmapFromBlob(aPromise, aGlobal, aBlob, aCropRect)
    1284             :   {
    1285           0 :   }
    1286             : 
    1287           0 :   NS_IMETHOD Run() override
    1288             :   {
    1289           0 :     DoCreateImageBitmapFromBlob();
    1290           0 :     return NS_OK;
    1291             :   }
    1292             : 
    1293             : private:
    1294           0 :   already_AddRefed<ImageBitmap> CreateImageBitmap() override
    1295             :   {
    1296             :     // _sourceSize_ is used to get the original size of the source image,
    1297             :     // before being cropped.
    1298           0 :     IntSize sourceSize;
    1299             : 
    1300             :     // Keep the orignal cropping rectangle because the mCropRect might be
    1301             :     // modified in DecodeAndCropBlob().
    1302           0 :     Maybe<IntRect> originalCropRect = mCropRect;
    1303             : 
    1304           0 :     RefPtr<layers::Image> data = DecodeAndCropBlob(*mBlob, mCropRect, sourceSize);
    1305             : 
    1306           0 :     if (NS_WARN_IF(!data)) {
    1307           0 :       mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
    1308           0 :       return nullptr;
    1309             :     }
    1310             : 
    1311             :     // Create ImageBitmap object.
    1312           0 :     RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
    1313             : 
    1314             :     // Set mIsCroppingAreaOutSideOfSourceImage.
    1315           0 :     imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect);
    1316             : 
    1317           0 :     return imageBitmap.forget();
    1318             :   }
    1319             : };
    1320             : 
    1321           0 : class CreateImageBitmapFromBlobWorkerTask final : public WorkerSameThreadRunnable,
    1322             :                                                   public CreateImageBitmapFromBlob
    1323             : {
    1324             :   // This is a synchronous task.
    1325           0 :   class DecodeBlobInMainThreadSyncTask final : public WorkerMainThreadRunnable
    1326             :   {
    1327             :   public:
    1328           0 :     DecodeBlobInMainThreadSyncTask(WorkerPrivate* aWorkerPrivate,
    1329             :                                    Blob& aBlob,
    1330             :                                    Maybe<IntRect>& aCropRect,
    1331             :                                    layers::Image** aImage,
    1332             :                                    IntSize& aSourceSize)
    1333           0 :     : WorkerMainThreadRunnable(aWorkerPrivate,
    1334           0 :                                NS_LITERAL_CSTRING("ImageBitmap :: Create Image from Blob"))
    1335             :     , mBlob(aBlob)
    1336             :     , mCropRect(aCropRect)
    1337             :     , mImage(aImage)
    1338           0 :     , mSourceSize(aSourceSize)
    1339             :     {
    1340           0 :     }
    1341             : 
    1342           0 :     bool MainThreadRun() override
    1343             :     {
    1344           0 :       RefPtr<layers::Image> image = DecodeAndCropBlob(mBlob, mCropRect, mSourceSize);
    1345             : 
    1346           0 :       if (NS_WARN_IF(!image)) {
    1347           0 :         return true;
    1348             :       }
    1349             : 
    1350           0 :       image.forget(mImage);
    1351             : 
    1352           0 :       return true;
    1353             :     }
    1354             : 
    1355             :   private:
    1356             :     Blob& mBlob;
    1357             :     Maybe<IntRect>& mCropRect;
    1358             :     layers::Image** mImage;
    1359             :     IntSize mSourceSize;
    1360             :   };
    1361             : 
    1362             : public:
    1363           0 :   CreateImageBitmapFromBlobWorkerTask(Promise* aPromise,
    1364             :                                   nsIGlobalObject* aGlobal,
    1365             :                                   mozilla::dom::Blob& aBlob,
    1366             :                                   const Maybe<IntRect>& aCropRect)
    1367           0 :   : WorkerSameThreadRunnable(GetCurrentThreadWorkerPrivate()),
    1368           0 :     CreateImageBitmapFromBlob(aPromise, aGlobal, aBlob, aCropRect)
    1369             :   {
    1370           0 :   }
    1371             : 
    1372           0 :   bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1373             :   {
    1374           0 :     return DoCreateImageBitmapFromBlob();
    1375             :   }
    1376             : 
    1377             : private:
    1378           0 :   already_AddRefed<ImageBitmap> CreateImageBitmap() override
    1379             :   {
    1380             :     // _sourceSize_ is used to get the original size of the source image,
    1381             :     // before being cropped.
    1382           0 :     IntSize sourceSize;
    1383             : 
    1384             :     // Keep the orignal cropping rectangle because the mCropRect might be
    1385             :     // modified in DecodeAndCropBlob().
    1386           0 :     Maybe<IntRect> originalCropRect = mCropRect;
    1387             : 
    1388           0 :     RefPtr<layers::Image> data;
    1389             : 
    1390           0 :     ErrorResult rv;
    1391             :     RefPtr<DecodeBlobInMainThreadSyncTask> task =
    1392           0 :       new DecodeBlobInMainThreadSyncTask(mWorkerPrivate, *mBlob, mCropRect,
    1393           0 :                                          getter_AddRefs(data), sourceSize);
    1394           0 :     task->Dispatch(Terminating, rv); // This is a synchronous call.
    1395             : 
    1396             :     // In case the worker is terminating, this rejection can be handled.
    1397           0 :     if (NS_WARN_IF(rv.Failed())) {
    1398           0 :       mPromise->MaybeReject(rv);
    1399           0 :       return nullptr;
    1400             :     }
    1401             : 
    1402           0 :     if (NS_WARN_IF(!data)) {
    1403           0 :       mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
    1404           0 :       return nullptr;
    1405             :     }
    1406             : 
    1407             :     // Create ImageBitmap object.
    1408           0 :     RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
    1409             : 
    1410             :     // Set mIsCroppingAreaOutSideOfSourceImage.
    1411           0 :     imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect);
    1412             : 
    1413           0 :     return imageBitmap.forget();
    1414             :   }
    1415             : 
    1416             : };
    1417             : 
    1418             : static void
    1419           0 : AsyncCreateImageBitmapFromBlob(Promise* aPromise, nsIGlobalObject* aGlobal,
    1420             :                                Blob& aBlob, const Maybe<IntRect>& aCropRect)
    1421             : {
    1422           0 :   if (NS_IsMainThread()) {
    1423             :     nsCOMPtr<nsIRunnable> task =
    1424           0 :       new CreateImageBitmapFromBlobTask(aPromise, aGlobal, aBlob, aCropRect);
    1425           0 :     NS_DispatchToCurrentThread(task); // Actually, to the main-thread.
    1426             :   } else {
    1427             :     RefPtr<CreateImageBitmapFromBlobWorkerTask> task =
    1428           0 :       new CreateImageBitmapFromBlobWorkerTask(aPromise, aGlobal, aBlob, aCropRect);
    1429           0 :     task->Dispatch(); // Actually, to the current worker-thread.
    1430             :   }
    1431           0 : }
    1432             : 
    1433             : /* static */ already_AddRefed<Promise>
    1434           0 : ImageBitmap::Create(nsIGlobalObject* aGlobal, const ImageBitmapSource& aSrc,
    1435             :                     const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv)
    1436             : {
    1437           0 :   MOZ_ASSERT(aGlobal);
    1438             : 
    1439           0 :   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
    1440             : 
    1441           0 :   if (NS_WARN_IF(aRv.Failed())) {
    1442           0 :     return nullptr;
    1443             :   }
    1444             : 
    1445           0 :   if (aCropRect.isSome() && (aCropRect->Width() == 0 || aCropRect->Height() == 0)) {
    1446           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    1447           0 :     return promise.forget();
    1448             :   }
    1449             : 
    1450           0 :   RefPtr<ImageBitmap> imageBitmap;
    1451             : 
    1452           0 :   if (aSrc.IsHTMLImageElement()) {
    1453           0 :     MOZ_ASSERT(NS_IsMainThread(),
    1454             :                "Creating ImageBitmap from HTMLImageElement off the main thread.");
    1455           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLImageElement(), aCropRect, aRv);
    1456           0 :   } else if (aSrc.IsHTMLVideoElement()) {
    1457           0 :     MOZ_ASSERT(NS_IsMainThread(),
    1458             :                "Creating ImageBitmap from HTMLVideoElement off the main thread.");
    1459           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLVideoElement(), aCropRect, aRv);
    1460           0 :   } else if (aSrc.IsHTMLCanvasElement()) {
    1461           0 :     MOZ_ASSERT(NS_IsMainThread(),
    1462             :                "Creating ImageBitmap from HTMLCanvasElement off the main thread.");
    1463           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLCanvasElement(), aCropRect, aRv);
    1464           0 :   } else if (aSrc.IsImageData()) {
    1465           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsImageData(), aCropRect, aRv);
    1466           0 :   } else if (aSrc.IsCanvasRenderingContext2D()) {
    1467           0 :     MOZ_ASSERT(NS_IsMainThread(),
    1468             :                "Creating ImageBitmap from CanvasRenderingContext2D off the main thread.");
    1469           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsCanvasRenderingContext2D(), aCropRect, aRv);
    1470           0 :   } else if (aSrc.IsImageBitmap()) {
    1471           0 :     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsImageBitmap(), aCropRect, aRv);
    1472           0 :   } else if (aSrc.IsBlob()) {
    1473           0 :     AsyncCreateImageBitmapFromBlob(promise, aGlobal, aSrc.GetAsBlob(), aCropRect);
    1474           0 :     return promise.forget();
    1475             :   } else {
    1476           0 :     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    1477           0 :     return nullptr;
    1478             :   }
    1479             : 
    1480           0 :   if (!aRv.Failed()) {
    1481           0 :     AsyncFulfillImageBitmapPromise(promise, imageBitmap);
    1482             :   }
    1483             : 
    1484           0 :   return promise.forget();
    1485             : }
    1486             : 
    1487             : /*static*/ JSObject*
    1488           0 : ImageBitmap::ReadStructuredClone(JSContext* aCx,
    1489             :                                  JSStructuredCloneReader* aReader,
    1490             :                                  nsIGlobalObject* aParent,
    1491             :                                  const nsTArray<RefPtr<DataSourceSurface>>& aClonedSurfaces,
    1492             :                                  uint32_t aIndex)
    1493             : {
    1494           0 :   MOZ_ASSERT(aCx);
    1495           0 :   MOZ_ASSERT(aReader);
    1496             :   // aParent might be null.
    1497             : 
    1498             :   uint32_t picRectX_;
    1499             :   uint32_t picRectY_;
    1500             :   uint32_t picRectWidth_;
    1501             :   uint32_t picRectHeight_;
    1502             :   uint32_t alphaType_;
    1503             :   uint32_t isCroppingAreaOutSideOfSourceImage_;
    1504             : 
    1505           0 :   if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
    1506           0 :       !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
    1507           0 :       !JS_ReadUint32Pair(aReader, &alphaType_,
    1508             :                                   &isCroppingAreaOutSideOfSourceImage_)) {
    1509           0 :     return nullptr;
    1510             :   }
    1511             : 
    1512           0 :   int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
    1513           0 :   int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
    1514           0 :   int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
    1515           0 :   int32_t picRectHeight = BitwiseCast<int32_t>(picRectHeight_);
    1516           0 :   const auto alphaType = BitwiseCast<gfxAlphaType>(alphaType_);
    1517             : 
    1518             :   // Create a new ImageBitmap.
    1519           0 :   MOZ_ASSERT(!aClonedSurfaces.IsEmpty());
    1520           0 :   MOZ_ASSERT(aIndex < aClonedSurfaces.Length());
    1521             : 
    1522             :   // RefPtr<ImageBitmap> needs to go out of scope before toObjectOrNull() is
    1523             :   // called because the static analysis thinks dereferencing XPCOM objects
    1524             :   // can GC (because in some cases it can!), and a return statement with a
    1525             :   // JSObject* type means that JSObject* is on the stack as a raw pointer
    1526             :   // while destructors are running.
    1527           0 :   JS::Rooted<JS::Value> value(aCx);
    1528             :   {
    1529           0 :     RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
    1530           0 :     RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aParent, img, alphaType);
    1531             : 
    1532           0 :     imageBitmap->mIsCroppingAreaOutSideOfSourceImage =
    1533           0 :       isCroppingAreaOutSideOfSourceImage_;
    1534             : 
    1535           0 :     ErrorResult error;
    1536           0 :     imageBitmap->SetPictureRect(IntRect(picRectX, picRectY,
    1537           0 :                                         picRectWidth, picRectHeight), error);
    1538           0 :     if (NS_WARN_IF(error.Failed())) {
    1539           0 :       error.SuppressException();
    1540           0 :       return nullptr;
    1541             :     }
    1542             : 
    1543           0 :     if (!GetOrCreateDOMReflector(aCx, imageBitmap, &value)) {
    1544           0 :       return nullptr;
    1545             :     }
    1546             : 
    1547             :     // Report memory allocation.
    1548           0 :     RegisterAllocation(aParent, aClonedSurfaces[aIndex]);
    1549             :   }
    1550             : 
    1551           0 :   return &(value.toObject());
    1552             : }
    1553             : 
    1554             : /*static*/ bool
    1555           0 : ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
    1556             :                                   nsTArray<RefPtr<DataSourceSurface>>& aClonedSurfaces,
    1557             :                                   ImageBitmap* aImageBitmap)
    1558             : {
    1559           0 :   MOZ_ASSERT(aWriter);
    1560           0 :   MOZ_ASSERT(aImageBitmap);
    1561             : 
    1562           0 :   const uint32_t picRectX = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.x);
    1563           0 :   const uint32_t picRectY = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.y);
    1564           0 :   const uint32_t picRectWidth = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.width);
    1565           0 :   const uint32_t picRectHeight = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.height);
    1566           0 :   const uint32_t alphaType = BitwiseCast<uint32_t>(aImageBitmap->mAlphaType);
    1567           0 :   const uint32_t isCroppingAreaOutSideOfSourceImage = aImageBitmap->mIsCroppingAreaOutSideOfSourceImage ? 1 : 0;
    1568             : 
    1569             :   // Indexing the cloned surfaces and send the index to the receiver.
    1570           0 :   uint32_t index = aClonedSurfaces.Length();
    1571             : 
    1572           0 :   if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
    1573           0 :       NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
    1574           0 :       NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
    1575           0 :       NS_WARN_IF(!JS_WriteUint32Pair(aWriter, alphaType,
    1576             :                                               isCroppingAreaOutSideOfSourceImage))) {
    1577           0 :     return false;
    1578             :   }
    1579             : 
    1580             :   RefPtr<SourceSurface> surface =
    1581           0 :     aImageBitmap->mData->GetAsSourceSurface();
    1582           0 :   RefPtr<DataSourceSurface> snapshot = surface->GetDataSurface();
    1583           0 :   RefPtr<DataSourceSurface> dstDataSurface;
    1584             :   {
    1585             :     // DataSourceSurfaceD2D1::GetStride() will call EnsureMapped implicitly and
    1586             :     // won't Unmap after exiting function. So instead calling GetStride()
    1587             :     // directly, using ScopedMap to get stride.
    1588           0 :     DataSourceSurface::ScopedMap map(snapshot, DataSourceSurface::READ);
    1589             :     dstDataSurface =
    1590           0 :       Factory::CreateDataSourceSurfaceWithStride(snapshot->GetSize(),
    1591           0 :                                                  snapshot->GetFormat(),
    1592             :                                                  map.GetStride(),
    1593           0 :                                                  true);
    1594             :   }
    1595           0 :   MOZ_ASSERT(dstDataSurface);
    1596           0 :   Factory::CopyDataSourceSurface(snapshot, dstDataSurface);
    1597           0 :   aClonedSurfaces.AppendElement(dstDataSurface);
    1598           0 :   return true;
    1599             : }
    1600             : 
    1601             : /*static*/ bool
    1602           1 : ImageBitmap::ExtensionsEnabled(JSContext* aCx, JSObject*)
    1603             : {
    1604           1 :   if (NS_IsMainThread()) {
    1605           0 :     return Preferences::GetBool("canvas.imagebitmap_extensions.enabled");
    1606             :   } else {
    1607           1 :     WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
    1608           1 :     MOZ_ASSERT(workerPrivate);
    1609           1 :     return workerPrivate->ImageBitmapExtensionsEnabled();
    1610             :   }
    1611             : }
    1612             : 
    1613             : // ImageBitmap extensions.
    1614             : ImageBitmapFormat
    1615           0 : ImageBitmap::FindOptimalFormat(const Optional<Sequence<ImageBitmapFormat>>& aPossibleFormats,
    1616             :                                ErrorResult& aRv)
    1617             : {
    1618           0 :   MOZ_ASSERT(mDataWrapper, "No ImageBitmapFormatUtils functionalities.");
    1619             : 
    1620           0 :   ImageBitmapFormat platformFormat = mDataWrapper->GetFormat();
    1621             : 
    1622           0 :   if (!aPossibleFormats.WasPassed() ||
    1623           0 :       aPossibleFormats.Value().Contains(platformFormat)) {
    1624           0 :     return platformFormat;
    1625             :   } else {
    1626             :     // If no matching is found, FindBestMatchingFromat() returns
    1627             :     // ImageBitmapFormat::EndGuard_ and we throw an exception.
    1628             :     ImageBitmapFormat optimalFormat =
    1629           0 :       FindBestMatchingFromat(platformFormat, aPossibleFormats.Value());
    1630             : 
    1631           0 :     if (optimalFormat == ImageBitmapFormat::EndGuard_) {
    1632           0 :       aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    1633             :     }
    1634             : 
    1635           0 :     return optimalFormat;
    1636             :   }
    1637             : }
    1638             : 
    1639             : int32_t
    1640           0 : ImageBitmap::MappedDataLength(ImageBitmapFormat aFormat, ErrorResult& aRv)
    1641             : {
    1642           0 :   MOZ_ASSERT(mDataWrapper, "No ImageBitmapFormatUtils functionalities.");
    1643             : 
    1644           0 :   if (aFormat == mDataWrapper->GetFormat()) {
    1645           0 :     return mDataWrapper->GetBufferLength();
    1646             :   } else {
    1647           0 :     return CalculateImageBufferSize(aFormat, Width(), Height());
    1648             :   }
    1649             : }
    1650             : 
    1651             : template<typename T>
    1652             : class MapDataIntoBufferSource
    1653             : {
    1654             : protected:
    1655           0 :   MapDataIntoBufferSource(JSContext* aCx,
    1656             :                           Promise *aPromise,
    1657             :                           ImageBitmap *aImageBitmap,
    1658             :                           const T& aBuffer,
    1659             :                           int32_t aOffset,
    1660             :                           ImageBitmapFormat aFormat)
    1661             :   : mPromise(aPromise)
    1662             :   , mImageBitmap(aImageBitmap)
    1663             :   , mBuffer(aCx, aBuffer.Obj())
    1664             :   , mOffset(aOffset)
    1665           0 :   , mFormat(aFormat)
    1666             :   {
    1667           0 :     MOZ_ASSERT(mPromise);
    1668           0 :     MOZ_ASSERT(JS_IsArrayBufferObject(mBuffer) ||
    1669             :                JS_IsArrayBufferViewObject(mBuffer));
    1670           0 :   }
    1671             : 
    1672           0 :   virtual ~MapDataIntoBufferSource() = default;
    1673             : 
    1674           0 :   void DoMapDataIntoBufferSource()
    1675             :   {
    1676           0 :     ErrorResult error;
    1677             : 
    1678             :     // Prepare destination buffer.
    1679           0 :     uint8_t* bufferData = nullptr;
    1680           0 :     uint32_t bufferLength = 0;
    1681           0 :     bool isSharedMemory = false;
    1682           0 :     if (JS_IsArrayBufferObject(mBuffer)) {
    1683           0 :       js::GetArrayBufferLengthAndData(mBuffer, &bufferLength, &isSharedMemory, &bufferData);
    1684           0 :     } else if (JS_IsArrayBufferViewObject(mBuffer)) {
    1685           0 :       js::GetArrayBufferViewLengthAndData(mBuffer, &bufferLength, &isSharedMemory, &bufferData);
    1686             :     } else {
    1687           0 :       error.ThrowWithCustomCleanup(NS_ERROR_NOT_IMPLEMENTED);
    1688           0 :       mPromise->MaybeReject(error);
    1689           0 :       return;
    1690             :     }
    1691             : 
    1692           0 :     if (NS_WARN_IF(!bufferData) || NS_WARN_IF(!bufferLength)) {
    1693           0 :       error.ThrowWithCustomCleanup(NS_ERROR_NOT_AVAILABLE);
    1694           0 :       mPromise->MaybeReject(error);
    1695           0 :       return;
    1696             :     }
    1697             : 
    1698             :     // Check length.
    1699             :     const int32_t neededBufferLength =
    1700           0 :       mImageBitmap->MappedDataLength(mFormat, error);
    1701             : 
    1702           0 :     if (((int32_t)bufferLength - mOffset) < neededBufferLength) {
    1703           0 :       error.ThrowWithCustomCleanup(NS_ERROR_DOM_INDEX_SIZE_ERR);
    1704           0 :       mPromise->MaybeReject(error);
    1705           0 :       return;
    1706             :     }
    1707             : 
    1708             :     // Call ImageBitmapFormatUtils.
    1709             :     UniquePtr<ImagePixelLayout> layout =
    1710           0 :       mImageBitmap->mDataWrapper->MapDataInto(bufferData,
    1711           0 :                                               mOffset,
    1712             :                                               bufferLength,
    1713             :                                               mFormat,
    1714           0 :                                               error);
    1715             : 
    1716           0 :     if (NS_WARN_IF(!layout)) {
    1717           0 :       mPromise->MaybeReject(error);
    1718           0 :       return;
    1719             :     }
    1720             : 
    1721           0 :     mPromise->MaybeResolve(*layout);
    1722             :   }
    1723             : 
    1724             :   RefPtr<Promise> mPromise;
    1725             :   RefPtr<ImageBitmap> mImageBitmap;
    1726             :   JS::PersistentRooted<JSObject*> mBuffer;
    1727             :   int32_t mOffset;
    1728             :   ImageBitmapFormat mFormat;
    1729             : };
    1730             : 
    1731             : template<typename T>
    1732             : class MapDataIntoBufferSourceTask final : public Runnable,
    1733             :                                           public MapDataIntoBufferSource<T>
    1734             : {
    1735             : public:
    1736           0 :   MapDataIntoBufferSourceTask(JSContext* aCx,
    1737             :                               Promise* aPromise,
    1738             :                               ImageBitmap* aImageBitmap,
    1739             :                               const T& aBuffer,
    1740             :                               int32_t aOffset,
    1741             :                               ImageBitmapFormat aFormat)
    1742             :     : Runnable("dom::MapDataIntoBufferSourceTask")
    1743             :     , MapDataIntoBufferSource<T>(aCx,
    1744             :                                  aPromise,
    1745             :                                  aImageBitmap,
    1746             :                                  aBuffer,
    1747             :                                  aOffset,
    1748           0 :                                  aFormat)
    1749             :   {
    1750           0 :   }
    1751             : 
    1752           0 :   virtual ~MapDataIntoBufferSourceTask() = default;
    1753             : 
    1754           0 :   NS_IMETHOD Run() override
    1755             :   {
    1756           0 :     MapDataIntoBufferSource<T>::DoMapDataIntoBufferSource();
    1757           0 :     return NS_OK;
    1758             :   }
    1759             : };
    1760             : 
    1761             : template<typename T>
    1762             : class MapDataIntoBufferSourceWorkerTask final : public WorkerSameThreadRunnable,
    1763             :                                                 public MapDataIntoBufferSource<T>
    1764             : {
    1765             : public:
    1766           0 :   MapDataIntoBufferSourceWorkerTask(JSContext* aCx,
    1767             :                                     Promise *aPromise,
    1768             :                                     ImageBitmap *aImageBitmap,
    1769             :                                     const T& aBuffer,
    1770             :                                     int32_t aOffset,
    1771             :                                     ImageBitmapFormat aFormat)
    1772             :   : WorkerSameThreadRunnable(GetCurrentThreadWorkerPrivate()),
    1773           0 :     MapDataIntoBufferSource<T>(aCx, aPromise, aImageBitmap, aBuffer, aOffset, aFormat)
    1774             :   {
    1775           0 :   }
    1776             : 
    1777           0 :   virtual ~MapDataIntoBufferSourceWorkerTask() = default;
    1778             : 
    1779           0 :   bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1780             :   {
    1781           0 :     MapDataIntoBufferSource<T>::DoMapDataIntoBufferSource();
    1782           0 :     return true;
    1783             :   }
    1784             : };
    1785             : 
    1786           0 : void AsyncMapDataIntoBufferSource(JSContext* aCx,
    1787             :                                   Promise *aPromise,
    1788             :                                   ImageBitmap *aImageBitmap,
    1789             :                                   const ArrayBufferViewOrArrayBuffer& aBuffer,
    1790             :                                   int32_t aOffset,
    1791             :                                   ImageBitmapFormat aFormat)
    1792             : {
    1793           0 :   MOZ_ASSERT(aCx);
    1794           0 :   MOZ_ASSERT(aPromise);
    1795           0 :   MOZ_ASSERT(aImageBitmap);
    1796             : 
    1797           0 :   if (NS_IsMainThread()) {
    1798           0 :     nsCOMPtr<nsIRunnable> task;
    1799             : 
    1800           0 :     if (aBuffer.IsArrayBuffer()) {
    1801           0 :       const ArrayBuffer& buffer = aBuffer.GetAsArrayBuffer();
    1802           0 :       task = new MapDataIntoBufferSourceTask<ArrayBuffer>(aCx, aPromise, aImageBitmap, buffer, aOffset, aFormat);
    1803           0 :     } else if (aBuffer.IsArrayBufferView()) {
    1804           0 :       const ArrayBufferView& bufferView = aBuffer.GetAsArrayBufferView();
    1805           0 :       task = new MapDataIntoBufferSourceTask<ArrayBufferView>(aCx, aPromise, aImageBitmap, bufferView, aOffset, aFormat);
    1806             :     }
    1807             : 
    1808           0 :     NS_DispatchToCurrentThread(task); // Actually, to the main-thread.
    1809             :   } else {
    1810           0 :     RefPtr<WorkerSameThreadRunnable> task;
    1811             : 
    1812           0 :     if (aBuffer.IsArrayBuffer()) {
    1813           0 :       const ArrayBuffer& buffer = aBuffer.GetAsArrayBuffer();
    1814           0 :       task = new MapDataIntoBufferSourceWorkerTask<ArrayBuffer>(aCx, aPromise, aImageBitmap, buffer, aOffset, aFormat);
    1815           0 :     } else if (aBuffer.IsArrayBufferView()) {
    1816           0 :       const ArrayBufferView& bufferView = aBuffer.GetAsArrayBufferView();
    1817           0 :       task = new MapDataIntoBufferSourceWorkerTask<ArrayBufferView>(aCx, aPromise, aImageBitmap, bufferView, aOffset, aFormat);
    1818             :     }
    1819             : 
    1820           0 :     task->Dispatch(); // Actually, to the current worker-thread.
    1821             :   }
    1822           0 : }
    1823             : 
    1824             : already_AddRefed<Promise>
    1825           0 : ImageBitmap::MapDataInto(JSContext* aCx,
    1826             :                          ImageBitmapFormat aFormat,
    1827             :                          const ArrayBufferViewOrArrayBuffer& aBuffer,
    1828             :                          int32_t aOffset, ErrorResult& aRv)
    1829             : {
    1830           0 :   MOZ_ASSERT(mDataWrapper, "No ImageBitmapFormatUtils functionalities.");
    1831           0 :   MOZ_ASSERT(aCx, "No JSContext while calling ImageBitmap::MapDataInto().");
    1832             : 
    1833           0 :   RefPtr<Promise> promise = Promise::Create(mParent, aRv);
    1834             : 
    1835           0 :   if (NS_WARN_IF(aRv.Failed())) {
    1836           0 :     return nullptr;
    1837             :   }
    1838             : 
    1839             :   // Check for cases that should throws.
    1840             :   // Case 1:
    1841             :   // If image bitmap was cropped to the source rectangle so that it contains any
    1842             :   // transparent black pixels (cropping area is outside of the source image),
    1843             :   // then reject promise with IndexSizeError and abort these steps.
    1844           0 :   if (mIsCroppingAreaOutSideOfSourceImage) {
    1845           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    1846           0 :     return promise.forget();
    1847             :   }
    1848             : 
    1849             :   // Case 2:
    1850             :   // If the image bitmap is going to be accessed in YUV422/YUV422 series with a
    1851             :   // cropping area starts at an odd x or y coordinate.
    1852           0 :   if (aFormat == ImageBitmapFormat::YUV422P ||
    1853           0 :       aFormat == ImageBitmapFormat::YUV420P ||
    1854           0 :       aFormat == ImageBitmapFormat::YUV420SP_NV12 ||
    1855             :       aFormat == ImageBitmapFormat::YUV420SP_NV21) {
    1856           0 :     if ((mPictureRect.x & 1) || (mPictureRect.y & 1)) {
    1857           0 :       aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    1858           0 :       return promise.forget();
    1859             :     }
    1860             :   }
    1861             : 
    1862           0 :   AsyncMapDataIntoBufferSource(aCx, promise, this, aBuffer, aOffset, aFormat);
    1863           0 :   return promise.forget();
    1864             : }
    1865             : 
    1866             : // ImageBitmapFactories extensions.
    1867             : static SurfaceFormat
    1868           0 : ImageFormatToSurfaceFromat(mozilla::dom::ImageBitmapFormat aFormat)
    1869             : {
    1870           0 :   switch(aFormat) {
    1871             :   case ImageBitmapFormat::RGBA32:
    1872           0 :     return SurfaceFormat::R8G8B8A8;
    1873             :   case ImageBitmapFormat::BGRA32:
    1874           0 :     return SurfaceFormat::B8G8R8A8;
    1875             :   case ImageBitmapFormat::RGB24:
    1876           0 :     return SurfaceFormat::R8G8B8;
    1877             :   case ImageBitmapFormat::BGR24:
    1878           0 :     return SurfaceFormat::B8G8R8;
    1879             :   case ImageBitmapFormat::GRAY8:
    1880           0 :     return SurfaceFormat::A8;
    1881             :   case ImageBitmapFormat::HSV:
    1882           0 :     return SurfaceFormat::HSV;
    1883             :   case ImageBitmapFormat::Lab:
    1884           0 :     return SurfaceFormat::Lab;
    1885             :   case ImageBitmapFormat::DEPTH:
    1886           0 :     return SurfaceFormat::Depth;
    1887             :   default:
    1888           0 :     return SurfaceFormat::UNKNOWN;
    1889             :   }
    1890             : }
    1891             : 
    1892             : static already_AddRefed<layers::Image>
    1893           0 : CreateImageFromBufferSourceRawData(const uint8_t*aBufferData,
    1894             :                                    uint32_t aBufferLength,
    1895             :                                    mozilla::dom::ImageBitmapFormat aFormat,
    1896             :                                    const Sequence<ChannelPixelLayout>& aLayout)
    1897             : {
    1898           0 :   MOZ_ASSERT(aBufferData);
    1899           0 :   MOZ_ASSERT(aBufferLength > 0);
    1900             : 
    1901           0 :   switch(aFormat) {
    1902             :   case ImageBitmapFormat::RGBA32:
    1903             :   case ImageBitmapFormat::BGRA32:
    1904             :   case ImageBitmapFormat::RGB24:
    1905             :   case ImageBitmapFormat::BGR24:
    1906             :   case ImageBitmapFormat::GRAY8:
    1907             :   case ImageBitmapFormat::HSV:
    1908             :   case ImageBitmapFormat::Lab:
    1909             :   case ImageBitmapFormat::DEPTH:
    1910             :   {
    1911           0 :     const nsTArray<ChannelPixelLayout>& channels = aLayout;
    1912           0 :     MOZ_ASSERT(channels.Length() != 0, "Empty Channels.");
    1913             : 
    1914           0 :     const SurfaceFormat srcFormat = ImageFormatToSurfaceFromat(aFormat);
    1915           0 :     const uint32_t srcStride = channels[0].mStride;
    1916           0 :     const IntSize srcSize(channels[0].mWidth, channels[0].mHeight);
    1917             : 
    1918             :     RefPtr<DataSourceSurface> dstDataSurface =
    1919           0 :       Factory::CreateDataSourceSurfaceWithStride(srcSize, srcFormat, srcStride);
    1920             : 
    1921           0 :     if (NS_WARN_IF(!dstDataSurface)) {
    1922           0 :       return nullptr;
    1923             :     }
    1924             : 
    1925             :     // Copy the raw data into the newly created DataSourceSurface.
    1926           0 :     DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE);
    1927           0 :     if (NS_WARN_IF(!dstMap.IsMapped())) {
    1928           0 :       return nullptr;
    1929             :     }
    1930             : 
    1931           0 :     const uint8_t* srcBufferPtr = aBufferData;
    1932           0 :     uint8_t* dstBufferPtr = dstMap.GetData();
    1933             : 
    1934           0 :     for (int i = 0; i < srcSize.height; ++i) {
    1935           0 :       memcpy(dstBufferPtr, srcBufferPtr, srcStride);
    1936           0 :       srcBufferPtr += srcStride;
    1937           0 :       dstBufferPtr += dstMap.GetStride();
    1938             :     }
    1939             : 
    1940             :     // Create an Image from the BGRA SourceSurface.
    1941           0 :     RefPtr<SourceSurface> surface = dstDataSurface;
    1942           0 :     RefPtr<layers::Image> image = CreateImageFromSurface(surface);
    1943             : 
    1944           0 :     if (NS_WARN_IF(!image)) {
    1945           0 :       return nullptr;
    1946             :     }
    1947             : 
    1948           0 :     return image.forget();
    1949             :   }
    1950             :   case ImageBitmapFormat::YUV444P:
    1951             :   case ImageBitmapFormat::YUV422P:
    1952             :   case ImageBitmapFormat::YUV420P:
    1953             :   case ImageBitmapFormat::YUV420SP_NV12:
    1954             :   case ImageBitmapFormat::YUV420SP_NV21:
    1955             :   {
    1956             :     // Prepare the PlanarYCbCrData.
    1957           0 :     const ChannelPixelLayout& yLayout = aLayout[0];
    1958           0 :     const ChannelPixelLayout& uLayout = aFormat != ImageBitmapFormat::YUV420SP_NV21 ? aLayout[1] : aLayout[2];
    1959           0 :     const ChannelPixelLayout& vLayout = aFormat != ImageBitmapFormat::YUV420SP_NV21 ? aLayout[2] : aLayout[1];
    1960             : 
    1961           0 :     layers::PlanarYCbCrData data;
    1962             : 
    1963             :     // Luminance buffer
    1964           0 :     data.mYChannel = const_cast<uint8_t*>(aBufferData + yLayout.mOffset);
    1965           0 :     data.mYStride = yLayout.mStride;
    1966           0 :     data.mYSize = gfx::IntSize(yLayout.mWidth, yLayout.mHeight);
    1967           0 :     data.mYSkip = yLayout.mSkip;
    1968             : 
    1969             :     // Chroma buffers
    1970           0 :     data.mCbChannel = const_cast<uint8_t*>(aBufferData + uLayout.mOffset);
    1971           0 :     data.mCrChannel = const_cast<uint8_t*>(aBufferData + vLayout.mOffset);
    1972           0 :     data.mCbCrStride = uLayout.mStride;
    1973           0 :     data.mCbCrSize = gfx::IntSize(uLayout.mWidth, uLayout.mHeight);
    1974           0 :     data.mCbSkip = uLayout.mSkip;
    1975           0 :     data.mCrSkip = vLayout.mSkip;
    1976             : 
    1977             :     // Picture rectangle.
    1978             :     // We set the picture rectangle to exactly the size of the source image to
    1979             :     // keep the full original data.
    1980           0 :     data.mPicX = 0;
    1981           0 :     data.mPicY = 0;
    1982           0 :     data.mPicSize = data.mYSize;
    1983             : 
    1984             :     // Create a layers::Image and set data.
    1985           0 :     if (aFormat == ImageBitmapFormat::YUV444P ||
    1986           0 :         aFormat == ImageBitmapFormat::YUV422P ||
    1987             :         aFormat == ImageBitmapFormat::YUV420P) {
    1988             :       RefPtr<layers::PlanarYCbCrImage> image =
    1989           0 :         new layers::RecyclingPlanarYCbCrImage(new layers::BufferRecycleBin());
    1990             : 
    1991           0 :       if (NS_WARN_IF(!image)) {
    1992           0 :         return nullptr;
    1993             :       }
    1994             : 
    1995             :       // Set Data.
    1996           0 :       if (NS_WARN_IF(!image->CopyData(data))) {
    1997           0 :         return nullptr;
    1998             :       }
    1999             : 
    2000           0 :       return image.forget();
    2001             :     } else {
    2002           0 :       RefPtr<layers::NVImage>image = new layers::NVImage();
    2003             : 
    2004           0 :       if (NS_WARN_IF(!image)) {
    2005           0 :         return nullptr;
    2006             :       }
    2007             : 
    2008             :       // Set Data.
    2009           0 :       if (NS_WARN_IF(!image->SetData(data))) {
    2010           0 :         return nullptr;
    2011             :       }
    2012             : 
    2013           0 :       return image.forget();
    2014             :     }
    2015             :   }
    2016             :   default:
    2017           0 :     return nullptr;
    2018             :   }
    2019             : }
    2020             : 
    2021             : /*
    2022             :  * This is a synchronous task.
    2023             :  * This class is used to create a layers::CairoImage from raw data in the main
    2024             :  * thread. While creating an ImageBitmap from an BufferSource, we need to create
    2025             :  * a SouceSurface from the BufferSource raw data and then set the SourceSurface
    2026             :  * into a layers::CairoImage. However, the layers::CairoImage asserts the
    2027             :  * setting operation in the main thread, so if we are going to create an
    2028             :  * ImageBitmap from an BufferSource off the main thread, we post an event to the
    2029             :  * main thread to create a layers::CairoImage from an BufferSource raw data.
    2030             :  *
    2031             :  * TODO: Once the layers::CairoImage is constructible off the main thread, which
    2032             :  *       means the SouceSurface could be released anywhere, we do not need this
    2033             :  *       task anymore.
    2034             :  */
    2035           0 : class CreateImageFromBufferSourceRawDataInMainThreadSyncTask final :
    2036             :   public WorkerMainThreadRunnable
    2037             : {
    2038             : public:
    2039           0 :   CreateImageFromBufferSourceRawDataInMainThreadSyncTask(const uint8_t* aBuffer,
    2040             :                                                          uint32_t aBufferLength,
    2041             :                                                          mozilla::dom::ImageBitmapFormat aFormat,
    2042             :                                                          const Sequence<ChannelPixelLayout>& aLayout,
    2043             :                                                          /*output*/ layers::Image** aImage)
    2044           0 :   : WorkerMainThreadRunnable(GetCurrentThreadWorkerPrivate(),
    2045           0 :                              NS_LITERAL_CSTRING("ImageBitmap-extensions :: Create Image from BufferSource Raw Data"))
    2046             :   , mImage(aImage)
    2047             :   , mBuffer(aBuffer)
    2048             :   , mBufferLength(aBufferLength)
    2049             :   , mFormat(aFormat)
    2050           0 :   , mLayout(aLayout)
    2051             :   {
    2052           0 :     MOZ_ASSERT(!(*aImage), "Don't pass an existing Image into CreateImageFromBufferSourceRawDataInMainThreadSyncTask.");
    2053           0 :   }
    2054             : 
    2055           0 :   bool MainThreadRun() override
    2056             :   {
    2057             :     RefPtr<layers::Image> image =
    2058           0 :       CreateImageFromBufferSourceRawData(mBuffer, mBufferLength, mFormat, mLayout);
    2059             : 
    2060           0 :     if (NS_WARN_IF(!image)) {
    2061           0 :       return true;
    2062             :     }
    2063             : 
    2064           0 :     image.forget(mImage);
    2065             : 
    2066           0 :     return true;
    2067             :   }
    2068             : 
    2069             : private:
    2070             :   layers::Image** mImage;
    2071             :   const uint8_t* mBuffer;
    2072             :   uint32_t mBufferLength;
    2073             :   mozilla::dom::ImageBitmapFormat mFormat;
    2074             :   const Sequence<ChannelPixelLayout>& mLayout;
    2075             : };
    2076             : 
    2077             : /*static*/ already_AddRefed<Promise>
    2078           0 : ImageBitmap::Create(nsIGlobalObject* aGlobal,
    2079             :                     const ImageBitmapSource& aBuffer,
    2080             :                     int32_t aOffset, int32_t aLength,
    2081             :                     mozilla::dom::ImageBitmapFormat aFormat,
    2082             :                     const Sequence<ChannelPixelLayout>& aLayout,
    2083             :                     ErrorResult& aRv)
    2084             : {
    2085           0 :   MOZ_ASSERT(aGlobal);
    2086             : 
    2087           0 :   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
    2088             : 
    2089           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2090           0 :     return nullptr;
    2091             :   }
    2092             : 
    2093           0 :   uint8_t* bufferData = nullptr;
    2094           0 :   uint32_t bufferLength = 0;
    2095             : 
    2096           0 :   if (aBuffer.IsArrayBuffer()) {
    2097           0 :     const ArrayBuffer& buffer = aBuffer.GetAsArrayBuffer();
    2098           0 :     buffer.ComputeLengthAndData();
    2099           0 :     bufferData = buffer.Data();
    2100           0 :     bufferLength = buffer.Length();
    2101           0 :   } else if (aBuffer.IsArrayBufferView()) {
    2102           0 :     const ArrayBufferView& bufferView = aBuffer.GetAsArrayBufferView();
    2103           0 :     bufferView.ComputeLengthAndData();
    2104           0 :     bufferData = bufferView.Data();
    2105           0 :     bufferLength = bufferView.Length();
    2106             :   } else {
    2107           0 :     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    2108           0 :     return promise.forget();
    2109             :   }
    2110             : 
    2111           0 :   MOZ_ASSERT(bufferData && bufferLength > 0, "Cannot read data from BufferSource.");
    2112             : 
    2113             :   // Check the buffer.
    2114           0 :   if (((uint32_t)(aOffset + aLength) > bufferLength)) {
    2115           0 :     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    2116           0 :     return promise.forget();
    2117             :   }
    2118             : 
    2119             :   // Create and Crop the raw data into a layers::Image
    2120           0 :   RefPtr<layers::Image> data;
    2121           0 :   if (NS_IsMainThread()) {
    2122           0 :     data = CreateImageFromBufferSourceRawData(bufferData + aOffset, bufferLength,
    2123           0 :                                               aFormat, aLayout);
    2124             :   } else {
    2125             :     RefPtr<CreateImageFromBufferSourceRawDataInMainThreadSyncTask> task =
    2126           0 :       new CreateImageFromBufferSourceRawDataInMainThreadSyncTask(bufferData + aOffset,
    2127             :                                                                  bufferLength,
    2128             :                                                                  aFormat,
    2129             :                                                                  aLayout,
    2130           0 :                                                                  getter_AddRefs(data));
    2131           0 :     task->Dispatch(Terminating, aRv);
    2132           0 :     if (aRv.Failed()) {
    2133           0 :       return promise.forget();
    2134             :     }
    2135             :   }
    2136             : 
    2137           0 :   if (NS_WARN_IF(!data)) {
    2138           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    2139           0 :     return promise.forget();
    2140             :   }
    2141             : 
    2142             :   // Create an ImageBimtap.
    2143             :   // Assume the data from an external buffer is not alpha-premultiplied.
    2144             :   RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aGlobal, data,
    2145           0 :                                                     gfxAlphaType::NonPremult);
    2146             : 
    2147             :   // Report memory allocation.
    2148           0 :   RegisterAllocation(aGlobal, data);
    2149             : 
    2150             :   // We don't need to call SetPictureRect() here because there is no cropping
    2151             :   // supported and the ImageBitmap's mPictureRect is the size of the source
    2152             :   // image in default
    2153             : 
    2154             :   // We don't need to set mIsCroppingAreaOutSideOfSourceImage here because there
    2155             :   // is no cropping supported and the mIsCroppingAreaOutSideOfSourceImage is
    2156             :   // false in default.
    2157             : 
    2158           0 :   AsyncFulfillImageBitmapPromise(promise, imageBitmap);
    2159             : 
    2160           0 :   return promise.forget();
    2161             : }
    2162             : 
    2163             : } // namespace dom
    2164             : } // namespace mozilla

Generated by: LCOV version 1.13