From ff3a9c51f3ffce38a9e4e039dc96f1ed1635c54c Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sun, 16 Nov 2025 07:40:07 +0800 Subject: [PATCH] add remove_from_parent html5ever callback --- src/browser/parser/Parser.zig | 22 +++++++++++++++++++--- src/browser/parser/html5ever.zig | 3 +++ src/html5ever/lib.rs | 6 ++++++ src/html5ever/sink.rs | 6 ++++-- src/html5ever/types.rs | 2 ++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/browser/parser/Parser.zig b/src/browser/parser/Parser.zig index efb85ab3..28649758 100644 --- a/src/browser/parser/Parser.zig +++ b/src/browser/parser/Parser.zig @@ -67,6 +67,7 @@ const Error = struct { append_doctype_to_document, add_attrs_if_missing, get_template_content, + remove_from_parent, }; }; @@ -84,7 +85,8 @@ pub fn parse(self: *Parser, html: []const u8) void { createCommentCallback, appendDoctypeToDocument, addAttrsIfMissingCallback, - getTemplateContentsCallback + getTemplateContentsCallback, + removeFromParentCallback, ); } @@ -102,7 +104,8 @@ pub fn parseFragment(self: *Parser, html: []const u8) void { createCommentCallback, appendDoctypeToDocument, addAttrsIfMissingCallback, - getTemplateContentsCallback + getTemplateContentsCallback, + removeFromParentCallback, ); } @@ -137,7 +140,8 @@ pub const Streaming = struct { createCommentCallback, appendDoctypeToDocument, addAttrsIfMissingCallback, - getTemplateContentsCallback + getTemplateContentsCallback, + removeFromParentCallback, ) orelse return error.ParserCreationFailed; } @@ -298,6 +302,18 @@ fn _appendCallback(self: *Parser, parent: *Node, node_or_text: h5e.NodeOrText) ! } } +fn removeFromParentCallback(ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) void { + const self: *Parser = @ptrCast(@alignCast(ctx)); + self._removeFromParentCallback(getNode(target_ref)) catch |err| { + self.err = .{ .err = err, .source = .remove_from_parent }; + }; +} + +fn _removeFromParentCallback(self: *Parser, node: *Node) !void { + const parent = node.parentNode() orelse return; + _ = try parent.removeChild(node, self.page); +} + fn getNode(ref: *anyopaque) *Node { const pn: *ParsedNode = @ptrCast(@alignCast(ref)); return pn.node; diff --git a/src/browser/parser/html5ever.zig b/src/browser/parser/html5ever.zig index 411d35e7..bec5ebcf 100644 --- a/src/browser/parser/html5ever.zig +++ b/src/browser/parser/html5ever.zig @@ -32,6 +32,7 @@ pub extern "c" fn html5ever_parse_document( appendDoctypeToDocument: *const fn (ctx: *anyopaque, StringSlice, StringSlice, StringSlice) callconv(.c) void, addAttrsIfMissingCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque, AttributeIterator) callconv(.c) void, getTemplateContentsCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) ?*anyopaque, + removeFromParentCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) void, ) void; pub extern "c" fn html5ever_parse_fragment( @@ -48,6 +49,7 @@ pub extern "c" fn html5ever_parse_fragment( appendDoctypeToDocument: *const fn (ctx: *anyopaque, StringSlice, StringSlice, StringSlice) callconv(.c) void, addAttrsIfMissingCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque, AttributeIterator) callconv(.c) void, getTemplateContentsCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) ?*anyopaque, + removeFromParentCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) void, ) void; pub extern "c" fn html5ever_attribute_iterator_next(ctx: *anyopaque) Nullable(Attribute); @@ -73,6 +75,7 @@ pub extern "c" fn html5ever_streaming_parser_create( appendDoctypeToDocument: *const fn (ctx: *anyopaque, StringSlice, StringSlice, StringSlice) callconv(.c) void, addAttrsIfMissingCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque, AttributeIterator) callconv(.c) void, getTemplateContentsCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) ?*anyopaque, + removeFromParentCallback: *const fn (ctx: *anyopaque, target_ref: *anyopaque) callconv(.c) void, ) ?*anyopaque; pub extern "c" fn html5ever_streaming_parser_feed( diff --git a/src/html5ever/lib.rs b/src/html5ever/lib.rs index f2d06ab1..7c74df00 100644 --- a/src/html5ever/lib.rs +++ b/src/html5ever/lib.rs @@ -46,6 +46,7 @@ pub extern "C" fn html5ever_parse_document( append_doctype_to_document: AppendDoctypeToDocumentCallback, add_attrs_if_missing_callback: AddAttrsIfMissingCallback, get_template_contents_callback: GetTemplateContentsCallback, + remove_from_parent_callback: RemoveFromParentCallback, ) -> () { if html.is_null() || len == 0 { return (); @@ -67,6 +68,7 @@ pub extern "C" fn html5ever_parse_document( append_doctype_to_document: append_doctype_to_document, add_attrs_if_missing_callback: add_attrs_if_missing_callback, get_template_contents_callback: get_template_contents_callback, + remove_from_parent_callback: remove_from_parent_callback, }; let bytes = unsafe { std::slice::from_raw_parts(html, len) }; @@ -90,6 +92,7 @@ pub extern "C" fn html5ever_parse_fragment( append_doctype_to_document: AppendDoctypeToDocumentCallback, add_attrs_if_missing_callback: AddAttrsIfMissingCallback, get_template_contents_callback: GetTemplateContentsCallback, + remove_from_parent_callback: RemoveFromParentCallback, ) -> () { if html.is_null() || len == 0 { return (); @@ -111,6 +114,7 @@ pub extern "C" fn html5ever_parse_fragment( append_doctype_to_document: append_doctype_to_document, add_attrs_if_missing_callback: add_attrs_if_missing_callback, get_template_contents_callback: get_template_contents_callback, + remove_from_parent_callback: remove_from_parent_callback, }; let bytes = unsafe { std::slice::from_raw_parts(html, len) }; @@ -193,6 +197,7 @@ pub extern "C" fn html5ever_streaming_parser_create( append_doctype_to_document: AppendDoctypeToDocumentCallback, add_attrs_if_missing_callback: AddAttrsIfMissingCallback, get_template_contents_callback: GetTemplateContentsCallback, + remove_from_parent_callback: RemoveFromParentCallback, ) -> *mut c_void { let arena = Box::new(typed_arena::Arena::new()); @@ -217,6 +222,7 @@ pub extern "C" fn html5ever_streaming_parser_create( append_doctype_to_document: append_doctype_to_document, add_attrs_if_missing_callback: add_attrs_if_missing_callback, get_template_contents_callback: get_template_contents_callback, + remove_from_parent_callback: remove_from_parent_callback, }; // Create a parser which implements TendrilSink for streaming parsing diff --git a/src/html5ever/sink.rs b/src/html5ever/sink.rs index 27f1ef9c..f947e1f1 100644 --- a/src/html5ever/sink.rs +++ b/src/html5ever/sink.rs @@ -57,6 +57,7 @@ pub struct Sink<'arena> { pub append_doctype_to_document: AppendDoctypeToDocumentCallback, pub add_attrs_if_missing_callback: AddAttrsIfMissingCallback, pub get_template_contents_callback: GetTemplateContentsCallback, + pub remove_from_parent_callback: RemoveFromParentCallback, } impl<'arena> TreeSink for Sink<'arena> { @@ -228,8 +229,9 @@ impl<'arena> TreeSink for Sink<'arena> { } fn remove_from_parent(&self, target: &Ref) { - _ = target; - panic!("remove_from_parent"); + unsafe { + (self.remove_from_parent_callback)(self.ctx, *target); + } } fn reparent_children(&self, node: &Ref, new_parent: &Ref) { diff --git a/src/html5ever/types.rs b/src/html5ever/types.rs index 71c5f8eb..4c7b364d 100644 --- a/src/html5ever/types.rs +++ b/src/html5ever/types.rs @@ -59,6 +59,8 @@ pub type AddAttrsIfMissingCallback = unsafe extern "C" fn( pub type GetTemplateContentsCallback = unsafe extern "C" fn(ctx: Ref, target: Ref) -> Ref; +pub type RemoveFromParentCallback = unsafe extern "C" fn(ctx: Ref, target: Ref) -> (); + pub type Ref = *const c_void; #[repr(C)]