From 3b8ccf4d77d3d0261d1b8e3ee3d0e9d6371b17f1 Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sun, 3 Aug 2025 20:48:55 +0300 Subject: [PATCH] LibWeb: Add initial support for `HTMLImageElement` in createImageBitmap --- .../LibWeb/HTML/WindowOrWorkerGlobalScope.cpp | 32 +++++++-- ...reateImageBitmap-exif-orientation_none.txt | 13 ++++ ...eateImageBitmap-exif-orientation_none.html | 61 ++++++++++++++++++ .../imagebitmap/resources/squares_1.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_2.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_3.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_4.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_5.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_6.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_7.jpg | Bin 0 -> 1227 bytes .../imagebitmap/resources/squares_8.jpg | Bin 0 -> 1227 bytes 11 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_1.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_2.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_3.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_4.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_5.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_6.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_7.jpg create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_8.jpg diff --git a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp index 011eb545bbf..9a614121738 100644 --- a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp @@ -242,11 +242,33 @@ GC::Ref WindowOrWorkerGlobalScopeMixin::create_image_bitmap_imp [&](CanvasImageSource const& image_source) { image_source.visit( // -> img - [&](GC::Root const&) { - dbgln("(STUBBED) createImageBitmap() for HTMLImageElement"); - auto const error = JS::Error::create(realm, "Not Implemented: createImageBitmap() for HTMLImageElement"sv); - TemporaryExecutionContext const context { relevant_realm(p->promise()), TemporaryExecutionContext::CallbacksEnabled::Yes }; - WebIDL::reject_promise(realm, *p, error); + [&](GC::Root const& image_element) { + // 1. If image's media data has no natural dimensions (e.g., it's a vector graphic with no specified content size) and options's resizeWidth or options's resizeHeight is not present, then return a promise rejected with an "InvalidStateError" DOMException. + auto const has_natural_dimensions = image_element->intrinsic_width().has_value() && image_element->intrinsic_height().has_value(); + if (!has_natural_dimensions && (!options.has_value() || !options->resize_width.has_value() || !options->resize_width.has_value())) { + WebIDL::reject_promise(realm, *p, WebIDL::InvalidStateError::create(image_bitmap->realm(), "Image data is detached"_string)); + return; + } + + // 2. If image's media data has no natural dimensions (e.g., it's a vector graphic with no specified content size), it should be rendered to a bitmap of the size specified by the resizeWidth and the resizeHeight options. + // 3. Set imageBitmap's bitmap data to a copy of image's media data, cropped to the source rectangle with formatting. If this is an animated image, imageBitmap's bitmap data must only be taken from the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation. + // FIXME: Actually crop the image to the source rectangle with formatting: https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#cropped-to-the-source-rectangle-with-formatting + RefPtr immutable_bitmap; + if (has_natural_dimensions) { + immutable_bitmap = image_element->default_image_bitmap(Gfx::IntSize { *image_element->intrinsic_width(), *image_element->intrinsic_height() }); + } else { + immutable_bitmap = image_element->default_image_bitmap(Gfx::IntSize { *options->resize_width, *options->resize_height }); + } + image_bitmap->set_bitmap(MUST(immutable_bitmap->bitmap()->clone())); + + // FIXME: 4. If image is not origin-clean, then set the origin-clean flag of imageBitmap's bitmap to false. + + // 5. Queue a global task, using the bitmap task source, to resolve promise with imageBitmap. + queue_global_task(Task::Source::BitmapTask, image_bitmap, GC::create_function(realm.heap(), [p, image_bitmap] { + auto& realm = relevant_realm(image_bitmap); + TemporaryExecutionContext const context { realm, TemporaryExecutionContext::CallbacksEnabled::Yes }; + WebIDL::resolve_promise(realm, *p, image_bitmap); + })); }, // -> SVG image [&](GC::Root const&) { diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.txt b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.txt new file mode 100644 index 00000000000..39effcaf7df --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.txt @@ -0,0 +1,13 @@ +Harness status: OK + +Found 8 tests + +8 Pass +Pass createImageBitmap with Orientation 1 +Pass createImageBitmap with Orientation 2 +Pass createImageBitmap with Orientation 3 +Pass createImageBitmap with Orientation 4 +Pass createImageBitmap with Orientation 5 +Pass createImageBitmap with Orientation 6 +Pass createImageBitmap with Orientation 7 +Pass createImageBitmap with Orientation 8 \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.html b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.html new file mode 100644 index 00000000000..8aea4daf2b3 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/createImageBitmap-exif-orientation_none.html @@ -0,0 +1,61 @@ + +Test that createImageBitmap honors EXIF orientation + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_1.jpg b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f0e8866b4d11f707e94b12be0042e0f4527bfab GIT binary patch literal 1227 zcmex=Bm<7<_#hv=|r|I2c$Ng&3F_pz@4T z46I-_1A`Z%G@Kp8sDV(!B#dA)Kma3D519Uco57iZnF$0yBr`KJGYcCF2yn2mv9fV; zaB*>RaB_0-@bhqS^Ko->@(S|u@e2qD3UKiV2@44b^9u+FfDB;->11Z%U}519;O68O zAQ}8Wz#z!M=)kamnNg5|Nsy6Qkn#T!25|;PMo@r2oDL>AIavQ6VGt1jxgRV5BmN&@ zkOC=YM$y2*#>&pg1kxdhspA#{4>KbJlOVGogFVAk2Z%{bs~R8-&JYOAptSwa=oY9yG_ykTp-f-Zu!|6RhNUY5_d=MACR3wbAWWudOWnRe zm@JnoBVKSWalbd}2!p^u}5CmZ{7*B3r_5s3{GQA@L zjXItu4`1$qh_dyTvnoKC%$62a`4Hv+8myZ9@IAy447?A{U0MKP^T-_(jeszRuqglk Fn*dq9vu6MR literal 0 HcmV?d00001 diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_2.jpg b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/manual/imagebitmap/resources/squares_2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..526f7a6c8299ef2d214e3c0966a8655b7a056f8a GIT binary patch literal 1227 zcmex=Bm<7<_#hv=|r|I2c$Ng&3F_K=Mos z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=RBC z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=LdM z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=P~% z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=N!1 z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=SMi z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|Bm<7<_#hv=|r|I2c$Ng&3F_K=K?6 z42)6?tY9_+gBPPToE^ld0ae4uz`!JoU^74fBUBHV{(qannSq%J1VAJ+Gcz*_8w&_< zu(7eSadL2RadL2Sa`Eu#!&C=|NldF6APmkB2+g3i z0?HUnO6I)}xnTiu7gy9&=?f61uxIENs6RBbLh_+ZU)8XS5P62BD+BjJn2aVwsfBLp1%+$FfNWg=mB9eob!{LeE`DFxLyzhVKEp_ZeR8R z!j>|