limit range collection to container range

This commit is contained in:
Karl Seguin
2026-07-16 12:41:20 +08:00
parent 60abfbc4f9
commit 41823f06c4
5 changed files with 28 additions and 27 deletions

View File

@@ -269,17 +269,10 @@ pub fn blob(_: *const Factory, arena: Allocator, child: anytype) !*@TypeOf(child
return chain.get(1);
}
pub fn abstractRange(self: *const Factory, arena: Allocator, child: anytype, frame: *Frame) !*@TypeOf(child) {
return self.abstractRangeIn(arena, child, frame.document.asNode(), frame);
}
// `container` is the initial start/end container: per spec, createRange()
// initializes both boundary points to (document, 0) of the document it was
// called on, which is not necessarily the frame's main document.
pub fn abstractRangeIn(_: *const Factory, arena: Allocator, child: anytype, container: *Node, frame: *Frame) !*@TypeOf(child) {
pub fn abstractRange(_: *const Factory, arena: Allocator, child: anytype, frame: *Frame) !*@TypeOf(child) {
const chain = try PrototypeChain(&.{ AbstractRange, @TypeOf(child) }).allocate(arena);
const doc = container;
const doc = frame.document.asNode();
const abstract_range = chain.get(0);
abstract_range.* = AbstractRange{
._rc = .{},

View File

@@ -162,15 +162,14 @@ pub fn setLocation(self: *Document, url: [:0]const u8) !void {
return frame.scheduleNavigation(url, .{ .reason = .script, .kind = .{ .push = null } }, .{ .script = frame });
}
// Approximation of quirks mode: an HTML document without a doctype is in
// quirks mode. (Legacy doctypes that also trigger quirks are not detected.)
// Approximation of quirks mode: an HTML document without a doctype is in quirks mode.
pub fn isQuirksMode(self: *const Document) bool {
if (self._type != .html) {
return false;
}
var child = self._proto.firstChild();
while (child) |c| : (child = c.nextSibling()) {
if (c._type == .document_type) {
var it = self._proto.childrenIterator();
while (it.next()) |child| {
if (child._type == .document_type) {
return false;
}
}

View File

@@ -1402,8 +1402,7 @@ pub fn getElementsByClassName(self: *Node, class_name: []const u8, frame: *Frame
try class_names.append(arena, try frame.dupeString(name));
}
const doc: ?*Document = if (self._type == .document) self._type.document else self.ownerDocument(frame);
const quirks = if (doc) |d| d.isQuirksMode() else false;
const quirks = if (self.ownerDocumentIncludingSelf(frame)) |doc| doc.isQuirksMode() else false;
return collections.NodeLive(.class_name).init(self, .{
.names = class_names.items,
.case_insensitive = quirks,

View File

@@ -38,11 +38,15 @@ pub fn init(frame: *Frame) !*Range {
}
// Both boundary points start at (container, 0); document.createRange()
// passes the document it was called on.
// passes the document it was called on, which is not necessarily the
// frame's main document.
pub fn initIn(container: *Node, frame: *Frame) !*Range {
const arena = try frame.getArena(.medium, "Range");
errdefer frame.releaseArena(arena);
return frame._factory.abstractRangeIn(arena, Range{ ._proto = undefined }, container, frame);
const range = try frame._factory.abstractRange(arena, Range{ ._proto = undefined }, frame);
range._proto._start_container = container;
range._proto._end_container = container;
return range;
}
pub fn asAbstractRange(self: *Range) *AbstractRange {
@@ -452,11 +456,14 @@ pub fn deleteContents(self: *Range, frame: *Frame) !void {
// range's boundary points. Appends the top-most contained nodes (those whose
// parent isn't contained) under `node`, without descending into them.
fn collectContained(self: *const Range, node: *Node, list: *std.ArrayList(*Node), arena: std.mem.Allocator) !void {
var child = node.firstChild();
while (child) |c| : (child = c.nextSibling()) {
var it = node.childrenIterator();
while (it.next()) |c| {
if (self.nodeContained(c)) {
try list.append(arena, c);
} else {
} else if (c.contains(self._proto._start_container) or c.contains(self._proto._end_container)) {
// A non-contained child either straddles a boundary point or lies
// entirely outside the range; only the former can have contained
// descendants, so don't descend into the rest.
try self.collectContained(c, list, arena);
}
}

View File

@@ -187,14 +187,17 @@ pub fn classAttributeContains(class_attr: []const u8, class_name: []const u8) bo
}
pub fn classAttributeContainsCase(class_attr: []const u8, class_name: []const u8, case_insensitive: bool) bool {
if (class_name.len == 0 or class_name.len > class_attr.len) return false;
if (class_name.len == 0 or class_name.len > class_attr.len) {
return false;
}
var search = class_attr;
while (if (case_insensitive)
std.ascii.indexOfIgnoreCase(search, class_name)
else
std.mem.indexOf(u8, search, class_name)) |pos|
{
while (true) {
const pos = (if (case_insensitive)
std.ascii.indexOfIgnoreCase(search, class_name)
else
std.mem.indexOf(u8, search, class_name)) orelse break;
const is_start = pos == 0 or isClassWhitespace(search[pos - 1]);
const end = pos + class_name.len;
const is_end = end == search.len or isClassWhitespace(search[end]);