1use crate::encoding::extract_a_character_encoding_from_a_meta_element;
13use crate::interface::Quirks;
14use crate::tokenizer::states::{Rawtext, Rcdata, ScriptData};
15use crate::tokenizer::TagKind::{EndTag, StartTag};
16use crate::tree_builder::tag_sets::*;
17use crate::tree_builder::types::*;
18use crate::tree_builder::{
19 html_elem, ElemName, NodeOrText::AppendNode, StrTendril, Tag, TreeBuilder, TreeSink,
20};
21use crate::QualName;
22use markup5ever::interface::tree_builder::create_element_with_flags;
23use markup5ever::{expanded_name, local_name, ns};
24use std::borrow::Cow::Borrowed;
25
26use crate::tendril::SliceExt;
27
28fn any_not_whitespace(x: &StrTendril) -> bool {
29 x.chars().any(|c| !c.is_ascii_whitespace())
31}
32
33fn current_node<Handle>(open_elems: &[Handle]) -> &Handle {
34 open_elems.last().expect("no current element")
35}
36
37#[rustfmt::skip]
52macro_rules! tag {
53 (<>) => {
55 crate::tokenizer::Tag { kind: crate::tokenizer::StartTag, .. }
56 };
57 (<>|$($tail:tt)*) => {
58 tag!(<>) | tag!($($tail)*)
59 };
60
61 (</>) => {
63 crate::tokenizer::Tag { kind: crate::tokenizer::EndTag, .. }
64 };
65 (</>|$($tail:tt)*) => {
66 tag!(</>) | tag!($($tail)*)
67 };
68
69 (<$tag:tt>) => {
71 crate::tokenizer::Tag { kind: crate::tokenizer::StartTag, name: local_name!($tag), .. }
72 };
73 (<$tag:tt>|$($tail:tt)*) => {
74 tag!(<$tag>) | tag!($($tail)*)
75 };
76
77 (</$tag:tt>) => {
79 crate::tokenizer::Tag { kind: crate::tokenizer::EndTag, name: local_name!($tag), .. }
80 };
81 (</$tag:tt>|$($tail:tt)*) => {
82 tag!(</$tag>) | tag!($($tail)*)
83 };
84}
85
86#[doc(hidden)]
87impl<Handle, Sink> TreeBuilder<Handle, Sink>
88where
89 Handle: Clone,
90 Sink: TreeSink<Handle = Handle>,
91{
92 pub(crate) fn step(&self, mode: InsertionMode, token: Token) -> ProcessResult<Handle> {
96 self.debug_step(mode, &token);
97
98 match mode {
99 InsertionMode::Initial => match token {
102 Token::Characters(SplitStatus::NotSplit, text) => {
103 ProcessResult::SplitWhitespace(text)
104 },
105 Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
106 Token::Comment(text) => self.append_comment_to_doc(text),
107 token => {
108 if !self.opts.iframe_srcdoc {
109 self.unexpected(&token);
110 self.set_quirks_mode(Quirks);
111 }
112 ProcessResult::Reprocess(InsertionMode::BeforeHtml, token)
113 },
114 },
115
116 InsertionMode::BeforeHtml => {
119 let anything_else = |token: Token| {
120 self.create_root(vec![]);
121 ProcessResult::Reprocess(InsertionMode::BeforeHead, token)
122 };
123
124 match token {
125 Token::Comment(text) => self.append_comment_to_doc(text),
126
127 Token::Characters(SplitStatus::NotSplit, text) => {
128 ProcessResult::SplitWhitespace(text)
129 },
130
131 Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
132 Token::Tag(tag @ tag!(<html>)) => {
133 self.create_root(tag.attrs);
134 self.mode.set(InsertionMode::BeforeHead);
135 ProcessResult::Done
136 },
137
138 Token::Tag(tag!(</head> | </body> | </html> | </br>)) => anything_else(token),
139 Token::Tag(tag @ tag!(</>)) => self.unexpected(&tag),
140
141 token => anything_else(token),
142 }
143 },
144
145 InsertionMode::BeforeHead => {
148 let anything_else = |token: Token| {
149 *self.head_elem.borrow_mut() = Some(self.insert_phantom(local_name!("head")));
150 ProcessResult::Reprocess(InsertionMode::InHead, token)
151 };
152 match token {
153 Token::Characters(SplitStatus::NotSplit, text) => {
154 ProcessResult::SplitWhitespace(text)
155 },
156 Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
157 Token::Comment(text) => self.append_comment(text),
158
159 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
160
161 Token::Tag(tag @ tag!(<head>)) => {
162 *self.head_elem.borrow_mut() = Some(self.insert_element_for(tag));
163 self.mode.set(InsertionMode::InHead);
164 ProcessResult::Done
165 },
166
167 Token::Tag(tag!(</head> | </body> | </html> | </br>)) => anything_else(token),
168
169 Token::Tag(tag @ tag!(</>)) => self.unexpected(&tag),
170
171 token => anything_else(token),
172 }
173 },
174
175 InsertionMode::InHead => {
178 let anything_else = |token: Token| {
179 self.pop();
180 ProcessResult::Reprocess(InsertionMode::AfterHead, token)
181 };
182
183 match token {
184 Token::Characters(SplitStatus::NotSplit, text) => {
185 ProcessResult::SplitWhitespace(text)
186 },
187 Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
188 Token::Comment(text) => self.append_comment(text),
189
190 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
191
192 Token::Tag(tag @ tag!(<base> | <basefont> | <bgsound> | <link> | <meta>)) => {
193 self.insert_and_pop_element_for(tag.clone());
194
195 if let Some(charset) = tag.get_attribute(&local_name!("charset")) {
201 return ProcessResult::EncodingIndicator(charset);
202 }
203 else if tag
209 .get_attribute(&local_name!("http-equiv"))
210 .is_some_and(|value| value.eq_ignore_ascii_case("content-type"))
211 {
212 if let Some(encoding) = tag
213 .get_attribute(&local_name!("content"))
214 .and_then(extract_a_character_encoding_from_a_meta_element)
215 {
216 return ProcessResult::EncodingIndicator(encoding);
217 }
218 }
219 ProcessResult::DoneAckSelfClosing
220 },
221
222 Token::Tag(tag @ tag!(<title>)) => self.parse_raw_data(tag, Rcdata),
223
224 Token::Tag(tag @ tag!(<noframes> | <style> | <noscript>)) => {
225 if (!self.opts.scripting_enabled) && (tag.name == local_name!("noscript")) {
226 self.insert_element_for(tag);
227 self.mode.set(InsertionMode::InHeadNoscript);
228 ProcessResult::Done
229 } else {
230 self.parse_raw_data(tag, Rawtext)
231 }
232 },
233
234 Token::Tag(tag @ tag!(<script>)) => {
235 let elem = create_element_with_flags(
236 &self.sink,
237 QualName::new(None, ns!(html), local_name!("script")),
238 tag.attrs,
239 tag.had_duplicate_attributes,
240 );
241 if self.is_fragment() {
242 self.sink.mark_script_already_started(&elem);
243 }
244 self.insert_appropriately(AppendNode(elem.clone()), None);
245 self.open_elems.borrow_mut().push(elem);
246 self.to_raw_text_mode(ScriptData)
247 },
248
249 Token::Tag(tag!(</head>)) => {
250 self.pop();
251 self.mode.set(InsertionMode::AfterHead);
252 ProcessResult::Done
253 },
254
255 Token::Tag(tag!(</body> | </html> | </br>)) => anything_else(token),
256
257 Token::Tag(tag @ tag!(<template>)) => {
258 self.active_formatting
259 .borrow_mut()
260 .push(FormatEntry::Marker);
261 self.frameset_ok.set(false);
262 self.mode.set(InsertionMode::InTemplate);
263 self.template_modes
264 .borrow_mut()
265 .push(InsertionMode::InTemplate);
266
267 if (self.should_attach_declarative_shadow(&tag)) {
268 let mut shadow_host = self.open_elems.borrow().last().unwrap().clone();
272 if self.is_fragment() && self.open_elems.borrow().len() == 1 {
273 shadow_host = self.context_elem.borrow().clone().unwrap();
274 }
275
276 let template =
278 self.insert_foreign_element(tag.clone(), ns!(html), true);
279
280 let succeeded =
283 self.attach_declarative_shadow(&tag, &shadow_host, &template);
284 if !succeeded {
285 self.pop();
288 self.insert_element_for(tag);
289 }
290 } else {
291 self.insert_element_for(tag);
292 }
293
294 ProcessResult::Done
295 },
296
297 Token::Tag(tag @ tag!(</template>)) => {
298 if !self.in_html_elem_named(local_name!("template")) {
299 self.unexpected(&tag);
300 } else {
301 self.generate_implied_end_tags(thorough_implied_end);
302 self.expect_to_close(local_name!("template"));
303 self.clear_active_formatting_to_marker();
304 self.template_modes.borrow_mut().pop();
305 self.mode.set(self.reset_insertion_mode());
306 }
307 ProcessResult::Done
308 },
309
310 Token::Tag(tag!(<head> | </>)) => self.unexpected(&token),
311
312 token => anything_else(token),
313 }
314 },
315
316 InsertionMode::InHeadNoscript => {
319 let anything_else = |token: Token| {
320 self.unexpected(&token);
321 self.pop();
322 ProcessResult::Reprocess(InsertionMode::InHead, token)
323 };
324 match token {
325 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
326
327 Token::Tag(tag!(</noscript>)) => {
328 self.pop();
329 self.mode.set(InsertionMode::InHead);
330 ProcessResult::Done
331 },
332
333 Token::Characters(SplitStatus::NotSplit, text) => {
334 ProcessResult::SplitWhitespace(text)
335 },
336 Token::Characters(SplitStatus::Whitespace, _) => {
337 self.step(InsertionMode::InHead, token)
338 },
339
340 Token::Comment(_) => self.step(InsertionMode::InHead, token),
341
342 Token::Tag(
343 tag!(<basefont> | <bgsound> | <link> | <meta> | <noframes> | <style>),
344 ) => self.step(InsertionMode::InHead, token),
345
346 Token::Tag(tag!(</br>)) => anything_else(token),
347
348 Token::Tag(tag!(<head> | <noscript> | </>)) => self.unexpected(&token),
349
350 token => anything_else(token),
351 }
352 },
353
354 InsertionMode::AfterHead => {
357 let anything_else = |token: Token| {
358 self.insert_phantom(local_name!("body"));
359 ProcessResult::Reprocess(InsertionMode::InBody, token)
360 };
361
362 match token {
363 Token::Characters(SplitStatus::NotSplit, text) => {
364 ProcessResult::SplitWhitespace(text)
365 },
366 Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
367 Token::Comment(text) => self.append_comment(text),
368
369 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
370
371 Token::Tag(tag @ tag!(<body>)) => {
372 self.insert_element_for(tag);
373 self.frameset_ok.set(false);
374 self.mode.set(InsertionMode::InBody);
375 ProcessResult::Done
376 },
377
378 Token::Tag(tag @ tag!(<frameset>)) => {
379 self.insert_element_for(tag);
380 self.mode.set(InsertionMode::InFrameset);
381 ProcessResult::Done
382 },
383
384 Token::Tag(
385 tag!(<base> | <basefont> | <bgsound> | <link> | <meta> |
386 <noframes> | <script> | <style> | <template> | <title>
387 ),
388 ) => {
389 self.unexpected(&token);
390 let head = self
391 .head_elem
392 .borrow()
393 .as_ref()
394 .expect("no head element")
395 .clone();
396 self.push(&head);
397 let result = self.step(InsertionMode::InHead, token);
398 self.remove_from_stack(&head);
399 result
400 },
401
402 Token::Tag(tag!(</template>)) => self.step(InsertionMode::InHead, token),
403
404 Token::Tag(tag!(</body> | </html> | </br>)) => anything_else(token),
405
406 Token::Tag(tag!(<head> | </>)) => self.unexpected(&token),
407
408 token => anything_else(token),
409 }
410 },
411
412 InsertionMode::InBody => match token {
415 Token::NullCharacter => self.unexpected(&token),
416
417 Token::Characters(_, text) => {
418 self.reconstruct_active_formatting_elements();
419 if any_not_whitespace(&text) {
420 self.frameset_ok.set(false);
421 }
422 self.append_text(text)
423 },
424
425 Token::Comment(text) => self.append_comment(text),
426
427 Token::Tag(tag @ tag!(<html>)) => {
428 self.unexpected(&tag);
429 if !self.in_html_elem_named(local_name!("template")) {
430 let open_elems = self.open_elems.borrow();
431 let top = html_elem(&open_elems);
432 self.sink.add_attrs_if_missing(top, tag.attrs);
433 }
434 ProcessResult::Done
435 },
436
437 Token::Tag(
438 tag!(<base> | <basefont> | <bgsound> | <link> | <meta> | <noframes>
439 | <script> | <style> | <template> | <title> | </template>),
440 ) => self.step(InsertionMode::InHead, token),
441
442 Token::Tag(tag @ tag!(<body>)) => {
443 self.unexpected(&tag);
444 let body_elem = self.body_elem().as_deref().cloned();
445 match body_elem {
446 Some(ref node)
447 if self.open_elems.borrow().len() != 1
448 && !self.in_html_elem_named(local_name!("template")) =>
449 {
450 self.frameset_ok.set(false);
451 self.sink.add_attrs_if_missing(node, tag.attrs)
452 },
453 _ => {},
454 }
455 ProcessResult::Done
456 },
457
458 Token::Tag(tag @ tag!(<frameset>)) => {
459 self.unexpected(&tag);
460 if !self.frameset_ok.get() {
461 return ProcessResult::Done;
462 }
463
464 let Some(body) = self.body_elem().map(|b| b.clone()) else {
465 return ProcessResult::Done;
466 };
467 self.sink.remove_from_parent(&body);
468
469 self.open_elems.borrow_mut().truncate(1);
472 self.insert_element_for(tag);
473 self.mode.set(InsertionMode::InFrameset);
474 ProcessResult::Done
475 },
476
477 Token::Eof => {
478 if !self.template_modes.borrow().is_empty() {
479 self.step(InsertionMode::InTemplate, token)
480 } else {
481 self.check_body_end();
482 self.stop_parsing()
483 }
484 },
485
486 Token::Tag(tag!(</body>)) => {
487 if self.in_scope_named(default_scope, local_name!("body")) {
488 self.check_body_end();
489 self.mode.set(InsertionMode::AfterBody);
490 } else {
491 self.sink
492 .parse_error(Borrowed("</body> with no <body> in scope"));
493 }
494 ProcessResult::Done
495 },
496
497 Token::Tag(tag!(</html>)) => {
498 if self.in_scope_named(default_scope, local_name!("body")) {
499 self.check_body_end();
500 ProcessResult::Reprocess(InsertionMode::AfterBody, token)
501 } else {
502 self.sink
503 .parse_error(Borrowed("</html> with no <body> in scope"));
504 ProcessResult::Done
505 }
506 },
507
508 Token::Tag(
509 tag @
510 tag!(<address> | <article> | <aside> | <blockquote> | <center> | <details> | <dialog> |
511 <dir> | <div> | <dl> | <fieldset> | <figcaption> | <figure> | <footer> | <header> |
512 <hgroup> | <main> | <nav> | <ol> | <p> | <search> | <section> | <summary> | <ul>),
513 ) => {
514 self.close_p_element_in_button_scope();
515 self.insert_element_for(tag);
516 ProcessResult::Done
517 },
518
519 Token::Tag(tag @ tag!(<menu>)) => {
520 self.close_p_element_in_button_scope();
521 self.insert_element_for(tag);
522 ProcessResult::Done
523 },
524
525 Token::Tag(tag @ tag!(<h1> | <h2> | <h3> | <h4> | <h5> | <h6>)) => {
526 self.close_p_element_in_button_scope();
527 if self.current_node_in(heading_tag) {
528 self.sink.parse_error(Borrowed("nested heading tags"));
529 self.pop();
530 }
531 self.insert_element_for(tag);
532 ProcessResult::Done
533 },
534
535 Token::Tag(tag @ tag!(<pre> | <listing>)) => {
536 self.close_p_element_in_button_scope();
537 self.insert_element_for(tag);
538 self.ignore_lf.set(true);
539 self.frameset_ok.set(false);
540 ProcessResult::Done
541 },
542
543 Token::Tag(tag @ tag!(<form>)) => {
544 if self.form_elem.borrow().is_some()
545 && !self.in_html_elem_named(local_name!("template"))
546 {
547 self.sink.parse_error(Borrowed("nested forms"));
548 } else {
549 self.close_p_element_in_button_scope();
550 let elem = self.insert_element_for(tag);
551 if !self.in_html_elem_named(local_name!("template")) {
552 *self.form_elem.borrow_mut() = Some(elem);
553 }
554 }
555 ProcessResult::Done
556 },
557
558 Token::Tag(tag @ tag!(<li> | <dd> | <dt>)) => {
559 declare_tag_set!(close_list = "li");
560 declare_tag_set!(close_defn = "dd" "dt");
561 declare_tag_set!(extra_special = [special_tag] - "address" "div" "p");
562 let list = match tag.name {
563 local_name!("li") => true,
564 local_name!("dd") | local_name!("dt") => false,
565 _ => unreachable!(),
566 };
567
568 self.frameset_ok.set(false);
569
570 let mut to_close = None;
571 for node in self.open_elems.borrow().iter().rev() {
572 let elem_name = self.sink.elem_name(node);
573 let name = elem_name.expanded();
574 let can_close = if list {
575 close_list(name)
576 } else {
577 close_defn(name)
578 };
579 if can_close {
580 to_close = Some(name.local.clone());
581 break;
582 }
583 if extra_special(name) {
584 break;
585 }
586 }
587
588 if let Some(name) = to_close {
589 self.generate_implied_end_except(name.clone());
590 self.expect_to_close(name);
591 }
592
593 self.close_p_element_in_button_scope();
594 self.insert_element_for(tag);
595 ProcessResult::Done
596 },
597
598 Token::Tag(tag @ tag!(<plaintext>)) => {
599 self.close_p_element_in_button_scope();
600 self.insert_element_for(tag);
601 ProcessResult::ToPlaintext
602 },
603
604 Token::Tag(tag @ tag!(<button>)) => {
605 if self.in_scope_named(default_scope, local_name!("button")) {
606 self.sink.parse_error(Borrowed("nested buttons"));
607 self.generate_implied_end_tags(cursory_implied_end);
608 self.pop_until_named(local_name!("button"));
609 }
610 self.reconstruct_active_formatting_elements();
611 self.insert_element_for(tag);
612 self.frameset_ok.set(false);
613 ProcessResult::Done
614 },
615
616 Token::Tag(
617 tag @
618 tag!(</address> | </article> | </aside> | </blockquote> | </button> | </center> |
619 </details> | </dialog> | </dir> | </div> | </dl> | </fieldset> | </figcaption> |
620 </figure> | </footer> | </header> | </hgroup> | </listing> | </main> | </menu> |
621 </nav> | </ol> | </pre> | </search> | </section> | </select> | </summary> | </ul>),
622 ) => {
623 if !self.in_scope_named(default_scope, tag.name.clone()) {
624 self.unexpected(&tag);
625 } else {
626 self.generate_implied_end_tags(cursory_implied_end);
627 self.expect_to_close(tag.name);
628 }
629 ProcessResult::Done
630 },
631
632 Token::Tag(tag!(</form>)) => {
633 if !self.in_html_elem_named(local_name!("template")) {
634 let Some(node) = self.form_elem.take() else {
635 self.sink
636 .parse_error(Borrowed("Null form element pointer on </form>"));
637 return ProcessResult::Done;
638 };
639 if !self.in_scope(default_scope, |n| self.sink.same_node(&node, &n)) {
640 self.sink
641 .parse_error(Borrowed("Form element not in scope on </form>"));
642 return ProcessResult::Done;
643 }
644 self.generate_implied_end_tags(cursory_implied_end);
645 let current = self.current_node().clone();
646 self.remove_from_stack(&node);
647 if !self.sink.same_node(¤t, &node) {
648 self.sink
649 .parse_error(Borrowed("Bad open element on </form>"));
650 }
651 } else {
652 if !self.in_scope_named(default_scope, local_name!("form")) {
653 self.sink
654 .parse_error(Borrowed("Form element not in scope on </form>"));
655 return ProcessResult::Done;
656 }
657 self.generate_implied_end_tags(cursory_implied_end);
658 if !self.current_node_named(local_name!("form")) {
659 self.sink
660 .parse_error(Borrowed("Bad open element on </form>"));
661 }
662 self.pop_until_named(local_name!("form"));
663 }
664 ProcessResult::Done
665 },
666 Token::Tag(tag @ tag!(</option>)) => {
669 let option_in_stack = self
670 .open_elems
671 .borrow()
672 .iter()
673 .find(|elem| self.html_elem_named(elem, local_name!("option")))
674 .cloned();
675
676 self.process_end_tag_in_body(tag);
677
678 if let Some(option) = option_in_stack {
679 if !self
680 .open_elems
681 .borrow()
682 .iter()
683 .any(|elem| self.sink.same_node(elem, &option))
684 {
685 self.sink
686 .maybe_clone_an_option_into_selectedcontent(&option);
687 }
688 }
689
690 ProcessResult::Done
691 },
692
693 Token::Tag(tag!(</p>)) => {
694 if !self.in_scope_named(button_scope, local_name!("p")) {
695 self.sink.parse_error(Borrowed("No <p> tag to close"));
696 self.insert_phantom(local_name!("p"));
697 }
698 self.close_p_element();
699 ProcessResult::Done
700 },
701
702 Token::Tag(tag @ tag!(</li> | </dd> | </dt>)) => {
703 let in_scope = if tag.name == local_name!("li") {
704 self.in_scope_named(list_item_scope, tag.name.clone())
705 } else {
706 self.in_scope_named(default_scope, tag.name.clone())
707 };
708 if in_scope {
709 self.generate_implied_end_except(tag.name.clone());
710 self.expect_to_close(tag.name);
711 } else {
712 self.sink.parse_error(Borrowed("No matching tag to close"));
713 }
714 ProcessResult::Done
715 },
716
717 Token::Tag(tag @ tag!(</h1> | </h2> | </h3> | </h4> | </h5> | </h6>)) => {
718 if self.in_scope(default_scope, |n| self.elem_in(&n, heading_tag)) {
719 self.generate_implied_end_tags(cursory_implied_end);
720 if !self.current_node_named(tag.name) {
721 self.sink.parse_error(Borrowed("Closing wrong heading tag"));
722 }
723 self.pop_until(heading_tag);
724 } else {
725 self.sink.parse_error(Borrowed("No heading tag to close"));
726 }
727 ProcessResult::Done
728 },
729
730 Token::Tag(tag @ tag!(<a>)) => {
731 self.handle_misnested_a_tags(&tag);
732 self.reconstruct_active_formatting_elements();
733 self.create_formatting_element_for(tag);
734 ProcessResult::Done
735 },
736
737 Token::Tag(
738 tag @
739 tag!(<b> | <big> | <code> | <em> | <font> | <i> | <s> | <small> | <strike> | <strong> | <tt> | <u>),
740 ) => {
741 self.reconstruct_active_formatting_elements();
742 self.create_formatting_element_for(tag);
743 ProcessResult::Done
744 },
745
746 Token::Tag(tag @ tag!(<nobr>)) => {
747 self.reconstruct_active_formatting_elements();
748 if self.in_scope_named(default_scope, local_name!("nobr")) {
749 self.sink.parse_error(Borrowed("Nested <nobr>"));
750 self.adoption_agency(local_name!("nobr"));
751 self.reconstruct_active_formatting_elements();
752 }
753 self.create_formatting_element_for(tag);
754 ProcessResult::Done
755 },
756
757 Token::Tag(
758 tag @ tag!(</a> | </b> | </big> | </code> | </em> | </font> | </i> | </nobr> |
759 </s> | </small> | </strike> | </strong> | </tt> | </u>),
760 ) => {
761 self.adoption_agency(tag.name);
762 ProcessResult::Done
763 },
764
765 Token::Tag(tag @ tag!(<applet> | <marquee> | <object>)) => {
766 self.reconstruct_active_formatting_elements();
767 self.insert_element_for(tag);
768 self.active_formatting
769 .borrow_mut()
770 .push(FormatEntry::Marker);
771 self.frameset_ok.set(false);
772 ProcessResult::Done
773 },
774
775 Token::Tag(tag @ tag!(</applet> | </marquee> | </object>)) => {
776 if !self.in_scope_named(default_scope, tag.name.clone()) {
777 self.unexpected(&tag);
778 } else {
779 self.generate_implied_end_tags(cursory_implied_end);
780 self.expect_to_close(tag.name);
781 self.clear_active_formatting_to_marker();
782 }
783 ProcessResult::Done
784 },
785
786 Token::Tag(tag @ tag!(<table>)) => {
787 if self.quirks_mode.get() != Quirks {
788 self.close_p_element_in_button_scope();
789 }
790 self.insert_element_for(tag);
791 self.frameset_ok.set(false);
792 self.mode.set(InsertionMode::InTable);
793 ProcessResult::Done
794 },
795
796 Token::Tag(tag @ tag!(</br>)) => {
797 self.unexpected(&tag);
798 self.step(
799 InsertionMode::InBody,
800 Token::Tag(Tag {
801 kind: StartTag,
802 attrs: vec![],
803 ..tag
804 }),
805 )
806 },
807
808 Token::Tag(tag @ tag!(<area> | <br> | <embed> | <img> | <keygen> | <wbr>)) => {
809 self.reconstruct_active_formatting_elements();
810 self.insert_and_pop_element_for(tag);
811 self.frameset_ok.set(false);
812 ProcessResult::DoneAckSelfClosing
813 },
814
815 Token::Tag(tag @ tag!(<input>)) => {
816 if self.is_fragment()
817 && self.html_elem_named(
818 self.context_elem.borrow().as_ref().unwrap(),
819 local_name!("select"),
820 )
821 {
822 self.unexpected(&tag);
823 }
824
825 if self.in_scope_named(default_scope, local_name!("select")) {
826 self.unexpected(&tag);
827 self.pop_until_named(local_name!("select"));
828 }
829
830 let is_type_hidden = self.is_type_hidden(&tag);
831
832 self.reconstruct_active_formatting_elements();
833 self.insert_and_pop_element_for(tag);
834
835 if !is_type_hidden {
836 self.frameset_ok.set(false);
837 }
838
839 ProcessResult::DoneAckSelfClosing
840 },
841
842 Token::Tag(tag @ tag!(<param> | <source> | <track>)) => {
843 self.insert_and_pop_element_for(tag);
844 ProcessResult::DoneAckSelfClosing
845 },
846
847 Token::Tag(tag @ tag!(<hr>)) => {
848 self.close_p_element_in_button_scope();
849 if self.in_scope_named(default_scope, local_name!("select")) {
850 self.generate_implied_end_tags(cursory_implied_end);
851 if self.in_scope_named(default_scope, local_name!("option"))
852 || self.in_scope_named(default_scope, local_name!("optgroup"))
853 {
854 self.sink.parse_error(Borrowed("hr in option"));
855 }
856 }
857
858 self.insert_and_pop_element_for(tag);
859 self.frameset_ok.set(false);
860 ProcessResult::DoneAckSelfClosing
861 },
862
863 Token::Tag(tag @ tag!(<image>)) => {
864 self.unexpected(&tag);
865 self.step(
866 InsertionMode::InBody,
867 Token::Tag(Tag {
868 name: local_name!("img"),
869 ..tag
870 }),
871 )
872 },
873
874 Token::Tag(tag @ tag!(<textarea>)) => {
875 self.ignore_lf.set(true);
876 self.frameset_ok.set(false);
877 self.parse_raw_data(tag, Rcdata)
878 },
879
880 Token::Tag(tag @ tag!(<xmp>)) => {
881 self.close_p_element_in_button_scope();
882 self.reconstruct_active_formatting_elements();
883 self.frameset_ok.set(false);
884 self.parse_raw_data(tag, Rawtext)
885 },
886
887 Token::Tag(tag @ tag!(<iframe>)) => {
888 self.frameset_ok.set(false);
889 self.parse_raw_data(tag, Rawtext)
890 },
891
892 Token::Tag(tag @ tag!(<noembed>)) => self.parse_raw_data(tag, Rawtext),
893
894 Token::Tag(tag @ tag!(<select>)) => {
896 if self.is_fragment()
897 && self.html_elem_named(
898 self.context_elem.borrow().as_ref().unwrap(),
899 local_name!("select"),
900 )
901 {
902 self.unexpected(&tag);
903 } else if self.in_scope_named(default_scope, local_name!("select")) {
904 self.unexpected(&tag);
905 self.pop_until_named(local_name!("select"));
906 } else {
907 self.reconstruct_active_formatting_elements();
908 self.insert_element_for(tag);
909 self.frameset_ok.set(false);
910 }
911
912 ProcessResult::Done
913 },
914
915 Token::Tag(tag @ tag!(<option>)) => {
916 if self.in_scope_named(default_scope, local_name!("select")) {
917 self.generate_implied_end_except(local_name!("optgroup"));
918 if self.in_scope_named(default_scope, local_name!("option")) {
919 self.sink.parse_error(Borrowed("nested options"));
920 }
921 } else if self.current_node_named(local_name!("option")) {
922 self.pop();
923 }
924
925 self.reconstruct_active_formatting_elements();
926 self.insert_element_for(tag);
927 ProcessResult::Done
928 },
929
930 Token::Tag(tag @ tag!(<optgroup>)) => {
931 if self.in_scope_named(default_scope, local_name!("select")) {
932 self.generate_implied_end_tags(cursory_implied_end);
933 if self.in_scope_named(default_scope, local_name!("option"))
934 || self.in_scope_named(default_scope, local_name!("optgroup"))
935 {
936 self.sink.parse_error(Borrowed("nested options"));
937 }
938 } else if self.current_node_named(local_name!("option")) {
939 self.pop();
940 }
941
942 self.reconstruct_active_formatting_elements();
943 self.insert_element_for(tag);
944 ProcessResult::Done
945 },
946
947 Token::Tag(tag @ tag!(<rb> | <rtc>)) => {
948 if self.in_scope_named(default_scope, local_name!("ruby")) {
949 self.generate_implied_end_tags(cursory_implied_end);
950 }
951 if !self.current_node_named(local_name!("ruby")) {
952 self.unexpected(&tag);
953 }
954 self.insert_element_for(tag);
955 ProcessResult::Done
956 },
957
958 Token::Tag(tag @ tag!(<rp> | <rt>)) => {
959 if self.in_scope_named(default_scope, local_name!("ruby")) {
960 self.generate_implied_end_except(local_name!("rtc"));
961 }
962 if !self.current_node_named(local_name!("rtc"))
963 && !self.current_node_named(local_name!("ruby"))
964 {
965 self.unexpected(&tag);
966 }
967 self.insert_element_for(tag);
968 ProcessResult::Done
969 },
970
971 Token::Tag(tag @ tag!(<math>)) => {
972 self.reconstruct_active_formatting_elements();
973 self.enter_foreign(tag, ns!(mathml))
974 },
975
976 Token::Tag(tag @ tag!(<svg>)) => {
977 self.reconstruct_active_formatting_elements();
978 self.enter_foreign(tag, ns!(svg))
979 },
980
981 Token::Tag(
982 tag!(<caption> | <col> | <colgroup> | <frame> | <head> |
983 <tbody> | <td> | <tfoot> | <th> | <thead> | <tr>),
984 ) => {
985 self.unexpected(&token);
986 ProcessResult::Done
987 },
988
989 Token::Tag(tag @ tag!(<>)) => {
990 if self.opts.scripting_enabled && tag.name == local_name!("noscript") {
991 self.parse_raw_data(tag, Rawtext)
992 } else {
993 self.reconstruct_active_formatting_elements();
994 self.insert_element_for(tag);
995 ProcessResult::Done
996 }
997 },
998
999 Token::Tag(tag @ tag!(</>)) => {
1000 self.process_end_tag_in_body(tag);
1001 ProcessResult::Done
1002 },
1003 },
1004
1005 InsertionMode::Text => match token {
1008 Token::Characters(_, text) => self.append_text(text),
1009
1010 Token::Eof => {
1011 self.unexpected(&token);
1012 if self.current_node_named(local_name!("script")) {
1013 let open_elems = self.open_elems.borrow();
1014 let current = current_node(&open_elems);
1015 self.sink.mark_script_already_started(current);
1016 }
1017 self.pop();
1018 ProcessResult::Reprocess(self.orig_mode.take().unwrap(), token)
1019 },
1020
1021 Token::Tag(tag @ tag!(</>)) => {
1022 let node = self.pop();
1023 self.mode.set(self.orig_mode.take().unwrap());
1024 if tag.name == local_name!("script") {
1025 return ProcessResult::Script(node);
1026 }
1027 ProcessResult::Done
1028 },
1029
1030 _ => unreachable!("impossible case in Text mode"),
1033 },
1034
1035 InsertionMode::InTable => match token {
1038 Token::NullCharacter | Token::Characters(..) => self.process_chars_in_table(token),
1039
1040 Token::Comment(text) => self.append_comment(text),
1041
1042 Token::Tag(tag @ tag!(<caption>)) => {
1043 self.pop_until_current(table_scope);
1044 self.active_formatting
1045 .borrow_mut()
1046 .push(FormatEntry::Marker);
1047 self.insert_element_for(tag);
1048 self.mode.set(InsertionMode::InCaption);
1049 ProcessResult::Done
1050 },
1051
1052 Token::Tag(tag @ tag!(<colgroup>)) => {
1053 self.pop_until_current(table_scope);
1054 self.insert_element_for(tag);
1055 self.mode.set(InsertionMode::InColumnGroup);
1056 ProcessResult::Done
1057 },
1058
1059 Token::Tag(tag!(<col>)) => {
1060 self.pop_until_current(table_scope);
1061 self.insert_phantom(local_name!("colgroup"));
1062 ProcessResult::Reprocess(InsertionMode::InColumnGroup, token)
1063 },
1064
1065 Token::Tag(tag @ tag!(<tbody> | <tfoot> | <thead>)) => {
1066 self.pop_until_current(table_scope);
1067 self.insert_element_for(tag);
1068 self.mode.set(InsertionMode::InTableBody);
1069 ProcessResult::Done
1070 },
1071
1072 Token::Tag(tag!(<td> | <th> | <tr>)) => {
1073 self.pop_until_current(table_scope);
1074 self.insert_phantom(local_name!("tbody"));
1075 ProcessResult::Reprocess(InsertionMode::InTableBody, token)
1076 },
1077
1078 Token::Tag(tag!(<table>)) => {
1079 self.unexpected(&token);
1080 if self.in_scope_named(table_scope, local_name!("table")) {
1081 self.pop_until_named(local_name!("table"));
1082 ProcessResult::Reprocess(self.reset_insertion_mode(), token)
1083 } else {
1084 ProcessResult::Done
1085 }
1086 },
1087
1088 Token::Tag(tag!(</table>)) => {
1089 if self.in_scope_named(table_scope, local_name!("table")) {
1090 self.pop_until_named(local_name!("table"));
1091 self.mode.set(self.reset_insertion_mode());
1092 } else {
1093 self.unexpected(&token);
1094 }
1095 ProcessResult::Done
1096 },
1097
1098 Token::Tag(
1099 tag!(</body> | </caption> | </col> | </colgroup> | </html> |
1100 </tbody> | </td> | </tfoot> | </th> | </thead> | </tr>),
1101 ) => self.unexpected(&token),
1102
1103 Token::Tag(tag!(<style> | <script> | <template> | </template>)) => {
1104 self.step(InsertionMode::InHead, token)
1105 },
1106
1107 Token::Tag(tag @ tag!(<input>)) => {
1108 self.unexpected(&tag);
1109 if self.is_type_hidden(&tag) {
1110 self.insert_and_pop_element_for(tag);
1111 ProcessResult::DoneAckSelfClosing
1112 } else {
1113 self.foster_parent_in_body(Token::Tag(tag))
1114 }
1115 },
1116
1117 Token::Tag(tag @ tag!(<form>)) => {
1118 self.unexpected(&tag);
1119 if !self.in_html_elem_named(local_name!("template"))
1120 && self.form_elem.borrow().is_none()
1121 {
1122 *self.form_elem.borrow_mut() = Some(self.insert_and_pop_element_for(tag));
1123 }
1124 ProcessResult::Done
1125 },
1126
1127 Token::Eof => self.step(InsertionMode::InBody, token),
1128
1129 token => {
1130 self.unexpected(&token);
1131 self.foster_parent_in_body(token)
1132 },
1133 },
1134
1135 InsertionMode::InTableText => match token {
1138 Token::NullCharacter => self.unexpected(&token),
1139
1140 Token::Characters(split, text) => {
1141 self.pending_table_text.borrow_mut().push((split, text));
1142 ProcessResult::Done
1143 },
1144
1145 token => {
1146 let pending = self.pending_table_text.take();
1147 let contains_nonspace = pending.iter().any(|&(split, ref text)| match split {
1148 SplitStatus::Whitespace => false,
1149 SplitStatus::NotWhitespace => true,
1150 SplitStatus::NotSplit => any_not_whitespace(text),
1151 });
1152
1153 if contains_nonspace {
1154 self.sink.parse_error(Borrowed("Non-space table text"));
1155 for (split, text) in pending.into_iter() {
1156 match self.foster_parent_in_body(Token::Characters(split, text)) {
1157 ProcessResult::Done => (),
1158 _ => panic!("not prepared to handle this!"),
1159 }
1160 }
1161 } else {
1162 for (_, text) in pending.into_iter() {
1163 self.append_text(text);
1164 }
1165 }
1166
1167 ProcessResult::Reprocess(self.orig_mode.take().unwrap(), token)
1168 },
1169 },
1170
1171 InsertionMode::InCaption => match token {
1174 Token::Tag(
1175 tag @ tag!(<caption> | <col> | <colgroup> | <tbody> | <td> | <tfoot> |
1176 <th> | <thead> | <tr> | </table> | </caption>),
1177 ) => {
1178 if self.in_scope_named(table_scope, local_name!("caption")) {
1179 self.generate_implied_end_tags(cursory_implied_end);
1180 self.expect_to_close(local_name!("caption"));
1181 self.clear_active_formatting_to_marker();
1182 match tag {
1183 Tag {
1184 kind: EndTag,
1185 name: local_name!("caption"),
1186 ..
1187 } => {
1188 self.mode.set(InsertionMode::InTable);
1189 ProcessResult::Done
1190 },
1191 _ => ProcessResult::Reprocess(InsertionMode::InTable, Token::Tag(tag)),
1192 }
1193 } else {
1194 self.unexpected(&tag);
1195 ProcessResult::Done
1196 }
1197 },
1198
1199 Token::Tag(
1200 tag!(</body> | </col> | </colgroup> | </html> | </tbody> |
1201 </td> | </tfoot> | </th> | </thead> | </tr>),
1202 ) => self.unexpected(&token),
1203
1204 token => self.step(InsertionMode::InBody, token),
1205 },
1206
1207 InsertionMode::InColumnGroup => match token {
1210 Token::Characters(SplitStatus::NotSplit, text) => {
1211 ProcessResult::SplitWhitespace(text)
1212 },
1213 Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
1214 Token::Comment(text) => self.append_comment(text),
1215
1216 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1217
1218 Token::Tag(tag @ tag!(<col>)) => {
1219 self.insert_and_pop_element_for(tag);
1220 ProcessResult::DoneAckSelfClosing
1221 },
1222
1223 Token::Tag(tag!(</colgroup>)) => {
1224 if self.current_node_named(local_name!("colgroup")) {
1225 self.pop();
1226 self.mode.set(InsertionMode::InTable);
1227 } else {
1228 self.unexpected(&token);
1229 }
1230 ProcessResult::Done
1231 },
1232
1233 Token::Tag(tag!(</col>)) => self.unexpected(&token),
1234
1235 Token::Tag(tag!(<template> | </template>)) => {
1236 self.step(InsertionMode::InHead, token)
1237 },
1238
1239 Token::Eof => self.step(InsertionMode::InBody, token),
1240
1241 token => {
1242 if self.current_node_named(local_name!("colgroup")) {
1243 self.pop();
1244 ProcessResult::Reprocess(InsertionMode::InTable, token)
1245 } else {
1246 self.unexpected(&token)
1247 }
1248 },
1249 },
1250
1251 InsertionMode::InTableBody => match token {
1254 Token::Tag(tag @ tag!(<tr>)) => {
1255 self.pop_until_current(table_body_context);
1256 self.insert_element_for(tag);
1257 self.mode.set(InsertionMode::InRow);
1258 ProcessResult::Done
1259 },
1260
1261 Token::Tag(tag!(<th> | <td>)) => {
1262 self.unexpected(&token);
1263 self.pop_until_current(table_body_context);
1264 self.insert_phantom(local_name!("tr"));
1265 ProcessResult::Reprocess(InsertionMode::InRow, token)
1266 },
1267
1268 Token::Tag(tag @ tag!(</tbody> | </tfoot> | </thead>)) => {
1269 if self.in_scope_named(table_scope, tag.name.clone()) {
1270 self.pop_until_current(table_body_context);
1271 self.pop();
1272 self.mode.set(InsertionMode::InTable);
1273 } else {
1274 self.unexpected(&tag);
1275 }
1276 ProcessResult::Done
1277 },
1278
1279 Token::Tag(
1280 tag!(<caption> | <col> | <colgroup> | <tbody> | <tfoot> | <thead> | </table>),
1281 ) => {
1282 declare_tag_set!(table_outer = "table" "tbody" "tfoot");
1283 if self.in_scope(table_scope, |e| self.elem_in(&e, table_outer)) {
1284 self.pop_until_current(table_body_context);
1285 self.pop();
1286 ProcessResult::Reprocess(InsertionMode::InTable, token)
1287 } else {
1288 self.unexpected(&token)
1289 }
1290 },
1291
1292 Token::Tag(
1293 tag!(</body> | </caption> | </col> | </colgroup> | </html> | </td> | </th> | </tr>),
1294 ) => self.unexpected(&token),
1295
1296 token => self.step(InsertionMode::InTable, token),
1297 },
1298
1299 InsertionMode::InRow => match token {
1302 Token::Tag(tag @ tag!(<th> | <td>)) => {
1303 self.pop_until_current(table_row_context);
1304 self.insert_element_for(tag);
1305 self.mode.set(InsertionMode::InCell);
1306 self.active_formatting
1307 .borrow_mut()
1308 .push(FormatEntry::Marker);
1309 ProcessResult::Done
1310 },
1311
1312 Token::Tag(tag!(</tr>)) => {
1313 if self.in_scope_named(table_scope, local_name!("tr")) {
1314 self.pop_until_current(table_row_context);
1315 let node = self.pop();
1316 self.assert_named(&node, local_name!("tr"));
1317 self.mode.set(InsertionMode::InTableBody);
1318 } else {
1319 self.unexpected(&token);
1320 }
1321 ProcessResult::Done
1322 },
1323
1324 Token::Tag(
1325 tag!(<caption> | <col> | <colgroup> | <tbody> | <tfoot> | <thead> | <tr> | </table>),
1326 ) => {
1327 if self.in_scope_named(table_scope, local_name!("tr")) {
1328 self.pop_until_current(table_row_context);
1329 let node = self.pop();
1330 self.assert_named(&node, local_name!("tr"));
1331 ProcessResult::Reprocess(InsertionMode::InTableBody, token)
1332 } else {
1333 self.unexpected(&token)
1334 }
1335 },
1336
1337 Token::Tag(tag @ tag!(</tbody> | </tfoot> | </thead>)) => {
1338 if self.in_scope_named(table_scope, tag.name.clone()) {
1339 if self.in_scope_named(table_scope, local_name!("tr")) {
1340 self.pop_until_current(table_row_context);
1341 let node = self.pop();
1342 self.assert_named(&node, local_name!("tr"));
1343 ProcessResult::Reprocess(InsertionMode::InTableBody, Token::Tag(tag))
1344 } else {
1345 ProcessResult::Done
1346 }
1347 } else {
1348 self.unexpected(&tag)
1349 }
1350 },
1351
1352 Token::Tag(
1353 tag!(</body> | </caption> | </col> | </colgroup> | </html> | </td> | </th>),
1354 ) => self.unexpected(&token),
1355
1356 token => self.step(InsertionMode::InTable, token),
1357 },
1358
1359 InsertionMode::InCell => match token {
1362 Token::Tag(tag @ tag!(</td> | </th>)) => {
1363 if self.in_scope_named(table_scope, tag.name.clone()) {
1364 self.generate_implied_end_tags(cursory_implied_end);
1365 self.expect_to_close(tag.name);
1366 self.clear_active_formatting_to_marker();
1367 self.mode.set(InsertionMode::InRow);
1368 } else {
1369 self.unexpected(&tag);
1370 }
1371 ProcessResult::Done
1372 },
1373
1374 Token::Tag(
1375 tag!(<caption> | <col> | <colgroup> | <tbody> | <td> | <tfoot> | <th> | <thead> | <tr>),
1376 ) => {
1377 if self.in_scope(table_scope, |n| self.elem_in(&n, td_th)) {
1378 self.close_the_cell();
1379 ProcessResult::Reprocess(InsertionMode::InRow, token)
1380 } else {
1381 self.unexpected(&token)
1382 }
1383 },
1384
1385 Token::Tag(tag!(</body> | </caption> | </col> | </colgroup> | </html>)) => {
1386 self.unexpected(&token)
1387 },
1388
1389 Token::Tag(tag @ tag!(</table> | </tbody> | </tfoot> | </thead> | </tr>)) => {
1390 if self.in_scope_named(table_scope, tag.name.clone()) {
1391 self.close_the_cell();
1392 ProcessResult::Reprocess(InsertionMode::InRow, Token::Tag(tag))
1393 } else {
1394 self.unexpected(&tag)
1395 }
1396 },
1397
1398 token => self.step(InsertionMode::InBody, token),
1399 },
1400
1401 InsertionMode::InTemplate => match token {
1404 Token::Characters(_, _) => self.step(InsertionMode::InBody, token),
1405 Token::Comment(_) => self.step(InsertionMode::InBody, token),
1406
1407 Token::Tag(
1408 tag!(<base> | <basefont> | <bgsound> | <link> | <meta> | <noframes> | <script> |
1409 <style> | <template> | <title> | </template>),
1410 ) => self.step(InsertionMode::InHead, token),
1411
1412 Token::Tag(tag!(<caption> | <colgroup> | <tbody> | <tfoot> | <thead>)) => {
1413 self.template_modes.borrow_mut().pop();
1414 self.template_modes
1415 .borrow_mut()
1416 .push(InsertionMode::InTable);
1417 ProcessResult::Reprocess(InsertionMode::InTable, token)
1418 },
1419
1420 Token::Tag(tag!(<col>)) => {
1421 self.template_modes.borrow_mut().pop();
1422 self.template_modes
1423 .borrow_mut()
1424 .push(InsertionMode::InColumnGroup);
1425 ProcessResult::Reprocess(InsertionMode::InColumnGroup, token)
1426 },
1427
1428 Token::Tag(tag!(<tr>)) => {
1429 self.template_modes.borrow_mut().pop();
1430 self.template_modes
1431 .borrow_mut()
1432 .push(InsertionMode::InTableBody);
1433 ProcessResult::Reprocess(InsertionMode::InTableBody, token)
1434 },
1435
1436 Token::Tag(tag!(<td> | <th>)) => {
1437 self.template_modes.borrow_mut().pop();
1438 self.template_modes.borrow_mut().push(InsertionMode::InRow);
1439 ProcessResult::Reprocess(InsertionMode::InRow, token)
1440 },
1441
1442 Token::Eof => {
1443 if !self.in_html_elem_named(local_name!("template")) {
1444 self.stop_parsing()
1445 } else {
1446 self.unexpected(&token);
1447 self.pop_until_named(local_name!("template"));
1448 self.clear_active_formatting_to_marker();
1449 self.template_modes.borrow_mut().pop();
1450 self.mode.set(self.reset_insertion_mode());
1451 ProcessResult::Reprocess(self.reset_insertion_mode(), token)
1452 }
1453 },
1454
1455 Token::Tag(tag @ tag!(<>)) => {
1456 self.template_modes.borrow_mut().pop();
1457 self.template_modes.borrow_mut().push(InsertionMode::InBody);
1458 ProcessResult::Reprocess(InsertionMode::InBody, Token::Tag(tag))
1459 },
1460
1461 token => self.unexpected(&token),
1462 },
1463
1464 InsertionMode::AfterBody => match token {
1467 Token::Characters(SplitStatus::NotSplit, text) => {
1468 ProcessResult::SplitWhitespace(text)
1469 },
1470 Token::Characters(SplitStatus::Whitespace, _) => {
1471 self.step(InsertionMode::InBody, token)
1472 },
1473 Token::Comment(text) => self.append_comment_to_html(text),
1474
1475 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1476
1477 Token::Tag(tag!(</html>)) => {
1478 if self.is_fragment() {
1479 self.unexpected(&token);
1480 } else {
1481 self.mode.set(InsertionMode::AfterAfterBody);
1482 }
1483 ProcessResult::Done
1484 },
1485
1486 Token::Eof => self.stop_parsing(),
1487
1488 token => {
1489 self.unexpected(&token);
1490 ProcessResult::Reprocess(InsertionMode::InBody, token)
1491 },
1492 },
1493
1494 InsertionMode::InFrameset => match token {
1497 Token::Characters(SplitStatus::NotSplit, text) => {
1498 ProcessResult::SplitWhitespace(text)
1499 },
1500 Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
1501 Token::Comment(text) => self.append_comment(text),
1502
1503 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1504
1505 Token::Tag(tag @ tag!(<frameset>)) => {
1506 self.insert_element_for(tag);
1507 ProcessResult::Done
1508 },
1509
1510 Token::Tag(tag!(</frameset>)) => {
1511 if self.open_elems.borrow().len() == 1 {
1512 self.unexpected(&token);
1513 } else {
1514 self.pop();
1515 if !self.is_fragment() && !self.current_node_named(local_name!("frameset"))
1516 {
1517 self.mode.set(InsertionMode::AfterFrameset);
1518 }
1519 }
1520 ProcessResult::Done
1521 },
1522
1523 Token::Tag(tag @ tag!(<frame>)) => {
1524 self.insert_and_pop_element_for(tag);
1525 ProcessResult::DoneAckSelfClosing
1526 },
1527
1528 Token::Tag(tag!(<noframes>)) => self.step(InsertionMode::InHead, token),
1529
1530 Token::Eof => {
1531 if self.open_elems.borrow().len() != 1 {
1532 self.unexpected(&token);
1533 }
1534 self.stop_parsing()
1535 },
1536
1537 token => self.unexpected(&token),
1538 },
1539
1540 InsertionMode::AfterFrameset => match token {
1543 Token::Characters(SplitStatus::NotSplit, text) => {
1544 ProcessResult::SplitWhitespace(text)
1545 },
1546 Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
1547 Token::Comment(text) => self.append_comment(text),
1548
1549 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1550
1551 Token::Tag(tag!(</html>)) => {
1552 self.mode.set(InsertionMode::AfterAfterFrameset);
1553 ProcessResult::Done
1554 },
1555
1556 Token::Tag(tag!(<noframes>)) => self.step(InsertionMode::InHead, token),
1557
1558 Token::Eof => self.stop_parsing(),
1559
1560 token => self.unexpected(&token),
1561 },
1562
1563 InsertionMode::AfterAfterBody => match token {
1566 Token::Characters(SplitStatus::NotSplit, text) => {
1567 ProcessResult::SplitWhitespace(text)
1568 },
1569 Token::Characters(SplitStatus::Whitespace, _) => {
1570 self.step(InsertionMode::InBody, token)
1571 },
1572 Token::Comment(text) => self.append_comment_to_doc(text),
1573
1574 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1575
1576 Token::Eof => self.stop_parsing(),
1577
1578 token => {
1579 self.unexpected(&token);
1580 ProcessResult::Reprocess(InsertionMode::InBody, token)
1581 },
1582 },
1583
1584 InsertionMode::AfterAfterFrameset => match token {
1587 Token::Characters(SplitStatus::NotSplit, text) => {
1588 ProcessResult::SplitWhitespace(text)
1589 },
1590 Token::Characters(SplitStatus::Whitespace, _) => {
1591 self.step(InsertionMode::InBody, token)
1592 },
1593 Token::Comment(text) => self.append_comment_to_doc(text),
1594
1595 Token::Tag(tag!(<html>)) => self.step(InsertionMode::InBody, token),
1596
1597 Token::Eof => self.stop_parsing(),
1598
1599 Token::Tag(tag!(<noframes>)) => self.step(InsertionMode::InHead, token),
1600
1601 token => self.unexpected(&token),
1602 },
1603 }
1604 }
1605
1606 pub(crate) fn step_foreign(&self, token: Token) -> ProcessResult<Handle> {
1609 match token {
1610 Token::NullCharacter => {
1611 self.unexpected(&token);
1612 self.append_text("\u{fffd}".to_tendril())
1613 },
1614
1615 Token::Characters(_, text) => {
1616 if any_not_whitespace(&text) {
1617 self.frameset_ok.set(false);
1618 }
1619 self.append_text(text)
1620 },
1621
1622 Token::Comment(text) => self.append_comment(text),
1623
1624 Token::Tag(
1625 tag @
1626 tag!(<b> | <big> | <blockquote> | <body> | <br> | <center> | <code> | <dd> | <div> | <dl> |
1627 <dt> | <em> | <embed> | <h1> | <h2> | <h3> | <h4> | <h5> | <h6> | <head> | <hr> | <i> |
1628 <img> | <li> | <listing> | <menu> | <meta> | <nobr> | <ol> | <p> | <pre> | <ruby> |
1629 <s> | <small> | <span> | <strong> | <strike> | <sub> | <sup> | <table> | <tt> |
1630 <u> | <ul> | <var> | </br> | </p>),
1631 ) => self.unexpected_start_tag_in_foreign_content(tag),
1632
1633 Token::Tag(tag @ tag!(<font>)) => {
1634 let unexpected = tag.attrs.iter().any(|attr| {
1635 matches!(
1636 attr.name.expanded(),
1637 expanded_name!("", "color")
1638 | expanded_name!("", "face")
1639 | expanded_name!("", "size")
1640 )
1641 });
1642 if unexpected {
1643 self.unexpected_start_tag_in_foreign_content(tag)
1644 } else {
1645 self.foreign_start_tag(tag)
1646 }
1647 },
1648
1649 Token::Tag(tag @ tag!(<>)) => self.foreign_start_tag(tag),
1650
1651 Token::Tag(tag @ tag!(</>)) => {
1653 let mut first = true;
1654 let mut stack_idx = self.open_elems.borrow().len() - 1;
1655 loop {
1656 if stack_idx == 0 {
1657 return ProcessResult::Done;
1658 }
1659
1660 let html;
1661 let eq;
1662 {
1663 let open_elems = self.open_elems.borrow();
1664 let node_name = self.sink.elem_name(&open_elems[stack_idx]);
1665 html = *node_name.ns() == ns!(html);
1666 eq = node_name.local_name().eq_ignore_ascii_case(&tag.name);
1667 }
1668 if !first && html {
1669 let mode = self.mode.get();
1670 return self.step(mode, Token::Tag(tag));
1671 }
1672
1673 if eq {
1674 self.open_elems.borrow_mut().truncate(stack_idx);
1675 return ProcessResult::Done;
1676 }
1677
1678 if first {
1679 self.unexpected(&tag);
1680 first = false;
1681 }
1682 stack_idx -= 1;
1683 }
1684 },
1685
1686 Token::Eof => panic!("impossible case in foreign content"),
1688 }
1689 }
1690}