Skip to content

Commit ceb4db3

Browse files
committed
wip
1 parent 2c7511d commit ceb4db3

File tree

9 files changed

+138
-3
lines changed

9 files changed

+138
-3
lines changed

html5ever/examples/arena.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub struct Node<'arena> {
5555
}
5656

5757
/// HTML node data which can be an element, a comment, a string, a DOCTYPE, etc...
58+
#[derive(Clone)]
5859
pub enum NodeData<'arena> {
5960
Document,
6061
Doctype {
@@ -338,8 +339,25 @@ impl<'arena> TreeSink for Sink<'arena> {
338339
new_parent.append(child)
339340
}
340341
}
342+
343+
fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
344+
// Allocate the new node in the arena using Clone
345+
let cloned_node = self.arena.alloc(Node::new(node.data.clone()));
346+
347+
// Clone all children and append them
348+
let mut child = node.first_child.get();
349+
while let Some(current_child) = child {
350+
let cloned_child = self.clone_subtree(&current_child);
351+
cloned_node.append(cloned_child);
352+
child = current_child.next_sibling.get();
353+
}
354+
355+
cloned_node
356+
}
357+
341358
}
342359

360+
343361
/// In this example an "arena" is created and filled with the DOM nodes.
344362
/// "Arena" is a type of allocation in which a block of memory is allocated
345363
/// and later filled with data, DOM nodes in this case. When the arena is deallocated
@@ -352,5 +370,33 @@ fn main() {
352370
io::stdin().read_to_end(&mut bytes).unwrap();
353371

354372
let arena = typed_arena::Arena::new();
355-
html5ever_parse_slice_into_arena(&bytes, &arena);
373+
let dom = html5ever_parse_slice_into_arena(&bytes, &arena);
374+
375+
// Print the DOM structure
376+
print_node(dom, 0);
377+
}
378+
379+
fn print_node<'arena>(node: &Node<'arena>, depth: usize) {
380+
let indent = " ".repeat(depth);
381+
382+
match &node.data {
383+
NodeData::Document => println!("{}Document", indent),
384+
NodeData::Doctype { name, .. } => println!("{}<!DOCTYPE {}>", indent, name),
385+
NodeData::Text { contents } => {
386+
let text = contents.borrow();
387+
if !text.trim().is_empty() {
388+
println!("{}\"{}\"", indent, text.trim());
389+
}
390+
}
391+
NodeData::Comment { contents } => println!("{}<!-- {} -->", indent, contents),
392+
NodeData::Element { name, .. } => println!("{}<{}>", indent, name.local),
393+
NodeData::ProcessingInstruction { target, .. } => println!("{}<?{}>", indent, target),
394+
}
395+
396+
// Print all children
397+
let mut child = node.first_child.get();
398+
while let Some(current_child) = child {
399+
print_node(current_child, depth + 1);
400+
child = current_child.next_sibling.get();
401+
}
356402
}

html5ever/examples/noop-tree-builder.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ impl TreeSink for Sink {
113113
fn remove_from_parent(&self, _target: &usize) {}
114114
fn reparent_children(&self, _node: &usize, _new_parent: &usize) {}
115115
fn mark_script_already_started(&self, _node: &usize) {}
116+
117+
fn clone_subtree(&self, _node: &Self::Handle) -> Self::Handle {
118+
// For this noop example, just return a new placeholder ID
119+
self.get_id()
120+
}
121+
116122
}
117123

118124
/// In this example we implement the TreeSink trait which takes each parsed elements and insert

html5ever/examples/print-tree-actions.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ impl TreeSink for Sink {
167167
fn pop(&self, elem: &usize) {
168168
println!("Popped element {elem}");
169169
}
170+
171+
fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
172+
println!("Clone subtree for node {node}");
173+
// For this example, just return a new placeholder ID
174+
self.get_id()
175+
}
176+
170177
}
171178

172179
/// Same example as the "noop-tree-builder", but this time every function implemented in our

html5ever/src/tree_builder/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ pub struct TreeBuilder<Handle, Sink> {
118118

119119
/// Form element pointer.
120120
form_elem: RefCell<Option<Handle>>,
121+
122+
/// selectedcontent element pointer.
123+
selectedcontent_elem: RefCell<Option<Handle>>,
121124
//§ END
122125
/// Frameset-ok flag.
123126
frameset_ok: Cell<bool>,
@@ -163,6 +166,7 @@ where
163166
active_formatting: Default::default(),
164167
head_elem: Default::default(),
165168
form_elem: Default::default(),
169+
selectedcontent_elem: Default::default(),
166170
frameset_ok: Cell::new(true),
167171
ignore_lf: Default::default(),
168172
foster_parenting: Default::default(),
@@ -203,6 +207,7 @@ where
203207
active_formatting: Default::default(),
204208
head_elem: Default::default(),
205209
form_elem: RefCell::new(form_elem),
210+
selectedcontent_elem: Default::default(),
206211
frameset_ok: Cell::new(true),
207212
ignore_lf: Default::default(),
208213
foster_parenting: Default::default(),
@@ -285,6 +290,10 @@ where
285290
tracer.trace_handle(form_elem);
286291
}
287292

293+
if let Some(selectedcontent_elem) = self.selectedcontent_elem.borrow().as_ref() {
294+
tracer.trace_handle(selectedcontent_elem);
295+
}
296+
288297
if let Some(context_elem) = self.context_elem.borrow().as_ref() {
289298
tracer.trace_handle(context_elem);
290299
}
@@ -923,6 +932,7 @@ where
923932
.borrow_mut()
924933
.pop()
925934
.expect("no current element");
935+
926936
self.sink.pop(&elem);
927937
elem
928938
}
@@ -1392,6 +1402,10 @@ where
13921402

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

1405+
if qname.local == local_name!("selectedcontent") && self.selectedcontent_elem.borrow().is_none() {
1406+
*self.selectedcontent_elem.borrow_mut() = Some(elem.clone());
1407+
}
1408+
13951409
match push {
13961410
PushFlag::Push => self.push(&elem),
13971411
PushFlag::NoPush => (),
@@ -1576,6 +1590,18 @@ where
15761590
self.remove_from_stack(&node);
15771591
}
15781592

1593+
fn maybe_clone_option_into_selectedcontent(&self, option: &Handle) {
1594+
if let Some(selectedcontent) = self.selectedcontent_elem.borrow().as_ref().cloned() {
1595+
self.clone_option_into_selectedcontent(option, &selectedcontent);
1596+
}
1597+
}
1598+
1599+
fn clone_option_into_selectedcontent(&self, option: &Handle, selectedcontent: &Handle) {
1600+
self.sink.reparent_children(selectedcontent, &self.sink.get_document());
1601+
let cloned_option = self.sink.clone_subtree(option);
1602+
self.sink.reparent_children(&cloned_option, selectedcontent);
1603+
}
1604+
15791605
//§ tree-construction
15801606
fn is_foreign(&self, token: &Token) -> bool {
15811607
if let Token::Eof = *token {

html5ever/src/tree_builder/rules.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ where
587587
ProcessResult::Done
588588
},
589589

590+
590591
Token::Tag(
591592
tag @
592593
tag!(</address> | </article> | </aside> | </blockquote> | </button> | </center> |
@@ -638,6 +639,33 @@ where
638639
ProcessResult::Done
639640
},
640641

642+
Token::Tag(tag!(</select>)) => {
643+
if self.in_scope_named(default_scope, local_name!("select")) {
644+
self.generate_implied_end_tags(cursory_implied_end);
645+
self.expect_to_close(local_name!("select"));
646+
} else {
647+
self.unexpected(&token);
648+
}
649+
ProcessResult::Done
650+
},
651+
652+
Token::Tag(tag @ tag!(</option>)) => {
653+
let option_in_stack = self.open_elems.borrow()
654+
.iter()
655+
.find(|elem| self.html_elem_named(elem, local_name!("option")))
656+
.cloned();
657+
658+
self.process_end_tag_in_body(tag);
659+
660+
if let Some(option) = option_in_stack {
661+
if !self.open_elems.borrow().iter().any(|elem| self.sink.same_node(elem, &option)) {
662+
self.maybe_clone_option_into_selectedcontent(&option);
663+
}
664+
}
665+
666+
ProcessResult::Done
667+
},
668+
641669
Token::Tag(tag!(</p>)) => {
642670
if !self.in_scope_named(button_scope, local_name!("p")) {
643671
self.sink.parse_error(Borrowed("No <p> tag to close"));

markup5ever/interface/tree_builder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ pub trait TreeSink {
236236
/// Remove all the children from node and append them to new_parent.
237237
fn reparent_children(&self, node: &Self::Handle, new_parent: &Self::Handle);
238238

239+
/// Clone a node and all its descendants, returning the cloned node.
240+
fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle;
241+
239242
/// Returns true if the adjusted current node is an HTML integration point
240243
/// and the token is a start tag.
241244
fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool {

rcdom/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use markup5ever::ExpandedName;
6060
use markup5ever::QualName;
6161

6262
/// The different kinds of nodes in the DOM.
63-
#[derive(Debug)]
63+
#[derive(Debug, Clone)]
6464
pub enum NodeData {
6565
/// The `Document` itself - the root node of a HTML document.
6666
Document,
@@ -417,6 +417,19 @@ impl TreeSink for RcDom {
417417
new_children.extend(mem::take(&mut *children));
418418
}
419419

420+
fn clone_subtree(&self, node: &Handle) -> Handle {
421+
let cloned_node = Node::new(node.data.clone());
422+
423+
// Clone all children recursively
424+
for child in node.children.borrow().iter() {
425+
let cloned_child = self.clone_subtree(child);
426+
append(&cloned_node, cloned_child);
427+
}
428+
429+
cloned_node
430+
}
431+
432+
420433
fn is_mathml_annotation_xml_integration_point(&self, target: &Handle) -> bool {
421434
if let NodeData::Element {
422435
mathml_annotation_xml_integration_point,

rcdom/tests/html-tree-sink.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use html5ever::tendril::StrTendril;
44
use html5ever::ExpandedName;
55
use html5ever::QualName;
66
use markup5ever::interface::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
7-
use markup5ever::{local_name, ns, Attribute};
7+
use markup5ever::{local_name, ns, Attribute, LocalName};
88
use markup5ever_rcdom::{Handle, RcDom};
99
use std::borrow::Cow;
1010
use std::cell::{Cell, RefCell};
@@ -111,6 +111,11 @@ impl TreeSink for LineCountingDOM {
111111
fn set_current_line(&self, line_number: u64) {
112112
self.current_line.set(line_number);
113113
}
114+
115+
fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
116+
self.rcdom.clone_subtree(node)
117+
}
118+
114119
}
115120

116121
#[test]

web_atoms/local_names.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,7 @@ section
879879
seed
880880
select
881881
selected
882+
selectedcontent
882883
selection
883884
selector
884885
semantics

0 commit comments

Comments
 (0)