Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion html5ever/examples/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct Node<'arena> {
}

/// HTML node data which can be an element, a comment, a string, a DOCTYPE, etc...
#[derive(Clone)]
pub enum NodeData<'arena> {
Document,
Doctype {
Expand Down Expand Up @@ -338,6 +339,21 @@ impl<'arena> TreeSink for Sink<'arena> {
new_parent.append(child)
}
}

fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
// Allocate the new node in the arena using Clone
let cloned_node = self.arena.alloc(Node::new(node.data.clone()));

// Clone all children and append them
let mut child = node.first_child.get();
while let Some(current_child) = child {
let cloned_child = self.clone_subtree(&current_child);
cloned_node.append(cloned_child);
child = current_child.next_sibling.get();
}

cloned_node
}
}

/// In this example an "arena" is created and filled with the DOM nodes.
Expand All @@ -352,5 +368,33 @@ fn main() {
io::stdin().read_to_end(&mut bytes).unwrap();

let arena = typed_arena::Arena::new();
html5ever_parse_slice_into_arena(&bytes, &arena);
let dom = html5ever_parse_slice_into_arena(&bytes, &arena);

// Print the DOM structure
print_node(dom, 0);
}

fn print_node<'arena>(node: &Node<'arena>, depth: usize) {
let indent = " ".repeat(depth);

match &node.data {
NodeData::Document => println!("{}Document", indent),
NodeData::Doctype { name, .. } => println!("{}<!DOCTYPE {}>", indent, name),
NodeData::Text { contents } => {
let text = contents.borrow();
if !text.trim().is_empty() {
println!("{}\"{}\"", indent, text.trim());
}
},
NodeData::Comment { contents } => println!("{}<!-- {} -->", indent, contents),
NodeData::Element { name, .. } => println!("{}<{}>", indent, name.local),
NodeData::ProcessingInstruction { target, .. } => println!("{}<?{}>", indent, target),
}

// Print all children
let mut child = node.first_child.get();
while let Some(current_child) = child {
print_node(current_child, depth + 1);
child = current_child.next_sibling.get();
}
}
5 changes: 5 additions & 0 deletions html5ever/examples/noop-tree-builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ impl TreeSink for Sink {
fn remove_from_parent(&self, _target: &usize) {}
fn reparent_children(&self, _node: &usize, _new_parent: &usize) {}
fn mark_script_already_started(&self, _node: &usize) {}

fn clone_subtree(&self, _node: &Self::Handle) -> Self::Handle {
// For this noop example, just return a new placeholder ID
self.get_id()
}
}

/// In this example we implement the TreeSink trait which takes each parsed elements and insert
Expand Down
6 changes: 6 additions & 0 deletions html5ever/examples/print-tree-actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ impl TreeSink for Sink {
fn pop(&self, elem: &usize) {
println!("Popped element {elem}");
}

fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
println!("Clone subtree for node {node}");
// For this example, just return a new placeholder ID
self.get_id()
}
}

/// Same example as the "noop-tree-builder", but this time every function implemented in our
Expand Down
40 changes: 30 additions & 10 deletions html5ever/src/tree_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ pub struct TreeBuilder<Handle, Sink> {

/// Form element pointer.
form_elem: RefCell<Option<Handle>>,

/// selectedcontent element pointer.
selectedcontent_elem: RefCell<Option<Handle>>,
//§ END
/// Frameset-ok flag.
frameset_ok: Cell<bool>,
Expand Down Expand Up @@ -163,6 +166,7 @@ where
active_formatting: Default::default(),
head_elem: Default::default(),
form_elem: Default::default(),
selectedcontent_elem: Default::default(),
frameset_ok: Cell::new(true),
ignore_lf: Default::default(),
foster_parenting: Default::default(),
Expand Down Expand Up @@ -203,6 +207,7 @@ where
active_formatting: Default::default(),
head_elem: Default::default(),
form_elem: RefCell::new(form_elem),
selectedcontent_elem: Default::default(),
frameset_ok: Cell::new(true),
ignore_lf: Default::default(),
foster_parenting: Default::default(),
Expand Down Expand Up @@ -285,6 +290,10 @@ where
tracer.trace_handle(form_elem);
}

if let Some(selectedcontent_elem) = self.selectedcontent_elem.borrow().as_ref() {
tracer.trace_handle(selectedcontent_elem);
}

if let Some(context_elem) = self.context_elem.borrow().as_ref() {
tracer.trace_handle(context_elem);
}
Expand Down Expand Up @@ -923,6 +932,7 @@ where
.borrow_mut()
.pop()
.expect("no current element");

self.sink.pop(&elem);
elem
}
Expand Down Expand Up @@ -1183,6 +1193,7 @@ where
n
}

/// Pop element until an element with the given name has been popped.
fn pop_until_named(&self, name: LocalName) -> usize {
self.pop_until(|p| *p.ns == ns!(html) && *p.local == name)
}
Expand Down Expand Up @@ -1269,16 +1280,6 @@ where
_ => continue,
};
match *name {
local_name!("select") => {
for ancestor in self.open_elems.borrow()[0..i].iter().rev() {
if self.html_elem_named(ancestor, local_name!("template")) {
return InsertionMode::InSelect;
} else if self.html_elem_named(ancestor, local_name!("table")) {
return InsertionMode::InSelectInTable;
}
}
return InsertionMode::InSelect;
},
local_name!("td") | local_name!("th") => {
if !last {
return InsertionMode::InCell;
Expand Down Expand Up @@ -1401,6 +1402,12 @@ where

self.insert_at(insertion_point, AppendNode(elem.clone()));

if qname.local == local_name!("selectedcontent")
&& self.selectedcontent_elem.borrow().is_none()
{
*self.selectedcontent_elem.borrow_mut() = Some(elem.clone());
}

match push {
PushFlag::Push => self.push(&elem),
PushFlag::NoPush => (),
Expand Down Expand Up @@ -1585,6 +1592,19 @@ where
self.remove_from_stack(&node);
}

fn maybe_clone_option_into_selectedcontent(&self, option: &Handle) {
if let Some(selectedcontent) = self.selectedcontent_elem.borrow().as_ref().cloned() {
self.clone_option_into_selectedcontent(option, &selectedcontent);
}
}

fn clone_option_into_selectedcontent(&self, option: &Handle, selectedcontent: &Handle) {
self.sink
.reparent_children(selectedcontent, &self.sink.get_document());
let cloned_option = self.sink.clone_subtree(option);
self.sink.reparent_children(&cloned_option, selectedcontent);
}

//§ tree-construction
fn is_foreign(&self, token: &Token) -> bool {
if let Token::Eof = *token {
Expand Down
Loading