tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ImageBitmap.cpp (80591B)


      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 
      9 #include "imgLoader.h"
     10 #include "imgTools.h"
     11 #include "jsapi.h"
     12 #include "mozilla/AppShutdown.h"
     13 #include "mozilla/CheckedInt.h"
     14 #include "mozilla/Mutex.h"
     15 #include "mozilla/ScopeExit.h"
     16 #include "mozilla/dom/BlobImpl.h"
     17 #include "mozilla/dom/CanvasRenderingContext2D.h"
     18 #include "mozilla/dom/CanvasUtils.h"
     19 #include "mozilla/dom/Document.h"
     20 #include "mozilla/dom/HTMLCanvasElement.h"
     21 #include "mozilla/dom/HTMLImageElement.h"
     22 #include "mozilla/dom/HTMLMediaElementBinding.h"
     23 #include "mozilla/dom/HTMLVideoElement.h"
     24 #include "mozilla/dom/ImageBitmapBinding.h"
     25 #include "mozilla/dom/OffscreenCanvas.h"
     26 #include "mozilla/dom/Promise.h"
     27 #include "mozilla/dom/SVGImageElement.h"
     28 #include "mozilla/dom/StructuredCloneTags.h"
     29 #include "mozilla/dom/VideoFrame.h"
     30 #include "mozilla/dom/WorkerPrivate.h"
     31 #include "mozilla/dom/WorkerRef.h"
     32 #include "mozilla/dom/WorkerRunnable.h"
     33 #include "mozilla/gfx/2D.h"
     34 #include "mozilla/gfx/Logging.h"
     35 #include "mozilla/gfx/Scale.h"
     36 #include "mozilla/gfx/Swizzle.h"
     37 #include "nsGlobalWindowInner.h"
     38 #include "nsIAsyncInputStream.h"
     39 #include "nsISerialEventTarget.h"
     40 #include "nsLayoutUtils.h"
     41 #include "nsNetUtil.h"
     42 #include "nsStreamUtils.h"
     43 
     44 using namespace mozilla::gfx;
     45 using namespace mozilla::layers;
     46 using mozilla::dom::HTMLMediaElement_Binding::HAVE_METADATA;
     47 using mozilla::dom::HTMLMediaElement_Binding::NETWORK_EMPTY;
     48 
     49 namespace mozilla::dom {
     50 
     51 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmap, mParent)
     52 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmap)
     53 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmap)
     54 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmap)
     55  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     56  NS_INTERFACE_MAP_ENTRY(nsISupports)
     57 NS_INTERFACE_MAP_END
     58 
     59 class ImageBitmapShutdownObserver;
     60 
     61 static StaticMutex sShutdownMutex;
     62 static ImageBitmapShutdownObserver* sShutdownObserver = nullptr;
     63 
     64 class SendShutdownToWorkerThread : public MainThreadWorkerControlRunnable {
     65 public:
     66  explicit SendShutdownToWorkerThread(ImageBitmap* aImageBitmap)
     67      : MainThreadWorkerControlRunnable("SendShutdownToWorkerThread"),
     68        mImageBitmap(aImageBitmap) {
     69    MOZ_ASSERT(GetCurrentThreadWorkerPrivate());
     70    mTarget = GetCurrentThreadWorkerPrivate()->ControlEventTarget();
     71    MOZ_ASSERT(mTarget);
     72  }
     73 
     74  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
     75    if (mImageBitmap) {
     76      mImageBitmap->OnShutdown();
     77      mImageBitmap = nullptr;
     78    }
     79    return true;
     80  }
     81 
     82  void DispatchToWorker() {
     83    MOZ_ASSERT(mTarget);
     84    (void)NS_WARN_IF(NS_FAILED(mTarget->Dispatch(this, NS_DISPATCH_NORMAL)));
     85    mTarget = nullptr;
     86  }
     87 
     88  nsCOMPtr<nsISerialEventTarget> mTarget;
     89  ImageBitmap* mImageBitmap;
     90 };
     91 
     92 /* This class observes shutdown notifications and sends that notification
     93 * to the worker thread if the image bitmap is on a worker thread.
     94 */
     95 class ImageBitmapShutdownObserver final : public nsIObserver {
     96 public:
     97  void Init() {
     98    sShutdownMutex.AssertCurrentThreadOwns();
     99    if (NS_IsMainThread()) {
    100      RegisterObserver();
    101      return;
    102    }
    103 
    104    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    105    MOZ_ASSERT(workerPrivate);
    106    auto* mainThreadEventTarget = workerPrivate->MainThreadEventTarget();
    107    MOZ_ASSERT(mainThreadEventTarget);
    108    RefPtr<ImageBitmapShutdownObserver> self = this;
    109    nsCOMPtr<nsIRunnable> r =
    110        NS_NewRunnableFunction("ImageBitmapShutdownObserver::RegisterObserver",
    111                               [self]() { self->RegisterObserver(); });
    112    mainThreadEventTarget->Dispatch(r.forget());
    113  }
    114 
    115  void RegisterObserver() {
    116    MOZ_ASSERT(NS_IsMainThread());
    117    nsContentUtils::RegisterShutdownObserver(this);
    118  }
    119 
    120  already_AddRefed<SendShutdownToWorkerThread> Track(
    121      ImageBitmap* aImageBitmap) {
    122    sShutdownMutex.AssertCurrentThreadOwns();
    123    MOZ_ASSERT(!mBitmaps.Contains(aImageBitmap));
    124 
    125    RefPtr<SendShutdownToWorkerThread> runnable = nullptr;
    126    if (!NS_IsMainThread()) {
    127      runnable = new SendShutdownToWorkerThread(aImageBitmap);
    128    }
    129 
    130    RefPtr<SendShutdownToWorkerThread> retval = runnable;
    131    mBitmaps.Insert(aImageBitmap);
    132    return retval.forget();
    133  }
    134 
    135  void Untrack(ImageBitmap* aImageBitmap) {
    136    sShutdownMutex.AssertCurrentThreadOwns();
    137    MOZ_ASSERT(mBitmaps.Contains(aImageBitmap));
    138 
    139    mBitmaps.Remove(aImageBitmap);
    140  }
    141 
    142  NS_DECL_THREADSAFE_ISUPPORTS
    143  NS_DECL_NSIOBSERVER
    144 private:
    145  ~ImageBitmapShutdownObserver() = default;
    146 
    147  nsTHashSet<ImageBitmap*> mBitmaps;
    148 };
    149 
    150 NS_IMPL_ISUPPORTS(ImageBitmapShutdownObserver, nsIObserver)
    151 
    152 NS_IMETHODIMP
    153 ImageBitmapShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
    154                                     const char16_t* aData) {
    155  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
    156    StaticMutexAutoLock lock(sShutdownMutex);
    157 
    158    for (const auto& bitmap : mBitmaps) {
    159      const auto& runnable = bitmap->mShutdownRunnable;
    160      if (runnable) {
    161        runnable->DispatchToWorker();
    162      } else {
    163        bitmap->OnShutdown();
    164      }
    165    }
    166 
    167    nsContentUtils::UnregisterShutdownObserver(this);
    168 
    169    sShutdownObserver = nullptr;
    170  }
    171 
    172  return NS_OK;
    173 }
    174 
    175 /*
    176 * If either aRect.width or aRect.height are negative, then return a new IntRect
    177 * which represents the same rectangle as the aRect does but with positive width
    178 * and height.
    179 */
    180 static IntRect FixUpNegativeDimension(const IntRect& aRect, ErrorResult& aRv) {
    181  gfx::IntRect rect = aRect;
    182 
    183  // fix up negative dimensions
    184  if (rect.width < 0) {
    185    CheckedInt32 checkedX = CheckedInt32(rect.x) + rect.width;
    186 
    187    if (!checkedX.isValid()) {
    188      aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    189      return rect;
    190    }
    191 
    192    rect.x = checkedX.value();
    193    rect.width = -(rect.width);
    194  }
    195 
    196  if (rect.height < 0) {
    197    CheckedInt32 checkedY = CheckedInt32(rect.y) + rect.height;
    198 
    199    if (!checkedY.isValid()) {
    200      aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    201      return rect;
    202    }
    203 
    204    rect.y = checkedY.value();
    205    rect.height = -(rect.height);
    206  }
    207 
    208  return rect;
    209 }
    210 
    211 /*
    212 * This helper function copies the data of the given DataSourceSurface,
    213 *  _aSurface_, in the given area, _aCropRect_, into a new DataSourceSurface.
    214 * This might return null if it can not create a new SourceSurface or it cannot
    215 * read data from the given _aSurface_.
    216 *
    217 * Warning: Even though the area of _aCropRect_ is just the same as the size of
    218 *          _aSurface_, this function still copy data into a new
    219 *          DataSourceSurface.
    220 */
    221 static already_AddRefed<DataSourceSurface> CropAndCopyDataSourceSurface(
    222    DataSourceSurface* aSurface, const IntRect& aCropRect) {
    223  MOZ_ASSERT(aSurface);
    224 
    225  // Check the aCropRect
    226  ErrorResult error;
    227  const IntRect positiveCropRect = FixUpNegativeDimension(aCropRect, error);
    228  if (NS_WARN_IF(error.Failed())) {
    229    error.SuppressException();
    230    return nullptr;
    231  }
    232 
    233  // Calculate the size of the new SourceSurface.
    234  // We cannot keep using aSurface->GetFormat() to create new DataSourceSurface,
    235  // since it might be SurfaceFormat::B8G8R8X8 which does not handle opacity,
    236  // however the specification explicitly define that "If any of the pixels on
    237  // this rectangle are outside the area where the input bitmap was placed, then
    238  // they will be transparent black in output."
    239  // So, instead, we force the output format to be SurfaceFormat::B8G8R8A8.
    240  const SurfaceFormat format = SurfaceFormat::B8G8R8A8;
    241  const int bytesPerPixel = BytesPerPixel(format);
    242  const IntSize dstSize =
    243      IntSize(positiveCropRect.width, positiveCropRect.height);
    244  const uint32_t dstStride = dstSize.width * bytesPerPixel;
    245 
    246  // Create a new SourceSurface.
    247  RefPtr<DataSourceSurface> dstDataSurface =
    248      Factory::CreateDataSourceSurfaceWithStride(dstSize, format, dstStride,
    249                                                 true);
    250 
    251  if (NS_WARN_IF(!dstDataSurface)) {
    252    return nullptr;
    253  }
    254 
    255  // Only do copying and cropping when the positiveCropRect intersects with
    256  // the size of aSurface.
    257  const IntRect surfRect(IntPoint(0, 0), aSurface->GetSize());
    258  if (surfRect.Intersects(positiveCropRect)) {
    259    const IntRect surfPortion = surfRect.Intersect(positiveCropRect);
    260    const IntPoint dest(std::max(0, surfPortion.X() - positiveCropRect.X()),
    261                        std::max(0, surfPortion.Y() - positiveCropRect.Y()));
    262 
    263    // Copy the raw data into the newly created DataSourceSurface.
    264    DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ);
    265    DataSourceSurface::ScopedMap dstMap(dstDataSurface,
    266                                        DataSourceSurface::WRITE);
    267    if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
    268      return nullptr;
    269    }
    270 
    271    uint8_t* srcBufferPtr = srcMap.GetData() +
    272                            surfPortion.y * srcMap.GetStride() +
    273                            surfPortion.x * bytesPerPixel;
    274    uint8_t* dstBufferPtr =
    275        dstMap.GetData() + dest.y * dstMap.GetStride() + dest.x * bytesPerPixel;
    276    CheckedInt<uint32_t> copiedBytesPerRaw =
    277        CheckedInt<uint32_t>(surfPortion.width) * bytesPerPixel;
    278    if (!copiedBytesPerRaw.isValid()) {
    279      return nullptr;
    280    }
    281 
    282    for (int i = 0; i < surfPortion.height; ++i) {
    283      memcpy(dstBufferPtr, srcBufferPtr, copiedBytesPerRaw.value());
    284      srcBufferPtr += srcMap.GetStride();
    285      dstBufferPtr += dstMap.GetStride();
    286    }
    287  }
    288 
    289  return dstDataSurface.forget();
    290 }
    291 
    292 /*
    293 * This helper function scales the data of the given DataSourceSurface,
    294 *  _aSurface_, in the given area, _aCropRect_, into a new DataSourceSurface.
    295 * This might return null if it can not create a new SourceSurface or it cannot
    296 * read data from the given _aSurface_.
    297 *
    298 */
    299 static already_AddRefed<DataSourceSurface> ScaleDataSourceSurface(
    300    DataSourceSurface* aSurface, const ImageBitmapOptions& aOptions) {
    301  if (NS_WARN_IF(!aSurface)) {
    302    return nullptr;
    303  }
    304 
    305  const SurfaceFormat format = aSurface->GetFormat();
    306  const int bytesPerPixel = BytesPerPixel(format);
    307 
    308  const IntSize srcSize = aSurface->GetSize();
    309  int32_t tmp;
    310 
    311  CheckedInt<int32_t> checked;
    312  CheckedInt<int32_t> dstWidth(
    313      aOptions.mResizeWidth.WasPassed() ? aOptions.mResizeWidth.Value() : 0);
    314  CheckedInt<int32_t> dstHeight(
    315      aOptions.mResizeHeight.WasPassed() ? aOptions.mResizeHeight.Value() : 0);
    316 
    317  if (!dstWidth.isValid() || !dstHeight.isValid()) {
    318    return nullptr;
    319  }
    320 
    321  if (!dstWidth.value()) {
    322    checked = srcSize.width * dstHeight;
    323    if (!checked.isValid()) {
    324      return nullptr;
    325    }
    326 
    327    tmp = ceil(checked.value() / double(srcSize.height));
    328    dstWidth = tmp;
    329  } else if (!dstHeight.value()) {
    330    checked = srcSize.height * dstWidth;
    331    if (!checked.isValid()) {
    332      return nullptr;
    333    }
    334 
    335    tmp = ceil(checked.value() / double(srcSize.width));
    336    dstHeight = tmp;
    337  }
    338 
    339  const IntSize dstSize(dstWidth.value(), dstHeight.value());
    340  const int32_t dstStride = dstSize.width * bytesPerPixel;
    341 
    342  // Create a new SourceSurface.
    343  RefPtr<DataSourceSurface> dstDataSurface =
    344      Factory::CreateDataSourceSurfaceWithStride(dstSize, format, dstStride,
    345                                                 true);
    346 
    347  if (NS_WARN_IF(!dstDataSurface)) {
    348    return nullptr;
    349  }
    350 
    351  // Copy the raw data into the newly created DataSourceSurface.
    352  DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ);
    353  DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE);
    354  if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
    355    return nullptr;
    356  }
    357 
    358  uint8_t* srcBufferPtr = srcMap.GetData();
    359  uint8_t* dstBufferPtr = dstMap.GetData();
    360 
    361  bool res = Scale(srcBufferPtr, srcSize.width, srcSize.height,
    362                   srcMap.GetStride(), dstBufferPtr, dstSize.width,
    363                   dstSize.height, dstMap.GetStride(), aSurface->GetFormat());
    364  if (!res) {
    365    return nullptr;
    366  }
    367 
    368  return dstDataSurface.forget();
    369 }
    370 
    371 static DataSourceSurface* FlipYDataSourceSurface(DataSourceSurface* aSurface) {
    372  MOZ_ASSERT(aSurface);
    373 
    374  // Invert in y direction.
    375  DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ_WRITE);
    376  if (NS_WARN_IF(!srcMap.IsMapped())) {
    377    return nullptr;
    378  }
    379 
    380  const int bpp = BytesPerPixel(aSurface->GetFormat());
    381  const IntSize srcSize = aSurface->GetSize();
    382  uint8_t* srcBufferPtr = srcMap.GetData();
    383  const uint32_t stride = srcMap.GetStride();
    384 
    385  CheckedInt<uint32_t> copiedBytesPerRaw = CheckedInt<uint32_t>(stride);
    386  if (!copiedBytesPerRaw.isValid()) {
    387    return nullptr;
    388  }
    389 
    390  for (int i = 0; i < srcSize.height / 2; ++i) {
    391    std::swap_ranges(srcBufferPtr + stride * i,
    392                     srcBufferPtr + stride * i + srcSize.width * bpp,
    393                     srcBufferPtr + stride * (srcSize.height - 1 - i));
    394  }
    395 
    396  return aSurface;
    397 }
    398 
    399 static DataSourceSurface* AlphaPremultiplyDataSourceSurface(
    400    DataSourceSurface* aSurface, const bool forward = true) {
    401  MOZ_ASSERT(aSurface);
    402 
    403  DataSourceSurface::MappedSurface surfaceMap;
    404 
    405  if (aSurface->Map(DataSourceSurface::MapType::READ_WRITE, &surfaceMap)) {
    406    if (forward) {
    407      PremultiplyData(surfaceMap.mData, surfaceMap.mStride,
    408                      aSurface->GetFormat(), surfaceMap.mData,
    409                      surfaceMap.mStride, aSurface->GetFormat(),
    410                      aSurface->GetSize());
    411    } else {
    412      UnpremultiplyData(surfaceMap.mData, surfaceMap.mStride,
    413                        aSurface->GetFormat(), surfaceMap.mData,
    414                        surfaceMap.mStride, aSurface->GetFormat(),
    415                        aSurface->GetSize());
    416    }
    417 
    418    aSurface->Unmap();
    419  } else {
    420    return nullptr;
    421  }
    422 
    423  return aSurface;
    424 }
    425 
    426 /*
    427 * Encapsulate the given _aSurface_ into a layers::SourceSurfaceImage.
    428 */
    429 static already_AddRefed<layers::Image> CreateImageFromSurface(
    430    SourceSurface* aSurface) {
    431  MOZ_ASSERT(aSurface);
    432  RefPtr<layers::SourceSurfaceImage> image =
    433      new layers::SourceSurfaceImage(aSurface->GetSize(), aSurface);
    434  return image.forget();
    435 }
    436 
    437 /*
    438 * CreateImageFromRawData(), CreateSurfaceFromRawData() and
    439 * CreateImageFromRawDataInMainThreadSyncTask are helpers for
    440 * create-from-ImageData case
    441 */
    442 static already_AddRefed<SourceSurface> CreateSurfaceFromRawData(
    443    const gfx::IntSize& aSize, uint32_t aStride, gfx::SurfaceFormat aFormat,
    444    uint8_t* aBuffer, uint32_t aBufferLength, const Maybe<IntRect>& aCropRect,
    445    const ImageBitmapOptions& aOptions) {
    446  MOZ_ASSERT(!aSize.IsEmpty());
    447  MOZ_ASSERT(aBuffer);
    448 
    449  // Wrap the source buffer into a SourceSurface.
    450  RefPtr<DataSourceSurface> dataSurface =
    451      Factory::CreateWrappingDataSourceSurface(aBuffer, aStride, aSize,
    452                                               aFormat);
    453 
    454  if (NS_WARN_IF(!dataSurface)) {
    455    return nullptr;
    456  }
    457 
    458  // The temporary cropRect variable is equal to the size of source buffer if we
    459  // do not need to crop, or it equals to the given cropping size.
    460  const IntRect cropRect =
    461      aCropRect.valueOr(IntRect(0, 0, aSize.width, aSize.height));
    462 
    463  // Copy the source buffer in the _cropRect_ area into a new SourceSurface.
    464  RefPtr<DataSourceSurface> result =
    465      CropAndCopyDataSourceSurface(dataSurface, cropRect);
    466  if (NS_WARN_IF(!result)) {
    467    return nullptr;
    468  }
    469 
    470  if (aOptions.mImageOrientation == ImageOrientation::FlipY) {
    471    result = FlipYDataSourceSurface(result);
    472 
    473    if (NS_WARN_IF(!result)) {
    474      return nullptr;
    475    }
    476  }
    477 
    478  if (aOptions.mPremultiplyAlpha == PremultiplyAlpha::Premultiply) {
    479    result = AlphaPremultiplyDataSourceSurface(result);
    480 
    481    if (NS_WARN_IF(!result)) {
    482      return nullptr;
    483    }
    484  }
    485 
    486  if (aOptions.mResizeWidth.WasPassed() || aOptions.mResizeHeight.WasPassed()) {
    487    dataSurface = result->GetDataSurface();
    488    result = ScaleDataSourceSurface(dataSurface, aOptions);
    489    if (NS_WARN_IF(!result)) {
    490      return nullptr;
    491    }
    492  }
    493 
    494  return result.forget();
    495 }
    496 
    497 static already_AddRefed<layers::Image> CreateImageFromRawData(
    498    const gfx::IntSize& aSize, uint32_t aStride, gfx::SurfaceFormat aFormat,
    499    uint8_t* aBuffer, uint32_t aBufferLength, const Maybe<IntRect>& aCropRect,
    500    const ImageBitmapOptions& aOptions) {
    501  MOZ_ASSERT(NS_IsMainThread());
    502 
    503  // Copy and crop the source buffer into a SourceSurface.
    504  RefPtr<SourceSurface> rgbaSurface = CreateSurfaceFromRawData(
    505      aSize, aStride, aFormat, aBuffer, aBufferLength, aCropRect, aOptions);
    506 
    507  if (NS_WARN_IF(!rgbaSurface)) {
    508    return nullptr;
    509  }
    510 
    511  // Convert RGBA to BGRA
    512  RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface();
    513  DataSourceSurface::ScopedMap rgbaMap(rgbaDataSurface,
    514                                       DataSourceSurface::READ);
    515  if (NS_WARN_IF(!rgbaMap.IsMapped())) {
    516    return nullptr;
    517  }
    518 
    519  RefPtr<DataSourceSurface> bgraDataSurface =
    520      Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(),
    521                                                 SurfaceFormat::B8G8R8A8,
    522                                                 rgbaMap.GetStride());
    523  if (NS_WARN_IF(!bgraDataSurface)) {
    524    return nullptr;
    525  }
    526 
    527  DataSourceSurface::ScopedMap bgraMap(bgraDataSurface,
    528                                       DataSourceSurface::WRITE);
    529  if (NS_WARN_IF(!bgraMap.IsMapped())) {
    530    return nullptr;
    531  }
    532 
    533  SwizzleData(rgbaMap.GetData(), rgbaMap.GetStride(), SurfaceFormat::R8G8B8A8,
    534              bgraMap.GetData(), bgraMap.GetStride(), SurfaceFormat::B8G8R8A8,
    535              bgraDataSurface->GetSize());
    536 
    537  // Create an Image from the BGRA SourceSurface.
    538  return CreateImageFromSurface(bgraDataSurface);
    539 }
    540 
    541 /*
    542 * This is a synchronous task.
    543 * This class is used to create a layers::SourceSurfaceImage from raw data in
    544 * the main thread. While creating an ImageBitmap from an ImageData, we need to
    545 * create a SouceSurface from the ImageData's raw data and then set the
    546 * SourceSurface into a layers::SourceSurfaceImage. However, the
    547 * layers::SourceSurfaceImage asserts the setting operation in the main thread,
    548 * so if we are going to create an ImageBitmap from an ImageData off the main
    549 * thread, we post an event to the main thread to create a
    550 * layers::SourceSurfaceImage from an ImageData's raw data.
    551 */
    552 class CreateImageFromRawDataInMainThreadSyncTask final
    553    : public WorkerMainThreadRunnable {
    554 public:
    555  CreateImageFromRawDataInMainThreadSyncTask(
    556      uint8_t* aBuffer, uint32_t aBufferLength, uint32_t aStride,
    557      gfx::SurfaceFormat aFormat, const gfx::IntSize& aSize,
    558      const Maybe<IntRect>& aCropRect, layers::Image** aImage,
    559      const ImageBitmapOptions& aOptions)
    560      : WorkerMainThreadRunnable(
    561            GetCurrentThreadWorkerPrivate(),
    562            "ImageBitmap :: Create Image from Raw Data"_ns),
    563        mImage(aImage),
    564        mBuffer(aBuffer),
    565        mBufferLength(aBufferLength),
    566        mStride(aStride),
    567        mFormat(aFormat),
    568        mSize(aSize),
    569        mCropRect(aCropRect),
    570        mOptions(aOptions) {
    571    MOZ_ASSERT(!(*aImage),
    572               "Don't pass an existing Image into "
    573               "CreateImageFromRawDataInMainThreadSyncTask.");
    574  }
    575 
    576  bool MainThreadRun() override {
    577    RefPtr<layers::Image> image = CreateImageFromRawData(
    578        mSize, mStride, mFormat, mBuffer, mBufferLength, mCropRect, mOptions);
    579 
    580    if (NS_WARN_IF(!image)) {
    581      return false;
    582    }
    583 
    584    image.forget(mImage);
    585 
    586    return true;
    587  }
    588 
    589 private:
    590  layers::Image** mImage;
    591  uint8_t* mBuffer;
    592  uint32_t mBufferLength;
    593  uint32_t mStride;
    594  gfx::SurfaceFormat mFormat;
    595  gfx::IntSize mSize;
    596  const Maybe<IntRect>& mCropRect;
    597  const ImageBitmapOptions mOptions;
    598 };
    599 
    600 /*
    601 * A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
    602 * security checking.
    603 */
    604 template <class ElementType>
    605 static already_AddRefed<SourceSurface> GetSurfaceFromElement(
    606    nsIGlobalObject* aGlobal, ElementType& aElement, bool* aWriteOnly,
    607    const ImageBitmapOptions& aOptions, gfxAlphaType* aAlphaType,
    608    ErrorResult& aRv) {
    609  uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
    610                   nsLayoutUtils::SFE_ORIENTATION_FROM_IMAGE |
    611                   nsLayoutUtils::SFE_EXACT_SIZE_SURFACE;
    612 
    613  // by default surfaces have premultiplied alpha
    614  // attempt to get non premultiplied if required
    615  if (aOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
    616    flags |= nsLayoutUtils::SFE_ALLOW_NON_PREMULT;
    617  }
    618 
    619  if (aOptions.mColorSpaceConversion == ColorSpaceConversion::None &&
    620      aElement.IsHTMLElement(nsGkAtoms::img)) {
    621    flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
    622  }
    623 
    624  Maybe<int32_t> resizeWidth, resizeHeight;
    625  if (aOptions.mResizeWidth.WasPassed()) {
    626    if (!CheckedInt32(aOptions.mResizeWidth.Value()).isValid()) {
    627      aRv.ThrowInvalidStateError("resizeWidth is too large");
    628      return nullptr;
    629    }
    630    resizeWidth.emplace(aOptions.mResizeWidth.Value());
    631  }
    632  if (aOptions.mResizeHeight.WasPassed()) {
    633    if (!CheckedInt32(aOptions.mResizeHeight.Value()).isValid()) {
    634      aRv.ThrowInvalidStateError("resizeHeight is too large");
    635      return nullptr;
    636    }
    637    resizeHeight.emplace(aOptions.mResizeHeight.Value());
    638  }
    639  SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromElement(
    640      &aElement, resizeWidth, resizeHeight, flags);
    641 
    642  RefPtr<SourceSurface> surface = res.GetSourceSurface();
    643  if (NS_WARN_IF(!surface)) {
    644    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    645    return nullptr;
    646  }
    647 
    648  *aWriteOnly = res.mIsWriteOnly;
    649  *aAlphaType = res.mAlphaType;
    650 
    651  return surface.forget();
    652 }
    653 
    654 ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
    655                         bool aAllocatedImageData, bool aWriteOnly,
    656                         gfxAlphaType aAlphaType)
    657    : mParent(aGlobal),
    658      mData(aData),
    659      mSurface(nullptr),
    660      mPictureRect(aData->GetPictureRect()),
    661      mAlphaType(aAlphaType),
    662      mAllocatedImageData(aAllocatedImageData),
    663      mWriteOnly(aWriteOnly) {
    664  MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
    665 
    666  StaticMutexAutoLock lock(sShutdownMutex);
    667  if (!sShutdownObserver &&
    668      !AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) {
    669    sShutdownObserver = new ImageBitmapShutdownObserver();
    670    sShutdownObserver->Init();
    671  }
    672  if (sShutdownObserver) {
    673    mShutdownRunnable = sShutdownObserver->Track(this);
    674  }
    675 }
    676 
    677 ImageBitmap::~ImageBitmap() {
    678  StaticMutexAutoLock lock(sShutdownMutex);
    679  if (mShutdownRunnable) {
    680    mShutdownRunnable->mImageBitmap = nullptr;
    681  }
    682  mShutdownRunnable = nullptr;
    683  if (sShutdownObserver) {
    684    sShutdownObserver->Untrack(this);
    685  }
    686 }
    687 
    688 JSObject* ImageBitmap::WrapObject(JSContext* aCx,
    689                                  JS::Handle<JSObject*> aGivenProto) {
    690  return ImageBitmap_Binding::Wrap(aCx, this, aGivenProto);
    691 }
    692 
    693 void ImageBitmap::Close() {
    694  RemoveAssociatedMemory();
    695  mData = nullptr;
    696  mSurface = nullptr;
    697  mPictureRect.SetEmpty();
    698 }
    699 
    700 void ImageBitmap::OnShutdown() { Close(); }
    701 
    702 void ImageBitmap::SetPictureRect(const IntRect& aRect, ErrorResult& aRv) {
    703  mPictureRect = FixUpNegativeDimension(aRect, aRv);
    704  mSurface = nullptr;
    705 }
    706 
    707 SurfaceFromElementResult ImageBitmap::SurfaceFrom(uint32_t aSurfaceFlags) {
    708  SurfaceFromElementResult sfer;
    709 
    710  if (!mData) {
    711    return sfer;
    712  }
    713 
    714  // An ImageBitmap, not being a DOM element, only has `origin-clean`
    715  // (via our `IsWriteOnly`), and does not participate in CORS.
    716  // Right now we mark this by setting mCORSUsed to true.
    717  sfer.mCORSUsed = true;
    718  sfer.mIsWriteOnly = mWriteOnly;
    719 
    720  if (mParent) {
    721    sfer.mPrincipal = mParent->PrincipalOrNull();
    722  }
    723 
    724  IntSize imageSize(mData->GetSize());
    725  IntRect imageRect(IntPoint(0, 0), imageSize);
    726  bool hasCropRect = mPictureRect.IsEqualEdges(imageRect);
    727 
    728  bool wantExactSize =
    729      bool(aSurfaceFlags & nsLayoutUtils::SFE_EXACT_SIZE_SURFACE);
    730  bool allowNonPremult =
    731      bool(aSurfaceFlags & nsLayoutUtils::SFE_ALLOW_NON_PREMULT);
    732  bool allowUncropped =
    733      bool(aSurfaceFlags & nsLayoutUtils::SFE_ALLOW_UNCROPPED_UNSCALED);
    734  bool requiresPremult =
    735      !allowNonPremult && mAlphaType == gfxAlphaType::NonPremult;
    736  bool requiresCrop = !allowUncropped && hasCropRect;
    737  if (wantExactSize || requiresPremult || requiresCrop || mSurface) {
    738    RefPtr<DrawTarget> dt = Factory::CreateDrawTarget(
    739        BackendType::SKIA, IntSize(1, 1), SurfaceFormat::B8G8R8A8);
    740    sfer.mSourceSurface = PrepareForDrawTarget(dt);
    741 
    742    if (!sfer.mSourceSurface) {
    743      return sfer;
    744    }
    745 
    746    MOZ_ASSERT(mSurface);
    747 
    748    sfer.mSize = sfer.mIntrinsicSize = sfer.mSourceSurface->GetSize();
    749    sfer.mHasSize = true;
    750    sfer.mAlphaType = IsOpaque(sfer.mSourceSurface->GetFormat())
    751                          ? gfxAlphaType::Opaque
    752                          : gfxAlphaType::Premult;
    753    return sfer;
    754  }
    755 
    756  if (hasCropRect) {
    757    IntRect imagePortion = imageRect.Intersect(mPictureRect);
    758 
    759    // the crop lies entirely outside the surface area, nothing to draw
    760    if (imagePortion.IsEmpty()) {
    761      return sfer;
    762    }
    763 
    764    sfer.mCropRect = Some(imagePortion);
    765    sfer.mIntrinsicSize = imagePortion.Size();
    766  } else {
    767    sfer.mIntrinsicSize = imageSize;
    768  }
    769 
    770  sfer.mSize = imageSize;
    771  sfer.mHasSize = true;
    772  sfer.mAlphaType = mAlphaType;
    773  sfer.mLayersImage = mData;
    774  return sfer;
    775 }
    776 
    777 /*
    778 * The functionality of PrepareForDrawTarget method:
    779 * (1) Get a SourceSurface from the mData (which is a layers::Image).
    780 * (2) Convert the SourceSurface to format B8G8R8A8 if the original format is
    781 *     R8G8B8, B8G8R8, HSV or Lab.
    782 *     Note: if the original format is A8 or Depth, then return null directly.
    783 * (3) Do cropping if the size of SourceSurface does not equal to the
    784 *     mPictureRect.
    785 * (4) Pre-multiply alpha if needed.
    786 */
    787 already_AddRefed<SourceSurface> ImageBitmap::PrepareForDrawTarget(
    788    gfx::DrawTarget* aTarget) {
    789  MOZ_ASSERT(aTarget);
    790 
    791  if (!mData) {
    792    return nullptr;
    793  }
    794 
    795  // We may have a cached surface optimized for the last DrawTarget. If it was
    796  // created via DrawTargetRecording, it may not be suitable for use with the
    797  // current DrawTarget, as we can only do readbacks via the
    798  // PersistentBufferProvider for the canvas, and not for individual
    799  // SourceSurfaceRecording objects. In such situations, the only thing we can
    800  // do is clear our cache and extract a new SourceSurface from mData.
    801  if (mSurface && mSurface->GetType() == gfx::SurfaceType::RECORDING &&
    802      !aTarget->IsRecording()) {
    803    RefPtr<gfx::DataSourceSurface> dataSurface = mSurface->GetDataSurface();
    804    if (!dataSurface) {
    805      mSurface = nullptr;
    806    }
    807  }
    808 
    809  // If we have a surface, then it is already cropped and premultiplied.
    810  if (mSurface) {
    811    return do_AddRef(mSurface);
    812  }
    813 
    814  RefPtr<gfx::SourceSurface> surface = mData->GetAsSourceSurface();
    815  if (NS_WARN_IF(!surface)) {
    816    return nullptr;
    817  }
    818 
    819  IntRect surfRect(0, 0, surface->GetSize().width, surface->GetSize().height);
    820  SurfaceFormat format = surface->GetFormat();
    821  bool isOpaque = IsOpaque(format);
    822  bool mustPremultiply = mAlphaType == gfxAlphaType::NonPremult && !isOpaque;
    823  bool hasCopied = false;
    824 
    825  // Check if we still need to crop our surface
    826  if (!mPictureRect.IsEqualEdges(surfRect)) {
    827    IntRect surfPortion = surfRect.Intersect(mPictureRect);
    828 
    829    // the crop lies entirely outside the surface area, nothing to draw
    830    if (surfPortion.IsEmpty()) {
    831      return nullptr;
    832    }
    833 
    834    IntPoint dest(std::max(0, surfPortion.X() - mPictureRect.X()),
    835                  std::max(0, surfPortion.Y() - mPictureRect.Y()));
    836 
    837    // We must initialize this target with mPictureRect.Size() because the
    838    // specification states that if the cropping area is given, then return an
    839    // ImageBitmap with the size equals to the cropping area. Ensure that the
    840    // format matches the surface, even though the DT type is similar to the
    841    // destination, i.e. blending an alpha surface to an opaque DT. However,
    842    // any pixels outside the surface portion must be filled with transparent
    843    // black, even if the surface is opaque, so force to an alpha format in
    844    // that case.
    845    if (!surfPortion.IsEqualEdges(mPictureRect) && isOpaque) {
    846      format = SurfaceFormat::B8G8R8A8;
    847    }
    848 
    849    // If we need to pre-multiply the alpha, then we need to be able to
    850    // read/write the pixel data, and as such, we want to avoid creating a
    851    // SourceSurfaceRecording for the same reasons earlier in this method.
    852    RefPtr<DrawTarget> cropped;
    853    if (mustPremultiply && aTarget->IsRecording()) {
    854      cropped = Factory::CreateDrawTarget(BackendType::SKIA,
    855                                          mPictureRect.Size(), format);
    856    } else {
    857      if (aTarget->CanCreateSimilarDrawTarget(mPictureRect.Size(), format)) {
    858        cropped = aTarget->CreateSimilarDrawTarget(mPictureRect.Size(), format);
    859      }
    860    }
    861 
    862    if (NS_WARN_IF(!cropped)) {
    863      return nullptr;
    864    }
    865 
    866    cropped->CopySurface(surface, surfPortion, dest);
    867    surface = cropped->GetBackingSurface();
    868    hasCopied = true;
    869    if (NS_WARN_IF(!surface)) {
    870      return nullptr;
    871    }
    872  }
    873 
    874  // Pre-multiply alpha here.
    875  // Ignore this step if the source surface does not have alpha channel; this
    876  // kind of source surfaces might come form layers::PlanarYCbCrImage. If the
    877  // crop rect imputed transparency, and the original surface was opaque, we
    878  // can skip doing the pre-multiply here as the only transparent pixels are
    879  // already transparent black.
    880  if (mustPremultiply) {
    881    MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::R8G8B8A8 ||
    882               surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
    883               surface->GetFormat() == SurfaceFormat::A8R8G8B8);
    884 
    885    RefPtr<DataSourceSurface> srcSurface = surface->GetDataSurface();
    886    if (NS_WARN_IF(!srcSurface)) {
    887      return nullptr;
    888    }
    889 
    890    if (hasCopied) {
    891      // If we are using our own local copy, then we can safely premultiply in
    892      // place without an additional allocation.
    893      DataSourceSurface::ScopedMap map(srcSurface,
    894                                       DataSourceSurface::READ_WRITE);
    895      if (!map.IsMapped()) {
    896        gfxCriticalError() << "Failed to map surface for premultiplying alpha.";
    897        return nullptr;
    898      }
    899 
    900      PremultiplyData(map.GetData(), map.GetStride(), srcSurface->GetFormat(),
    901                      map.GetData(), map.GetStride(), srcSurface->GetFormat(),
    902                      surface->GetSize());
    903    } else {
    904      RefPtr<DataSourceSurface> dstSurface = Factory::CreateDataSourceSurface(
    905          srcSurface->GetSize(), srcSurface->GetFormat());
    906      if (NS_WARN_IF(!dstSurface)) {
    907        return nullptr;
    908      }
    909 
    910      DataSourceSurface::ScopedMap srcMap(srcSurface, DataSourceSurface::READ);
    911      if (!srcMap.IsMapped()) {
    912        gfxCriticalError()
    913            << "Failed to map source surface for premultiplying alpha.";
    914        return nullptr;
    915      }
    916 
    917      DataSourceSurface::ScopedMap dstMap(dstSurface, DataSourceSurface::WRITE);
    918      if (!dstMap.IsMapped()) {
    919        gfxCriticalError()
    920            << "Failed to map destination surface for premultiplying alpha.";
    921        return nullptr;
    922      }
    923 
    924      PremultiplyData(srcMap.GetData(), srcMap.GetStride(),
    925                      srcSurface->GetFormat(), dstMap.GetData(),
    926                      dstMap.GetStride(), dstSurface->GetFormat(),
    927                      dstSurface->GetSize());
    928 
    929      surface = std::move(dstSurface);
    930    }
    931  }
    932 
    933  // Replace our surface with one optimized for the target we're about to draw
    934  // to, under the assumption it'll likely be drawn again to that target.
    935  // This call should be a no-op for already-optimized surfaces
    936  mSurface = aTarget->OptimizeSourceSurface(surface);
    937  if (!mSurface) {
    938    mSurface = std::move(surface);
    939  }
    940  return do_AddRef(mSurface);
    941 }
    942 
    943 already_AddRefed<layers::Image> ImageBitmap::TransferAsImage() {
    944  RefPtr<layers::Image> image = mData;
    945  Close();
    946  return image.forget();
    947 }
    948 
    949 UniquePtr<ImageBitmapCloneData> ImageBitmap::ToCloneData() const {
    950  if (!mData) {
    951    // A closed image cannot be cloned.
    952    return nullptr;
    953  }
    954 
    955  RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
    956  if (!surface) {
    957    // It might just not be possible to get/map the surface. (e.g. from another
    958    // process)
    959    return nullptr;
    960  }
    961 
    962  RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
    963  if (NS_WARN_IF(!dataSurface)) {
    964    // This can reasonably fail in many cases (e.g. canvas state doesn't allow
    965    // reading back the snapshot).
    966    return nullptr;
    967  }
    968 
    969  auto result = MakeUnique<ImageBitmapCloneData>();
    970  result->mPictureRect = mPictureRect;
    971  result->mAlphaType = mAlphaType;
    972  result->mSurface = std::move(dataSurface);
    973  result->mWriteOnly = mWriteOnly;
    974  return result;
    975 }
    976 
    977 /* static */
    978 already_AddRefed<ImageBitmap> ImageBitmap::CreateFromSourceSurface(
    979    nsIGlobalObject* aGlobal, gfx::SourceSurface* aSource, ErrorResult& aRv) {
    980  RefPtr<layers::Image> data = CreateImageFromSurface(aSource);
    981  RefPtr<ImageBitmap> ret =
    982      new ImageBitmap(aGlobal, data, true, false /* writeOnly */);
    983  return ret.forget();
    984 }
    985 
    986 /* static */
    987 already_AddRefed<ImageBitmap> ImageBitmap::CreateFromCloneData(
    988    nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData) {
    989  RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
    990 
    991  RefPtr<ImageBitmap> ret = new ImageBitmap(
    992      aGlobal, data, true, aData->mWriteOnly, aData->mAlphaType);
    993 
    994  ErrorResult rv;
    995  ret->SetPictureRect(aData->mPictureRect, rv);
    996  return ret.forget();
    997 }
    998 
    999 /* static */
   1000 already_AddRefed<ImageBitmap> ImageBitmap::CreateFromOffscreenCanvas(
   1001    nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas,
   1002    ErrorResult& aRv) {
   1003  // Check write-only mode.
   1004  bool writeOnly = aOffscreenCanvas.IsWriteOnly();
   1005  uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
   1006                   nsLayoutUtils::SFE_EXACT_SIZE_SURFACE;
   1007 
   1008  SurfaceFromElementResult res =
   1009      nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, flags);
   1010 
   1011  RefPtr<SourceSurface> surface = res.GetSourceSurface();
   1012 
   1013  if (NS_WARN_IF(!surface)) {
   1014    aRv.ThrowUnknownError("Failed to create ImageBitmap from OffscreenCanvas");
   1015    return nullptr;
   1016  }
   1017 
   1018  RefPtr<layers::Image> data = CreateImageFromSurface(surface);
   1019 
   1020  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, true, writeOnly);
   1021 
   1022  return ret.forget();
   1023 }
   1024 
   1025 /* static */
   1026 already_AddRefed<ImageBitmap> ImageBitmap::CreateImageBitmapInternal(
   1027    nsIGlobalObject* aGlobal, gfx::SourceSurface* aSurface,
   1028    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1029    const bool aWriteOnly, const bool aAllocatedImageData, const bool aMustCopy,
   1030    const gfxAlphaType aAlphaType, ErrorResult& aRv) {
   1031  bool needToReportMemoryAllocation = aAllocatedImageData;
   1032  const IntSize srcSize = aSurface->GetSize();
   1033  IntRect cropRect =
   1034      aCropRect.valueOr(IntRect(0, 0, srcSize.width, srcSize.height));
   1035 
   1036  RefPtr<SourceSurface> surface = aSurface;
   1037  RefPtr<DataSourceSurface> dataSurface;
   1038 
   1039  // handle alpha premultiplication if surface not of correct type
   1040 
   1041  gfxAlphaType alphaType = aAlphaType;
   1042  bool requiresPremultiply = false;
   1043  bool requiresUnpremultiply = false;
   1044 
   1045  if (!IsOpaque(surface->GetFormat())) {
   1046    if (aAlphaType == gfxAlphaType::Premult &&
   1047        aOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
   1048      requiresUnpremultiply = true;
   1049      alphaType = gfxAlphaType::NonPremult;
   1050    } else if (aAlphaType == gfxAlphaType::NonPremult &&
   1051               aOptions.mPremultiplyAlpha == PremultiplyAlpha::Premultiply) {
   1052      requiresPremultiply = true;
   1053      alphaType = gfxAlphaType::Premult;
   1054    }
   1055  }
   1056 
   1057  /*
   1058   * if we don't own the data and need to modify the buffer.
   1059   * or
   1060   * we need to crop and flip, where crop must come first.
   1061   * or
   1062   * the caller demands a copy (WebGL contexts).
   1063   */
   1064  bool willModify = aOptions.mImageOrientation == ImageOrientation::FlipY ||
   1065                    requiresPremultiply || requiresUnpremultiply;
   1066  if ((willModify && !aAllocatedImageData) ||
   1067      (aOptions.mImageOrientation == ImageOrientation::FlipY &&
   1068       aCropRect.isSome()) ||
   1069      aMustCopy) {
   1070    dataSurface = surface->GetDataSurface();
   1071 
   1072    dataSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect);
   1073    if (NS_WARN_IF(!dataSurface)) {
   1074      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1075      return nullptr;
   1076    }
   1077 
   1078    surface = dataSurface;
   1079    cropRect.SetRect(0, 0, dataSurface->GetSize().width,
   1080                     dataSurface->GetSize().height);
   1081    needToReportMemoryAllocation = true;
   1082  }
   1083 
   1084  // flip image in Y direction
   1085  if (aOptions.mImageOrientation == ImageOrientation::FlipY) {
   1086    if (!dataSurface) {
   1087      dataSurface = surface->GetDataSurface();
   1088    }
   1089 
   1090    surface = FlipYDataSourceSurface(dataSurface);
   1091    if (NS_WARN_IF(!surface)) {
   1092      return nullptr;
   1093    }
   1094  }
   1095 
   1096  if (requiresPremultiply) {
   1097    if (!dataSurface) {
   1098      dataSurface = surface->GetDataSurface();
   1099    }
   1100 
   1101    surface = AlphaPremultiplyDataSourceSurface(dataSurface, true);
   1102    if (NS_WARN_IF(!surface)) {
   1103      return nullptr;
   1104    }
   1105  }
   1106 
   1107  // resize if required
   1108  if (aOptions.mResizeWidth.WasPassed() || aOptions.mResizeHeight.WasPassed()) {
   1109    if (!dataSurface) {
   1110      dataSurface = surface->GetDataSurface();
   1111    };
   1112 
   1113    surface = ScaleDataSourceSurface(dataSurface, aOptions);
   1114    if (NS_WARN_IF(!surface)) {
   1115      aRv.ThrowInvalidStateError("Failed to create resized image");
   1116      return nullptr;
   1117    }
   1118 
   1119    needToReportMemoryAllocation = true;
   1120    cropRect.SetRect(0, 0, surface->GetSize().width, surface->GetSize().height);
   1121  }
   1122 
   1123  if (requiresUnpremultiply) {
   1124    if (!dataSurface) {
   1125      dataSurface = surface->GetDataSurface();
   1126    }
   1127 
   1128    surface = AlphaPremultiplyDataSourceSurface(dataSurface, false);
   1129    if (NS_WARN_IF(!surface)) {
   1130      return nullptr;
   1131    }
   1132  }
   1133 
   1134  // Create an Image from the SourceSurface.
   1135  RefPtr<layers::Image> data = CreateImageFromSurface(surface);
   1136  RefPtr<ImageBitmap> ret = new ImageBitmap(
   1137      aGlobal, data, needToReportMemoryAllocation, aWriteOnly, alphaType);
   1138 
   1139  // Set the picture rectangle.
   1140  ret->SetPictureRect(cropRect, aRv);
   1141 
   1142  return ret.forget();
   1143 }
   1144 
   1145 /* static */
   1146 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1147    nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
   1148    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1149    ErrorResult& aRv) {
   1150  // Check if the image element is completely available or not.
   1151  if (!aImageEl.Complete()) {
   1152    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1153    return nullptr;
   1154  }
   1155 
   1156  bool writeOnly = true;
   1157  gfxAlphaType alphaType = gfxAlphaType::NonPremult;
   1158 
   1159  // Get the SourceSurface out from the image element and then do security
   1160  // checking.
   1161  RefPtr<SourceSurface> surface = GetSurfaceFromElement(
   1162      aGlobal, aImageEl, &writeOnly, aOptions, &alphaType, aRv);
   1163 
   1164  if (NS_WARN_IF(aRv.Failed())) {
   1165    return nullptr;
   1166  }
   1167 
   1168  bool needToReportMemoryAllocation = false;
   1169  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1170                                   writeOnly, needToReportMemoryAllocation,
   1171                                   false, alphaType, aRv);
   1172 }
   1173 /* static */
   1174 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1175    nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
   1176    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1177    ErrorResult& aRv) {
   1178  bool writeOnly = true;
   1179  gfxAlphaType alphaType = gfxAlphaType::NonPremult;
   1180 
   1181  // Get the SourceSurface out from the image element and then do security
   1182  // checking.
   1183  RefPtr<SourceSurface> surface = GetSurfaceFromElement(
   1184      aGlobal, aImageEl, &writeOnly, aOptions, &alphaType, aRv);
   1185 
   1186  if (NS_WARN_IF(aRv.Failed())) {
   1187    return nullptr;
   1188  }
   1189 
   1190  bool needToReportMemoryAllocation = false;
   1191 
   1192  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1193                                   writeOnly, needToReportMemoryAllocation,
   1194                                   false, alphaType, aRv);
   1195 }
   1196 
   1197 /* static */
   1198 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1199    nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
   1200    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1201    ErrorResult& aRv) {
   1202  aVideoEl.LogVisibility(
   1203      mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_IMAGEBITMAP);
   1204 
   1205  // Check network state.
   1206  if (aVideoEl.NetworkState() == NETWORK_EMPTY) {
   1207    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1208    return nullptr;
   1209  }
   1210 
   1211  // Check ready state.
   1212  // Cannot be HTMLMediaElement::HAVE_NOTHING or
   1213  // HTMLMediaElement::HAVE_METADATA.
   1214  if (aVideoEl.ReadyState() <= HAVE_METADATA) {
   1215    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1216    return nullptr;
   1217  }
   1218 
   1219  // Check security.
   1220  nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
   1221  bool hadCrossOriginRedirects = aVideoEl.HadCrossOriginRedirects();
   1222  bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
   1223  bool writeOnly = CanvasUtils::CheckWriteOnlySecurity(CORSUsed, principal,
   1224                                                       hadCrossOriginRedirects);
   1225 
   1226  // Create ImageBitmap.
   1227  RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
   1228  if (!data) {
   1229    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   1230    return nullptr;
   1231  }
   1232 
   1233  RefPtr<SourceSurface> surface = data->GetAsSourceSurface();
   1234  if (!surface) {
   1235    // preserve original behavior in case of unavailble surface
   1236    RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false, writeOnly);
   1237    return ret.forget();
   1238  }
   1239 
   1240  bool needToReportMemoryAllocation = false;
   1241 
   1242  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1243                                   writeOnly, needToReportMemoryAllocation,
   1244                                   false, gfxAlphaType::Premult, aRv);
   1245 }
   1246 
   1247 /* static */
   1248 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1249    nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
   1250    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1251    ErrorResult& aRv) {
   1252  if (aCanvasEl.Width() == 0 || aCanvasEl.Height() == 0) {
   1253    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1254    return nullptr;
   1255  }
   1256 
   1257  bool writeOnly = true;
   1258  gfxAlphaType alphaType = gfxAlphaType::NonPremult;
   1259 
   1260  RefPtr<SourceSurface> surface = GetSurfaceFromElement(
   1261      aGlobal, aCanvasEl, &writeOnly, aOptions, &alphaType, aRv);
   1262 
   1263  if (NS_WARN_IF(aRv.Failed())) {
   1264    return nullptr;
   1265  }
   1266 
   1267  if (!writeOnly) {
   1268    writeOnly = aCanvasEl.IsWriteOnly();
   1269  }
   1270 
   1271  // If the HTMLCanvasElement's rendering context is WebGL/WebGPU,
   1272  // then the snapshot we got from the HTMLCanvasElement is
   1273  // a DataSourceSurface which is a copy of the rendering context.
   1274  // We handle cropping in this case.
   1275  bool needToReportMemoryAllocation = false;
   1276  bool mustCopy = false;
   1277 
   1278  if ((aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL1 ||
   1279       aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2 ||
   1280       aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGPU) &&
   1281      aCropRect.isSome()) {
   1282    mustCopy = true;
   1283  }
   1284 
   1285  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1286                                   writeOnly, needToReportMemoryAllocation,
   1287                                   mustCopy, alphaType, aRv);
   1288 }
   1289 
   1290 /* static */
   1291 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1292    nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas,
   1293    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1294    ErrorResult& aRv) {
   1295  if (aOffscreenCanvas.Width() == 0) {
   1296    aRv.ThrowInvalidStateError("Passed-in canvas has width 0");
   1297    return nullptr;
   1298  }
   1299 
   1300  if (aOffscreenCanvas.Height() == 0) {
   1301    aRv.ThrowInvalidStateError("Passed-in canvas has height 0");
   1302    return nullptr;
   1303  }
   1304 
   1305  uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
   1306                   nsLayoutUtils::SFE_EXACT_SIZE_SURFACE;
   1307 
   1308  // by default surfaces have premultiplied alpha
   1309  // attempt to get non premultiplied if required
   1310  if (aOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
   1311    flags |= nsLayoutUtils::SFE_ALLOW_NON_PREMULT;
   1312  }
   1313 
   1314  SurfaceFromElementResult res =
   1315      nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, flags);
   1316 
   1317  RefPtr<SourceSurface> surface = res.GetSourceSurface();
   1318  if (NS_WARN_IF(!surface)) {
   1319    aRv.ThrowInvalidStateError("Passed-in canvas failed to create snapshot");
   1320    return nullptr;
   1321  }
   1322 
   1323  gfxAlphaType alphaType = res.mAlphaType;
   1324  bool writeOnly = res.mIsWriteOnly;
   1325 
   1326  // If the OffscreenCanvas's rendering context is WebGL/WebGPU, then the
   1327  // snapshot we got from the OffscreenCanvas is a DataSourceSurface which
   1328  // is a copy of the rendering context. We handle cropping in this case.
   1329  bool needToReportMemoryAllocation = false;
   1330  bool mustCopy =
   1331      aCropRect.isSome() &&
   1332      (aOffscreenCanvas.GetContextType() == CanvasContextType::WebGL1 ||
   1333       aOffscreenCanvas.GetContextType() == CanvasContextType::WebGL2 ||
   1334       aOffscreenCanvas.GetContextType() == CanvasContextType::WebGPU);
   1335 
   1336  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1337                                   writeOnly, needToReportMemoryAllocation,
   1338                                   mustCopy, alphaType, aRv);
   1339 }
   1340 
   1341 /* static */
   1342 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1343    nsIGlobalObject* aGlobal, ImageData& aImageData,
   1344    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1345    ErrorResult& aRv) {
   1346  // Copy data into SourceSurface.
   1347  RootedSpiderMonkeyInterface<Uint8ClampedArray> array(RootingCx());
   1348  if (!array.Init(aImageData.GetDataObject())) {
   1349    aRv.ThrowInvalidStateError(
   1350        "Failed to extract Uint8ClampedArray from ImageData (security check "
   1351        "failed?)");
   1352    return nullptr;
   1353  }
   1354  const SurfaceFormat FORMAT = SurfaceFormat::R8G8B8A8;
   1355  // ImageData's underlying data is not alpha-premultiplied.
   1356  auto alphaType = (aOptions.mPremultiplyAlpha == PremultiplyAlpha::Premultiply)
   1357                       ? gfxAlphaType::Premult
   1358                       : gfxAlphaType::NonPremult;
   1359 
   1360  const uint32_t BYTES_PER_PIXEL = BytesPerPixel(FORMAT);
   1361  const uint32_t imageWidth = aImageData.Width();
   1362  const uint32_t imageHeight = aImageData.Height();
   1363  const uint32_t imageStride = imageWidth * BYTES_PER_PIXEL;
   1364  const gfx::IntSize imageSize(imageWidth, imageHeight);
   1365 
   1366  // Check the ImageData is neutered or not.
   1367  if (imageWidth == 0 || imageHeight == 0) {
   1368    aRv.ThrowInvalidStateError("Passed-in image is empty");
   1369    return nullptr;
   1370  }
   1371 
   1372  return array.ProcessFixedData(
   1373      [&](const Span<const uint8_t>& aData) -> already_AddRefed<ImageBitmap> {
   1374        const uint32_t dataLength = aData.Length();
   1375        if ((imageWidth * imageHeight * BYTES_PER_PIXEL) != dataLength) {
   1376          aRv.ThrowInvalidStateError("Data size / image format mismatch");
   1377          return nullptr;
   1378        }
   1379 
   1380        // Create and Crop the raw data into a layers::Image
   1381        RefPtr<layers::Image> data;
   1382 
   1383        uint8_t* fixedData = const_cast<uint8_t*>(aData.Elements());
   1384 
   1385        if (NS_IsMainThread()) {
   1386          data =
   1387              CreateImageFromRawData(imageSize, imageStride, FORMAT, fixedData,
   1388                                     dataLength, aCropRect, aOptions);
   1389        } else {
   1390          RefPtr<CreateImageFromRawDataInMainThreadSyncTask> task =
   1391              new CreateImageFromRawDataInMainThreadSyncTask(
   1392                  fixedData, dataLength, imageStride, FORMAT, imageSize,
   1393                  aCropRect, getter_AddRefs(data), aOptions);
   1394          task->Dispatch(GetCurrentThreadWorkerPrivate(), Canceling, aRv);
   1395        }
   1396 
   1397        if (NS_WARN_IF(!data)) {
   1398          aRv.ThrowInvalidStateError("Failed to create internal image");
   1399          return nullptr;
   1400        }
   1401 
   1402        // Create an ImageBitmap.
   1403        RefPtr<ImageBitmap> ret = new ImageBitmap(
   1404            aGlobal, data, true, false /* write-only */, alphaType);
   1405 
   1406        // The cropping information has been handled in the
   1407        // CreateImageFromRawData() function.
   1408 
   1409        return ret.forget();
   1410      });
   1411 }
   1412 
   1413 /* static */
   1414 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1415    nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
   1416    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1417    ErrorResult& aRv) {
   1418  nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal);
   1419  nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(win);
   1420  if (NS_WARN_IF(!window) || !window->GetExtantDoc()) {
   1421    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   1422    return nullptr;
   1423  }
   1424 
   1425  window->GetExtantDoc()->WarnOnceAbout(
   1426      DeprecatedOperations::eCreateImageBitmapCanvasRenderingContext2D);
   1427 
   1428  // Check write-only mode.
   1429  bool writeOnly =
   1430      aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly();
   1431 
   1432  RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
   1433 
   1434  if (NS_WARN_IF(!surface)) {
   1435    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   1436    return nullptr;
   1437  }
   1438 
   1439  const IntSize surfaceSize = surface->GetSize();
   1440  if (surfaceSize.width == 0 || surfaceSize.height == 0) {
   1441    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1442    return nullptr;
   1443  }
   1444 
   1445  bool needToReportMemoryAllocation = false;
   1446 
   1447  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1448                                   writeOnly, needToReportMemoryAllocation,
   1449                                   false, gfxAlphaType::Premult, aRv);
   1450 }
   1451 
   1452 /* static */
   1453 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1454    nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
   1455    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1456    ErrorResult& aRv) {
   1457  if (!aImageBitmap.mData) {
   1458    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   1459    return nullptr;
   1460  }
   1461 
   1462  IntRect cropRect;
   1463  RefPtr<SourceSurface> surface;
   1464  RefPtr<DataSourceSurface> dataSurface;
   1465  gfxAlphaType alphaType;
   1466 
   1467  bool needToReportMemoryAllocation = false;
   1468 
   1469  if (aImageBitmap.mSurface &&
   1470      (dataSurface = aImageBitmap.mSurface->GetDataSurface())) {
   1471    // the source imageBitmap already has a cropped surface, and we can get a
   1472    // DataSourceSurface from it, so just use it directly
   1473    surface = aImageBitmap.mSurface;
   1474    cropRect = aCropRect.valueOr(IntRect(IntPoint(0, 0), surface->GetSize()));
   1475    alphaType = IsOpaque(surface->GetFormat()) ? gfxAlphaType::Opaque
   1476                                               : gfxAlphaType::Premult;
   1477  } else {
   1478    RefPtr<layers::Image> data = aImageBitmap.mData;
   1479    surface = data->GetAsSourceSurface();
   1480    if (NS_WARN_IF(!surface)) {
   1481      aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   1482      return nullptr;
   1483    }
   1484 
   1485    cropRect = aImageBitmap.mPictureRect;
   1486    alphaType = aImageBitmap.mAlphaType;
   1487    if (aCropRect.isSome()) {
   1488      // get new crop rect relative to original uncropped surface
   1489      IntRect newCropRect = aCropRect.ref();
   1490      newCropRect = FixUpNegativeDimension(newCropRect, aRv);
   1491 
   1492      newCropRect.MoveBy(cropRect.X(), cropRect.Y());
   1493 
   1494      if (cropRect.Contains(newCropRect)) {
   1495        // new crop region within existing surface
   1496        // safe to just crop this with new rect
   1497        cropRect = newCropRect;
   1498      } else {
   1499        // crop includes area outside original cropped region
   1500        // create new surface cropped by original bitmap crop rect
   1501        RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
   1502 
   1503        surface = CropAndCopyDataSourceSurface(dataSurface, cropRect);
   1504        if (NS_WARN_IF(!surface)) {
   1505          aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   1506          return nullptr;
   1507        }
   1508        needToReportMemoryAllocation = true;
   1509        cropRect = aCropRect.ref();
   1510      }
   1511    }
   1512  }
   1513 
   1514  return CreateImageBitmapInternal(
   1515      aGlobal, surface, Some(cropRect), aOptions, aImageBitmap.mWriteOnly,
   1516      needToReportMemoryAllocation, false, alphaType, aRv);
   1517 }
   1518 
   1519 /* static */
   1520 already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
   1521    nsIGlobalObject* aGlobal, VideoFrame& aVideoFrame,
   1522    const Maybe<IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1523    ErrorResult& aRv) {
   1524  if (aVideoFrame.CodedWidth() == 0) {
   1525    aRv.ThrowInvalidStateError("Passed-in video frame has width 0");
   1526    return nullptr;
   1527  }
   1528 
   1529  if (aVideoFrame.CodedHeight() == 0) {
   1530    aRv.ThrowInvalidStateError("Passed-in video frame has height 0");
   1531    return nullptr;
   1532  }
   1533 
   1534  uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE;
   1535 
   1536  // by default surfaces have premultiplied alpha
   1537  // attempt to get non premultiplied if required
   1538  if (aOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
   1539    flags |= nsLayoutUtils::SFE_ALLOW_NON_PREMULT;
   1540  }
   1541 
   1542  SurfaceFromElementResult res =
   1543      nsLayoutUtils::SurfaceFromVideoFrame(&aVideoFrame, flags);
   1544 
   1545  RefPtr<SourceSurface> surface = res.GetSourceSurface();
   1546  if (NS_WARN_IF(!surface)) {
   1547    aRv.ThrowInvalidStateError("Passed-in video frame has no surface data");
   1548    return nullptr;
   1549  }
   1550 
   1551  gfxAlphaType alphaType = res.mAlphaType;
   1552  bool writeOnly = res.mIsWriteOnly;
   1553  bool needToReportMemoryAllocation = false;
   1554  bool mustCopy = false;
   1555 
   1556  return CreateImageBitmapInternal(aGlobal, surface, aCropRect, aOptions,
   1557                                   writeOnly, needToReportMemoryAllocation,
   1558                                   mustCopy, alphaType, aRv);
   1559 }
   1560 
   1561 class FulfillImageBitmapPromise {
   1562 protected:
   1563  FulfillImageBitmapPromise(Promise* aPromise, ImageBitmap* aImageBitmap)
   1564      : mPromise(aPromise), mImageBitmap(aImageBitmap) {
   1565    MOZ_ASSERT(aPromise);
   1566  }
   1567 
   1568  void DoFulfillImageBitmapPromise() { mPromise->MaybeResolve(mImageBitmap); }
   1569 
   1570 private:
   1571  RefPtr<Promise> mPromise;
   1572  RefPtr<ImageBitmap> mImageBitmap;
   1573 };
   1574 
   1575 class FulfillImageBitmapPromiseTask final : public Runnable,
   1576                                            public FulfillImageBitmapPromise {
   1577 public:
   1578  FulfillImageBitmapPromiseTask(Promise* aPromise, ImageBitmap* aImageBitmap)
   1579      : Runnable("dom::FulfillImageBitmapPromiseTask"),
   1580        FulfillImageBitmapPromise(aPromise, aImageBitmap) {}
   1581 
   1582  NS_IMETHOD Run() override {
   1583    DoFulfillImageBitmapPromise();
   1584    return NS_OK;
   1585  }
   1586 };
   1587 
   1588 class FulfillImageBitmapPromiseWorkerTask final
   1589    : public WorkerSameThreadRunnable,
   1590      public FulfillImageBitmapPromise {
   1591 public:
   1592  FulfillImageBitmapPromiseWorkerTask(Promise* aPromise,
   1593                                      ImageBitmap* aImageBitmap)
   1594      : WorkerSameThreadRunnable("FulfillImageBitmapPromiseWorkerTask"),
   1595        FulfillImageBitmapPromise(aPromise, aImageBitmap) {}
   1596 
   1597  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
   1598    DoFulfillImageBitmapPromise();
   1599    return true;
   1600  }
   1601 };
   1602 
   1603 static void AsyncFulfillImageBitmapPromise(Promise* aPromise,
   1604                                           ImageBitmap* aImageBitmap) {
   1605  if (NS_IsMainThread()) {
   1606    nsCOMPtr<nsIRunnable> task =
   1607        new FulfillImageBitmapPromiseTask(aPromise, aImageBitmap);
   1608    NS_DispatchToCurrentThread(task);  // Actually, to the main-thread.
   1609  } else {
   1610    RefPtr<FulfillImageBitmapPromiseWorkerTask> task =
   1611        new FulfillImageBitmapPromiseWorkerTask(aPromise, aImageBitmap);
   1612    task->Dispatch(GetCurrentThreadWorkerPrivate());  // Actually, to the
   1613                                                      // current worker-thread.
   1614  }
   1615 }
   1616 
   1617 class CreateImageBitmapFromBlobRunnable;
   1618 
   1619 class CreateImageBitmapFromBlob final : public DiscardableRunnable,
   1620                                        public imgIContainerCallback,
   1621                                        public nsIInputStreamCallback {
   1622  friend class CreateImageBitmapFromBlobRunnable;
   1623 
   1624 public:
   1625  NS_DECL_ISUPPORTS_INHERITED
   1626  NS_DECL_IMGICONTAINERCALLBACK
   1627  NS_DECL_NSIINPUTSTREAMCALLBACK
   1628 
   1629  static already_AddRefed<CreateImageBitmapFromBlob> Create(
   1630      Promise* aPromise, nsIGlobalObject* aGlobal, Blob& aBlob,
   1631      const Maybe<IntRect>& aCropRect, nsIEventTarget* aMainThreadEventTarget,
   1632      const ImageBitmapOptions& aOptions);
   1633 
   1634  NS_IMETHOD Run() override {
   1635    MOZ_ASSERT(IsCurrentThread());
   1636 
   1637    nsresult rv = StartMimeTypeAndDecodeAndCropBlob();
   1638    if (NS_WARN_IF(NS_FAILED(rv))) {
   1639      MimeTypeAndDecodeAndCropBlobCompletedMainThread(nullptr, rv);
   1640    }
   1641 
   1642    return NS_OK;
   1643  }
   1644 
   1645  // Called by the WorkerRef.
   1646  void WorkerShuttingDown();
   1647 
   1648 private:
   1649  CreateImageBitmapFromBlob(Promise* aPromise, nsIGlobalObject* aGlobal,
   1650                            already_AddRefed<nsIInputStream> aInputStream,
   1651                            const Maybe<IntRect>& aCropRect,
   1652                            nsIEventTarget* aMainThreadEventTarget,
   1653                            const ImageBitmapOptions& aOptions)
   1654      : DiscardableRunnable("dom::CreateImageBitmapFromBlob"),
   1655 
   1656        mMutex("dom::CreateImageBitmapFromBlob::mMutex"),
   1657        mPromise(aPromise),
   1658        mGlobalObject(aGlobal),
   1659        mInputStream(std::move(aInputStream)),
   1660        mCropRect(aCropRect),
   1661        mMainThreadEventTarget(aMainThreadEventTarget),
   1662        mOptions(aOptions),
   1663        mThread(PR_GetCurrentThread()) {}
   1664 
   1665  virtual ~CreateImageBitmapFromBlob() = default;
   1666 
   1667  bool IsCurrentThread() const { return mThread == PR_GetCurrentThread(); }
   1668 
   1669  // Called on the owning thread.
   1670  nsresult StartMimeTypeAndDecodeAndCropBlob();
   1671 
   1672  // Will be called when the decoding + cropping is completed on the
   1673  // main-thread. This could the not the owning thread!
   1674  void MimeTypeAndDecodeAndCropBlobCompletedMainThread(layers::Image* aImage,
   1675                                                       nsresult aStatus);
   1676 
   1677  // Will be called when the decoding + cropping is completed on the owning
   1678  // thread.
   1679  void MimeTypeAndDecodeAndCropBlobCompletedOwningThread(layers::Image* aImage,
   1680                                                         nsresult aStatus);
   1681 
   1682  // This is called on the main-thread only.
   1683  nsresult MimeTypeAndDecodeAndCropBlob();
   1684 
   1685  // This is called on the main-thread only.
   1686  nsresult DecodeAndCropBlob(const nsACString& aMimeType);
   1687 
   1688  // This is called on the main-thread only.
   1689  nsresult GetMimeTypeSync(nsACString& aMimeType);
   1690 
   1691  // This is called on the main-thread only.
   1692  nsresult GetMimeTypeAsync();
   1693 
   1694  Mutex mMutex MOZ_UNANNOTATED;
   1695 
   1696  // The access to this object is protected by mutex but is always nullified on
   1697  // the owning thread.
   1698  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
   1699 
   1700  // Touched only on the owning thread.
   1701  RefPtr<Promise> mPromise;
   1702 
   1703  // Touched only on the owning thread.
   1704  nsCOMPtr<nsIGlobalObject> mGlobalObject;
   1705 
   1706  nsCOMPtr<nsIInputStream> mInputStream;
   1707  Maybe<IntRect> mCropRect;
   1708  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
   1709  const ImageBitmapOptions mOptions;
   1710  void* mThread;
   1711 };
   1712 
   1713 NS_IMPL_ISUPPORTS_INHERITED(CreateImageBitmapFromBlob, DiscardableRunnable,
   1714                            imgIContainerCallback, nsIInputStreamCallback)
   1715 
   1716 class CreateImageBitmapFromBlobRunnable final : public WorkerThreadRunnable {
   1717 public:
   1718  explicit CreateImageBitmapFromBlobRunnable(CreateImageBitmapFromBlob* aTask,
   1719                                             layers::Image* aImage,
   1720                                             nsresult aStatus)
   1721      : WorkerThreadRunnable("CreateImageBitmapFromBlobRunnable"),
   1722        mTask(aTask),
   1723        mImage(aImage),
   1724        mStatus(aStatus) {}
   1725 
   1726  // Override Predispatch/PostDispatch to remove the noise of assertion for
   1727  // nested Worker.
   1728  virtual bool PreDispatch(WorkerPrivate*) override { return true; }
   1729  virtual void PostDispatch(WorkerPrivate*, bool) override {}
   1730 
   1731  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
   1732    mTask->MimeTypeAndDecodeAndCropBlobCompletedOwningThread(mImage, mStatus);
   1733    return true;
   1734  }
   1735 
   1736 private:
   1737  RefPtr<CreateImageBitmapFromBlob> mTask;
   1738  RefPtr<layers::Image> mImage;
   1739  nsresult mStatus;
   1740 };
   1741 
   1742 static void AsyncCreateImageBitmapFromBlob(Promise* aPromise,
   1743                                           nsIGlobalObject* aGlobal,
   1744                                           Blob& aBlob,
   1745                                           const Maybe<IntRect>& aCropRect,
   1746                                           const ImageBitmapOptions& aOptions) {
   1747  // Let's identify the main-thread event target.
   1748  nsCOMPtr<nsIEventTarget> mainThreadEventTarget;
   1749  if (NS_IsMainThread()) {
   1750    mainThreadEventTarget = aGlobal->SerialEventTarget();
   1751  } else {
   1752    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   1753    MOZ_ASSERT(workerPrivate);
   1754    mainThreadEventTarget = workerPrivate->MainThreadEventTarget();
   1755  }
   1756 
   1757  RefPtr<CreateImageBitmapFromBlob> task = CreateImageBitmapFromBlob::Create(
   1758      aPromise, aGlobal, aBlob, aCropRect, mainThreadEventTarget, aOptions);
   1759  if (NS_WARN_IF(!task)) {
   1760    aPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
   1761    return;
   1762  }
   1763 
   1764  NS_DispatchToCurrentThread(task);
   1765 }
   1766 
   1767 /* static */
   1768 already_AddRefed<Promise> ImageBitmap::Create(
   1769    nsIGlobalObject* aGlobal, const ImageBitmapSource& aSrc,
   1770    const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
   1771    ErrorResult& aRv) {
   1772  MOZ_ASSERT(aGlobal);
   1773 
   1774  RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
   1775 
   1776  if (NS_WARN_IF(aRv.Failed())) {
   1777    return nullptr;
   1778  }
   1779 
   1780  if (aCropRect.isSome()) {
   1781    if (aCropRect->Width() == 0) {
   1782      aRv.ThrowRangeError(
   1783          "The crop rect width passed to createImageBitmap must be nonzero");
   1784      return promise.forget();
   1785    }
   1786 
   1787    if (aCropRect->Height() == 0) {
   1788      aRv.ThrowRangeError(
   1789          "The crop rect height passed to createImageBitmap must be nonzero");
   1790      return promise.forget();
   1791    }
   1792  }
   1793 
   1794  if (aOptions.mResizeWidth.WasPassed() && aOptions.mResizeWidth.Value() == 0) {
   1795    aRv.ThrowInvalidStateError(
   1796        "The resizeWidth passed to createImageBitmap must be nonzero");
   1797    return promise.forget();
   1798  }
   1799 
   1800  if (aOptions.mResizeHeight.WasPassed() &&
   1801      aOptions.mResizeHeight.Value() == 0) {
   1802    aRv.ThrowInvalidStateError(
   1803        "The resizeHeight passed to createImageBitmap must be nonzero");
   1804    return promise.forget();
   1805  }
   1806 
   1807  RefPtr<ImageBitmap> imageBitmap;
   1808 
   1809  if (aSrc.IsHTMLImageElement()) {
   1810    MOZ_ASSERT(
   1811        NS_IsMainThread(),
   1812        "Creating ImageBitmap from HTMLImageElement off the main thread.");
   1813    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLImageElement(),
   1814                                 aCropRect, aOptions, aRv);
   1815  } else if (aSrc.IsSVGImageElement()) {
   1816    MOZ_ASSERT(
   1817        NS_IsMainThread(),
   1818        "Creating ImageBitmap from SVGImageElement off the main thread.");
   1819    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsSVGImageElement(),
   1820                                 aCropRect, aOptions, aRv);
   1821  } else if (aSrc.IsHTMLVideoElement()) {
   1822    MOZ_ASSERT(
   1823        NS_IsMainThread(),
   1824        "Creating ImageBitmap from HTMLVideoElement off the main thread.");
   1825    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLVideoElement(),
   1826                                 aCropRect, aOptions, aRv);
   1827  } else if (aSrc.IsHTMLCanvasElement()) {
   1828    MOZ_ASSERT(
   1829        NS_IsMainThread(),
   1830        "Creating ImageBitmap from HTMLCanvasElement off the main thread.");
   1831    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLCanvasElement(),
   1832                                 aCropRect, aOptions, aRv);
   1833  } else if (aSrc.IsOffscreenCanvas()) {
   1834    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsOffscreenCanvas(),
   1835                                 aCropRect, aOptions, aRv);
   1836  } else if (aSrc.IsImageData()) {
   1837    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsImageData(), aCropRect,
   1838                                 aOptions, aRv);
   1839  } else if (aSrc.IsCanvasRenderingContext2D()) {
   1840    MOZ_ASSERT(NS_IsMainThread(),
   1841               "Creating ImageBitmap from CanvasRenderingContext2D off the "
   1842               "main thread.");
   1843    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsCanvasRenderingContext2D(),
   1844                                 aCropRect, aOptions, aRv);
   1845  } else if (aSrc.IsImageBitmap()) {
   1846    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsImageBitmap(), aCropRect,
   1847                                 aOptions, aRv);
   1848  } else if (aSrc.IsBlob()) {
   1849    AsyncCreateImageBitmapFromBlob(promise, aGlobal, aSrc.GetAsBlob(),
   1850                                   aCropRect, aOptions);
   1851    return promise.forget();
   1852  } else if (aSrc.IsVideoFrame()) {
   1853    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsVideoFrame(), aCropRect,
   1854                                 aOptions, aRv);
   1855  } else {
   1856    MOZ_CRASH("Unsupported type!");
   1857    return nullptr;
   1858  }
   1859 
   1860  if (!aRv.Failed()) {
   1861    AsyncFulfillImageBitmapPromise(promise, imageBitmap);
   1862  }
   1863 
   1864  return promise.forget();
   1865 }
   1866 
   1867 /*static*/
   1868 JSObject* ImageBitmap::ReadStructuredClone(
   1869    JSContext* aCx, JSStructuredCloneReader* aReader, nsIGlobalObject* aParent,
   1870    const nsTArray<RefPtr<DataSourceSurface>>& aClonedSurfaces,
   1871    uint32_t aIndex) {
   1872  MOZ_ASSERT(aCx);
   1873  MOZ_ASSERT(aReader);
   1874  // aParent might be null.
   1875 
   1876  uint32_t picRectX_;
   1877  uint32_t picRectY_;
   1878  uint32_t picRectWidth_;
   1879  uint32_t picRectHeight_;
   1880  uint32_t alphaType_;
   1881  uint32_t writeOnly;
   1882 
   1883  if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
   1884      !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
   1885      !JS_ReadUint32Pair(aReader, &alphaType_, &writeOnly)) {
   1886    return nullptr;
   1887  }
   1888 
   1889  int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
   1890  int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
   1891  int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
   1892  int32_t picRectHeight = BitwiseCast<int32_t>(picRectHeight_);
   1893  const auto alphaType = BitwiseCast<gfxAlphaType>(alphaType_);
   1894 
   1895  // Create a new ImageBitmap.
   1896  MOZ_ASSERT(!aClonedSurfaces.IsEmpty());
   1897  MOZ_ASSERT(aIndex < aClonedSurfaces.Length());
   1898 
   1899  // RefPtr<ImageBitmap> needs to go out of scope before toObjectOrNull() is
   1900  // called because the static analysis thinks dereferencing XPCOM objects
   1901  // can GC (because in some cases it can!), and a return statement with a
   1902  // JSObject* type means that JSObject* is on the stack as a raw pointer
   1903  // while destructors are running.
   1904  JS::Rooted<JS::Value> value(aCx);
   1905  {
   1906 #ifdef FUZZING
   1907    if (aIndex >= aClonedSurfaces.Length()) {
   1908      return nullptr;
   1909    }
   1910 #endif
   1911    RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
   1912    RefPtr<ImageBitmap> imageBitmap =
   1913        new ImageBitmap(aParent, img, true, !!writeOnly, alphaType);
   1914 
   1915    ErrorResult error;
   1916    imageBitmap->SetPictureRect(
   1917        IntRect(picRectX, picRectY, picRectWidth, picRectHeight), error);
   1918    if (NS_WARN_IF(error.Failed())) {
   1919      error.SuppressException();
   1920      return nullptr;
   1921    }
   1922 
   1923    if (!GetOrCreateDOMReflector(aCx, imageBitmap, &value)) {
   1924      return nullptr;
   1925    }
   1926  }
   1927 
   1928  return &(value.toObject());
   1929 }
   1930 
   1931 /*static*/
   1932 void ImageBitmap::WriteStructuredClone(
   1933    JSStructuredCloneWriter* aWriter,
   1934    nsTArray<RefPtr<DataSourceSurface>>& aClonedSurfaces,
   1935    ImageBitmap* aImageBitmap, ErrorResult& aRv) {
   1936  MOZ_ASSERT(aWriter);
   1937  MOZ_ASSERT(aImageBitmap);
   1938 
   1939  if (aImageBitmap->IsWriteOnly()) {
   1940    return aRv.ThrowDataCloneError("Cannot clone ImageBitmap, is write-only");
   1941  }
   1942 
   1943  if (!aImageBitmap->mData) {
   1944    // A closed image cannot be cloned.
   1945    return aRv.ThrowDataCloneError("Cannot clone ImageBitmap, is closed");
   1946  }
   1947 
   1948  const uint32_t picRectX = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.x);
   1949  const uint32_t picRectY = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.y);
   1950  const uint32_t picRectWidth =
   1951      BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.width);
   1952  const uint32_t picRectHeight =
   1953      BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.height);
   1954  const uint32_t alphaType = BitwiseCast<uint32_t>(aImageBitmap->mAlphaType);
   1955 
   1956  // Indexing the cloned surfaces and send the index to the receiver.
   1957  uint32_t index = aClonedSurfaces.Length();
   1958 
   1959  if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
   1960      NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
   1961      NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
   1962      NS_WARN_IF(
   1963          !JS_WriteUint32Pair(aWriter, alphaType, aImageBitmap->mWriteOnly))) {
   1964    return aRv.ThrowDataCloneError(
   1965        "Cannot clone ImageBitmap, failed to write params");
   1966  }
   1967 
   1968  RefPtr<SourceSurface> surface = aImageBitmap->mData->GetAsSourceSurface();
   1969  if (NS_WARN_IF(!surface)) {
   1970    return aRv.ThrowDataCloneError("Cannot clone ImageBitmap, no surface");
   1971  }
   1972 
   1973  RefPtr<DataSourceSurface> snapshot = surface->GetDataSurface();
   1974  if (NS_WARN_IF(!snapshot)) {
   1975    return aRv.ThrowDataCloneError("Cannot clone ImageBitmap, no data surface");
   1976  }
   1977 
   1978  RefPtr<DataSourceSurface> dstDataSurface;
   1979  {
   1980    // DataSourceSurfaceD2D1::GetStride() will call EnsureMapped implicitly and
   1981    // won't Unmap after exiting function. So instead calling GetStride()
   1982    // directly, using ScopedMap to get stride.
   1983    DataSourceSurface::ScopedMap map(snapshot, DataSourceSurface::READ);
   1984    if (NS_WARN_IF(!map.IsMapped())) {
   1985      return aRv.ThrowDataCloneError(
   1986          "Cannot clone ImageBitmap, cannot map surface");
   1987    }
   1988 
   1989    dstDataSurface = Factory::CreateDataSourceSurfaceWithStride(
   1990        snapshot->GetSize(), snapshot->GetFormat(), map.GetStride(), true);
   1991  }
   1992  if (NS_WARN_IF(!dstDataSurface)) {
   1993    return aRv.ThrowDataCloneError("Cannot clone ImageBitmap, out of memory");
   1994  }
   1995  Factory::CopyDataSourceSurface(snapshot, dstDataSurface);
   1996  aClonedSurfaces.AppendElement(dstDataSurface);
   1997 }
   1998 
   1999 size_t ImageBitmap::GetAllocatedSize() const {
   2000  if (!mAllocatedImageData || !mData) {
   2001    return 0;
   2002  }
   2003 
   2004  // Calculate how many bytes are used.
   2005  switch (mData->GetFormat()) {
   2006    case ImageFormat::PLANAR_YCBCR:
   2007      return mData->AsPlanarYCbCrImage()->GetDataSize();
   2008    case ImageFormat::NV_IMAGE:
   2009      return mData->AsNVImage()->GetBufferSize();
   2010    default:
   2011      break;
   2012  }
   2013 
   2014  IntSize size = mData->GetSize();
   2015  CheckedInt<uint32_t> bytes =
   2016      CheckedInt<uint32_t>(size.width) * size.height * 4;
   2017  return bytes.isValid() ? bytes.value() : 0;
   2018 }
   2019 
   2020 size_t BindingJSObjectMallocBytes(ImageBitmap* aBitmap) {
   2021  return aBitmap->GetAllocatedSize();
   2022 }
   2023 
   2024 void ImageBitmap::RemoveAssociatedMemory() {
   2025  if (!mAllocatedImageData) {
   2026    return;
   2027  }
   2028  if (JSObject* wrapper = GetWrapperMaybeDead()) {
   2029    if (size_t bytes = BindingJSObjectMallocBytes(this)) {
   2030      JS::RemoveAssociatedMemory(wrapper, bytes, JS::MemoryUse::DOMBinding);
   2031    }
   2032  }
   2033  mAllocatedImageData = false;
   2034 }
   2035 
   2036 /* static */
   2037 already_AddRefed<CreateImageBitmapFromBlob> CreateImageBitmapFromBlob::Create(
   2038    Promise* aPromise, nsIGlobalObject* aGlobal, Blob& aBlob,
   2039    const Maybe<IntRect>& aCropRect, nsIEventTarget* aMainThreadEventTarget,
   2040    const ImageBitmapOptions& aOptions) {
   2041  // Get the internal stream of the blob.
   2042  nsCOMPtr<nsIInputStream> stream;
   2043  ErrorResult error;
   2044  aBlob.Impl()->CreateInputStream(getter_AddRefs(stream), error);
   2045  if (NS_WARN_IF(error.Failed())) {
   2046    return nullptr;
   2047  }
   2048 
   2049  if (!NS_InputStreamIsBuffered(stream)) {
   2050    nsCOMPtr<nsIInputStream> bufferedStream;
   2051    nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
   2052                                            stream.forget(), 4096);
   2053    if (NS_WARN_IF(NS_FAILED(rv))) {
   2054      return nullptr;
   2055    }
   2056 
   2057    stream = bufferedStream;
   2058  }
   2059 
   2060  RefPtr<CreateImageBitmapFromBlob> task = new CreateImageBitmapFromBlob(
   2061      aPromise, aGlobal, stream.forget(), aCropRect, aMainThreadEventTarget,
   2062      aOptions);
   2063 
   2064  // Nothing to do for the main-thread.
   2065  if (NS_IsMainThread()) {
   2066    return task.forget();
   2067  }
   2068 
   2069  // Let's use a WorkerRef to keep the worker alive if this is not the
   2070  // main-thread.
   2071  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   2072  MOZ_ASSERT(workerPrivate);
   2073 
   2074  RefPtr<StrongWorkerRef> workerRef =
   2075      StrongWorkerRef::Create(workerPrivate, "CreateImageBitmapFromBlob",
   2076                              [task]() { task->WorkerShuttingDown(); });
   2077  if (NS_WARN_IF(!workerRef)) {
   2078    return nullptr;
   2079  }
   2080 
   2081  task->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
   2082  return task.forget();
   2083 }
   2084 
   2085 nsresult CreateImageBitmapFromBlob::StartMimeTypeAndDecodeAndCropBlob() {
   2086  MOZ_ASSERT(IsCurrentThread());
   2087 
   2088  // Workers.
   2089  if (!NS_IsMainThread()) {
   2090    RefPtr<CreateImageBitmapFromBlob> self = this;
   2091    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
   2092        "CreateImageBitmapFromBlob::MimeTypeAndDecodeAndCropBlob", [self]() {
   2093          nsresult rv = self->MimeTypeAndDecodeAndCropBlob();
   2094          if (NS_WARN_IF(NS_FAILED(rv))) {
   2095            self->MimeTypeAndDecodeAndCropBlobCompletedMainThread(nullptr, rv);
   2096          }
   2097        });
   2098 
   2099    return mMainThreadEventTarget->Dispatch(r.forget());
   2100  }
   2101 
   2102  // Main-thread.
   2103  return MimeTypeAndDecodeAndCropBlob();
   2104 }
   2105 
   2106 nsresult CreateImageBitmapFromBlob::MimeTypeAndDecodeAndCropBlob() {
   2107  MOZ_ASSERT(NS_IsMainThread());
   2108 
   2109  nsAutoCString mimeType;
   2110  nsresult rv = GetMimeTypeSync(mimeType);
   2111  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   2112    return GetMimeTypeAsync();
   2113  }
   2114 
   2115  if (NS_WARN_IF(NS_FAILED(rv))) {
   2116    return rv;
   2117  }
   2118 
   2119  return DecodeAndCropBlob(mimeType);
   2120 }
   2121 
   2122 nsresult CreateImageBitmapFromBlob::DecodeAndCropBlob(
   2123    const nsACString& aMimeType) {
   2124  // Get the Component object.
   2125  nsCOMPtr<imgITools> imgtool = do_GetService(NS_IMGTOOLS_CID);
   2126  if (NS_WARN_IF(!imgtool)) {
   2127    return NS_ERROR_FAILURE;
   2128  }
   2129 
   2130  // Decode image.
   2131  nsresult rv = imgtool->DecodeImageAsync(mInputStream, aMimeType, this,
   2132                                          mMainThreadEventTarget);
   2133  if (NS_WARN_IF(NS_FAILED(rv))) {
   2134    return rv;
   2135  }
   2136 
   2137  return NS_OK;
   2138 }
   2139 
   2140 static nsresult sniff_cb(nsIInputStream* aInputStream, void* aClosure,
   2141                         const char* aFromRawSegment, uint32_t aToOffset,
   2142                         uint32_t aCount, uint32_t* aWriteCount) {
   2143  nsACString* mimeType = static_cast<nsACString*>(aClosure);
   2144  MOZ_ASSERT(mimeType);
   2145 
   2146  if (aCount > 0) {
   2147    imgLoader::GetMimeTypeFromContent(aFromRawSegment, aCount, *mimeType);
   2148  }
   2149 
   2150  *aWriteCount = 0;
   2151 
   2152  // We don't want to consume data from the stream.
   2153  return NS_ERROR_FAILURE;
   2154 }
   2155 
   2156 nsresult CreateImageBitmapFromBlob::GetMimeTypeSync(nsACString& aMimeType) {
   2157  uint32_t dummy;
   2158  return mInputStream->ReadSegments(sniff_cb, &aMimeType, 128, &dummy);
   2159 }
   2160 
   2161 nsresult CreateImageBitmapFromBlob::GetMimeTypeAsync() {
   2162  nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
   2163      do_QueryInterface(mInputStream);
   2164  if (NS_WARN_IF(!asyncInputStream)) {
   2165    // If the stream is not async, why are we here?
   2166    return NS_ERROR_FAILURE;
   2167  }
   2168 
   2169  return asyncInputStream->AsyncWait(this, 0, 128, mMainThreadEventTarget);
   2170 }
   2171 
   2172 NS_IMETHODIMP
   2173 CreateImageBitmapFromBlob::OnInputStreamReady(nsIAsyncInputStream* aStream) {
   2174  // The stream should have data now. Let's start from scratch again.
   2175  nsresult rv = MimeTypeAndDecodeAndCropBlob();
   2176  if (NS_WARN_IF(NS_FAILED(rv))) {
   2177    MimeTypeAndDecodeAndCropBlobCompletedMainThread(nullptr, rv);
   2178  }
   2179 
   2180  return NS_OK;
   2181 }
   2182 
   2183 NS_IMETHODIMP
   2184 CreateImageBitmapFromBlob::OnImageReady(imgIContainer* aImgContainer,
   2185                                        nsresult aStatus) {
   2186  MOZ_ASSERT(NS_IsMainThread());
   2187 
   2188  if (NS_FAILED(aStatus)) {
   2189    MimeTypeAndDecodeAndCropBlobCompletedMainThread(nullptr, aStatus);
   2190    return NS_OK;
   2191  }
   2192 
   2193  MOZ_ASSERT(aImgContainer);
   2194 
   2195  // Get the surface out.
   2196  uint32_t frameFlags =
   2197      imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
   2198  uint32_t whichFrame = imgIContainer::FRAME_FIRST;
   2199 
   2200  if (mOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
   2201    frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
   2202  }
   2203 
   2204  if (mOptions.mColorSpaceConversion == ColorSpaceConversion::None) {
   2205    frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
   2206  }
   2207 
   2208  RefPtr<SourceSurface> surface =
   2209      aImgContainer->GetFrame(whichFrame, frameFlags);
   2210 
   2211  if (NS_WARN_IF(!surface)) {
   2212    MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2213        nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
   2214    return NS_OK;
   2215  }
   2216 
   2217  // Crop the source surface if needed.
   2218  RefPtr<SourceSurface> croppedSurface = surface;
   2219  RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
   2220 
   2221  // force a copy into unprotected memory as a side effect of
   2222  // CropAndCopyDataSourceSurface
   2223  bool copyRequired = mCropRect.isSome() ||
   2224                      mOptions.mImageOrientation == ImageOrientation::FlipY;
   2225 
   2226  if (copyRequired) {
   2227    // The blob is just decoded into a RasterImage and not optimized yet, so the
   2228    // _surface_ we get is a DataSourceSurface which wraps the RasterImage's
   2229    // raw buffer.
   2230    //
   2231    // The _surface_ might already be optimized so that its type is not
   2232    // SurfaceType::DATA. However, we could keep using the generic cropping and
   2233    // copying since the decoded buffer is only used in this ImageBitmap so we
   2234    // should crop it to save memory usage.
   2235    //
   2236    // TODO: Bug1189632 is going to refactor this create-from-blob part to
   2237    //       decode the blob off the main thread. Re-check if we should do
   2238    //       cropping at this moment again there.
   2239 
   2240    IntRect cropRect =
   2241        mCropRect.isSome() ? mCropRect.ref() : dataSurface->GetRect();
   2242 
   2243    croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect);
   2244    if (NS_WARN_IF(!croppedSurface)) {
   2245      MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2246          nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
   2247      return NS_OK;
   2248    }
   2249 
   2250    dataSurface = croppedSurface->GetDataSurface();
   2251 
   2252    if (mCropRect.isSome()) {
   2253      mCropRect->SetRect(0, 0, dataSurface->GetSize().width,
   2254                         dataSurface->GetSize().height);
   2255    }
   2256  }
   2257 
   2258  if (mOptions.mImageOrientation == ImageOrientation::FlipY) {
   2259    croppedSurface = FlipYDataSourceSurface(dataSurface);
   2260  }
   2261 
   2262  if (mOptions.mResizeWidth.WasPassed() || mOptions.mResizeHeight.WasPassed()) {
   2263    dataSurface = croppedSurface->GetDataSurface();
   2264    croppedSurface = ScaleDataSourceSurface(dataSurface, mOptions);
   2265    if (NS_WARN_IF(!croppedSurface)) {
   2266      MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2267          nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
   2268      return NS_OK;
   2269    }
   2270    if (mCropRect.isSome()) {
   2271      mCropRect->SetRect(0, 0, croppedSurface->GetSize().width,
   2272                         croppedSurface->GetSize().height);
   2273    }
   2274  }
   2275 
   2276  if (NS_WARN_IF(!croppedSurface)) {
   2277    MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2278        nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
   2279    return NS_OK;
   2280  }
   2281 
   2282  // Create an Image from the source surface.
   2283  RefPtr<layers::Image> image = CreateImageFromSurface(croppedSurface);
   2284 
   2285  if (NS_WARN_IF(!image)) {
   2286    MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2287        nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
   2288    return NS_OK;
   2289  }
   2290 
   2291  MimeTypeAndDecodeAndCropBlobCompletedMainThread(image, NS_OK);
   2292  return NS_OK;
   2293 }
   2294 
   2295 void CreateImageBitmapFromBlob::MimeTypeAndDecodeAndCropBlobCompletedMainThread(
   2296    layers::Image* aImage, nsresult aStatus) {
   2297  MOZ_ASSERT(NS_IsMainThread());
   2298 
   2299  if (!IsCurrentThread()) {
   2300    MutexAutoLock lock(mMutex);
   2301 
   2302    if (!mWorkerRef) {
   2303      // The worker is already gone.
   2304      return;
   2305    }
   2306 
   2307    RefPtr<CreateImageBitmapFromBlobRunnable> r =
   2308        new CreateImageBitmapFromBlobRunnable(this, aImage, aStatus);
   2309    r->Dispatch(mWorkerRef->Private());
   2310    return;
   2311  }
   2312 
   2313  MimeTypeAndDecodeAndCropBlobCompletedOwningThread(aImage, aStatus);
   2314 }
   2315 
   2316 void CreateImageBitmapFromBlob::
   2317    MimeTypeAndDecodeAndCropBlobCompletedOwningThread(layers::Image* aImage,
   2318                                                      nsresult aStatus) {
   2319  MOZ_ASSERT(IsCurrentThread());
   2320 
   2321  if (!mPromise) {
   2322    // The worker is going to be released soon. No needs to continue.
   2323    return;
   2324  }
   2325 
   2326  // Let's release what has to be released on the owning thread.
   2327  auto raii = MakeScopeExit([&] {
   2328    // Doing this we also release the worker.
   2329    mWorkerRef = nullptr;
   2330 
   2331    mPromise = nullptr;
   2332    mGlobalObject = nullptr;
   2333  });
   2334 
   2335  if (NS_WARN_IF(NS_FAILED(aStatus))) {
   2336    mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
   2337    return;
   2338  }
   2339 
   2340  gfxAlphaType alphaType = gfxAlphaType::Premult;
   2341 
   2342  if (mOptions.mPremultiplyAlpha == PremultiplyAlpha::None) {
   2343    alphaType = gfxAlphaType::NonPremult;
   2344  }
   2345 
   2346  // Create ImageBitmap object.
   2347  RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(
   2348      mGlobalObject, aImage, true, false /* write-only */, alphaType);
   2349 
   2350  if (mCropRect.isSome()) {
   2351    ErrorResult rv;
   2352    imageBitmap->SetPictureRect(mCropRect.ref(), rv);
   2353 
   2354    if (rv.Failed()) {
   2355      mPromise->MaybeReject(std::move(rv));
   2356      return;
   2357    }
   2358  }
   2359 
   2360  mPromise->MaybeResolve(imageBitmap);
   2361 }
   2362 
   2363 void CreateImageBitmapFromBlob::WorkerShuttingDown() {
   2364  MOZ_ASSERT(IsCurrentThread());
   2365 
   2366  MutexAutoLock lock(mMutex);
   2367 
   2368  // Let's release all the non-thread-safe objects now.
   2369  mWorkerRef = nullptr;
   2370  mPromise = nullptr;
   2371  mGlobalObject = nullptr;
   2372 }
   2373 
   2374 }  // namespace mozilla::dom