From 466cdb4ee70d134bf740cf71b0448be94edc15ad Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sat, 31 Jan 2026 10:44:56 +0800 Subject: [PATCH] improve correctness of CSS.escape --- src/browser/tests/css.html | 6 ++++-- src/browser/webapi/CSS.zig | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/browser/tests/css.html b/src/browser/tests/css.html index ac0b6aba..ee0db0e0 100644 --- a/src/browser/tests/css.html +++ b/src/browser/tests/css.html @@ -20,8 +20,10 @@ { testing.expectEqual('\\30 abc', CSS.escape('0abc')); testing.expectEqual('\\31 23', CSS.escape('123')); - testing.expectEqual('\\-test', CSS.escape('-test')); - testing.expectEqual('\\--test', CSS.escape('--test')); + testing.expectEqual('\\-', CSS.escape('-')); + testing.expectEqual('-test', CSS.escape('-test')); + testing.expectEqual('--test', CSS.escape('--test')); + testing.expectEqual('-\\33 ', CSS.escape('-3')); } diff --git a/src/browser/webapi/CSS.zig b/src/browser/webapi/CSS.zig index a2f320f7..2eed5cf3 100644 --- a/src/browser/webapi/CSS.zig +++ b/src/browser/webapi/CSS.zig @@ -42,15 +42,23 @@ pub fn parseDimension(value: []const u8) ?f64 { /// https://drafts.csswg.org/cssom/#the-css.escape()-method pub fn escape(_: *const CSS, value: []const u8, page: *Page) ![]const u8 { if (value.len == 0) { - return error.InvalidCharacterError; + return ""; } const first = value[0]; + if (first == '-' and value.len == 1) { + return "\\-"; + } // Count how many characters we need for the output var out_len: usize = escapeLen(true, first); - for (value[1..]) |c| { - out_len += escapeLen(false, c); + for (value[1..], 0..) |c, i| { + // Second char (i==0) is a digit and first is '-', needs hex escape + if (i == 0 and first == '-' and c >= '0' and c <= '9') { + out_len += 2 + hexDigitsNeeded(c); + } else { + out_len += escapeLen(false, c); + } } if (out_len == value.len) { @@ -67,8 +75,13 @@ pub fn escape(_: *const CSS, value: []const u8, page: *Page) ![]const u8 { pos = 1; } - for (value[1..]) |c| { - if (!needsEscape(false, c)) { + for (value[1..], 0..) |c, i| { + // Second char (i==0) is a digit and first is '-', needs hex escape + if (i == 0 and first == '-' and c >= '0' and c <= '9') { + result[pos] = '\\'; + const hex_str = std.fmt.bufPrint(result[pos + 1 ..], "{x} ", .{c}) catch unreachable; + pos += 1 + hex_str.len; + } else if (!needsEscape(false, c)) { result[pos] = c; pos += 1; } else { @@ -105,9 +118,6 @@ fn needsEscape(comptime is_first: bool, c: u8) bool { if (c >= '0' and c <= '9') { return true; } - if (c == '-') { - return true; - } } // Characters that need escaping