Blame image/imgTools.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
Packit f0b94e
 *
Packit f0b94e
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "imgTools.h"
Packit f0b94e
Packit f0b94e
#include "DecodePool.h"
Packit f0b94e
#include "gfxUtils.h"
Packit f0b94e
#include "mozilla/gfx/2D.h"
Packit f0b94e
#include "mozilla/gfx/Logging.h"
Packit f0b94e
#include "mozilla/RefPtr.h"
Packit f0b94e
#include "nsCOMPtr.h"
Packit f0b94e
#include "nsIDocument.h"
Packit f0b94e
#include "nsIDOMDocument.h"
Packit f0b94e
#include "nsError.h"
Packit f0b94e
#include "imgLoader.h"
Packit f0b94e
#include "imgICache.h"
Packit f0b94e
#include "imgIContainer.h"
Packit f0b94e
#include "imgIEncoder.h"
Packit f0b94e
#include "nsStreamUtils.h"
Packit f0b94e
#include "nsStringStream.h"
Packit f0b94e
#include "nsContentUtils.h"
Packit f0b94e
#include "nsProxyRelease.h"
Packit f0b94e
#include "ImageFactory.h"
Packit f0b94e
#include "Image.h"
Packit f0b94e
#include "ScriptedNotificationObserver.h"
Packit f0b94e
#include "imgIScriptedNotificationObserver.h"
Packit f0b94e
#include "gfxPlatform.h"
Packit f0b94e
#include "jsfriendapi.h"
Packit f0b94e
Packit f0b94e
using namespace mozilla::gfx;
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
namespace image {
Packit f0b94e
Packit f0b94e
namespace {
Packit f0b94e
Packit f0b94e
class ImageDecoderHelper final : public Runnable,
Packit f0b94e
                                 public nsIInputStreamCallback {
Packit f0b94e
 public:
Packit f0b94e
  NS_DECL_ISUPPORTS_INHERITED
Packit f0b94e
Packit f0b94e
  ImageDecoderHelper(already_AddRefed<image::Image> aImage,
Packit f0b94e
                     already_AddRefed<nsIInputStream> aInputStream,
Packit f0b94e
                     nsIEventTarget* aEventTarget,
Packit f0b94e
                     imgIContainerCallback* aCallback,
Packit f0b94e
                     nsIEventTarget* aCallbackEventTarget)
Packit f0b94e
      : Runnable("ImageDecoderHelper"),
Packit f0b94e
        mImage(Move(aImage)),
Packit f0b94e
        mInputStream(Move(aInputStream)),
Packit f0b94e
        mEventTarget(aEventTarget),
Packit f0b94e
        mCallback(aCallback),
Packit f0b94e
        mCallbackEventTarget(aCallbackEventTarget),
Packit f0b94e
        mStatus(NS_OK) {
Packit f0b94e
    MOZ_ASSERT(NS_IsMainThread());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  NS_IMETHOD
Packit f0b94e
  Run() override {
Packit f0b94e
    // This runnable is dispatched on the Image thread when reading data, but
Packit f0b94e
    // at the end, it goes back to the main-thread in order to complete the
Packit f0b94e
    // operation.
Packit f0b94e
    if (NS_IsMainThread()) {
Packit f0b94e
      // Let the Image know we've sent all the data.
Packit f0b94e
      mImage->OnImageDataComplete(nullptr, nullptr, mStatus, true);
Packit f0b94e
Packit f0b94e
      RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
Packit f0b94e
      tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
Packit f0b94e
Packit f0b94e
      nsCOMPtr<imgIContainer> container;
Packit f0b94e
      if (NS_SUCCEEDED(mStatus)) {
Packit f0b94e
        container = do_QueryInterface(mImage);
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      mCallback->OnImageReady(container, mStatus);
Packit f0b94e
      return NS_OK;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    uint64_t length;
Packit f0b94e
    nsresult rv = mInputStream->Available(&length);
Packit f0b94e
    if (rv == NS_BASE_STREAM_CLOSED) {
Packit f0b94e
      return OperationCompleted(NS_OK);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (NS_WARN_IF(NS_FAILED(rv))) {
Packit f0b94e
      return OperationCompleted(rv);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // Nothing else to read, but maybe we just need to wait.
Packit f0b94e
    if (length == 0) {
Packit f0b94e
      nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
Packit f0b94e
          do_QueryInterface(mInputStream);
Packit f0b94e
      if (asyncInputStream) {
Packit f0b94e
        rv = asyncInputStream->AsyncWait(this, 0, 0, mEventTarget);
Packit f0b94e
        if (NS_WARN_IF(NS_FAILED(rv))) {
Packit f0b94e
          return OperationCompleted(rv);
Packit f0b94e
        }
Packit f0b94e
        return NS_OK;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      // We really have nothing else to read.
Packit f0b94e
      if (length == 0) {
Packit f0b94e
        return OperationCompleted(NS_OK);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // Send the source data to the Image.
Packit f0b94e
    rv = mImage->OnImageDataAvailable(nullptr, nullptr, mInputStream, 0,
Packit f0b94e
                                      uint32_t(length));
Packit f0b94e
    if (NS_WARN_IF(NS_FAILED(rv))) {
Packit f0b94e
      return OperationCompleted(rv);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
Packit f0b94e
    if (NS_WARN_IF(NS_FAILED(rv))) {
Packit f0b94e
      return OperationCompleted(rv);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  NS_IMETHOD
Packit f0b94e
  OnInputStreamReady(nsIAsyncInputStream* aAsyncInputStream) override {
Packit f0b94e
    MOZ_ASSERT(!NS_IsMainThread());
Packit f0b94e
    return Run();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsresult OperationCompleted(nsresult aStatus) {
Packit f0b94e
    MOZ_ASSERT(!NS_IsMainThread());
Packit f0b94e
Packit f0b94e
    mStatus = aStatus;
Packit f0b94e
    mCallbackEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  ~ImageDecoderHelper() {
Packit f0b94e
    NS_ReleaseOnMainThreadSystemGroup("ImageDecoderHelper::mImage",
Packit f0b94e
                                      mImage.forget());
Packit f0b94e
    NS_ReleaseOnMainThreadSystemGroup("ImageDecoderHelper::mCallback",
Packit f0b94e
                                      mCallback.forget());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<image::Image> mImage;
Packit f0b94e
Packit f0b94e
  nsCOMPtr<nsIInputStream> mInputStream;
Packit f0b94e
  nsCOMPtr<nsIEventTarget> mEventTarget;
Packit f0b94e
  nsCOMPtr<imgIContainerCallback> mCallback;
Packit f0b94e
  nsCOMPtr<nsIEventTarget> mCallbackEventTarget;
Packit f0b94e
Packit f0b94e
  nsresult mStatus;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS_INHERITED(ImageDecoderHelper, Runnable,
Packit f0b94e
                            nsIInputStreamCallback)
Packit f0b94e
Packit f0b94e
}  // namespace
Packit f0b94e
Packit f0b94e
/* ========== imgITools implementation ========== */
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS(imgTools, imgITools)
Packit f0b94e
Packit f0b94e
imgTools::imgTools() { /* member initializers and constructor code */
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
imgTools::~imgTools() { /* destructor code */
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::DecodeImageFromArrayBuffer(JS::HandleValue aArrayBuffer,
Packit f0b94e
                                     const nsACString& aMimeType,
Packit f0b94e
                                     JSContext* aCx,
Packit f0b94e
                                     imgIContainer** aContainer) {
Packit f0b94e
  if (!aArrayBuffer.isObject()) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  JS::Rooted<JSObject*> obj(aCx,
Packit f0b94e
                            js::UnwrapArrayBuffer(&aArrayBuffer.toObject()));
Packit f0b94e
  if (!obj) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  uint8_t* bufferData = nullptr;
Packit f0b94e
  uint32_t bufferLength = 0;
Packit f0b94e
  bool isSharedMemory = false;
Packit f0b94e
Packit f0b94e
  js::GetArrayBufferLengthAndData(obj, &bufferLength, &isSharedMemory,
Packit f0b94e
                                  &bufferData);
Packit f0b94e
  return DecodeImageFromBuffer((char*)bufferData, bufferLength, aMimeType,
Packit f0b94e
                               aContainer);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::DecodeImageFromBuffer(const char* aBuffer, uint32_t aSize,
Packit f0b94e
                                const nsACString& aMimeType,
Packit f0b94e
                                imgIContainer** aContainer) {
Packit f0b94e
  MOZ_ASSERT(NS_IsMainThread());
Packit f0b94e
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aBuffer);
Packit f0b94e
Packit f0b94e
  // Create a new image container to hold the decoded data.
Packit f0b94e
  nsAutoCString mimeType(aMimeType);
Packit f0b94e
  RefPtr<image::Image> image =
Packit f0b94e
      ImageFactory::CreateAnonymousImage(mimeType, aSize);
Packit f0b94e
  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
Packit f0b94e
Packit f0b94e
  if (image->HasError()) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Let's create a temporary inputStream.
Packit f0b94e
  nsCOMPtr<nsIInputStream> stream;
Packit f0b94e
  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), aBuffer, aSize,
Packit f0b94e
                                      NS_ASSIGNMENT_DEPEND);
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
  MOZ_ASSERT(stream);
Packit f0b94e
  MOZ_ASSERT(NS_InputStreamIsBuffered(stream));
Packit f0b94e
Packit f0b94e
  rv = image->OnImageDataAvailable(nullptr, nullptr, stream, 0, aSize);
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
Packit f0b94e
  // Let the Image know we've sent all the data.
Packit f0b94e
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
Packit f0b94e
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
Packit f0b94e
  // All done.
Packit f0b94e
  image.forget(aContainer);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::DecodeImageAsync(nsIInputStream* aInStr, const nsACString& aMimeType,
Packit f0b94e
                           imgIContainerCallback* aCallback,
Packit f0b94e
                           nsIEventTarget* aEventTarget) {
Packit f0b94e
  MOZ_ASSERT(NS_IsMainThread());
Packit f0b94e
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aInStr);
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aCallback);
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aEventTarget);
Packit f0b94e
Packit f0b94e
  nsresult rv;
Packit f0b94e
Packit f0b94e
  // Let's continuing the reading on a separate thread.
Packit f0b94e
  DecodePool* decodePool = DecodePool::Singleton();
Packit f0b94e
  MOZ_ASSERT(decodePool);
Packit f0b94e
Packit f0b94e
  RefPtr<nsIEventTarget> target = decodePool->GetIOEventTarget();
Packit f0b94e
  NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
Packit f0b94e
Packit f0b94e
  // Prepare the input stream.
Packit f0b94e
  nsCOMPtr<nsIInputStream> stream = aInStr;
Packit f0b94e
  if (!NS_InputStreamIsBuffered(aInStr)) {
Packit f0b94e
    nsCOMPtr<nsIInputStream> bufStream;
Packit f0b94e
    rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), stream.forget(),
Packit f0b94e
                                   1024);
Packit f0b94e
    NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
    stream = bufStream.forget();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Create a new image container to hold the decoded data.
Packit f0b94e
  nsAutoCString mimeType(aMimeType);
Packit f0b94e
  RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType, 0);
Packit f0b94e
Packit f0b94e
  // Already an error?
Packit f0b94e
  if (image->HasError()) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<ImageDecoderHelper> helper = new ImageDecoderHelper(
Packit f0b94e
      image.forget(), stream.forget(), target, aCallback, aEventTarget);
Packit f0b94e
  rv = target->Dispatch(helper.forget(), NS_DISPATCH_NORMAL);
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * This takes a DataSourceSurface rather than a SourceSurface because some
Packit f0b94e
 * of the callers have a DataSourceSurface and we don't want to call
Packit f0b94e
 * GetDataSurface on such surfaces since that may incure a conversion to
Packit f0b94e
 * SurfaceType::DATA which we don't need.
Packit f0b94e
 */
Packit f0b94e
static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
Packit f0b94e
                                const nsACString& aMimeType,
Packit f0b94e
                                const nsAString& aOutputOptions,
Packit f0b94e
                                nsIInputStream** aStream) {
Packit f0b94e
  MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8,
Packit f0b94e
             "We're assuming B8G8R8A8");
Packit f0b94e
Packit f0b94e
  // Get an image encoder for the media type
Packit f0b94e
  nsAutoCString encoderCID(
Packit f0b94e
      NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
Packit f0b94e
  if (!encoder) {
Packit f0b94e
    return NS_IMAGELIB_ERROR_NO_ENCODER;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  DataSourceSurface::MappedSurface map;
Packit f0b94e
  if (!aDataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  IntSize size = aDataSurface->GetSize();
Packit f0b94e
  uint32_t dataLength = map.mStride * size.height;
Packit f0b94e
Packit f0b94e
  // Encode the bitmap
Packit f0b94e
  nsresult rv = encoder->InitFromData(
Packit f0b94e
      map.mData, dataLength, size.width, size.height, map.mStride,
Packit f0b94e
      imgIEncoder::INPUT_FORMAT_HOSTARGB, aOutputOptions);
Packit f0b94e
  aDataSurface->Unmap();
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
Packit f0b94e
  encoder.forget(aStream);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::EncodeImage(imgIContainer* aContainer, const nsACString& aMimeType,
Packit f0b94e
                      const nsAString& aOutputOptions,
Packit f0b94e
                      nsIInputStream** aStream) {
Packit f0b94e
  // Use frame 0 from the image container.
Packit f0b94e
  RefPtr<SourceSurface> frame = aContainer->GetFrame(
Packit f0b94e
      imgIContainer::FRAME_FIRST, imgIContainer::FLAG_SYNC_DECODE);
Packit f0b94e
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
Packit f0b94e
Packit f0b94e
  RefPtr<DataSourceSurface> dataSurface;
Packit f0b94e
Packit f0b94e
  if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) {
Packit f0b94e
    dataSurface = frame->GetDataSurface();
Packit f0b94e
  } else {
Packit f0b94e
    // Convert format to SurfaceFormat::B8G8R8A8
Packit f0b94e
    dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(
Packit f0b94e
        frame, SurfaceFormat::B8G8R8A8);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
Packit f0b94e
Packit f0b94e
  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::EncodeScaledImage(imgIContainer* aContainer,
Packit f0b94e
                            const nsACString& aMimeType, int32_t aScaledWidth,
Packit f0b94e
                            int32_t aScaledHeight,
Packit f0b94e
                            const nsAString& aOutputOptions,
Packit f0b94e
                            nsIInputStream** aStream) {
Packit f0b94e
  NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
Packit f0b94e
Packit f0b94e
  // If no scaled size is specified, we'll just encode the image at its
Packit f0b94e
  // original size (no scaling).
Packit f0b94e
  if (aScaledWidth == 0 && aScaledHeight == 0) {
Packit f0b94e
    return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Retrieve the image's size.
Packit f0b94e
  int32_t imageWidth = 0;
Packit f0b94e
  int32_t imageHeight = 0;
Packit f0b94e
  aContainer->GetWidth(&imageWidth);
Packit f0b94e
  aContainer->GetHeight(&imageHeight);
Packit f0b94e
Packit f0b94e
  // If the given width or height is zero we'll replace it with the image's
Packit f0b94e
  // original dimensions.
Packit f0b94e
  IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth,
Packit f0b94e
                     aScaledHeight == 0 ? imageHeight : aScaledHeight);
Packit f0b94e
Packit f0b94e
  // Use frame 0 from the image container.
Packit f0b94e
  RefPtr<SourceSurface> frame =
Packit f0b94e
      aContainer->GetFrameAtSize(scaledSize, imgIContainer::FRAME_FIRST,
Packit f0b94e
                                 imgIContainer::FLAG_HIGH_QUALITY_SCALING |
Packit f0b94e
                                     imgIContainer::FLAG_SYNC_DECODE);
Packit f0b94e
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
Packit f0b94e
Packit f0b94e
  RefPtr<DataSourceSurface> dataSurface =
Packit f0b94e
      Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8);
Packit f0b94e
  if (NS_WARN_IF(!dataSurface)) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  DataSourceSurface::MappedSurface map;
Packit f0b94e
  if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
Packit f0b94e
      BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride,
Packit f0b94e
      SurfaceFormat::B8G8R8A8);
Packit f0b94e
  if (!dt) {
Packit f0b94e
    gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData";
Packit f0b94e
    return NS_ERROR_OUT_OF_MEMORY;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  IntSize frameSize = frame->GetSize();
Packit f0b94e
  dt->DrawSurface(frame, Rect(0, 0, scaledSize.width, scaledSize.height),
Packit f0b94e
                  Rect(0, 0, frameSize.width, frameSize.height),
Packit f0b94e
                  DrawSurfaceOptions(),
Packit f0b94e
                  DrawOptions(1.0f, CompositionOp::OP_SOURCE));
Packit f0b94e
Packit f0b94e
  dataSurface->Unmap();
Packit f0b94e
Packit f0b94e
  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::EncodeCroppedImage(imgIContainer* aContainer,
Packit f0b94e
                             const nsACString& aMimeType, int32_t aOffsetX,
Packit f0b94e
                             int32_t aOffsetY, int32_t aWidth, int32_t aHeight,
Packit f0b94e
                             const nsAString& aOutputOptions,
Packit f0b94e
                             nsIInputStream** aStream) {
Packit f0b94e
  NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);
Packit f0b94e
Packit f0b94e
  // Offsets must be zero when no width and height are given or else we're out
Packit f0b94e
  // of bounds.
Packit f0b94e
  NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
Packit f0b94e
Packit f0b94e
  // If no size is specified then we'll preserve the image's original dimensions
Packit f0b94e
  // and don't need to crop.
Packit f0b94e
  if (aWidth == 0 && aHeight == 0) {
Packit f0b94e
    return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Use frame 0 from the image container.
Packit f0b94e
  RefPtr<SourceSurface> frame = aContainer->GetFrame(
Packit f0b94e
      imgIContainer::FRAME_FIRST, imgIContainer::FLAG_SYNC_DECODE);
Packit f0b94e
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
Packit f0b94e
Packit f0b94e
  int32_t frameWidth = frame->GetSize().width;
Packit f0b94e
  int32_t frameHeight = frame->GetSize().height;
Packit f0b94e
Packit f0b94e
  // If the given width or height is zero we'll replace it with the image's
Packit f0b94e
  // original dimensions.
Packit f0b94e
  if (aWidth == 0) {
Packit f0b94e
    aWidth = frameWidth;
Packit f0b94e
  } else if (aHeight == 0) {
Packit f0b94e
    aHeight = frameHeight;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Check that the given crop rectangle is within image bounds.
Packit f0b94e
  NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
Packit f0b94e
                frameHeight >= aOffsetY + aHeight);
Packit f0b94e
Packit f0b94e
  RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
Packit f0b94e
      IntSize(aWidth, aHeight), SurfaceFormat::B8G8R8A8,
Packit f0b94e
      /* aZero = */ true);
Packit f0b94e
  if (NS_WARN_IF(!dataSurface)) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  DataSourceSurface::MappedSurface map;
Packit f0b94e
  if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
Packit f0b94e
    return NS_ERROR_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
Packit f0b94e
      BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride,
Packit f0b94e
      SurfaceFormat::B8G8R8A8);
Packit f0b94e
  if (!dt) {
Packit f0b94e
    gfxWarning()
Packit f0b94e
        << "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData";
Packit f0b94e
    return NS_ERROR_OUT_OF_MEMORY;
Packit f0b94e
  }
Packit f0b94e
  dt->CopySurface(frame, IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
Packit f0b94e
                  IntPoint(0, 0));
Packit f0b94e
Packit f0b94e
  dataSurface->Unmap();
Packit f0b94e
Packit f0b94e
  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
Packit f0b94e
                                 imgINotificationObserver** aObserver) {
Packit f0b94e
  NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader) {
Packit f0b94e
  nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
Packit f0b94e
  NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache) {
Packit f0b94e
  nsCOMPtr<imgILoader> loader;
Packit f0b94e
  nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
  return CallQueryInterface(loader, aCache);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace image
Packit f0b94e
}  // namespace mozilla