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