diff --git a/Libraries/LibWeb/HTML/ImageData.cpp b/Libraries/LibWeb/HTML/ImageData.cpp index 346275b4259..94133a96c05 100644 --- a/Libraries/LibWeb/HTML/ImageData.cpp +++ b/Libraries/LibWeb/HTML/ImageData.cpp @@ -19,28 +19,15 @@ namespace Web::HTML { GC_DEFINE_ALLOCATOR(ImageData); // https://html.spec.whatwg.org/multipage/canvas.html#dom-imagedata -WebIDL::ExceptionOr> ImageData::create(JS::Realm& realm, u32 sw, u32 sh, Optional const&) +WebIDL::ExceptionOr> ImageData::create(JS::Realm& realm, u32 sw, u32 sh, Optional const& settings) { - 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."_string); // 2. Initialize this given sw, sh, and settings set to settings. // 3. Initialize the image data of this to transparent black. - // - // If the Canvas Pixel ArrayBuffer cannot be allocated, then rethrow the RangeError thrown by JavaScript, and return. - Checked size = sw; - size *= sh; - size *= sizeof(u32); - if (size.has_overflow()) - return WebIDL::IndexSizeError::create(realm, "The specified image size could not created"_string); - - auto data = TRY(JS::Uint8ClampedArray::create(realm, size.value())); - auto bitmap = TRY_OR_THROW_OOM(vm, Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::AlphaType::Unpremultiplied, Gfx::IntSize(sw, sh), sw * sizeof(u32), data->data().data())); - - return realm.create(realm, bitmap, data); + return initialize(realm, sh, sw, settings); } WebIDL::ExceptionOr> ImageData::construct_impl(JS::Realm& realm, u32 sw, u32 sh, Optional const& settings) @@ -49,7 +36,7 @@ WebIDL::ExceptionOr> ImageData::construct_impl(JS::Realm& rea } // https://html.spec.whatwg.org/multipage/canvas.html#dom-imagedata-with-data -WebIDL::ExceptionOr> ImageData::create(JS::Realm& realm, GC::Root const& data, u32 sw, Optional sh, Optional const&) +WebIDL::ExceptionOr> ImageData::create(JS::Realm& realm, GC::Root const& data, u32 sw, Optional sh, Optional const& settings) { auto& vm = realm.vm(); @@ -82,9 +69,8 @@ WebIDL::ExceptionOr> ImageData::create(JS::Realm& realm, GC:: return WebIDL::IndexSizeError::create(realm, "Source height must be equal to the calculated height of the data."_string); // 7. Initialize this given sw, sh, settings set to settings, and source set to data. - auto bitmap = TRY_OR_THROW_OOM(vm, Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::AlphaType::Unpremultiplied, Gfx::IntSize(sw, height), sw * sizeof(u32), uint8_clamped_array_data.data().data())); - - return realm.create(realm, bitmap, uint8_clamped_array_data); + // FIXME: This seems to be a spec issue, sh is an optional but height always have a value. + return initialize(realm, height, sw, settings, uint8_clamped_array_data); } WebIDL::ExceptionOr> ImageData::construct_impl(JS::Realm& realm, GC::Root const& data, u32 sw, Optional sh, Optional const& settings) @@ -92,9 +78,53 @@ WebIDL::ExceptionOr> ImageData::construct_impl(JS::Realm& rea return ImageData::create(realm, data, sw, move(sh), settings); } -ImageData::ImageData(JS::Realm& realm, NonnullRefPtr bitmap, GC::Ref data) +// https://html.spec.whatwg.org/multipage/canvas.html#initialize-an-imagedata-object +WebIDL::ExceptionOr> ImageData::initialize(JS::Realm& realm, u32 rows, u32 pixels_per_row, Optional const& settings, GC::Ptr source, Optional default_color_space) +{ + auto data = TRY([&]() -> WebIDL::ExceptionOr> { + // 1. If source was given, then initialize the data attribute of imageData to source. + if (source) { + return GC::Ref { *source }; + } + + Checked size = rows; + size *= pixels_per_row; + size *= sizeof(u32); + if (size.has_overflow()) + return WebIDL::IndexSizeError::create(realm, "The specified image size could not created"_string); + + // 2. Otherwise (source was not given), initialize the data attribute of imageData to a new Uint8ClampedArray object. + // The Uint8ClampedArray object must use a new Canvas Pixel ArrayBuffer for its storage, and must have a zero start + // offset and a length equal to the length of its storage, in bytes. The Canvas Pixel ArrayBuffer must have the + // correct size to store rows × pixelsPerRow pixels. + // 3. If the Canvas Pixel ArrayBuffer cannot be allocated, then rethrow the RangeError thrown by JavaScript, and return. + return TRY(JS::Uint8ClampedArray::create(realm, sizeof(u32) * rows * pixels_per_row)); + }()); + + // AD-HOC: Create the bitmap backed by the Uint8ClampedArray. + auto bitmap = TRY_OR_THROW_OOM(realm.vm(), Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::AlphaType::Unpremultiplied, Gfx::IntSize(pixels_per_row, rows), pixels_per_row * sizeof(u32), data->data().data())); + + // 4. Initialize the width attribute of imageData to pixelsPerRow. + // 5. Initialize the height attribute of imageData to rows. + + // 6. If settings was given and settings["colorSpace"] exists, then initialize the colorSpace attribute of imageData to settings["colorSpace"]. + Bindings::PredefinedColorSpace color_space {}; + if (settings.has_value()) + color_space = settings->color_space; + // 7. Otherwise, if defaultColorSpace was given, then initialize the colorSpace attribute of imageData to defaultColorSpace. + else if (default_color_space.has_value()) + color_space = *default_color_space; + // 8. Otherwise, initialize the colorSpace attribute of imageData to "srgb". + else + color_space = Bindings::PredefinedColorSpace::Srgb; + + return realm.create(realm, move(bitmap), data, color_space); +} + +ImageData::ImageData(JS::Realm& realm, NonnullRefPtr bitmap, GC::Ref data, Bindings::PredefinedColorSpace color_space) : PlatformObject(realm) , m_bitmap(move(bitmap)) + , m_color_space(color_space) , m_data(move(data)) { } diff --git a/Libraries/LibWeb/HTML/ImageData.h b/Libraries/LibWeb/HTML/ImageData.h index 652060f8939..079f0b8d875 100644 --- a/Libraries/LibWeb/HTML/ImageData.h +++ b/Libraries/LibWeb/HTML/ImageData.h @@ -39,13 +39,18 @@ public: JS::Uint8ClampedArray* data(); const JS::Uint8ClampedArray* data() const; + Bindings::PredefinedColorSpace color_space() const { return m_color_space; } + private: - ImageData(JS::Realm&, NonnullRefPtr, GC::Ref); + [[nodiscard]] static WebIDL::ExceptionOr> initialize(JS::Realm&, u32 rows, u32 pixels_per_row, Optional const&, GC::Ptr = {}, Optional = {}); + + ImageData(JS::Realm&, NonnullRefPtr, GC::Ref, Bindings::PredefinedColorSpace); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; NonnullRefPtr m_bitmap; + Bindings::PredefinedColorSpace m_color_space; GC::Ref m_data; }; diff --git a/Libraries/LibWeb/HTML/ImageData.idl b/Libraries/LibWeb/HTML/ImageData.idl index d0647facc6e..34b67542700 100644 --- a/Libraries/LibWeb/HTML/ImageData.idl +++ b/Libraries/LibWeb/HTML/ImageData.idl @@ -13,5 +13,5 @@ interface ImageData { readonly attribute unsigned long width; readonly attribute unsigned long height; readonly attribute Uint8ClampedArray data; - [FIXME] readonly attribute PredefinedColorSpace colorSpace; + readonly attribute PredefinedColorSpace colorSpace; };