implement html5ever append_based_on_parent_node and append_before_sibling

This commit is contained in:
Karl Seguin
2025-12-24 07:37:21 +08:00
parent 0ca97d01ac
commit 9969ff7165
6 changed files with 121 additions and 12 deletions

View File

@@ -49,6 +49,8 @@ pub extern "C" fn html5ever_parse_document(
get_template_contents_callback: GetTemplateContentsCallback,
remove_from_parent_callback: RemoveFromParentCallback,
reparent_children_callback: ReparentChildrenCallback,
append_before_sibling_callback: AppendBeforeSiblingCallback,
append_based_on_parent_node_callback: AppendBasedOnParentNodeCallback,
) -> () {
if html.is_null() || len == 0 {
return ();
@@ -73,6 +75,8 @@ pub extern "C" fn html5ever_parse_document(
get_template_contents_callback: get_template_contents_callback,
remove_from_parent_callback: remove_from_parent_callback,
reparent_children_callback: reparent_children_callback,
append_before_sibling_callback: append_before_sibling_callback,
append_based_on_parent_node_callback: append_based_on_parent_node_callback,
};
let bytes = unsafe { std::slice::from_raw_parts(html, len) };
@@ -99,6 +103,8 @@ pub extern "C" fn html5ever_parse_fragment(
get_template_contents_callback: GetTemplateContentsCallback,
remove_from_parent_callback: RemoveFromParentCallback,
reparent_children_callback: ReparentChildrenCallback,
append_before_sibling_callback: AppendBeforeSiblingCallback,
append_based_on_parent_node_callback: AppendBasedOnParentNodeCallback,
) -> () {
if html.is_null() || len == 0 {
return ();
@@ -123,6 +129,8 @@ pub extern "C" fn html5ever_parse_fragment(
get_template_contents_callback: get_template_contents_callback,
remove_from_parent_callback: remove_from_parent_callback,
reparent_children_callback: reparent_children_callback,
append_before_sibling_callback: append_before_sibling_callback,
append_based_on_parent_node_callback: append_based_on_parent_node_callback,
};
let bytes = unsafe { std::slice::from_raw_parts(html, len) };
@@ -209,6 +217,8 @@ pub extern "C" fn html5ever_streaming_parser_create(
get_template_contents_callback: GetTemplateContentsCallback,
remove_from_parent_callback: RemoveFromParentCallback,
reparent_children_callback: ReparentChildrenCallback,
append_before_sibling_callback: AppendBeforeSiblingCallback,
append_based_on_parent_node_callback: AppendBasedOnParentNodeCallback,
) -> *mut c_void {
let arena = Box::new(typed_arena::Arena::new());
@@ -236,6 +246,8 @@ pub extern "C" fn html5ever_streaming_parser_create(
get_template_contents_callback: get_template_contents_callback,
remove_from_parent_callback: remove_from_parent_callback,
reparent_children_callback: reparent_children_callback,
append_before_sibling_callback: append_before_sibling_callback,
append_based_on_parent_node_callback: append_based_on_parent_node_callback,
};
// Create a parser which implements TendrilSink for streaming parsing

View File

@@ -60,6 +60,8 @@ pub struct Sink<'arena> {
pub get_template_contents_callback: GetTemplateContentsCallback,
pub remove_from_parent_callback: RemoveFromParentCallback,
pub reparent_children_callback: ReparentChildrenCallback,
pub append_before_sibling_callback: AppendBeforeSiblingCallback,
pub append_based_on_parent_node_callback: AppendBasedOnParentNodeCallback,
}
impl<'arena> TreeSink for Sink<'arena> {
@@ -189,9 +191,30 @@ impl<'arena> TreeSink for Sink<'arena> {
}
fn append_before_sibling(&self, sibling: &Ref, child: NodeOrText<Ref>) {
_ = sibling;
_ = child;
panic!("append_before_sibling");
match child {
NodeOrText::AppendText(ref t) => {
let byte_slice = t.as_ref().as_bytes();
let static_slice: &'static [u8] = unsafe {
std::mem::transmute(byte_slice)
};
unsafe {
(self.append_before_sibling_callback)(self.ctx, *sibling, CNodeOrText{
tag: 1,
node: ptr::null(),
text: StringSlice { ptr: static_slice.as_ptr(), len: static_slice.len()},
});
};
},
NodeOrText::AppendNode(node) => {
unsafe {
(self.append_before_sibling_callback)(self.ctx, *sibling, CNodeOrText{
tag: 0,
node: node,
text: StringSlice::default()
});
};
}
}
}
fn append_based_on_parent_node(
@@ -200,10 +223,30 @@ impl<'arena> TreeSink for Sink<'arena> {
prev_element: &Ref,
child: NodeOrText<Ref>,
) {
_ = element;
_ = prev_element;
_ = child;
panic!("append_based_on_parent_node");
match child {
NodeOrText::AppendText(ref t) => {
let byte_slice = t.as_ref().as_bytes();
let static_slice: &'static [u8] = unsafe {
std::mem::transmute(byte_slice)
};
unsafe {
(self.append_based_on_parent_node_callback)(self.ctx, *element, *prev_element, CNodeOrText{
tag: 1,
node: ptr::null(),
text: StringSlice { ptr: static_slice.as_ptr(), len: static_slice.len()},
});
};
},
NodeOrText::AppendNode(node) => {
unsafe {
(self.append_based_on_parent_node_callback)(self.ctx, *element, *prev_element, CNodeOrText{
tag: 0,
node: node,
text: StringSlice::default()
});
};
}
}
}
fn append_doctype_to_document(

View File

@@ -69,6 +69,19 @@ pub type RemoveFromParentCallback = unsafe extern "C" fn(ctx: Ref, target: Ref)
pub type ReparentChildrenCallback = unsafe extern "C" fn(ctx: Ref, node: Ref, new_parent: Ref) -> ();
pub type AppendBeforeSiblingCallback = unsafe extern "C" fn(
ctx: Ref,
sibling: Ref,
node_or_text: CNodeOrText
) -> ();
pub type AppendBasedOnParentNodeCallback = unsafe extern "C" fn(
ctx: Ref,
element: Ref,
prev_element: Ref,
node_or_text: CNodeOrText
) -> ();
pub type Ref = *const c_void;
#[repr(C)]