From 350586335dd507c98000edc7cdbe77822e2da262 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Tue, 17 Feb 2026 02:21:36 +0300 Subject: [PATCH 1/5] add `createImageData` and `putImageData` to `CanvasReneringContext2D` --- .../canvas/CanvasRenderingContext2D.zig | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/browser/webapi/canvas/CanvasRenderingContext2D.zig b/src/browser/webapi/canvas/CanvasRenderingContext2D.zig index 0c5ca1e7..eb351e43 100644 --- a/src/browser/webapi/canvas/CanvasRenderingContext2D.zig +++ b/src/browser/webapi/canvas/CanvasRenderingContext2D.zig @@ -23,6 +23,8 @@ const js = @import("../../js/js.zig"); const color = @import("../../color.zig"); const Page = @import("../../Page.zig"); +const ImageData = @import("../ImageData.zig"); + /// This class doesn't implement a `constructor`. /// It can be obtained with a call to `HTMLCanvasElement#getContext`. /// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D @@ -85,6 +87,35 @@ pub fn getTextBaseline(_: *const CanvasRenderingContext2D) []const u8 { return "alphabetic"; } +const WidthOrImageData = union(enum) { + width: u32, + image_data: *ImageData, +}; + +pub fn createImageData( + _: *const CanvasRenderingContext2D, + width_or_image_data: WidthOrImageData, + /// If `ImageData` variant preferred, this is null. + maybe_height: ?u32, + /// Can be used if width and height provided. + maybe_settings: ?ImageData.ConstructorSettings, + page: *Page, +) !*ImageData { + switch (width_or_image_data) { + .width => |width| { + const height = maybe_height orelse return error.TypeError; + return ImageData.constructor(width, height, maybe_settings, page); + }, + .image_data => |image_data| { + return ImageData.constructor(image_data._width, image_data._height, null, page); + }, + } + + unreachable; +} + +pub fn putImageData(_: *const CanvasRenderingContext2D, _: *ImageData, _: f64, _: f64, _: ?f64, _: ?f64, _: ?f64, _: ?f64) void {} + pub fn save(_: *CanvasRenderingContext2D) void {} pub fn restore(_: *CanvasRenderingContext2D) void {} pub fn scale(_: *CanvasRenderingContext2D, _: f64, _: f64) void {} @@ -131,6 +162,9 @@ pub const JsApi = struct { pub var class_id: bridge.ClassId = undefined; }; + pub const createImageData = bridge.function(CanvasRenderingContext2D.createImageData, .{ .dom_exception = true }); + pub const putImageData = bridge.function(CanvasRenderingContext2D.putImageData, .{}); + pub const save = bridge.function(CanvasRenderingContext2D.save, .{}); pub const restore = bridge.function(CanvasRenderingContext2D.restore, .{}); From 16318bb9f6152d292a8b5230419377152cdece9d Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Tue, 17 Feb 2026 02:53:17 +0300 Subject: [PATCH 2/5] add tests --- .../canvas/canvas_rendering_context_2d.html | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/browser/tests/canvas/canvas_rendering_context_2d.html b/src/browser/tests/canvas/canvas_rendering_context_2d.html index 22bcaa20..91158022 100644 --- a/src/browser/tests/canvas/canvas_rendering_context_2d.html +++ b/src/browser/tests/canvas/canvas_rendering_context_2d.html @@ -33,3 +33,57 @@ testing.expectEqual(ctx.fillStyle, "rgba(255, 0, 0, 0.06)"); } + + + + + + From 1023b2ca9c4c4db707b761c493ca4de4d7d6c261 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Tue, 17 Feb 2026 16:43:26 +0300 Subject: [PATCH 3/5] test blocks need at least a single assertion --- src/browser/tests/canvas/canvas_rendering_context_2d.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/browser/tests/canvas/canvas_rendering_context_2d.html b/src/browser/tests/canvas/canvas_rendering_context_2d.html index 91158022..701fbdef 100644 --- a/src/browser/tests/canvas/canvas_rendering_context_2d.html +++ b/src/browser/tests/canvas/canvas_rendering_context_2d.html @@ -74,6 +74,7 @@ const ctx = element.getContext("2d"); const imageData = ctx.createImageData(10, 10); + testing.expectEqual(true, imageData instanceof ImageData); // Modify some pixel data. imageData.data[0] = 255; imageData.data[1] = 0; From 944f34b833dccfd87b50886ec31a27bbc76afa96 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Wed, 18 Feb 2026 21:48:35 +0300 Subject: [PATCH 4/5] `createImageData`: remove unnecessary `unreachable` --- src/browser/webapi/canvas/CanvasRenderingContext2D.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/browser/webapi/canvas/CanvasRenderingContext2D.zig b/src/browser/webapi/canvas/CanvasRenderingContext2D.zig index eb351e43..f9aa0b18 100644 --- a/src/browser/webapi/canvas/CanvasRenderingContext2D.zig +++ b/src/browser/webapi/canvas/CanvasRenderingContext2D.zig @@ -110,8 +110,6 @@ pub fn createImageData( return ImageData.constructor(image_data._width, image_data._height, null, page); }, } - - unreachable; } pub fn putImageData(_: *const CanvasRenderingContext2D, _: *ImageData, _: f64, _: f64, _: ?f64, _: ?f64, _: ?f64, _: ?f64) void {} From 96cfdebced9ce884320510b11e64fd6e23913965 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Thu, 19 Feb 2026 12:02:50 +0300 Subject: [PATCH 5/5] `ImageData#constructor`: check bounds of dimensions + don't overflow size Also adds a related `too-large` test. --- src/browser/tests/image_data.html | 8 ++++---- src/browser/webapi/ImageData.zig | 11 +++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/browser/tests/image_data.html b/src/browser/tests/image_data.html index ccaef668..3cf3282e 100644 --- a/src/browser/tests/image_data.html +++ b/src/browser/tests/image_data.html @@ -59,10 +59,6 @@ } - + + diff --git a/src/browser/webapi/ImageData.zig b/src/browser/webapi/ImageData.zig index 05fcae6c..c9ced5f1 100644 --- a/src/browser/webapi/ImageData.zig +++ b/src/browser/webapi/ImageData.zig @@ -58,7 +58,10 @@ pub fn constructor( maybe_settings: ?ConstructorSettings, page: *Page, ) !*ImageData { - if (width == 0 or height == 0) { + // Though arguments are unsigned long, these are capped to max. i32 on Chrome. + // https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/html/canvas/image_data.cc#L61 + const max_i32 = std.math.maxInt(i32); + if (width == 0 or width > max_i32 or height == 0 or height > max_i32) { return error.IndexSizeError; } @@ -70,7 +73,11 @@ pub fn constructor( return error.TypeError; } - const size = width * height * 4; + var size, var overflown = @mulWithOverflow(width, height); + if (overflown == 1) return error.IndexSizeError; + size, overflown = @mulWithOverflow(size, 4); + if (overflown == 1) return error.IndexSizeError; + return page._factory.create(ImageData{ ._width = width, ._height = height,