Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / html / ImageBitmap.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ImageBitmap.h"
28
29 #include "BitmapImage.h"
30 #include "Blob.h"
31 #include "CachedImage.h"
32 #include "ExceptionOr.h"
33 #include "FileReaderLoader.h"
34 #include "FileReaderLoaderClient.h"
35 #include "HTMLCanvasElement.h"
36 #include "HTMLImageElement.h"
37 #include "HTMLVideoElement.h"
38 #include "ImageBitmapOptions.h"
39 #include "ImageBuffer.h"
40 #include "ImageData.h"
41 #include "IntRect.h"
42 #include "JSImageBitmap.h"
43 #include "LayoutSize.h"
44 #include "SharedBuffer.h"
45 #include <wtf/StdLibExtras.h>
46
47 namespace WebCore {
48
49 Ref<ImageBitmap> ImageBitmap::create()
50 {
51     return adoptRef(*new ImageBitmap);
52 }
53
54 void ImageBitmap::createPromise(ScriptExecutionContext& scriptExecutionContext, ImageBitmap::Source&& source, ImageBitmapOptions&& options, ImageBitmap::Promise&& promise)
55 {
56     WTF::switchOn(source,
57         [&] (auto& specificSource) {
58             createPromise(scriptExecutionContext, specificSource, WTFMove(options), std::nullopt, WTFMove(promise));
59         }
60     );
61 }
62
63 void ImageBitmap::createPromise(ScriptExecutionContext& scriptExecutionContext, ImageBitmap::Source&& source, ImageBitmapOptions&& options, int sx, int sy, int sw, int sh, ImageBitmap::Promise&& promise)
64 {
65     // 1. If either the sw or sh arguments are specified but zero, return a promise
66     //    rejected with an "RangeError" DOMException and abort these steps.
67     if (!sw || !sh) {
68         promise.reject(RangeError, "Cannot create ImageBitmap with a width or height of 0");
69         return;
70     }
71
72     WTF::switchOn(source,
73         [&] (auto& specificSource) {
74             createPromise(scriptExecutionContext, specificSource, WTFMove(options), IntRect { sx, sy, sw, sh }, WTFMove(promise));
75         }
76     );
77 }
78
79 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<HTMLImageElement>& imageElement, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
80 {
81     UNUSED_PARAM(imageElement);
82     UNUSED_PARAM(options);
83     UNUSED_PARAM(rect);
84
85     // 2. If image is not completely available, then return a promise rejected with
86     // an "InvalidStateError" DOMException and abort these steps.
87
88     // 3. If image's media data has no intrinsic dimensions (e.g. it's a vector graphic
89     //    with no specified content size), and both or either of the resizeWidth and
90     //    resizeHeight options are not specified, then return a promise rejected with
91     //    an "InvalidStateError" DOMException and abort these steps.
92
93     // 4. If image's media data has no intrinsic dimensions (e.g. it's a vector graphics
94     //    with no specified content size), it should be rendered to a bitmap of the size
95     //    specified by the resizeWidth and the resizeHeight options.
96
97     // 5. If the sw and sh arguments are not specified and image's media data has both or
98     //    either of its intrinsic width and intrinsic height values equal to 0, then return
99     //    a promise rejected with an "InvalidStateError" DOMException and abort these steps.
100
101     // 6. If the sh argument is not specified and image's media data has an intrinsic height
102     //    of 0, then return a promise rejected with an "InvalidStateError" DOMException and
103     //    abort these steps.
104
105     // 7. Create a new ImageBitmap object.
106     auto imageBitmap = create();
107
108     // 8. Let the ImageBitmap object's bitmap data be a copy of image's media data, cropped to
109     //    the source rectangle with formatting. If this is an animated image, the ImageBitmap
110     //    object's bitmap data must only be taken from the default image of the animation (the
111     //    one that the format defines is to be used when animation is not supported or is disabled),
112     //    or, if there is no such image, the first frame of the animation.
113
114     // 9. If the origin of image's image is not the same origin as the origin specified by the
115     //    entry settings object, then set the origin-clean flag of the ImageBitmap object's
116     //    bitmap to false.
117
118     // 10. Return a new promise, but continue running these steps in parallel.
119
120     // 11. Resolve the promise with the new ImageBitmap object as the value.
121     return promise.resolve(WTFMove(imageBitmap));
122 }
123
124 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<HTMLCanvasElement>& canvasElement, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
125 {
126     UNUSED_PARAM(canvasElement);
127     UNUSED_PARAM(options);
128     UNUSED_PARAM(rect);
129
130     // 2. If the canvas element's bitmap has either a horizontal dimension or a vertical
131     //    dimension equal to zero, then return a promise rejected with an "InvalidStateError"
132     //    DOMException and abort these steps.
133
134     // 3. Create a new ImageBitmap object.
135     auto imageBitmap = create();
136
137     // 4. Let the ImageBitmap object's bitmap data be a copy of the canvas element's bitmap
138     //    data, cropped to the source rectangle with formatting.
139
140     // 5. Set the origin-clean flag of the ImageBitmap object's bitmap to the same value as
141     //    the origin-clean flag of the canvas element's bitmap.
142
143     // 6. Return a new promise, but continue running these steps in parallel.
144
145     // 7. Resolve the promise with the new ImageBitmap object as the value.
146     return promise.resolve(WTFMove(imageBitmap));
147 }
148
149 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<HTMLVideoElement>& videoElement, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
150 {
151     UNUSED_PARAM(videoElement);
152     UNUSED_PARAM(options);
153     UNUSED_PARAM(rect);
154
155     // 2. If the video element's networkState attribute is NETWORK_EMPTY, then return
156     //    a promise rejected with an "InvalidStateError" DOMException and abort these
157     //    steps.
158
159     // 3. If the video element's readyState attribute is either HAVE_NOTHING or
160     //    HAVE_METADATA, then return a promise rejected with an "InvalidStateError"
161     //    DOMException and abort these steps.
162
163     // 4. Create a new ImageBitmap object.
164     auto imageBitmap = create();
165
166     // 5. Let the ImageBitmap object's bitmap data be a copy of the frame at the current
167     //    playback position, at the media resource's intrinsic width and intrinsic height
168     //    (i.e. after any aspect-ratio correction has been applied), cropped to the source
169     //    rectangle with formatting.
170
171     // 6. If the origin of the video element is not the same origin as the origin specified
172     //    by the entry settings object, then set the origin-clean flag of the ImageBitmap
173     //    object's bitmap to false.
174
175     // 7. Return a new promise, but continue running these steps in parallel.
176
177     // 8. Resolve the promise with the new ImageBitmap object as the value.
178     return promise.resolve(WTFMove(imageBitmap));
179 }
180
181 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<ImageBitmap>& existingImageBitmap, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
182 {
183     UNUSED_PARAM(existingImageBitmap);
184     UNUSED_PARAM(options);
185     UNUSED_PARAM(rect);
186
187     // 2. If image's [[Detached]] internal slot value is true, return a promise
188     //    rejected with an "InvalidStateError" DOMException and abort these steps.
189
190     // 3. Create a new ImageBitmap object.
191     auto imageBitmap = create();
192
193     // 4. Let the ImageBitmap object's bitmap data be a copy of the image argument's
194     //    bitmap data, cropped to the source rectangle with formatting.
195
196     // 5. Set the origin-clean flag of the ImageBitmap object's bitmap to the same
197     //    value as the origin-clean flag of the bitmap of the image argument.
198
199     // 6. Return a new promise, but continue running these steps in parallel.
200
201     // 7. Resolve the promise with the new ImageBitmap object as the value.
202     return promise.resolve(WTFMove(imageBitmap));
203 }
204
205 class PendingImageBitmap final : public ActiveDOMObject, public FileReaderLoaderClient {
206 public:
207     static void fetch(ScriptExecutionContext& scriptExecutionContext, RefPtr<Blob>&& blob, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
208     {
209         auto pendingImageBitmap = new PendingImageBitmap(scriptExecutionContext, WTFMove(blob), WTFMove(options), WTFMove(rect), WTFMove(promise));
210         pendingImageBitmap->start(scriptExecutionContext);
211     }
212
213 private:
214     PendingImageBitmap(ScriptExecutionContext& scriptExecutionContext, RefPtr<Blob>&& blob, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
215         : ActiveDOMObject(&scriptExecutionContext)
216         , m_blobLoader(FileReaderLoader::ReadAsArrayBuffer, this)
217         , m_blob(WTFMove(blob))
218         , m_options(WTFMove(options))
219         , m_rect(WTFMove(rect))
220         , m_promise(WTFMove(promise))
221     {
222     }
223
224     void start(ScriptExecutionContext& scriptExecutionContext)
225     {
226         m_blobLoader.start(&scriptExecutionContext, *m_blob);
227     }
228
229     // ActiveDOMObject
230
231     const char* activeDOMObjectName() const override
232     {
233         return "PendingImageBitmap";
234     }
235
236     bool canSuspendForDocumentSuspension() const override
237     {
238         // FIXME: Deal with suspension.
239         return false;
240     }
241
242     // FileReaderLoaderClient
243
244     void didStartLoading() override
245     {
246     }
247
248     void didReceiveData() override
249     {
250     }
251
252     void didFinishLoading() override
253     {
254         createImageBitmap(m_blobLoader.arrayBufferResult());
255         delete this;
256     }
257
258     void didFail(int) override
259     {
260         createImageBitmap(nullptr);
261         delete this;
262     }
263
264     void createImageBitmap(RefPtr<ArrayBuffer> arrayBuffer)
265     {
266         UNUSED_PARAM(arrayBuffer);
267
268         // 3. Read the Blob object's data. If an error occurs during reading of the object,
269         //    then reject the promise with an "InvalidStateError" DOMException, and abort
270         //    these steps.
271
272         // 4. Apply the image sniffing rules to determine the file format of the image data,
273         //    with MIME type of the Blob (as given by the Blob object's type attribute) giving
274         //    the official type.
275
276         // 5. If the image data is not in a supported image file format (e.g. it's not an image
277         //    at all), or if the image data is corrupted in some fatal way such that the image
278         //    dimensions cannot be obtained (e.g. a vector graphic with no intrinsic size), then
279         //    reject the promise with an "InvalidStateError" DOMException, and abort these steps.
280
281         // 6. Create a new ImageBitmap object.
282         auto imageBitmap = ImageBitmap::create();
283
284         // 7. Let the ImageBitmap object's bitmap data be the image data read from the Blob object,
285         //    cropped to the source rectangle with formatting. If this is an animated image, the
286         //    ImageBitmap object's bitmap data must only be taken from the default image of the
287         //    animation (the one that the format defines is to be used when animation is not supported
288         //    or is disabled), or, if there is no such image, the first frame of the animation.
289
290         // 8. Resolve the promise with the new ImageBitmap object as the value.
291         m_promise.resolve(WTFMove(imageBitmap));
292     }
293
294     FileReaderLoader m_blobLoader;
295     RefPtr<Blob> m_blob;
296     ImageBitmapOptions m_options;
297     std::optional<IntRect> m_rect;
298     ImageBitmap::Promise m_promise;
299 };
300
301 void ImageBitmap::createPromise(ScriptExecutionContext& scriptExecutionContext, RefPtr<Blob>& blob, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
302 {
303     // 2. Return a new promise, but continue running these steps in parallel.
304     PendingImageBitmap::fetch(scriptExecutionContext, WTFMove(blob), WTFMove(options), WTFMove(rect), WTFMove(promise));
305 }
306
307 void ImageBitmap::createPromise(ScriptExecutionContext&, RefPtr<ImageData>& imageData, ImageBitmapOptions&& options, std::optional<IntRect> rect, ImageBitmap::Promise&& promise)
308 {
309     UNUSED_PARAM(imageData);
310     UNUSED_PARAM(options);
311     UNUSED_PARAM(rect);
312
313     // 2. If the image object's data attribute value's [[Detached]] internal slot value
314     //    is true, return a promise rejected with an "InvalidStateError" DOMException
315     //    and abort these steps.
316
317     // 3. Create a new ImageBitmap object.
318     auto imageBitmap = create();
319
320     // 4. Let the ImageBitmap object's bitmap data be the image data given by the ImageData
321     //    object, cropped to the source rectangle with formatting.
322
323     // 5. Return a new promise, but continue running these steps in parallel.
324     // 6. Resolve the promise with the new ImageBitmap object as the value.
325     promise.resolve(imageBitmap);
326 }
327
328 ImageBitmap::ImageBitmap() = default;
329
330 ImageBitmap::~ImageBitmap() = default;
331
332 unsigned ImageBitmap::width() const
333 {
334     if (m_detached || !m_bitmapData)
335         return 0;
336
337     // FIXME: Is this the right width?
338     return m_bitmapData->logicalSize().width();
339 }
340
341 unsigned ImageBitmap::height() const
342 {
343     if (m_detached || !m_bitmapData)
344         return 0;
345
346     // FIXME: Is this the right height?
347     return m_bitmapData->logicalSize().height();
348 }
349
350 void ImageBitmap::close()
351 {
352     m_detached = true;
353     m_bitmapData = nullptr;
354 }
355
356 }