gecko-dev/dom/canvas/ImageBitmap.h
Andrew Osmond f918a60e22 Bug 1746093 - Allow OffscreenCanvas as an input for CanvasImageSource and ImageBitmapSource. r=lsalzman,emilio
As per the spec, we should allow one to create ImageBitmaps, and call
CanvasRenderingContext2D's drawImage and createPattern using an
OffscreenCanvas.

Differential Revision: https://phabricator.services.mozilla.com/D133808
2021-12-15 21:36:21 +00:00

275 lines
9.5 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ImageBitmap_h
#define mozilla_dom_ImageBitmap_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/ImageBitmapBinding.h"
#include "mozilla/dom/ImageBitmapSource.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "ImageData.h"
#include "gfxTypes.h" // for gfxAlphaType
#include "nsCycleCollectionParticipant.h"
struct JSContext;
struct JSStructuredCloneReader;
struct JSStructuredCloneWriter;
class nsIGlobalObject;
namespace mozilla {
class ErrorResult;
namespace gfx {
class DataSourceSurface;
class DrawTarget;
class SourceSurface;
} // namespace gfx
namespace layers {
class Image;
}
namespace dom {
class OffscreenCanvas;
class ArrayBufferViewOrArrayBuffer;
class CanvasRenderingContext2D;
class CreateImageBitmapFromBlob;
class CreateImageBitmapFromBlobTask;
class CreateImageBitmapFromBlobWorkerTask;
class File;
class HTMLCanvasElement;
class HTMLImageElement;
class HTMLVideoElement;
class ImageBitmapShutdownObserver;
class ImageData;
class ImageUtils;
class Promise;
class PostMessageEvent; // For StructuredClone between windows.
class SVGImageElement;
struct ImageBitmapCloneData final {
RefPtr<gfx::DataSourceSurface> mSurface;
gfx::IntRect mPictureRect;
gfxAlphaType mAlphaType;
bool mWriteOnly;
};
/*
* ImageBitmap is an opaque handler to several kinds of image-like objects from
* HTMLImageElement, HTMLVideoElement, HTMLCanvasElement, ImageData to
* CanvasRenderingContext2D and Image Blob.
*
* An ImageBitmap could be painted to a canvas element.
*
* Generally, an ImageBitmap only keeps a reference to its source object's
* buffer, but if the source object is an ImageData, an Blob or a
* HTMLCanvasElement with WebGL rendering context, the ImageBitmap copy the
* source object's buffer.
*/
class ImageBitmap final : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageBitmap)
nsCOMPtr<nsIGlobalObject> GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
uint32_t Width() const { return mPictureRect.Width(); }
uint32_t Height() const { return mPictureRect.Height(); }
void Close();
/*
* The PrepareForDrawTarget() might return null if the mPictureRect does not
* intersect with the size of mData.
*/
already_AddRefed<gfx::SourceSurface> PrepareForDrawTarget(
gfx::DrawTarget* aTarget);
/*
* Transfer ownership of buffer to caller. So this function call
* Close() implicitly.
*/
already_AddRefed<layers::Image> TransferAsImage();
// This method returns null if the image has been already closed.
UniquePtr<ImageBitmapCloneData> ToCloneData() const;
static already_AddRefed<ImageBitmap> CreateFromSourceSurface(
nsIGlobalObject* aGlobal, gfx::SourceSurface* aSource, ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateFromCloneData(
nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData);
static already_AddRefed<ImageBitmap> CreateFromOffscreenCanvas(
nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas,
ErrorResult& aRv);
static already_AddRefed<Promise> Create(nsIGlobalObject* aGlobal,
const ImageBitmapSource& aSrc,
const Maybe<gfx::IntRect>& aCropRect,
const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static JSObject* ReadStructuredClone(
JSContext* aCx, JSStructuredCloneReader* aReader,
nsIGlobalObject* aParent,
const nsTArray<RefPtr<gfx::DataSourceSurface>>& aClonedSurfaces,
uint32_t aIndex);
static bool WriteStructuredClone(
JSStructuredCloneWriter* aWriter,
nsTArray<RefPtr<gfx::DataSourceSurface>>& aClonedSurfaces,
ImageBitmap* aImageBitmap);
friend CreateImageBitmapFromBlob;
friend CreateImageBitmapFromBlobTask;
friend CreateImageBitmapFromBlobWorkerTask;
size_t GetAllocatedSize() const;
void OnShutdown();
bool IsWriteOnly() const { return mWriteOnly; }
bool IsClosed() const { return !mData; };
protected:
/*
* The default value of aIsPremultipliedAlpha is TRUE because that the
* data stored in HTMLImageElement, HTMLVideoElement, HTMLCanvasElement,
* CanvasRenderingContext2D are alpha-premultiplied in default.
*
* Actually, if one HTMLCanvasElement's rendering context is WebGLContext, it
* is possible to get un-premultipliedAlpha data out. But, we do not do it in
* the CreateInternal(from HTMLCanvasElement) method.
*
* It is also possible to decode an image which is encoded with alpha channel
* to be non-premultipliedAlpha. This could be applied in
* 1) the CreateInternal(from HTMLImageElement) method (which might trigger
* re-decoding if the original decoded data is alpha-premultiplied) and
* 2) while decoding a blob. But we do not do it in both code path too.
*
* ImageData's underlying data is triggered as non-premultipliedAlpha, so set
* the aIsPremultipliedAlpha to be false in the
* CreateInternal(from ImageData) method.
*/
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, bool aWriteOnly,
gfxAlphaType aAlphaType = gfxAlphaType::Premult);
virtual ~ImageBitmap();
void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateImageBitmapInternal(
nsIGlobalObject* aGlobal, gfx::SourceSurface* aSurface,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
const bool aWriteOnly, const bool aAllocatedImageData,
const bool aMustCopy, const gfxAlphaType aAlphaType, ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, ImageData& aImageData,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<ImageBitmap> CreateInternal(
nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
const Maybe<gfx::IntRect>& aCropRect, const ImageBitmapOptions& aOptions,
ErrorResult& aRv);
nsCOMPtr<nsIGlobalObject> mParent;
/*
* The mData is the data buffer of an ImageBitmap, so the mData must not be
* null.
*
* The mSurface is a cache for drawing the ImageBitmap onto a
* HTMLCanvasElement. The mSurface is null while the ImageBitmap is created
* and then will be initialized while the PrepareForDrawTarget() method is
* called first time.
*
* The mSurface might just be a reference to the same data buffer of the mData
* if the are of mPictureRect is just the same as the mData's size. Or, it is
* a independent data buffer which is copied and cropped form the mData's data
* buffer.
*/
RefPtr<layers::Image> mData;
RefPtr<gfx::SourceSurface> mSurface;
/*
* The mPictureRect is the size of the source image in default, however, if
* users specify the cropping area while creating an ImageBitmap, then this
* mPictureRect is the cropping area.
*
* Note that if the CreateInternal() copies and crops data from the source
* image, then this mPictureRect is just the size of the final mData.
*
* The mPictureRect will be used at PrepareForDrawTarget() while user is going
* to draw this ImageBitmap into a HTMLCanvasElement.
*/
gfx::IntRect mPictureRect;
gfxAlphaType mAlphaType;
RefPtr<ImageBitmapShutdownObserver> mShutdownObserver;
/*
* Whether this object allocated allocated and owns the image data.
*/
bool mAllocatedImageData;
/*
* Write-Only flag is set to true if this image has been generated from a
* cross-origin source. This is the opposite of what is called 'origin-clean'
* in the spec.
*/
bool mWriteOnly;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ImageBitmap_h