1use std::borrow::Cow;
4use std::cell::{Ref, RefCell};
5use std::rc::Rc;
6
7use blitz_dom::{BaseDocument, NodeId, QualName};
8use html5ever::TokenizerResult;
9use html5ever::buffer_queue::BufferQueue;
10use html5ever::tendril::StrTendril;
11use html5ever::tokenizer::{Tokenizer, TokenizerOpts};
12use html5ever::tree_builder::{
13 ElementFlags, NodeOrText, QuirksMode, TreeBuilder, TreeBuilderOpts, TreeSink,
14};
15
16use crate::DocumentHtmlParser;
17
18pub struct StreamInput(BufferQueue);
19
20impl StreamInput {
21 pub fn new(text: &str) -> Self {
22 let queue = BufferQueue::default();
23 queue.push_back(StrTendril::from(text));
24 Self(queue)
25 }
26}
27
28pub struct StreamingParser {
29 tokenizer: Tokenizer<TreeBuilder<NodeId, StreamSink>>,
30 input: StreamInput,
31}
32
33impl StreamingParser {
34 pub fn new(document: Rc<RefCell<BaseDocument>>, html: &str) -> Self {
35 let builder = TreeBuilder::new(
36 StreamSink { document },
37 TreeBuilderOpts {
38 scripting_enabled: true,
39 drop_doctype: false,
40 ..Default::default()
41 },
42 );
43 Self {
44 tokenizer: Tokenizer::new(builder, TokenizerOpts::default()),
45 input: StreamInput::new(html),
46 }
47 }
48
49 pub fn next_script(&mut self) -> Option<NodeId> {
50 loop {
53 match self.tokenizer.feed(&self.input.0) {
54 TokenizerResult::Script(id) => return Some(id),
55 TokenizerResult::Done => return None,
56 TokenizerResult::EncodingIndicator(_) => {}
57 }
58 }
59 }
60
61 pub fn feed_written(&mut self, input: &StreamInput) -> Option<NodeId> {
63 loop {
66 match self.tokenizer.feed(&input.0) {
67 TokenizerResult::Script(id) => return Some(id),
68 TokenizerResult::Done => return None,
69 TokenizerResult::EncodingIndicator(_) => {}
70 }
71 }
72 }
73
74 pub fn finish(&mut self) {
75 self.tokenizer.end();
76 }
77}
78
79struct StreamSink {
80 document: Rc<RefCell<BaseDocument>>,
81}
82
83impl StreamSink {
84 fn with_sink<R>(&self, callback: impl FnOnce(&DocumentHtmlParser<'_, '_>) -> R) -> R {
85 let mut document = self.document.borrow_mut();
86 let mut mutator = document.mutate();
87 let sink = DocumentHtmlParser::new(&mut mutator);
88 callback(&sink)
89 }
90}
91
92impl TreeSink for StreamSink {
93 type Output = ();
94 type Handle = NodeId;
95 type ElemName<'a>
96 = Ref<'a, QualName>
97 where
98 Self: 'a;
99
100 fn finish(self) {}
101
102 fn parse_error(&self, _: Cow<'static, str>) {}
103
104 fn get_document(&self) -> NodeId {
105 self.document.borrow().root_node().id
106 }
107
108 fn elem_name<'a>(&'a self, target: &'a NodeId) -> Self::ElemName<'a> {
109 Ref::map(self.document.borrow(), |document| {
110 &document
111 .get_node(*target)
112 .expect("parser element disappeared")
113 .element_data()
114 .expect("parser handle is not an element")
115 .name
116 })
117 }
118
119 fn create_element(
120 &self,
121 name: QualName,
122 attributes: Vec<html5ever::Attribute>,
123 flags: ElementFlags,
124 ) -> NodeId {
125 self.with_sink(|sink| sink.create_element(name, attributes, flags))
126 }
127
128 fn create_comment(&self, text: StrTendril) -> NodeId {
129 self.with_sink(|sink| sink.create_comment(text))
130 }
131
132 fn create_pi(&self, target: StrTendril, data: StrTendril) -> NodeId {
133 self.with_sink(|sink| sink.create_pi(target, data))
134 }
135
136 fn append(&self, parent: &NodeId, child: NodeOrText<NodeId>) {
137 self.with_sink(|sink| sink.append(parent, child));
138 }
139
140 fn append_before_sibling(&self, sibling: &NodeId, child: NodeOrText<NodeId>) {
141 self.with_sink(|sink| sink.append_before_sibling(sibling, child));
142 }
143
144 fn append_based_on_parent_node(
145 &self,
146 element: &NodeId,
147 previous: &NodeId,
148 child: NodeOrText<NodeId>,
149 ) {
150 self.with_sink(|sink| sink.append_based_on_parent_node(element, previous, child));
151 }
152
153 fn append_doctype_to_document(
154 &self,
155 name: StrTendril,
156 public_id: StrTendril,
157 system_id: StrTendril,
158 ) {
159 self.with_sink(|sink| sink.append_doctype_to_document(name, public_id, system_id));
160 }
161
162 fn get_template_contents(&self, target: &NodeId) -> NodeId {
163 self.with_sink(|sink| sink.get_template_contents(target))
164 }
165
166 fn same_node(&self, left: &NodeId, right: &NodeId) -> bool {
167 left == right
168 }
169
170 fn set_quirks_mode(&self, mode: QuirksMode) {
171 self.document
172 .borrow_mut()
173 .set_document_quirks_mode(match mode {
174 QuirksMode::NoQuirks => 0,
175 QuirksMode::LimitedQuirks => 1,
176 QuirksMode::Quirks => 2,
177 });
178 }
179
180 fn add_attrs_if_missing(&self, target: &NodeId, attributes: Vec<html5ever::Attribute>) {
181 self.with_sink(|sink| sink.add_attrs_if_missing(target, attributes));
182 }
183
184 fn remove_from_parent(&self, target: &NodeId) {
185 self.with_sink(|sink| sink.remove_from_parent(target));
186 }
187
188 fn reparent_children(&self, previous: &NodeId, parent: &NodeId) {
189 self.with_sink(|sink| sink.reparent_children(previous, parent));
190 }
191
192 fn allow_declarative_shadow_roots(&self, intended_parent: &NodeId) -> bool {
193 self.with_sink(|sink| sink.allow_declarative_shadow_roots(intended_parent))
194 }
195
196 fn attach_declarative_shadow(
197 &self,
198 location: &NodeId,
199 template: &NodeId,
200 attributes: &[html5ever::Attribute],
201 ) -> bool {
202 self.with_sink(|sink| sink.attach_declarative_shadow(location, template, attributes))
203 }
204
205 fn pop(&self, node: &NodeId) {
206 self.with_sink(|sink| sink.pop(node));
207 }
208}