Clamp insert index

Because we don't fully process CSS, indexes that code expect might be out of
bounds. The specific case comes from https://github.com/lightpanda-io/browser/issues/2214
which uses fullcalender library. This library uses a @font-face which we do not
process and thus end up with incorrect indexes. As a quick workaround aligned
with previous fixes for these types of cases (and what the original issue
recommended), we simply clamp the index.
This commit is contained in:
Karl Seguin
2026-04-23 11:23:37 +08:00
parent cd40491267
commit e68dd2b284
2 changed files with 34 additions and 2 deletions

View File

@@ -498,6 +498,28 @@
}
</script>
<script id="CSSStyleSheet_insertRule_out_of_range_index">
{
// Our lack of fully processing sources (e.g. @import, @font-face) means that
// our indexes are sometimes not what libraries expect. As a workaround we
// clamp the index to the end of the rule list. See #2214.
const style = document.createElement('style');
document.head.appendChild(style);
const sheet = style.sheet;
const returned = sheet.insertRule('.out-of-range { color: red; }', 99);
testing.expectEqual(0, returned);
testing.expectEqual(1, sheet.cssRules.length);
testing.expectEqual('.out-of-range', sheet.cssRules[0].selectorText);
// And at the tail of a non-empty sheet
const tail = sheet.insertRule('.tail { color: blue; }', 99);
testing.expectEqual(1, tail);
testing.expectEqual(2, sheet.cssRules.length);
testing.expectEqual('.tail', sheet.cssRules[1].selectorText);
}
</script>
<script id="CSSStyleSheet_replaceSync">
{
const sheet = new CSSStyleSheet();

View File

@@ -79,7 +79,7 @@ pub fn getOwnerRule(self: *const CSSStyleSheet) ?*CSSRule {
}
pub fn insertRule(self: *CSSStyleSheet, rule: []const u8, maybe_index: ?u32, frame: *Frame) !u32 {
const index = maybe_index orelse 0;
const requested_index = maybe_index orelse 0;
var it = Parser.parseStylesheet(rule);
const parsed_rule = it.next() orelse {
if (it.has_skipped_at_rule) {
@@ -88,7 +88,7 @@ pub fn insertRule(self: *CSSStyleSheet, rule: []const u8, maybe_index: ?u32, fra
// CSS parser. To prevent JS apps (like Expo/Reanimated) from crashing
// during initialization, we simulate a successful insertion by returning
// the requested index.
return index;
return requested_index;
}
return error.SyntaxError;
};
@@ -103,6 +103,16 @@ pub fn insertRule(self: *CSSStyleSheet, rule: []const u8, maybe_index: ?u32, fra
try style.setCssText(parsed_rule.block, frame);
const rules = try self.getCssRules(frame);
// Per spec, an index > rules.length should throw IndexSizeError. But because
// we don't process @import and @font-face, indexes that code hard-codes can
// be off. As a workaround, we clamp to the tail.
// See #2214 (and the sibling #1970 / #1972 tolerance for at-rules).
const length = rules.length();
const index = if (requested_index > length) length else requested_index;
if (index != requested_index) {
log.debug(.not_implemented, "insertRule clamped index", .{});
}
try rules.insert(index, style_rule._proto, frame);
// Notify StyleManager that rules have changed