Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_dom_ImageBitmap_h
8 : #define mozilla_dom_ImageBitmap_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/dom/ImageBitmapSource.h"
12 : #include "mozilla/dom/TypedArray.h"
13 : #include "mozilla/gfx/Rect.h"
14 : #include "mozilla/Maybe.h"
15 : #include "mozilla/UniquePtr.h"
16 : #include "nsCycleCollectionParticipant.h"
17 :
18 : struct JSContext;
19 : struct JSStructuredCloneReader;
20 : struct JSStructuredCloneWriter;
21 :
22 : class nsIGlobalObject;
23 :
24 : namespace mozilla {
25 :
26 : class ErrorResult;
27 :
28 : namespace gfx {
29 : class DataSourceSurface;
30 : class DrawTarget;
31 : class SourceSurface;
32 : }
33 :
34 : namespace layers {
35 : class Image;
36 : }
37 :
38 : namespace dom {
39 : class OffscreenCanvas;
40 :
41 : namespace workers {
42 : class WorkerStructuredCloneClosure;
43 : }
44 :
45 : class ArrayBufferViewOrArrayBuffer;
46 : class CanvasRenderingContext2D;
47 : struct ChannelPixelLayout;
48 : class CreateImageBitmapFromBlob;
49 : class CreateImageBitmapFromBlobTask;
50 : class CreateImageBitmapFromBlobWorkerTask;
51 : class File;
52 : class HTMLCanvasElement;
53 : class HTMLImageElement;
54 : class HTMLVideoElement;
55 : enum class ImageBitmapFormat : uint8_t;
56 : class ImageData;
57 : class ImageUtils;
58 : template<typename T> class MapDataIntoBufferSource;
59 : class Promise;
60 : class PostMessageEvent; // For StructuredClone between windows.
61 :
62 0 : struct ImageBitmapCloneData final
63 : {
64 : RefPtr<gfx::DataSourceSurface> mSurface;
65 : gfx::IntRect mPictureRect;
66 : gfxAlphaType mAlphaType;
67 : bool mIsCroppingAreaOutSideOfSourceImage;
68 : };
69 :
70 : /*
71 : * ImageBitmap is an opaque handler to several kinds of image-like objects from
72 : * HTMLImageElement, HTMLVideoElement, HTMLCanvasElement, ImageData to
73 : * CanvasRenderingContext2D and Image Blob.
74 : *
75 : * An ImageBitmap could be painted to a canvas element.
76 : *
77 : * Generally, an ImageBitmap only keeps a reference to its source object's
78 : * buffer, but if the source object is an ImageData, an Blob or a
79 : * HTMLCanvasElement with WebGL rendering context, the ImageBitmap copy the
80 : * source object's buffer.
81 : */
82 : class ImageBitmap final : public nsISupports,
83 : public nsWrapperCache
84 : {
85 : public:
86 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
87 0 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageBitmap)
88 :
89 0 : nsCOMPtr<nsIGlobalObject> GetParentObject() const { return mParent; }
90 :
91 : virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
92 :
93 0 : uint32_t Width() const
94 : {
95 0 : return mPictureRect.Width();
96 : }
97 :
98 0 : uint32_t Height() const
99 : {
100 0 : return mPictureRect.Height();
101 : }
102 :
103 : void Close();
104 :
105 : /*
106 : * The PrepareForDrawTarget() might return null if the mPictureRect does not
107 : * intersect with the size of mData.
108 : */
109 : already_AddRefed<gfx::SourceSurface>
110 : PrepareForDrawTarget(gfx::DrawTarget* aTarget);
111 :
112 : /*
113 : * Transfer ownership of buffer to caller. So this function call
114 : * Close() implicitly.
115 : */
116 : already_AddRefed<layers::Image>
117 : TransferAsImage();
118 :
119 : UniquePtr<ImageBitmapCloneData>
120 : ToCloneData() const;
121 :
122 : static already_AddRefed<ImageBitmap>
123 : CreateFromCloneData(nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData);
124 :
125 : static already_AddRefed<ImageBitmap>
126 : CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
127 : OffscreenCanvas& aOffscreenCanvas,
128 : ErrorResult& aRv);
129 :
130 : static already_AddRefed<Promise>
131 : Create(nsIGlobalObject* aGlobal, const ImageBitmapSource& aSrc,
132 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
133 :
134 : static already_AddRefed<Promise>
135 : Create(nsIGlobalObject* aGlobal,
136 : const ImageBitmapSource& aBuffer,
137 : int32_t aOffset, int32_t aLength,
138 : mozilla::dom::ImageBitmapFormat aFormat,
139 : const Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
140 : ErrorResult& aRv);
141 :
142 : static JSObject*
143 : ReadStructuredClone(JSContext* aCx,
144 : JSStructuredCloneReader* aReader,
145 : nsIGlobalObject* aParent,
146 : const nsTArray<RefPtr<gfx::DataSourceSurface>>& aClonedSurfaces,
147 : uint32_t aIndex);
148 :
149 : static bool
150 : WriteStructuredClone(JSStructuredCloneWriter* aWriter,
151 : nsTArray<RefPtr<gfx::DataSourceSurface>>& aClonedSurfaces,
152 : ImageBitmap* aImageBitmap);
153 :
154 : // Mozilla Extensions
155 : // aObj is an optional argument that isn't used by ExtensionsEnabled() and
156 : // only exists because the bindings layer insists on passing it to us. All
157 : // other consumers of this function should only call it passing one argument.
158 : static bool ExtensionsEnabled(JSContext* aCx, JSObject* aObj = nullptr);
159 :
160 : friend CreateImageBitmapFromBlob;
161 : friend CreateImageBitmapFromBlobTask;
162 : friend CreateImageBitmapFromBlobWorkerTask;
163 :
164 : template<typename T>
165 : friend class MapDataIntoBufferSource;
166 :
167 : // Mozilla Extensions
168 : ImageBitmapFormat
169 : FindOptimalFormat(const Optional<Sequence<ImageBitmapFormat>>& aPossibleFormats,
170 : ErrorResult& aRv);
171 :
172 : int32_t
173 : MappedDataLength(ImageBitmapFormat aFormat, ErrorResult& aRv);
174 :
175 : already_AddRefed<Promise>
176 : MapDataInto(JSContext* aCx,
177 : ImageBitmapFormat aFormat,
178 : const ArrayBufferViewOrArrayBuffer& aBuffer,
179 : int32_t aOffset, ErrorResult& aRv);
180 :
181 : protected:
182 :
183 : /*
184 : * The default value of aIsPremultipliedAlpha is TRUE because that the
185 : * data stored in HTMLImageElement, HTMLVideoElement, HTMLCanvasElement,
186 : * CanvasRenderingContext2D are alpha-premultiplied in default.
187 : *
188 : * Actually, if one HTMLCanvasElement's rendering context is WebGLContext, it
189 : * is possible to get un-premultipliedAlpha data out. But, we do not do it in
190 : * the CreateInternal(from HTMLCanvasElement) method.
191 : *
192 : * It is also possible to decode an image which is encoded with alpha channel
193 : * to be non-premultipliedAlpha. This could be applied in
194 : * 1) the CreateInternal(from HTMLImageElement) method (which might trigger
195 : * re-decoding if the original decoded data is alpha-premultiplied) and
196 : * 2) while decoding a blob. But we do not do it in both code path too.
197 : *
198 : * ImageData's underlying data is triggered as non-premultipliedAlpha, so set
199 : * the aIsPremultipliedAlpha to be false in the
200 : * CreateInternal(from ImageData) method.
201 : */
202 : ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
203 : gfxAlphaType aAlphaType = gfxAlphaType::Premult);
204 :
205 : virtual ~ImageBitmap();
206 :
207 : void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
208 :
209 : void SetIsCroppingAreaOutSideOfSourceImage(const gfx::IntSize& aSourceSize,
210 : const Maybe<gfx::IntRect>& aCroppingRect);
211 :
212 : static already_AddRefed<ImageBitmap>
213 : CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
214 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
215 :
216 : static already_AddRefed<ImageBitmap>
217 : CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
218 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
219 :
220 : static already_AddRefed<ImageBitmap>
221 : CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
222 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
223 :
224 : static already_AddRefed<ImageBitmap>
225 : CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
226 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
227 :
228 : static already_AddRefed<ImageBitmap>
229 : CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
230 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
231 :
232 : static already_AddRefed<ImageBitmap>
233 : CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
234 : const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
235 :
236 : nsCOMPtr<nsIGlobalObject> mParent;
237 :
238 : /*
239 : * The mData is the data buffer of an ImageBitmap, so the mData must not be
240 : * null.
241 : *
242 : * The mSurface is a cache for drawing the ImageBitmap onto a
243 : * HTMLCanvasElement. The mSurface is null while the ImageBitmap is created
244 : * and then will be initialized while the PrepareForDrawTarget() method is
245 : * called first time.
246 : *
247 : * The mSurface might just be a reference to the same data buffer of the mData
248 : * if the are of mPictureRect is just the same as the mData's size. Or, it is
249 : * a independent data buffer which is copied and cropped form the mData's data
250 : * buffer.
251 : */
252 : RefPtr<layers::Image> mData;
253 : RefPtr<gfx::SourceSurface> mSurface;
254 :
255 : /*
256 : * This is used in the ImageBitmap-Extensions implementation.
257 : * ImageUtils is a wrapper to layers::Image, which add some common methods for
258 : * accessing the layers::Image's data.
259 : */
260 : UniquePtr<ImageUtils> mDataWrapper;
261 :
262 : /*
263 : * The mPictureRect is the size of the source image in default, however, if
264 : * users specify the cropping area while creating an ImageBitmap, then this
265 : * mPictureRect is the cropping area.
266 : *
267 : * Note that if the CreateInternal() copies and crops data from the source
268 : * image, then this mPictureRect is just the size of the final mData.
269 : *
270 : * The mPictureRect will be used at PrepareForDrawTarget() while user is going
271 : * to draw this ImageBitmap into a HTMLCanvasElement.
272 : */
273 : gfx::IntRect mPictureRect;
274 :
275 : const gfxAlphaType mAlphaType;
276 :
277 : /*
278 : * Set mIsCroppingAreaOutSideOfSourceImage if image bitmap was cropped to the
279 : * source rectangle so that it contains any transparent black pixels (cropping
280 : * area is outside of the source image).
281 : * This is used in mapDataInto() to check if we should reject promise with
282 : * IndexSizeError.
283 : */
284 : bool mIsCroppingAreaOutSideOfSourceImage;
285 :
286 : };
287 :
288 : } // namespace dom
289 : } // namespace mozilla
290 :
291 : #endif // mozilla_dom_ImageBitmap_h
292 :
293 :
|