mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-04 23:30:20 +00:00
LibWeb: Don't crash when setting offscreen canvas size to 0
Previously, this would crash because `Gfx::Bitmap` can't have a zero size.
This commit is contained in:
parent
f882c446cb
commit
5413716802
Notes:
github-actions[bot]
2025-07-04 15:11:48 +00:00
Author: https://github.com/tcl3
Commit: 5413716802
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5255
Reviewed-by: https://github.com/AtkinsSJ ✅
5 changed files with 78 additions and 18 deletions
|
@ -45,6 +45,11 @@ static void default_source_size(CanvasImageSource const& image, float& source_wi
|
||||||
[&source_width, &source_height](GC::Root<OffscreenCanvas> const& source) {
|
[&source_width, &source_height](GC::Root<OffscreenCanvas> const& source) {
|
||||||
auto const bitmap = source->bitmap();
|
auto const bitmap = source->bitmap();
|
||||||
|
|
||||||
|
if (!bitmap) {
|
||||||
|
source_width = 0;
|
||||||
|
source_height = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
source_width = bitmap->width();
|
source_width = bitmap->width();
|
||||||
source_height = bitmap->height();
|
source_height = bitmap->height();
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,15 +31,16 @@ WebIDL::ExceptionOr<GC::Ref<OffscreenCanvas>> OffscreenCanvas::construct_impl(
|
||||||
WebIDL::UnsignedLong width,
|
WebIDL::UnsignedLong width,
|
||||||
WebIDL::UnsignedLong height)
|
WebIDL::UnsignedLong height)
|
||||||
{
|
{
|
||||||
|
RefPtr<Gfx::Bitmap> bitmap;
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
// The new OffscreenCanvas(width, height) constructor steps are:
|
// The new OffscreenCanvas(width, height) constructor steps are:
|
||||||
auto bitmap_or_error = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize { width, height });
|
auto bitmap_or_error = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize { width, height });
|
||||||
|
|
||||||
if (bitmap_or_error.is_error()) {
|
if (bitmap_or_error.is_error()) {
|
||||||
return WebIDL::InvalidStateError::create(realm, MUST(String::formatted("Error in allocating bitmap: {}", bitmap_or_error.error())));
|
return WebIDL::InvalidStateError::create(realm, MUST(String::formatted("Error in allocating bitmap: {}", bitmap_or_error.error())));
|
||||||
}
|
}
|
||||||
|
bitmap = bitmap_or_error.release_value();
|
||||||
auto bitmap = bitmap_or_error.release_value();
|
}
|
||||||
|
|
||||||
// 1. Initialize the bitmap of this to a rectangular array of transparent black pixels of the dimensions specified by width and height.
|
// 1. Initialize the bitmap of this to a rectangular array of transparent black pixels of the dimensions specified by width and height.
|
||||||
// noop, the pixel value to set is equal to 0x00000000, which the bitmap already contains
|
// noop, the pixel value to set is equal to 0x00000000, which the bitmap already contains
|
||||||
|
@ -71,7 +72,7 @@ WebIDL::ExceptionOr<GC::Ref<OffscreenCanvas>> OffscreenCanvas::construct_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/canvas.html#dom-offscreencanvas
|
// https://html.spec.whatwg.org/multipage/canvas.html#dom-offscreencanvas
|
||||||
OffscreenCanvas::OffscreenCanvas(JS::Realm& realm, NonnullRefPtr<Gfx::Bitmap> bitmap)
|
OffscreenCanvas::OffscreenCanvas(JS::Realm& realm, RefPtr<Gfx::Bitmap> bitmap)
|
||||||
: EventTarget(realm)
|
: EventTarget(realm)
|
||||||
, m_bitmap { move(bitmap) }
|
, m_bitmap { move(bitmap) }
|
||||||
{
|
{
|
||||||
|
@ -102,11 +103,17 @@ HTML::TransferType OffscreenCanvas::primary_interface() const
|
||||||
|
|
||||||
WebIDL::UnsignedLong OffscreenCanvas::width() const
|
WebIDL::UnsignedLong OffscreenCanvas::width() const
|
||||||
{
|
{
|
||||||
|
if (!m_bitmap)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return m_bitmap->size().width();
|
return m_bitmap->size().width();
|
||||||
}
|
}
|
||||||
|
|
||||||
WebIDL::UnsignedLong OffscreenCanvas::height() const
|
WebIDL::UnsignedLong OffscreenCanvas::height() const
|
||||||
{
|
{
|
||||||
|
if (!m_bitmap)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return m_bitmap->size().height();
|
return m_bitmap->size().height();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +136,11 @@ void OffscreenCanvas::reset_context_to_default_state()
|
||||||
|
|
||||||
void OffscreenCanvas::set_new_bitmap_size(Gfx::IntSize new_size)
|
void OffscreenCanvas::set_new_bitmap_size(Gfx::IntSize new_size)
|
||||||
{
|
{
|
||||||
|
if (new_size.width() == 0 || new_size.height() == 0)
|
||||||
|
m_bitmap = nullptr;
|
||||||
|
else {
|
||||||
m_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize { new_size.width(), new_size.height() }));
|
m_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize { new_size.width(), new_size.height() }));
|
||||||
|
}
|
||||||
|
|
||||||
m_context.visit(
|
m_context.visit(
|
||||||
[&](GC::Ref<OffscreenCanvasRenderingContext2D>& context) {
|
[&](GC::Ref<OffscreenCanvasRenderingContext2D>& context) {
|
||||||
|
@ -145,7 +156,7 @@ void OffscreenCanvas::set_new_bitmap_size(Gfx::IntSize new_size)
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
NonnullRefPtr<Gfx::Bitmap> OffscreenCanvas::bitmap() const
|
RefPtr<Gfx::Bitmap> OffscreenCanvas::bitmap() const
|
||||||
{
|
{
|
||||||
return m_bitmap;
|
return m_bitmap;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +182,8 @@ WebIDL::ExceptionOr<void> OffscreenCanvas::set_height(WebIDL::UnsignedLong value
|
||||||
|
|
||||||
Gfx::IntSize OffscreenCanvas::bitmap_size_for_canvas() const
|
Gfx::IntSize OffscreenCanvas::bitmap_size_for_canvas() const
|
||||||
{
|
{
|
||||||
|
if (!m_bitmap)
|
||||||
|
return { 0, 0 };
|
||||||
return m_bitmap->size();
|
return m_bitmap->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,10 +237,14 @@ WebIDL::ExceptionOr<GC::Ref<ImageBitmap>> OffscreenCanvas::transfer_to_image_bit
|
||||||
auto image = ImageBitmap::create(realm());
|
auto image = ImageBitmap::create(realm());
|
||||||
image->set_bitmap(m_bitmap);
|
image->set_bitmap(m_bitmap);
|
||||||
|
|
||||||
// 4. Set this OffscreenCanvas object 's bitmap to reference a newly created bitmap of the same dimensions and color space as the previous bitmap, and with its pixels initialized to transparent black, or opaque black if the rendering context' s alpha is false.
|
// 4. Set this OffscreenCanvas object's bitmap to reference a newly created bitmap of the same dimensions and color space as the previous bitmap, and with its pixels initialized to transparent black, or opaque black if the rendering context' s alpha is false.
|
||||||
// FIXME: implement the checking of the alpha from the context
|
// FIXME: implement the checking of the alpha from the context
|
||||||
auto size = bitmap_size_for_canvas();
|
auto size = bitmap_size_for_canvas();
|
||||||
|
if (size.is_empty()) {
|
||||||
|
m_bitmap = nullptr;
|
||||||
|
} else {
|
||||||
m_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, size));
|
m_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, size));
|
||||||
|
}
|
||||||
|
|
||||||
// 5. Return image.
|
// 5. Return image.
|
||||||
return image;
|
return image;
|
||||||
|
@ -262,7 +279,9 @@ GC::Ref<WebIDL::Promise> OffscreenCanvas::convert_to_blob(Optional<ImageEncodeOp
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Let bitmap be a copy of this OffscreenCanvas object's bitmap.
|
// 4. Let bitmap be a copy of this OffscreenCanvas object's bitmap.
|
||||||
auto bitmap = MUST(m_bitmap->clone());
|
RefPtr<Gfx::Bitmap> bitmap;
|
||||||
|
if (m_bitmap)
|
||||||
|
bitmap = MUST(m_bitmap->clone());
|
||||||
|
|
||||||
// 5. Let result be a new promise object.
|
// 5. Let result be a new promise object.
|
||||||
auto result_promise = WebIDL::create_promise(realm());
|
auto result_promise = WebIDL::create_promise(realm());
|
||||||
|
|
|
@ -32,8 +32,7 @@ class OffscreenCanvas : public DOM::EventTarget
|
||||||
GC_DECLARE_ALLOCATOR(OffscreenCanvas);
|
GC_DECLARE_ALLOCATOR(OffscreenCanvas);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static GC::Ref<OffscreenCanvas> create(JS::Realm&, WebIDL::UnsignedLong width,
|
static GC::Ref<OffscreenCanvas> create(JS::Realm&, WebIDL::UnsignedLong width, WebIDL::UnsignedLong height);
|
||||||
WebIDL::UnsignedLong height);
|
|
||||||
|
|
||||||
static WebIDL::ExceptionOr<GC::Ref<OffscreenCanvas>> construct_impl(
|
static WebIDL::ExceptionOr<GC::Ref<OffscreenCanvas>> construct_impl(
|
||||||
JS::Realm&,
|
JS::Realm&,
|
||||||
|
@ -50,7 +49,7 @@ public:
|
||||||
WebIDL::UnsignedLong width() const;
|
WebIDL::UnsignedLong width() const;
|
||||||
WebIDL::UnsignedLong height() const;
|
WebIDL::UnsignedLong height() const;
|
||||||
|
|
||||||
NonnullRefPtr<Gfx::Bitmap> bitmap() const;
|
RefPtr<Gfx::Bitmap> bitmap() const;
|
||||||
|
|
||||||
WebIDL::ExceptionOr<void> set_width(WebIDL::UnsignedLong);
|
WebIDL::ExceptionOr<void> set_width(WebIDL::UnsignedLong);
|
||||||
WebIDL::ExceptionOr<void> set_height(WebIDL::UnsignedLong);
|
WebIDL::ExceptionOr<void> set_height(WebIDL::UnsignedLong);
|
||||||
|
@ -69,7 +68,7 @@ public:
|
||||||
GC::Ptr<WebIDL::CallbackType> oncontextrestored();
|
GC::Ptr<WebIDL::CallbackType> oncontextrestored();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OffscreenCanvas(JS::Realm&, NonnullRefPtr<Gfx::Bitmap> bitmap);
|
OffscreenCanvas(JS::Realm&, RefPtr<Gfx::Bitmap> bitmap);
|
||||||
|
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
@ -85,7 +84,7 @@ private:
|
||||||
|
|
||||||
Variant<GC::Ref<HTML::OffscreenCanvasRenderingContext2D>, GC::Ref<WebGL::WebGLRenderingContext>, GC::Ref<WebGL::WebGL2RenderingContext>, Empty> m_context;
|
Variant<GC::Ref<HTML::OffscreenCanvasRenderingContext2D>, GC::Ref<WebGL::WebGLRenderingContext>, GC::Ref<WebGL::WebGL2RenderingContext>, Empty> m_context;
|
||||||
|
|
||||||
NonnullRefPtr<Gfx::Bitmap> m_bitmap;
|
RefPtr<Gfx::Bitmap> m_bitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Pass Setting width/height IDL attributes to 0
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>OffscreenCanvas test: 2d.canvas.host.size.attributes.idl.set.zero</title>
|
||||||
|
<script src="../../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
|
||||||
|
|
||||||
|
<h1>2d.canvas.host.size.attributes.idl.set.zero</h1>
|
||||||
|
<p class="desc">Setting width/height IDL attributes to 0</p>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var t = async_test("Setting width/height IDL attributes to 0");
|
||||||
|
var t_pass = t.done.bind(t);
|
||||||
|
var t_fail = t.step_func(function(reason) {
|
||||||
|
throw reason;
|
||||||
|
});
|
||||||
|
t.step(function() {
|
||||||
|
|
||||||
|
var canvas = new OffscreenCanvas(100, 50);
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
canvas.width = 0;
|
||||||
|
canvas.height = 0;
|
||||||
|
_assertSame(canvas.width, 0, "canvas.width", "0");
|
||||||
|
_assertSame(canvas.height, 0, "canvas.height", "0");
|
||||||
|
t.done();
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue