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