| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  |  * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2024-03-23 21:45:59 +01:00
										 |  |  |  * Copyright (c) 2024, Kenneth Myhra <kennethmyhra@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibGfx/Bitmap.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:33:26 +04:30
										 |  |  | #include <LibJS/Runtime/TypedArray.h>
 | 
					
						
							| 
									
										
										
										
											2022-09-25 16:38:21 -06:00
										 |  |  | #include <LibWeb/Bindings/Intrinsics.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-26 15:08:16 +02:00
										 |  |  | #include <LibWeb/HTML/ImageData.h>
 | 
					
						
							| 
									
										
										
										
											2024-03-26 14:31:32 +01:00
										 |  |  | #include <LibWeb/WebIDL/Buffers.h>
 | 
					
						
							| 
									
										
										
										
											2024-03-23 21:45:59 +01:00
										 |  |  | #include <LibWeb/WebIDL/DOMException.h>
 | 
					
						
							|  |  |  | #include <LibWeb/WebIDL/ExceptionOr.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 18:20:36 +02:00
										 |  |  | namespace Web::HTML { | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-19 19:47:52 +01:00
										 |  |  | JS_DEFINE_ALLOCATOR(ImageData); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-26 14:34:11 +01:00
										 |  |  | // https://html.spec.whatwg.org/multipage/canvas.html#dom-imagedata
 | 
					
						
							| 
									
										
										
										
											2024-03-23 21:45:59 +01:00
										 |  |  | WebIDL::ExceptionOr<JS::NonnullGCPtr<ImageData>> ImageData::create(JS::Realm& realm, u32 sw, u32 sh, Optional<ImageDataSettings> const&) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& vm = realm.vm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1. If one or both of sw and sh are zero, then throw an "IndexSizeError" DOMException.
 | 
					
						
							|  |  |  |     if (sw == 0 || sh == 0) | 
					
						
							|  |  |  |         return WebIDL::IndexSizeError::create(realm, "The source width and height must be greater than zero."_fly_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Initialize this given sw, sh, and settings set to settings.
 | 
					
						
							|  |  |  |     // 3. Initialize the image data of this to transparent black.
 | 
					
						
							|  |  |  |     auto data = TRY(JS::Uint8ClampedArray::create(realm, sw * sh * 4)); | 
					
						
							| 
									
										
										
										
											2024-04-15 09:36:57 +02:00
										 |  |  |     auto bitmap = TRY_OR_THROW_OOM(vm, Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize(sw, sh), 1, sw * sizeof(u32), data->data().data())); | 
					
						
							| 
									
										
										
										
											2024-03-23 21:45:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return realm.heap().allocate<ImageData>(realm, realm, bitmap, data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebIDL::ExceptionOr<JS::NonnullGCPtr<ImageData>> ImageData::construct_impl(JS::Realm& realm, u32 sw, u32 sh, Optional<ImageDataSettings> const& settings) | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-23 21:45:59 +01:00
										 |  |  |     return ImageData::create(realm, sw, sh, settings); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-26 14:31:32 +01:00
										 |  |  | // https://html.spec.whatwg.org/multipage/canvas.html#dom-imagedata-with-data
 | 
					
						
							|  |  |  | WebIDL::ExceptionOr<JS::NonnullGCPtr<ImageData>> ImageData::create(JS::Realm& realm, JS::Handle<WebIDL::BufferSource> const& data, u32 sw, Optional<u32> sh, Optional<ImageDataSettings> const&) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& vm = realm.vm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!is<JS::Uint8ClampedArray>(*data->raw_object())) | 
					
						
							|  |  |  |         return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Uint8ClampedArray"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& uint8_clamped_array_data = static_cast<JS::Uint8ClampedArray&>(*data->raw_object()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1. Let length be the number of bytes in data.
 | 
					
						
							|  |  |  |     auto length = uint8_clamped_array_data.byte_length().length(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. If length is not a nonzero integral multiple of four, then throw an "InvalidStateError" DOMException.
 | 
					
						
							|  |  |  |     if (length == 0 || length % 4 != 0) | 
					
						
							|  |  |  |         return WebIDL::InvalidStateError::create(realm, "Source data must have a non-sero length that is a multiple of four."_fly_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 3. Let length be length divided by four.
 | 
					
						
							|  |  |  |     length = length / 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 4. If length is not an integral multiple of sw, then throw an "IndexSizeError" DOMException.
 | 
					
						
							|  |  |  |     // NOTE: At this step, the length is guaranteed to be greater than zero (otherwise the second step above would have aborted the steps),
 | 
					
						
							|  |  |  |     //       so if sw is zero, this step will throw the exception and return.
 | 
					
						
							|  |  |  |     if (sw == 0 || length % sw != 0) | 
					
						
							|  |  |  |         return WebIDL::IndexSizeError::create(realm, "Source width must be a multiple of source data's length."_fly_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 5. Let height be length divided by sw.
 | 
					
						
							|  |  |  |     auto height = length / sw; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 6. If sh was given and its value is not equal to height, then throw an "IndexSizeError" DOMException.
 | 
					
						
							|  |  |  |     if (sh.has_value() && sh.value() != height) | 
					
						
							|  |  |  |         return WebIDL::IndexSizeError::create(realm, "Source height must be equal to the calculated height of the data."_fly_string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 7. Initialize this given sw, sh, settings set to settings, and source set to data.
 | 
					
						
							| 
									
										
										
										
											2024-04-15 09:42:17 +02:00
										 |  |  |     auto bitmap = TRY_OR_THROW_OOM(vm, Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize(sw, height), 1, sw * sizeof(u32), uint8_clamped_array_data.data().data())); | 
					
						
							| 
									
										
										
										
											2024-03-26 14:31:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return realm.heap().allocate<ImageData>(realm, realm, bitmap, uint8_clamped_array_data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebIDL::ExceptionOr<JS::NonnullGCPtr<ImageData>> ImageData::construct_impl(JS::Realm& realm, JS::Handle<WebIDL::BufferSource> const& data, u32 sw, Optional<u32> sh, Optional<ImageDataSettings> const& settings) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ImageData::create(realm, data, sw, move(sh), settings); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-25 16:38:21 -06:00
										 |  |  | ImageData::ImageData(JS::Realm& realm, NonnullRefPtr<Gfx::Bitmap> bitmap, JS::NonnullGCPtr<JS::Uint8ClampedArray> data) | 
					
						
							|  |  |  |     : PlatformObject(realm) | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  |     , m_bitmap(move(bitmap)) | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  |     , m_data(move(data)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 13:21:51 -06:00
										 |  |  | ImageData::~ImageData() = default; | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 08:41:28 +02:00
										 |  |  | void ImageData::initialize(JS::Realm& realm) | 
					
						
							| 
									
										
										
										
											2023-01-10 06:28:20 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-07 08:41:28 +02:00
										 |  |  |     Base::initialize(realm); | 
					
						
							| 
									
										
										
										
											2024-03-16 13:13:08 +01:00
										 |  |  |     WEB_SET_PROTOTYPE_FOR_INTERFACE(ImageData); | 
					
						
							| 
									
										
										
										
											2023-01-10 06:28:20 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  | void ImageData::visit_edges(Cell::Visitor& visitor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Base::visit_edges(visitor); | 
					
						
							| 
									
										
										
										
											2023-11-19 16:18:00 +13:00
										 |  |  |     visitor.visit(m_data); | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  | unsigned ImageData::width() const | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_bitmap->width(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  | unsigned ImageData::height() const | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_bitmap->height(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | JS::Uint8ClampedArray* ImageData::data() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  |     return m_data; | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const JS::Uint8ClampedArray* ImageData::data() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-09-02 23:07:05 +02:00
										 |  |  |     return m_data; | 
					
						
							| 
									
										
										
										
											2020-04-21 23:49:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |