LibWeb/HTML: Fix crash creating canvas pattern without context

This isn't a full fix, as the paint function does not handle this
either. But instead of getting the bitmap from the image source
immediately, follow the spec a bit more closely by creating the
CanvasPatern object with the ImageSource directly.

Fixes a crash for the 5 included WPT tests.
This commit is contained in:
Shannon Booth 2025-01-11 15:56:30 +13:00 committed by Tim Ledbetter
parent dfdcfc8e88
commit f388d3c88c
Notes: github-actions[bot] 2025-01-12 18:41:35 +00:00
13 changed files with 233 additions and 18 deletions

View file

@ -46,8 +46,17 @@ void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFun
// 6. The resulting bitmap is what is to be rendered, with the same origin and same scale.
auto const bitmap_width = m_immutable_bitmap->width();
auto const bitmap_height = m_immutable_bitmap->height();
// FIXME: This doesn't handle a 'none' canvas context mode.
auto bitmap = m_image.visit(
[](GC::Root<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->immutable_bitmap(); },
[](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->current_image_bitmap(); },
[](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*source->surface()); },
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
[](GC::Root<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); });
VERIFY(bitmap);
auto const bitmap_width = bitmap->width();
auto const bitmap_height = bitmap->height();
paint([=, this](auto point) {
point.translate_by(physical_bounding_box.location());
@ -78,8 +87,8 @@ void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFun
VERIFY_NOT_REACHED();
}
}();
if (m_immutable_bitmap->rect().contains(point))
return m_immutable_bitmap->get_pixel(point.x(), point.y());
if (bitmap->rect().contains(point))
return bitmap->get_pixel(point.x(), point.y());
return Gfx::Color();
});
}
@ -127,16 +136,8 @@ WebIDL::ExceptionOr<GC::Ptr<CanvasPattern>> CanvasPattern::create(JS::Realm& rea
if (!repetition_value.has_value())
return WebIDL::SyntaxError::create(realm, "Repetition value is not valid"_string);
// Note: Bitmap won't be null here, as if it were it would have "bad" usability.
auto bitmap = image.visit(
[](GC::Root<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->immutable_bitmap(); },
[](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->current_image_bitmap(); },
[](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*source->surface()); },
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
[](GC::Root<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); });
// 6. Let pattern be a new CanvasPattern object with the image image and the repetition behavior given by repetition.
auto pattern = TRY_OR_THROW_OOM(realm.vm(), CanvasPatternPaintStyle::create(*bitmap, *repetition_value));
auto pattern = TRY_OR_THROW_OOM(realm.vm(), CanvasPatternPaintStyle::create(image, *repetition_value));
// FIXME: 7. If image is not origin-clean, then mark pattern as not origin-clean.