rusteerio 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/CONTRIBUTING.md +73 -0
  2. package/Cargo.lock +1051 -0
  3. package/Cargo.toml +36 -0
  4. package/LICENSE +21 -0
  5. package/README.md +252 -2
  6. package/RELEASING.md +138 -0
  7. package/THIRD_PARTY_NOTICES.md +7443 -0
  8. package/build.rs +3 -0
  9. package/dist/chunk-DKULX6VO.mjs +3185 -0
  10. package/dist/chunk-DKULX6VO.mjs.map +1 -0
  11. package/dist/chunk-OHPGEY3E.mjs +32 -0
  12. package/dist/chunk-OHPGEY3E.mjs.map +1 -0
  13. package/dist/index.cjs +3230 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.mts +113 -0
  16. package/dist/index.d.ts +113 -0
  17. package/dist/index.mjs +38 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/slim.cjs +2441 -0
  20. package/dist/slim.cjs.map +1 -0
  21. package/dist/slim.d.mts +11 -0
  22. package/dist/slim.d.ts +11 -0
  23. package/dist/slim.mjs +19 -0
  24. package/dist/slim.mjs.map +1 -0
  25. package/dist/types-BP6TpxE5.d.mts +532 -0
  26. package/dist/types-BP6TpxE5.d.ts +532 -0
  27. package/dist/utils.cjs +61 -0
  28. package/dist/utils.cjs.map +1 -0
  29. package/dist/utils.d.mts +13 -0
  30. package/dist/utils.d.ts +13 -0
  31. package/dist/utils.mjs +17 -0
  32. package/dist/utils.mjs.map +1 -0
  33. package/native/src/arena.rs +1781 -0
  34. package/native/src/attributes.rs +923 -0
  35. package/native/src/codec.rs +172 -0
  36. package/native/src/diagnostics.rs +1249 -0
  37. package/native/src/extraction.rs +226 -0
  38. package/native/src/gc.rs +166 -0
  39. package/native/src/hook_sink.rs +727 -0
  40. package/native/src/hook_stream.rs +513 -0
  41. package/native/src/lib.rs +2095 -0
  42. package/native/src/location.rs +392 -0
  43. package/native/src/runtime.rs +189 -0
  44. package/native/src/selector.rs +1287 -0
  45. package/native/src/sink.rs +261 -0
  46. package/native/src/stream.rs +334 -0
  47. package/native/src/tokenizer.rs +355 -0
  48. package/native/src/tracker.rs +232 -0
  49. package/native/vendor/README.md +25 -0
  50. package/native/vendor/html5ever-0.35.0/.cargo_vcs_info.json +6 -0
  51. package/native/vendor/html5ever-0.35.0/Cargo.lock +828 -0
  52. package/native/vendor/html5ever-0.35.0/Cargo.toml +85 -0
  53. package/native/vendor/html5ever-0.35.0/LICENSE-APACHE +201 -0
  54. package/native/vendor/html5ever-0.35.0/LICENSE-MIT +25 -0
  55. package/native/vendor/html5ever-0.35.0/README.md +60 -0
  56. package/native/vendor/html5ever-0.35.0/benches/html5ever.rs +86 -0
  57. package/native/vendor/html5ever-0.35.0/data/bench/lipsum-zh.html +19 -0
  58. package/native/vendor/html5ever-0.35.0/data/bench/lipsum.html +40 -0
  59. package/native/vendor/html5ever-0.35.0/data/bench/medium-fragment.html +24 -0
  60. package/native/vendor/html5ever-0.35.0/data/bench/small-fragment.html +7 -0
  61. package/native/vendor/html5ever-0.35.0/data/bench/strong.html +1 -0
  62. package/native/vendor/html5ever-0.35.0/data/bench/tiny-fragment.html +1 -0
  63. package/native/vendor/html5ever-0.35.0/examples/arena.rs +356 -0
  64. package/native/vendor/html5ever-0.35.0/examples/capi/tokenize.c +74 -0
  65. package/native/vendor/html5ever-0.35.0/examples/noop-tokenize.rs +47 -0
  66. package/native/vendor/html5ever-0.35.0/examples/noop-tree-builder.rs +132 -0
  67. package/native/vendor/html5ever-0.35.0/examples/print-tree-actions.rs +185 -0
  68. package/native/vendor/html5ever-0.35.0/examples/tokenize.rs +111 -0
  69. package/native/vendor/html5ever-0.35.0/src/driver.rs +148 -0
  70. package/native/vendor/html5ever-0.35.0/src/lib.rs +30 -0
  71. package/native/vendor/html5ever-0.35.0/src/macros.rs +34 -0
  72. package/native/vendor/html5ever-0.35.0/src/serialize/mod.rs +255 -0
  73. package/native/vendor/html5ever-0.35.0/src/tokenizer/char_ref/mod.rs +451 -0
  74. package/native/vendor/html5ever-0.35.0/src/tokenizer/interface.rs +99 -0
  75. package/native/vendor/html5ever-0.35.0/src/tokenizer/mod.rs +2305 -0
  76. package/native/vendor/html5ever-0.35.0/src/tokenizer/states.rs +97 -0
  77. package/native/vendor/html5ever-0.35.0/src/tree_builder/data.rs +170 -0
  78. package/native/vendor/html5ever-0.35.0/src/tree_builder/mod.rs +1848 -0
  79. package/native/vendor/html5ever-0.35.0/src/tree_builder/rules.rs +1494 -0
  80. package/native/vendor/html5ever-0.35.0/src/tree_builder/tag_sets.rs +114 -0
  81. package/native/vendor/html5ever-0.35.0/src/tree_builder/types.rs +91 -0
  82. package/native/vendor/html5ever-0.35.0/src/util/str.rs +52 -0
  83. package/native/vendor/html5gum-0.8.4/Cargo.lock +1006 -0
  84. package/native/vendor/html5gum-0.8.4/Cargo.toml +109 -0
  85. package/native/vendor/html5gum-0.8.4/LICENSE +19 -0
  86. package/native/vendor/html5gum-0.8.4/README.md +110 -0
  87. package/native/vendor/html5gum-0.8.4/benches/files/0050.html +2131 -0
  88. package/native/vendor/html5gum-0.8.4/benches/files/6D30.html +1004 -0
  89. package/native/vendor/html5gum-0.8.4/benches/files.rs +32 -0
  90. package/native/vendor/html5gum-0.8.4/benches/patterns.rs +31 -0
  91. package/native/vendor/html5gum-0.8.4/src/arrayvec.rs +29 -0
  92. package/native/vendor/html5gum-0.8.4/src/char_validator.rs +134 -0
  93. package/native/vendor/html5gum-0.8.4/src/emitters/callback.rs +676 -0
  94. package/native/vendor/html5gum-0.8.4/src/emitters/default.rs +207 -0
  95. package/native/vendor/html5gum-0.8.4/src/emitters/emitter.rs +344 -0
  96. package/native/vendor/html5gum-0.8.4/src/emitters/html5ever.rs +306 -0
  97. package/native/vendor/html5gum-0.8.4/src/emitters/mod.rs +25 -0
  98. package/native/vendor/html5gum-0.8.4/src/entities.rs +3342 -0
  99. package/native/vendor/html5gum-0.8.4/src/error.rs +96 -0
  100. package/native/vendor/html5gum-0.8.4/src/htmlstring.rs +130 -0
  101. package/native/vendor/html5gum-0.8.4/src/lib.rs +66 -0
  102. package/native/vendor/html5gum-0.8.4/src/machine.rs +2136 -0
  103. package/native/vendor/html5gum-0.8.4/src/machine_helper.rs +277 -0
  104. package/native/vendor/html5gum-0.8.4/src/read_helper.rs +244 -0
  105. package/native/vendor/html5gum-0.8.4/src/reader.rs +440 -0
  106. package/native/vendor/html5gum-0.8.4/src/span.rs +98 -0
  107. package/native/vendor/html5gum-0.8.4/src/state.rs +16 -0
  108. package/native/vendor/html5gum-0.8.4/src/testutils.rs +71 -0
  109. package/native/vendor/html5gum-0.8.4/src/tokenizer.rs +189 -0
  110. package/native/vendor/html5gum-0.8.4/src/utils.rs +88 -0
  111. package/native/vendor/markup5ever-0.35.0/.cargo_vcs_info.json +6 -0
  112. package/native/vendor/markup5ever-0.35.0/Cargo.toml +45 -0
  113. package/native/vendor/markup5ever-0.35.0/LICENSE-APACHE +201 -0
  114. package/native/vendor/markup5ever-0.35.0/LICENSE-MIT +25 -0
  115. package/native/vendor/markup5ever-0.35.0/interface/mod.rs +422 -0
  116. package/native/vendor/markup5ever-0.35.0/interface/tree_builder.rs +280 -0
  117. package/native/vendor/markup5ever-0.35.0/lib.rs +59 -0
  118. package/native/vendor/markup5ever-0.35.0/serialize.rs +77 -0
  119. package/native/vendor/markup5ever-0.35.0/util/buffer_queue.rs +333 -0
  120. package/native/vendor/markup5ever-0.35.0/util/smallcharset.rs +88 -0
  121. package/package.json +137 -4
  122. package/rusteerio.darwin-arm64.node +0 -0
  123. package/rusteerio.darwin-x64.node +0 -0
  124. package/rusteerio.linux-arm64-gnu.node +0 -0
  125. package/rusteerio.linux-arm64-musl.node +0 -0
  126. package/rusteerio.linux-x64-gnu.node +0 -0
  127. package/rusteerio.linux-x64-musl.node +0 -0
  128. package/rusteerio.win32-arm64-msvc.node +0 -0
  129. package/rusteerio.win32-x64-msvc.node +0 -0
  130. package/scripts/check-native.mjs +15 -0
  131. package/scripts/check-release.mjs +235 -0
  132. package/scripts/fix-declarations.mjs +27 -0
  133. package/scripts/generate-notices.mjs +176 -0
  134. package/scripts/notices/README.md +13 -0
  135. package/scripts/notices/cheerio-MIT.txt +21 -0
  136. package/scripts/notices/html5ever-AUTHORS.txt +20 -0
  137. package/scripts/notices/html5ever-COPYRIGHT.txt +8 -0
  138. package/scripts/notices/html5ever-LICENSE-APACHE.txt +201 -0
  139. package/scripts/notices/html5ever-LICENSE-MIT.txt +25 -0
  140. package/scripts/notices/napi-rs-MIT.txt +43 -0
  141. package/scripts/notices/neon-MIT.txt +19 -0
  142. package/scripts/notices/runtime-01c266bced4a434da005.txt +3 -0
  143. package/scripts/notices/runtime-0a54e647fe54104658b5.txt +14 -0
  144. package/scripts/notices/runtime-0b74dfa0bcee5c420c6b.txt +25 -0
  145. package/scripts/notices/runtime-0d542e0c8804e39aa7f3.txt +177 -0
  146. package/scripts/notices/runtime-0f96a83840e146e43c0e.txt +21 -0
  147. package/scripts/notices/runtime-123a331b5dbf04c30097.txt +25 -0
  148. package/scripts/notices/runtime-172020dbfd5b53a226df.txt +34 -0
  149. package/scripts/notices/runtime-209fbbe0ad52d9235e37.txt +26 -0
  150. package/scripts/notices/runtime-23f18e03dc49df91622f.txt +23 -0
  151. package/scripts/notices/runtime-268872b9816f90fd8e85.txt +220 -0
  152. package/scripts/notices/runtime-35242e7a83f69875e6ed.txt +176 -0
  153. package/scripts/notices/runtime-378f5840b258e2779c39.txt +25 -0
  154. package/scripts/notices/runtime-4108245a1f2df9d4e94d.txt +25 -0
  155. package/scripts/notices/runtime-4455bf75a91154108304.txt +21 -0
  156. package/scripts/notices/runtime-553fffcd9b1cb158bc3e.txt +13 -0
  157. package/scripts/notices/runtime-62c7a1e35f56406896d7.txt +176 -0
  158. package/scripts/notices/runtime-6485b8ed310d3f0340bf.txt +25 -0
  159. package/scripts/notices/runtime-69fef7b0f322a6555415.txt +201 -0
  160. package/scripts/notices/runtime-6df43f6f4b5d4587f3d8.txt +187 -0
  161. package/scripts/notices/runtime-799e9ca9d179295ef372.txt +24 -0
  162. package/scripts/notices/runtime-7b63ecd5f1902af1b637.txt +25 -0
  163. package/scripts/notices/runtime-7bc7d5de2a0b793d4e1a.txt +21 -0
  164. package/scripts/notices/runtime-7e12e5df4bae12cb2158.txt +24 -0
  165. package/scripts/notices/runtime-861399f8c21c042b1105.txt +12 -0
  166. package/scripts/notices/runtime-8ada45cd9f843acf64e4.txt +201 -0
  167. package/scripts/notices/runtime-90eb64f0279b0d9432ac.txt +12 -0
  168. package/scripts/notices/runtime-a60eea817514531668d7.txt +201 -0
  169. package/scripts/notices/runtime-a7c936ff1ed8fa340172.txt +25 -0
  170. package/scripts/notices/runtime-ab6eec6caf0fa5775e41.txt +275 -0
  171. package/scripts/notices/runtime-b1181a40b2a7b25cf66f.txt +19 -0
  172. package/scripts/notices/runtime-b71bd43a069ca0641a9e.txt +25 -0
  173. package/scripts/notices/runtime-c16f8dcf1a368b83be78.txt +201 -0
  174. package/scripts/notices/runtime-c2cfccb812fe482101a8.txt +21 -0
  175. package/scripts/notices/runtime-e99d88d232bf57d70f0f.txt +25 -0
  176. package/scripts/notices/runtime-f32fb3b417a194167cfa.txt +9 -0
  177. package/scripts/notices/runtime-f5062c9a188d81dfe66b.txt +39 -0
  178. package/scripts/notices/runtime-f9070a832833fa7488fd.txt +4 -0
  179. package/scripts/notices/runtime-fab3dd6bdab226f1c086.txt +373 -0
  180. package/scripts/notices/runtime-fba3318d0c600380177e.txt +62 -0
  181. package/scripts/notices/runtime-ff8f68cb076caf8cefe7.txt +25 -0
  182. package/scripts/notices/runtime-ff92bed461f50338dd70.txt +74 -0
  183. package/scripts/notices/runtime.json +1632 -0
  184. package/scripts/notices/sources.json +555 -0
  185. package/scripts/notices/xray-MIT.txt +21 -0
  186. package/src/attributes.ts +271 -0
  187. package/src/codec.ts +74 -0
  188. package/src/dom.ts +87 -0
  189. package/src/extract-plan.ts +97 -0
  190. package/src/extract.ts +130 -0
  191. package/src/hooks.ts +220 -0
  192. package/src/index.ts +223 -0
  193. package/src/io.ts +491 -0
  194. package/src/native.ts +135 -0
  195. package/src/nodes.ts +290 -0
  196. package/src/parse.ts +53 -0
  197. package/src/parser-types.ts +157 -0
  198. package/src/router.ts +327 -0
  199. package/src/selection.ts +566 -0
  200. package/src/slim.ts +12 -0
  201. package/src/transport.ts +104 -0
  202. package/src/types.ts +186 -0
  203. package/src/utils.ts +29 -0
  204. package/src/workers.ts +21 -0
  205. package/tsconfig.json +15 -0
  206. package/tsup.config.ts +16 -0
@@ -0,0 +1,1494 @@
1
+ // Copyright 2014-2017 The html5ever Project Developers. See the
2
+ // COPYRIGHT file at the top-level directory of this distribution.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5
+ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6
+ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7
+ // option. This file may not be copied, modified, or distributed
8
+ // except according to those terms.
9
+
10
+ // The tree builder rules, as a single, enormous nested match expression.
11
+
12
+ use crate::interface::Quirks;
13
+ use crate::tokenizer::states::{Rawtext, Rcdata, ScriptData};
14
+ use crate::tokenizer::TagKind::{EndTag, StartTag};
15
+ use crate::tree_builder::tag_sets::*;
16
+ use crate::tree_builder::types::*;
17
+ use crate::tree_builder::{
18
+ create_element, html_elem, ElemName, NodeOrText::AppendNode, StrTendril, Tag, TreeBuilder,
19
+ TreeSink,
20
+ };
21
+ use crate::QualName;
22
+ use markup5ever::{expanded_name, local_name, ns};
23
+ use std::borrow::Cow::Borrowed;
24
+
25
+ use crate::tendril::SliceExt;
26
+ use match_token::match_token;
27
+
28
+ fn any_not_whitespace(x: &StrTendril) -> bool {
29
+ // FIXME: this might be much faster as a byte scan
30
+ x.chars().any(|c| !c.is_ascii_whitespace())
31
+ }
32
+
33
+ fn current_node<Handle>(open_elems: &[Handle]) -> &Handle {
34
+ open_elems.last().expect("no current element")
35
+ }
36
+
37
+ #[doc(hidden)]
38
+ impl<Handle, Sink> TreeBuilder<Handle, Sink>
39
+ where
40
+ Handle: Clone,
41
+ Sink: TreeSink<Handle = Handle>,
42
+ {
43
+ pub(crate) fn step(&self, mode: InsertionMode, token: Token) -> ProcessResult<Handle> {
44
+ self.debug_step(mode, &token);
45
+
46
+ match mode {
47
+ //§ the-initial-insertion-mode
48
+ InsertionMode::Initial => match_token!(token {
49
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
50
+ Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
51
+ Token::Comment(text) => self.append_comment_to_doc(text),
52
+ token => {
53
+ if !self.opts.iframe_srcdoc {
54
+ self.unexpected(&token);
55
+ self.set_quirks_mode(Quirks);
56
+ }
57
+ ProcessResult::Reprocess(InsertionMode::BeforeHtml, token)
58
+ }
59
+ }),
60
+
61
+ //§ the-before-html-insertion-mode
62
+ InsertionMode::BeforeHtml => match_token!(token {
63
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
64
+ Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
65
+ Token::Comment(text) => self.append_comment_to_doc(text),
66
+
67
+ tag @ <html> => {
68
+ self.create_root(tag.attrs);
69
+ self.mode.set(InsertionMode::BeforeHead);
70
+ ProcessResult::Done
71
+ }
72
+
73
+ </head> </body> </html> </br> => else,
74
+
75
+ tag @ </_> => self.unexpected(&tag),
76
+
77
+ token => {
78
+ self.create_root(vec!());
79
+ ProcessResult::Reprocess(InsertionMode::BeforeHead, token)
80
+ }
81
+ }),
82
+
83
+ //§ the-before-head-insertion-mode
84
+ InsertionMode::BeforeHead => match_token!(token {
85
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
86
+ Token::Characters(SplitStatus::Whitespace, _) => ProcessResult::Done,
87
+ Token::Comment(text) => self.append_comment(text),
88
+
89
+ <html> => self.step(InsertionMode::InBody, token),
90
+
91
+ tag @ <head> => {
92
+ *self.head_elem.borrow_mut() = Some(self.insert_element_for(tag));
93
+ self.mode.set(InsertionMode::InHead);
94
+ ProcessResult::Done
95
+ }
96
+
97
+ </head> </body> </html> </br> => else,
98
+
99
+ tag @ </_> => self.unexpected(&tag),
100
+
101
+ token => {
102
+ *self.head_elem.borrow_mut() = Some(self.insert_phantom(local_name!("head")));
103
+ ProcessResult::Reprocess(InsertionMode::InHead, token)
104
+ }
105
+ }),
106
+
107
+ //§ parsing-main-inhead
108
+ // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
109
+ InsertionMode::InHead => match_token!(token {
110
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
111
+ Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
112
+ Token::Comment(text) => self.append_comment(text),
113
+
114
+ <html> => self.step(InsertionMode::InBody, token),
115
+
116
+ tag @ <base> <basefont> <bgsound> <link> <meta> => {
117
+ // FIXME: handle <meta charset=...> and <meta http-equiv="Content-Type">
118
+ self.insert_and_pop_element_for(tag);
119
+ ProcessResult::DoneAckSelfClosing
120
+ }
121
+
122
+ tag @ <title> => {
123
+ self.parse_raw_data(tag, Rcdata)
124
+ }
125
+
126
+ tag @ <noframes> <style> <noscript> => {
127
+ if (!self.opts.scripting_enabled) && (tag.name == local_name!("noscript")) {
128
+ self.insert_element_for(tag);
129
+ self.mode.set(InsertionMode::InHeadNoscript);
130
+ ProcessResult::Done
131
+ } else {
132
+ self.parse_raw_data(tag, Rawtext)
133
+ }
134
+ }
135
+
136
+ tag @ <script> => {
137
+ let elem = create_element(
138
+ &self.sink, QualName::new(None, ns!(html), local_name!("script")),
139
+ tag.attrs);
140
+ if self.is_fragment() {
141
+ self.sink.mark_script_already_started(&elem);
142
+ }
143
+ self.insert_appropriately(AppendNode(elem.clone()), None);
144
+ self.push(&elem);
145
+ self.to_raw_text_mode(ScriptData)
146
+ }
147
+
148
+ </head> => {
149
+ self.pop();
150
+ self.mode.set(InsertionMode::AfterHead);
151
+ ProcessResult::Done
152
+ }
153
+
154
+ </body> </html> </br> => else,
155
+
156
+ tag @ <template> => {
157
+ self.active_formatting.borrow_mut().push(FormatEntry::Marker);
158
+ self.frameset_ok.set(false);
159
+ self.mode.set(InsertionMode::InTemplate);
160
+ self.template_modes.borrow_mut().push(InsertionMode::InTemplate);
161
+
162
+ if (self.should_attach_declarative_shadow(&tag)) {
163
+ // Attach shadow path
164
+
165
+ // Step 1. Let declarative shadow host element be adjusted current node.
166
+ let mut shadow_host = self.open_elems.borrow().last().unwrap().clone();
167
+ if self.is_fragment() && self.open_elems.borrow().len() == 1 {
168
+ shadow_host = self.context_elem.borrow().clone().unwrap();
169
+ }
170
+
171
+ // Step 2. Let template be the result of insert a foreign element for template start tag, with HTML namespace and true.
172
+ let template = self.insert_foreign_element(tag.clone(), ns!(html), true);
173
+
174
+ // Step 3 - 8.
175
+ // Attach a shadow root with declarative shadow host element, mode, clonable, serializable, delegatesFocus, and "named".
176
+ let succeeded = self.attach_declarative_shadow(&tag, &shadow_host, &template);
177
+ if !succeeded {
178
+ // Step 8.1.1. Insert an element at the adjusted insertion location with template.
179
+ // Pop the current template element created in step 2 first.
180
+ self.pop();
181
+ self.insert_element_for(tag);
182
+ }
183
+ } else {
184
+ self.insert_element_for(tag);
185
+ }
186
+
187
+ ProcessResult::Done
188
+ }
189
+
190
+ tag @ </template> => {
191
+ if !self.in_html_elem_named(local_name!("template")) {
192
+ self.unexpected(&tag);
193
+ } else {
194
+ self.generate_implied_end_tags(thorough_implied_end);
195
+ self.expect_to_close(local_name!("template"));
196
+ self.clear_active_formatting_to_marker();
197
+ self.template_modes.borrow_mut().pop();
198
+ self.mode.set(self.reset_insertion_mode());
199
+ }
200
+ ProcessResult::Done
201
+ }
202
+
203
+ <head> => self.unexpected(&token),
204
+ tag @ </_> => self.unexpected(&tag),
205
+
206
+ token => {
207
+ self.pop();
208
+ ProcessResult::Reprocess(InsertionMode::AfterHead, token)
209
+ }
210
+ }),
211
+
212
+ //§ parsing-main-inheadnoscript
213
+ InsertionMode::InHeadNoscript => match_token!(token {
214
+ <html> => self.step(InsertionMode::InBody, token),
215
+
216
+ </noscript> => {
217
+ self.pop();
218
+ self.mode.set(InsertionMode::InHead);
219
+ ProcessResult::Done
220
+ },
221
+
222
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
223
+ Token::Characters(SplitStatus::Whitespace, _) => self.step(InsertionMode::InHead, token),
224
+
225
+ Token::Comment(_) => self.step(InsertionMode::InHead, token),
226
+
227
+ <basefont> <bgsound> <link> <meta> <noframes> <style>
228
+ => self.step(InsertionMode::InHead, token),
229
+
230
+ </br> => else,
231
+
232
+ <head> <noscript> => self.unexpected(&token),
233
+ tag @ </_> => self.unexpected(&tag),
234
+
235
+ token => {
236
+ self.unexpected(&token);
237
+ self.pop();
238
+ ProcessResult::Reprocess(InsertionMode::InHead, token)
239
+ },
240
+ }),
241
+
242
+ //§ the-after-head-insertion-mode
243
+ InsertionMode::AfterHead => match_token!(token {
244
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
245
+ Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
246
+ Token::Comment(text) => self.append_comment(text),
247
+
248
+ <html> => self.step(InsertionMode::InBody, token),
249
+
250
+ tag @ <body> => {
251
+ self.insert_element_for(tag);
252
+ self.frameset_ok.set(false);
253
+ self.mode.set(InsertionMode::InBody);
254
+ ProcessResult::Done
255
+ }
256
+
257
+ tag @ <frameset> => {
258
+ self.insert_element_for(tag);
259
+ self.mode.set(InsertionMode::InFrameset);
260
+ ProcessResult::Done
261
+ }
262
+
263
+ <base> <basefont> <bgsound> <link> <meta>
264
+ <noframes> <script> <style> <template> <title> => {
265
+ self.unexpected(&token);
266
+ let head = self.head_elem.borrow().as_ref().expect("no head element").clone();
267
+ self.push(&head);
268
+ let result = self.step(InsertionMode::InHead, token);
269
+ self.remove_from_stack(&head);
270
+ result
271
+ }
272
+
273
+ </template> => self.step(InsertionMode::InHead, token),
274
+
275
+ </body> </html> </br> => else,
276
+
277
+ <head> => self.unexpected(&token),
278
+ tag @ </_> => self.unexpected(&tag),
279
+
280
+ token => {
281
+ self.insert_phantom(local_name!("body"));
282
+ ProcessResult::Reprocess(InsertionMode::InBody, token)
283
+ }
284
+ }),
285
+
286
+ //§ parsing-main-inbody
287
+ InsertionMode::InBody => match_token!(token {
288
+ Token::NullCharacter => self.unexpected(&token),
289
+
290
+ Token::Characters(_, text) => {
291
+ self.reconstruct_active_formatting_elements();
292
+ if any_not_whitespace(&text) {
293
+ self.frameset_ok.set(false);
294
+ }
295
+ self.append_text(text)
296
+ }
297
+
298
+ Token::Comment(text) => self.append_comment(text),
299
+
300
+ tag @ <html> => {
301
+ self.unexpected(&tag);
302
+ if !self.in_html_elem_named(local_name!("template")) {
303
+ let open_elems = self.open_elems.borrow();
304
+ let top = html_elem(&open_elems);
305
+ self.sink.add_attrs_if_missing(top, tag.attrs);
306
+ }
307
+ ProcessResult::Done
308
+ }
309
+
310
+ <base> <basefont> <bgsound> <link> <meta> <noframes>
311
+ <script> <style> <template> <title> </template> => {
312
+ self.step(InsertionMode::InHead, token)
313
+ }
314
+
315
+ tag @ <body> => {
316
+ self.unexpected(&tag);
317
+ let body_elem = self.body_elem().as_deref().cloned();
318
+ match body_elem {
319
+ Some(ref node) if self.open_elems.borrow().len() != 1 &&
320
+ !self.in_html_elem_named(local_name!("template")) => {
321
+ self.frameset_ok.set(false);
322
+ self.sink.add_attrs_if_missing(node, tag.attrs)
323
+ },
324
+ _ => {}
325
+ }
326
+ ProcessResult::Done
327
+ }
328
+
329
+ tag @ <frameset> => {
330
+ self.unexpected(&tag);
331
+ if !self.frameset_ok.get() { return ProcessResult::Done; }
332
+
333
+ let Some(body) = self.body_elem().map(|b| b.clone()) else {
334
+ return ProcessResult::Done;
335
+ };
336
+ self.sink.remove_from_parent(&body);
337
+
338
+ // FIXME: can we get here in the fragment case?
339
+ // What to do with the first element then?
340
+ self.truncate_stack(1);
341
+ self.insert_element_for(tag);
342
+ self.mode.set(InsertionMode::InFrameset);
343
+ ProcessResult::Done
344
+ }
345
+
346
+ Token::Eof => {
347
+ if !self.template_modes.borrow().is_empty() {
348
+ self.step(InsertionMode::InTemplate, token)
349
+ } else {
350
+ self.check_body_end();
351
+ self.stop_parsing()
352
+ }
353
+ }
354
+
355
+ </body> => {
356
+ if self.in_scope_named(default_scope, local_name!("body")) {
357
+ self.check_body_end();
358
+ self.mode.set(InsertionMode::AfterBody);
359
+ } else {
360
+ self.sink.parse_error(Borrowed("</body> with no <body> in scope"));
361
+ }
362
+ ProcessResult::Done
363
+ }
364
+
365
+ </html> => {
366
+ if self.in_scope_named(default_scope, local_name!("body")) {
367
+ self.check_body_end();
368
+ ProcessResult::Reprocess(InsertionMode::AfterBody, token)
369
+ } else {
370
+ self.sink.parse_error(Borrowed("</html> with no <body> in scope"));
371
+ ProcessResult::Done
372
+ }
373
+ }
374
+
375
+ tag @ <address> <article> <aside> <blockquote> <center> <details> <dialog>
376
+ <dir> <div> <dl> <fieldset> <figcaption> <figure> <footer> <header>
377
+ <hgroup> <main> <nav> <ol> <p> <search> <section> <summary> <ul> => {
378
+ self.close_p_element_in_button_scope();
379
+ self.insert_element_for(tag);
380
+ ProcessResult::Done
381
+ }
382
+
383
+ tag @ <menu> => {
384
+ self.close_p_element_in_button_scope();
385
+ self.insert_element_for(tag);
386
+ ProcessResult::Done
387
+ }
388
+
389
+ tag @ <h1> <h2> <h3> <h4> <h5> <h6> => {
390
+ self.close_p_element_in_button_scope();
391
+ if self.current_node_in(heading_tag) {
392
+ self.sink.parse_error(Borrowed("nested heading tags"));
393
+ self.pop();
394
+ }
395
+ self.insert_element_for(tag);
396
+ ProcessResult::Done
397
+ }
398
+
399
+ tag @ <pre> <listing> => {
400
+ self.close_p_element_in_button_scope();
401
+ self.insert_element_for(tag);
402
+ self.ignore_lf.set(true);
403
+ self.frameset_ok.set(false);
404
+ ProcessResult::Done
405
+ }
406
+
407
+ tag @ <form> => {
408
+ if self.form_elem.borrow().is_some() &&
409
+ !self.in_html_elem_named(local_name!("template")) {
410
+ self.sink.parse_error(Borrowed("nested forms"));
411
+ } else {
412
+ self.close_p_element_in_button_scope();
413
+ let elem = self.insert_element_for(tag);
414
+ if !self.in_html_elem_named(local_name!("template")) {
415
+ *self.form_elem.borrow_mut() = Some(elem);
416
+ }
417
+ }
418
+ ProcessResult::Done
419
+ }
420
+
421
+ tag @ <li> <dd> <dt> => {
422
+ declare_tag_set!(close_list = "li");
423
+ declare_tag_set!(close_defn = "dd" "dt");
424
+ declare_tag_set!(extra_special = [special_tag] - "address" "div" "p");
425
+ let list = match tag.name {
426
+ local_name!("li") => true,
427
+ local_name!("dd") | local_name!("dt") => false,
428
+ _ => unreachable!(),
429
+ };
430
+
431
+ self.frameset_ok.set(false);
432
+
433
+ let mut to_close = None;
434
+ for node in self.open_elems.borrow().iter().rev() {
435
+ let elem_name = self.sink.elem_name(node);
436
+ let name = elem_name.expanded();
437
+ let can_close = if list {
438
+ close_list(name)
439
+ } else {
440
+ close_defn(name)
441
+ };
442
+ if can_close {
443
+ to_close = Some(name.local.clone());
444
+ break;
445
+ }
446
+ if extra_special(name) {
447
+ break;
448
+ }
449
+ }
450
+
451
+ if let Some(name) = to_close {
452
+ self.generate_implied_end_except(name.clone());
453
+ self.expect_to_close(name);
454
+ }
455
+
456
+ self.close_p_element_in_button_scope();
457
+ self.insert_element_for(tag);
458
+ ProcessResult::Done
459
+ }
460
+
461
+ tag @ <plaintext> => {
462
+ self.close_p_element_in_button_scope();
463
+ self.insert_element_for(tag);
464
+ ProcessResult::ToPlaintext
465
+ }
466
+
467
+ tag @ <button> => {
468
+ if self.in_scope_named(default_scope, local_name!("button")) {
469
+ self.sink.parse_error(Borrowed("nested buttons"));
470
+ self.generate_implied_end_tags(cursory_implied_end);
471
+ self.pop_until_named(local_name!("button"));
472
+ }
473
+ self.reconstruct_active_formatting_elements();
474
+ self.insert_element_for(tag);
475
+ self.frameset_ok.set(false);
476
+ ProcessResult::Done
477
+ }
478
+
479
+ tag @ </address> </article> </aside> </blockquote> </button> </center>
480
+ </details> </dialog> </dir> </div> </dl> </fieldset> </figcaption>
481
+ </figure> </footer> </header> </hgroup> </listing> </main> </menu>
482
+ </nav> </ol> </pre> </search> </section> </summary> </ul> => {
483
+ if !self.in_scope_named(default_scope, tag.name.clone()) {
484
+ self.unexpected(&tag);
485
+ } else {
486
+ self.generate_implied_end_tags(cursory_implied_end);
487
+ self.expect_to_close(tag.name);
488
+ }
489
+ ProcessResult::Done
490
+ }
491
+
492
+ </form> => {
493
+ if !self.in_html_elem_named(local_name!("template")) {
494
+ let Some(node) = self.form_elem.take() else {
495
+ self.sink.parse_error(Borrowed("Null form element pointer on </form>"));
496
+ return ProcessResult::Done;
497
+ };
498
+ if !self.in_scope(default_scope, |n| self.sink.same_node(&node, &n)) {
499
+ self.sink.parse_error(Borrowed("Form element not in scope on </form>"));
500
+ return ProcessResult::Done;
501
+ }
502
+ self.generate_implied_end_tags(cursory_implied_end);
503
+ let current = self.current_node().clone();
504
+ self.remove_from_stack(&node);
505
+ if !self.sink.same_node(&current, &node) {
506
+ self.sink.parse_error(Borrowed("Bad open element on </form>"));
507
+ }
508
+ } else {
509
+ if !self.in_scope_named(default_scope, local_name!("form")) {
510
+ self.sink.parse_error(Borrowed("Form element not in scope on </form>"));
511
+ return ProcessResult::Done;
512
+ }
513
+ self.generate_implied_end_tags(cursory_implied_end);
514
+ if !self.current_node_named(local_name!("form")) {
515
+ self.sink.parse_error(Borrowed("Bad open element on </form>"));
516
+ }
517
+ self.pop_until_named(local_name!("form"));
518
+ }
519
+ ProcessResult::Done
520
+ }
521
+
522
+ </p> => {
523
+ if !self.in_scope_named(button_scope, local_name!("p")) {
524
+ self.sink.parse_error(Borrowed("No <p> tag to close"));
525
+ self.insert_phantom(local_name!("p"));
526
+ }
527
+ self.close_p_element();
528
+ ProcessResult::Done
529
+ }
530
+
531
+ tag @ </li> </dd> </dt> => {
532
+ let in_scope = if tag.name == local_name!("li") {
533
+ self.in_scope_named(list_item_scope, tag.name.clone())
534
+ } else {
535
+ self.in_scope_named(default_scope, tag.name.clone())
536
+ };
537
+ if in_scope {
538
+ self.generate_implied_end_except(tag.name.clone());
539
+ self.expect_to_close(tag.name);
540
+ } else {
541
+ self.sink.parse_error(Borrowed("No matching tag to close"));
542
+ }
543
+ ProcessResult::Done
544
+ }
545
+
546
+ tag @ </h1> </h2> </h3> </h4> </h5> </h6> => {
547
+ if self.in_scope(default_scope, |n| self.elem_in(&n, heading_tag)) {
548
+ self.generate_implied_end_tags(cursory_implied_end);
549
+ if !self.current_node_named(tag.name) {
550
+ self.sink.parse_error(Borrowed("Closing wrong heading tag"));
551
+ }
552
+ self.pop_until(heading_tag);
553
+ } else {
554
+ self.sink.parse_error(Borrowed("No heading tag to close"));
555
+ }
556
+ ProcessResult::Done
557
+ }
558
+
559
+ tag @ <a> => {
560
+ self.handle_misnested_a_tags(&tag);
561
+ self.reconstruct_active_formatting_elements();
562
+ self.create_formatting_element_for(tag);
563
+ ProcessResult::Done
564
+ }
565
+
566
+ tag @ <b> <big> <code> <em> <font> <i> <s> <small> <strike> <strong> <tt> <u> => {
567
+ self.reconstruct_active_formatting_elements();
568
+ self.create_formatting_element_for(tag);
569
+ ProcessResult::Done
570
+ }
571
+
572
+ tag @ <nobr> => {
573
+ self.reconstruct_active_formatting_elements();
574
+ if self.in_scope_named(default_scope, local_name!("nobr")) {
575
+ self.sink.parse_error(Borrowed("Nested <nobr>"));
576
+ self.adoption_agency(local_name!("nobr"));
577
+ self.reconstruct_active_formatting_elements();
578
+ }
579
+ self.create_formatting_element_for(tag);
580
+ ProcessResult::Done
581
+ }
582
+
583
+ tag @ </a> </b> </big> </code> </em> </font> </i> </nobr>
584
+ </s> </small> </strike> </strong> </tt> </u> => {
585
+ self.adoption_agency(tag.name);
586
+ ProcessResult::Done
587
+ }
588
+
589
+ tag @ <applet> <marquee> <object> => {
590
+ self.reconstruct_active_formatting_elements();
591
+ self.insert_element_for(tag);
592
+ self.active_formatting.borrow_mut().push(FormatEntry::Marker);
593
+ self.frameset_ok.set(false);
594
+ ProcessResult::Done
595
+ }
596
+
597
+ tag @ </applet> </marquee> </object> => {
598
+ if !self.in_scope_named(default_scope, tag.name.clone()) {
599
+ self.unexpected(&tag);
600
+ } else {
601
+ self.generate_implied_end_tags(cursory_implied_end);
602
+ self.expect_to_close(tag.name);
603
+ self.clear_active_formatting_to_marker();
604
+ }
605
+ ProcessResult::Done
606
+ }
607
+
608
+ tag @ <table> => {
609
+ if self.quirks_mode.get() != Quirks {
610
+ self.close_p_element_in_button_scope();
611
+ }
612
+ self.insert_element_for(tag);
613
+ self.frameset_ok.set(false);
614
+ self.mode.set(InsertionMode::InTable);
615
+ ProcessResult::Done
616
+ }
617
+
618
+ tag @ </br> => {
619
+ self.unexpected(&tag);
620
+ self.step(InsertionMode::InBody, Token::Tag(Tag {
621
+ kind: StartTag,
622
+ attrs: vec!(),
623
+ ..tag
624
+ }))
625
+ }
626
+
627
+ tag @ <area> <br> <embed> <img> <keygen> <wbr> <input> => {
628
+ let keep_frameset_ok = match tag.name {
629
+ local_name!("input") => self.is_type_hidden(&tag),
630
+ _ => false,
631
+ };
632
+ self.reconstruct_active_formatting_elements();
633
+ self.insert_and_pop_element_for(tag);
634
+ if !keep_frameset_ok {
635
+ self.frameset_ok.set(false);
636
+ }
637
+ ProcessResult::DoneAckSelfClosing
638
+ }
639
+
640
+ tag @ <param> <source> <track> => {
641
+ self.insert_and_pop_element_for(tag);
642
+ ProcessResult::DoneAckSelfClosing
643
+ }
644
+
645
+ tag @ <hr> => {
646
+ self.close_p_element_in_button_scope();
647
+ self.insert_and_pop_element_for(tag);
648
+ self.frameset_ok.set(false);
649
+ ProcessResult::DoneAckSelfClosing
650
+ }
651
+
652
+ tag @ <image> => {
653
+ self.unexpected(&tag);
654
+ self.step(InsertionMode::InBody, Token::Tag(Tag {
655
+ name: local_name!("img"),
656
+ ..tag
657
+ }))
658
+ }
659
+
660
+ tag @ <textarea> => {
661
+ self.ignore_lf.set(true);
662
+ self.frameset_ok.set(false);
663
+ self.parse_raw_data(tag, Rcdata)
664
+ }
665
+
666
+ tag @ <xmp> => {
667
+ self.close_p_element_in_button_scope();
668
+ self.reconstruct_active_formatting_elements();
669
+ self.frameset_ok.set(false);
670
+ self.parse_raw_data(tag, Rawtext)
671
+ }
672
+
673
+ tag @ <iframe> => {
674
+ self.frameset_ok.set(false);
675
+ self.parse_raw_data(tag, Rawtext)
676
+ }
677
+
678
+ tag @ <noembed> => {
679
+ self.parse_raw_data(tag, Rawtext)
680
+ }
681
+
682
+ // <noscript> handled in wildcard case below
683
+
684
+ tag @ <select> => {
685
+ self.reconstruct_active_formatting_elements();
686
+ self.insert_element_for(tag);
687
+ self.frameset_ok.set(false);
688
+ // NB: mode == InBody but possibly self.mode != mode, if
689
+ // we're processing "as in the rules for InBody".
690
+ self.mode.set(match self.mode.get() {
691
+ InsertionMode::InTable | InsertionMode::InCaption | InsertionMode::InTableBody
692
+ | InsertionMode::InRow | InsertionMode::InCell => InsertionMode::InSelectInTable,
693
+ _ => InsertionMode::InSelect,
694
+ });
695
+ ProcessResult::Done
696
+ }
697
+
698
+ tag @ <optgroup> <option> => {
699
+ if self.current_node_named(local_name!("option")) {
700
+ self.pop();
701
+ }
702
+ self.reconstruct_active_formatting_elements();
703
+ self.insert_element_for(tag);
704
+ ProcessResult::Done
705
+ }
706
+
707
+ tag @ <rb> <rtc> => {
708
+ if self.in_scope_named(default_scope, local_name!("ruby")) {
709
+ self.generate_implied_end_tags(cursory_implied_end);
710
+ }
711
+ if !self.current_node_named(local_name!("ruby")) {
712
+ self.unexpected(&tag);
713
+ }
714
+ self.insert_element_for(tag);
715
+ ProcessResult::Done
716
+ }
717
+
718
+ tag @ <rp> <rt> => {
719
+ if self.in_scope_named(default_scope, local_name!("ruby")) {
720
+ self.generate_implied_end_except(local_name!("rtc"));
721
+ }
722
+ if !self.current_node_named(local_name!("rtc")) && !self.current_node_named(local_name!("ruby")) {
723
+ self.unexpected(&tag);
724
+ }
725
+ self.insert_element_for(tag);
726
+ ProcessResult::Done
727
+ }
728
+
729
+ tag @ <math> => self.enter_foreign(tag, ns!(mathml)),
730
+
731
+ tag @ <svg> => self.enter_foreign(tag, ns!(svg)),
732
+
733
+ <caption> <col> <colgroup> <frame> <head>
734
+ <tbody> <td> <tfoot> <th> <thead> <tr> => {
735
+ self.unexpected(&token);
736
+ ProcessResult::Done
737
+ }
738
+
739
+ tag @ <_> => {
740
+ if self.opts.scripting_enabled && tag.name == local_name!("noscript") {
741
+ self.parse_raw_data(tag, Rawtext)
742
+ } else {
743
+ self.reconstruct_active_formatting_elements();
744
+ self.insert_element_for(tag);
745
+ ProcessResult::Done
746
+ }
747
+ }
748
+
749
+ tag @ </_> => {
750
+ self.process_end_tag_in_body(tag);
751
+ ProcessResult::Done
752
+ }
753
+
754
+ // FIXME: This should be unreachable, but match_token requires a
755
+ // catch-all case.
756
+ _ => panic!("impossible case in InBody mode"),
757
+ }),
758
+
759
+ //§ parsing-main-incdata
760
+ InsertionMode::Text => match_token!(token {
761
+ Token::Characters(_, text) => self.append_text(text),
762
+
763
+ Token::Eof => {
764
+ self.unexpected(&token);
765
+ if self.current_node_named(local_name!("script")) {
766
+ let open_elems = self.open_elems.borrow();
767
+ let current = current_node(&open_elems);
768
+ self.sink.mark_script_already_started(current);
769
+ }
770
+ self.pop();
771
+ ProcessResult::Reprocess(self.orig_mode.take().unwrap(), token)
772
+ }
773
+
774
+ tag @ </_> => {
775
+ let node = self.pop();
776
+ self.mode.set(self.orig_mode.take().unwrap());
777
+ if tag.name == local_name!("script") {
778
+ return ProcessResult::Script(node);
779
+ }
780
+ ProcessResult::Done
781
+ }
782
+
783
+ // The spec doesn't say what to do here.
784
+ // Other tokens are impossible?
785
+ _ => panic!("impossible case in Text mode"),
786
+ }),
787
+
788
+ //§ parsing-main-intable
789
+ InsertionMode::InTable => match_token!(token {
790
+ // FIXME: hack, should implement pat | pat for match_token instead
791
+ Token::NullCharacter => self.process_chars_in_table(token),
792
+
793
+ Token::Characters(..) => self.process_chars_in_table(token),
794
+
795
+ Token::Comment(text) => self.append_comment(text),
796
+
797
+ tag @ <caption> => {
798
+ self.pop_until_current(table_scope);
799
+ self.active_formatting.borrow_mut().push(FormatEntry::Marker);
800
+ self.insert_element_for(tag);
801
+ self.mode.set(InsertionMode::InCaption);
802
+ ProcessResult::Done
803
+ }
804
+
805
+ tag @ <colgroup> => {
806
+ self.pop_until_current(table_scope);
807
+ self.insert_element_for(tag);
808
+ self.mode.set(InsertionMode::InColumnGroup);
809
+ ProcessResult::Done
810
+ }
811
+
812
+ <col> => {
813
+ self.pop_until_current(table_scope);
814
+ self.insert_phantom(local_name!("colgroup"));
815
+ ProcessResult::Reprocess(InsertionMode::InColumnGroup, token)
816
+ }
817
+
818
+ tag @ <tbody> <tfoot> <thead> => {
819
+ self.pop_until_current(table_scope);
820
+ self.insert_element_for(tag);
821
+ self.mode.set(InsertionMode::InTableBody);
822
+ ProcessResult::Done
823
+ }
824
+
825
+ <td> <th> <tr> => {
826
+ self.pop_until_current(table_scope);
827
+ self.insert_phantom(local_name!("tbody"));
828
+ ProcessResult::Reprocess(InsertionMode::InTableBody, token)
829
+ }
830
+
831
+ <table> => {
832
+ self.unexpected(&token);
833
+ if self.in_scope_named(table_scope, local_name!("table")) {
834
+ self.pop_until_named(local_name!("table"));
835
+ ProcessResult::Reprocess(self.reset_insertion_mode(), token)
836
+ } else {
837
+ ProcessResult::Done
838
+ }
839
+ }
840
+
841
+ </table> => {
842
+ if self.in_scope_named(table_scope, local_name!("table")) {
843
+ self.pop_until_named(local_name!("table"));
844
+ self.mode.set(self.reset_insertion_mode());
845
+ } else {
846
+ self.unexpected(&token);
847
+ }
848
+ ProcessResult::Done
849
+ }
850
+
851
+ </body> </caption> </col> </colgroup> </html>
852
+ </tbody> </td> </tfoot> </th> </thead> </tr> =>
853
+ self.unexpected(&token),
854
+
855
+ <style> <script> <template> </template>
856
+ => self.step(InsertionMode::InHead, token),
857
+
858
+ tag @ <input> => {
859
+ self.unexpected(&tag);
860
+ if self.is_type_hidden(&tag) {
861
+ self.insert_and_pop_element_for(tag);
862
+ ProcessResult::DoneAckSelfClosing
863
+ } else {
864
+ self.foster_parent_in_body(Token::Tag(tag))
865
+ }
866
+ }
867
+
868
+ tag @ <form> => {
869
+ self.unexpected(&tag);
870
+ if !self.in_html_elem_named(local_name!("template")) && self.form_elem.borrow().is_none() {
871
+ *self.form_elem.borrow_mut() = Some(self.insert_and_pop_element_for(tag));
872
+ }
873
+ ProcessResult::Done
874
+ }
875
+
876
+ Token::Eof => self.step(InsertionMode::InBody, token),
877
+
878
+ token => {
879
+ self.unexpected(&token);
880
+ self.foster_parent_in_body(token)
881
+ }
882
+ }),
883
+
884
+ //§ parsing-main-intabletext
885
+ InsertionMode::InTableText => match_token!(token {
886
+ Token::NullCharacter => self.unexpected(&token),
887
+
888
+ Token::Characters(split, text) => {
889
+ self.pending_table_text.borrow_mut().push((split, text));
890
+ ProcessResult::Done
891
+ }
892
+
893
+ token => {
894
+ let pending = self.pending_table_text.take();
895
+ let contains_nonspace = pending.iter().any(|&(split, ref text)| {
896
+ match split {
897
+ SplitStatus::Whitespace => false,
898
+ SplitStatus::NotWhitespace => true,
899
+ SplitStatus::NotSplit => any_not_whitespace(text),
900
+ }
901
+ });
902
+
903
+ if contains_nonspace {
904
+ self.sink.parse_error(Borrowed("Non-space table text"));
905
+ for (split, text) in pending.into_iter() {
906
+ match self.foster_parent_in_body(Token::Characters(split, text)) {
907
+ ProcessResult::Done => (),
908
+ _ => panic!("not prepared to handle this!"),
909
+ }
910
+ }
911
+ } else {
912
+ for (_, text) in pending.into_iter() {
913
+ self.append_text(text);
914
+ }
915
+ }
916
+
917
+ ProcessResult::Reprocess(self.orig_mode.take().unwrap(), token)
918
+ }
919
+ }),
920
+
921
+ //§ parsing-main-incaption
922
+ InsertionMode::InCaption => match_token!(token {
923
+ tag @ <caption> <col> <colgroup> <tbody> <td> <tfoot>
924
+ <th> <thead> <tr> </table> </caption> => {
925
+ if self.in_scope_named(table_scope, local_name!("caption")) {
926
+ self.generate_implied_end_tags(cursory_implied_end);
927
+ self.expect_to_close(local_name!("caption"));
928
+ self.clear_active_formatting_to_marker();
929
+ match tag {
930
+ Tag { kind: EndTag, name: local_name!("caption"), .. } => {
931
+ self.mode.set(InsertionMode::InTable);
932
+ ProcessResult::Done
933
+ }
934
+ _ => ProcessResult::Reprocess(InsertionMode::InTable, Token::Tag(tag))
935
+ }
936
+ } else {
937
+ self.unexpected(&tag);
938
+ ProcessResult::Done
939
+ }
940
+ }
941
+
942
+ </body> </col> </colgroup> </html> </tbody>
943
+ </td> </tfoot> </th> </thead> </tr> => self.unexpected(&token),
944
+
945
+ token => self.step(InsertionMode::InBody, token),
946
+ }),
947
+
948
+ //§ parsing-main-incolgroup
949
+ InsertionMode::InColumnGroup => match_token!(token {
950
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
951
+ Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
952
+ Token::Comment(text) => self.append_comment(text),
953
+
954
+ <html> => self.step(InsertionMode::InBody, token),
955
+
956
+ tag @ <col> => {
957
+ self.insert_and_pop_element_for(tag);
958
+ ProcessResult::DoneAckSelfClosing
959
+ }
960
+
961
+ </colgroup> => {
962
+ if self.current_node_named(local_name!("colgroup")) {
963
+ self.pop();
964
+ self.mode.set(InsertionMode::InTable);
965
+ } else {
966
+ self.unexpected(&token);
967
+ }
968
+ ProcessResult::Done
969
+ }
970
+
971
+ </col> => self.unexpected(&token),
972
+
973
+ <template> </template> => self.step(InsertionMode::InHead, token),
974
+
975
+ Token::Eof => self.step(InsertionMode::InBody, token),
976
+
977
+ token => {
978
+ if self.current_node_named(local_name!("colgroup")) {
979
+ self.pop();
980
+ ProcessResult::Reprocess(InsertionMode::InTable, token)
981
+ } else {
982
+ self.unexpected(&token)
983
+ }
984
+ }
985
+ }),
986
+
987
+ //§ parsing-main-intbody
988
+ InsertionMode::InTableBody => match_token!(token {
989
+ tag @ <tr> => {
990
+ self.pop_until_current(table_body_context);
991
+ self.insert_element_for(tag);
992
+ self.mode.set(InsertionMode::InRow);
993
+ ProcessResult::Done
994
+ }
995
+
996
+ <th> <td> => {
997
+ self.unexpected(&token);
998
+ self.pop_until_current(table_body_context);
999
+ self.insert_phantom(local_name!("tr"));
1000
+ ProcessResult::Reprocess(InsertionMode::InRow, token)
1001
+ }
1002
+
1003
+ tag @ </tbody> </tfoot> </thead> => {
1004
+ if self.in_scope_named(table_scope, tag.name.clone()) {
1005
+ self.pop_until_current(table_body_context);
1006
+ self.pop();
1007
+ self.mode.set(InsertionMode::InTable);
1008
+ } else {
1009
+ self.unexpected(&tag);
1010
+ }
1011
+ ProcessResult::Done
1012
+ }
1013
+
1014
+ <caption> <col> <colgroup> <tbody> <tfoot> <thead> </table> => {
1015
+ declare_tag_set!(table_outer = "table" "tbody" "tfoot");
1016
+ if self.in_scope(table_scope, |e| self.elem_in(&e, table_outer)) {
1017
+ self.pop_until_current(table_body_context);
1018
+ self.pop();
1019
+ ProcessResult::Reprocess(InsertionMode::InTable, token)
1020
+ } else {
1021
+ self.unexpected(&token)
1022
+ }
1023
+ }
1024
+
1025
+ </body> </caption> </col> </colgroup> </html> </td> </th> </tr>
1026
+ => self.unexpected(&token),
1027
+
1028
+ token => self.step(InsertionMode::InTable, token),
1029
+ }),
1030
+
1031
+ //§ parsing-main-intr
1032
+ InsertionMode::InRow => match_token!(token {
1033
+ tag @ <th> <td> => {
1034
+ self.pop_until_current(table_row_context);
1035
+ self.insert_element_for(tag);
1036
+ self.mode.set(InsertionMode::InCell);
1037
+ self.active_formatting.borrow_mut().push(FormatEntry::Marker);
1038
+ ProcessResult::Done
1039
+ }
1040
+
1041
+ </tr> => {
1042
+ if self.in_scope_named(table_scope, local_name!("tr")) {
1043
+ self.pop_until_current(table_row_context);
1044
+ let node = self.pop();
1045
+ self.assert_named(&node, local_name!("tr"));
1046
+ self.mode.set(InsertionMode::InTableBody);
1047
+ } else {
1048
+ self.unexpected(&token);
1049
+ }
1050
+ ProcessResult::Done
1051
+ }
1052
+
1053
+ <caption> <col> <colgroup> <tbody> <tfoot> <thead> <tr> </table> => {
1054
+ if self.in_scope_named(table_scope, local_name!("tr")) {
1055
+ self.pop_until_current(table_row_context);
1056
+ let node = self.pop();
1057
+ self.assert_named(&node, local_name!("tr"));
1058
+ ProcessResult::Reprocess(InsertionMode::InTableBody, token)
1059
+ } else {
1060
+ self.unexpected(&token)
1061
+ }
1062
+ }
1063
+
1064
+ tag @ </tbody> </tfoot> </thead> => {
1065
+ if self.in_scope_named(table_scope, tag.name.clone()) {
1066
+ if self.in_scope_named(table_scope, local_name!("tr")) {
1067
+ self.pop_until_current(table_row_context);
1068
+ let node = self.pop();
1069
+ self.assert_named(&node, local_name!("tr"));
1070
+ ProcessResult::Reprocess(InsertionMode::InTableBody, Token::Tag(tag))
1071
+ } else {
1072
+ ProcessResult::Done
1073
+ }
1074
+ } else {
1075
+ self.unexpected(&tag)
1076
+ }
1077
+ }
1078
+
1079
+ </body> </caption> </col> </colgroup> </html> </td> </th>
1080
+ => self.unexpected(&token),
1081
+
1082
+ token => self.step(InsertionMode::InTable, token),
1083
+ }),
1084
+
1085
+ //§ parsing-main-intd
1086
+ InsertionMode::InCell => match_token!(token {
1087
+ tag @ </td> </th> => {
1088
+ if self.in_scope_named(table_scope, tag.name.clone()) {
1089
+ self.generate_implied_end_tags(cursory_implied_end);
1090
+ self.expect_to_close(tag.name);
1091
+ self.clear_active_formatting_to_marker();
1092
+ self.mode.set(InsertionMode::InRow);
1093
+ } else {
1094
+ self.unexpected(&tag);
1095
+ }
1096
+ ProcessResult::Done
1097
+ }
1098
+
1099
+ <caption> <col> <colgroup> <tbody> <td> <tfoot> <th> <thead> <tr> => {
1100
+ if self.in_scope(table_scope, |n| self.elem_in(&n, td_th)) {
1101
+ self.close_the_cell();
1102
+ ProcessResult::Reprocess(InsertionMode::InRow, token)
1103
+ } else {
1104
+ self.unexpected(&token)
1105
+ }
1106
+ }
1107
+
1108
+ </body> </caption> </col> </colgroup> </html>
1109
+ => self.unexpected(&token),
1110
+
1111
+ tag @ </table> </tbody> </tfoot> </thead> </tr> => {
1112
+ if self.in_scope_named(table_scope, tag.name.clone()) {
1113
+ self.close_the_cell();
1114
+ ProcessResult::Reprocess(InsertionMode::InRow, Token::Tag(tag))
1115
+ } else {
1116
+ self.unexpected(&tag)
1117
+ }
1118
+ }
1119
+
1120
+ token => self.step(InsertionMode::InBody, token),
1121
+ }),
1122
+
1123
+ //§ parsing-main-inselect
1124
+ InsertionMode::InSelect => match_token!(token {
1125
+ Token::NullCharacter => self.unexpected(&token),
1126
+ Token::Characters(_, text) => self.append_text(text),
1127
+ Token::Comment(text) => self.append_comment(text),
1128
+
1129
+ <html> => self.step(InsertionMode::InBody, token),
1130
+
1131
+ tag @ <option> => {
1132
+ if self.current_node_named(local_name!("option")) {
1133
+ self.pop();
1134
+ }
1135
+ self.insert_element_for(tag);
1136
+ ProcessResult::Done
1137
+ }
1138
+
1139
+ tag @ <optgroup> => {
1140
+ if self.current_node_named(local_name!("option")) {
1141
+ self.pop();
1142
+ }
1143
+ if self.current_node_named(local_name!("optgroup")) {
1144
+ self.pop();
1145
+ }
1146
+ self.insert_element_for(tag);
1147
+ ProcessResult::Done
1148
+ }
1149
+
1150
+ tag @ <hr> => {
1151
+ if self.current_node_named(local_name!("option")) {
1152
+ self.pop();
1153
+ }
1154
+ if self.current_node_named(local_name!("optgroup")) {
1155
+ self.pop();
1156
+ }
1157
+ self.insert_element_for(tag);
1158
+ self.pop();
1159
+ ProcessResult::DoneAckSelfClosing
1160
+ }
1161
+
1162
+ </optgroup> => {
1163
+ if self.open_elems.borrow().len() >= 2
1164
+ && self.current_node_named(local_name!("option"))
1165
+ && self.html_elem_named(&self.open_elems.borrow()[self.open_elems.borrow().len() - 2],
1166
+ local_name!("optgroup")) {
1167
+ self.pop();
1168
+ }
1169
+ if self.current_node_named(local_name!("optgroup")) {
1170
+ self.pop();
1171
+ } else {
1172
+ self.unexpected(&token);
1173
+ }
1174
+ ProcessResult::Done
1175
+ }
1176
+
1177
+ </option> => {
1178
+ if self.current_node_named(local_name!("option")) {
1179
+ self.pop();
1180
+ } else {
1181
+ self.unexpected(&token);
1182
+ }
1183
+ ProcessResult::Done
1184
+ }
1185
+
1186
+ tag @ <select> </select> => {
1187
+ let in_scope = self.in_scope_named(select_scope, local_name!("select"));
1188
+
1189
+ if !in_scope || tag.kind == StartTag {
1190
+ self.unexpected(&tag);
1191
+ }
1192
+
1193
+ if in_scope {
1194
+ self.pop_until_named(local_name!("select"));
1195
+ self.mode.set(self.reset_insertion_mode());
1196
+ }
1197
+ ProcessResult::Done
1198
+ }
1199
+
1200
+ <input> <keygen> <textarea> => {
1201
+ self.unexpected(&token);
1202
+ if self.in_scope_named(select_scope, local_name!("select")) {
1203
+ self.pop_until_named(local_name!("select"));
1204
+ ProcessResult::Reprocess(self.reset_insertion_mode(), token)
1205
+ } else {
1206
+ ProcessResult::Done
1207
+ }
1208
+ }
1209
+
1210
+ <script> <template> </template> => self.step(InsertionMode::InHead, token),
1211
+
1212
+ Token::Eof => self.step(InsertionMode::InBody, token),
1213
+
1214
+ token => self.unexpected(&token),
1215
+ }),
1216
+
1217
+ //§ parsing-main-inselectintable
1218
+ InsertionMode::InSelectInTable => match_token!(token {
1219
+ <caption> <table> <tbody> <tfoot> <thead> <tr> <td> <th> => {
1220
+ self.unexpected(&token);
1221
+ self.pop_until_named(local_name!("select"));
1222
+ ProcessResult::Reprocess(self.reset_insertion_mode(), token)
1223
+ }
1224
+
1225
+ tag @ </caption> </table> </tbody> </tfoot> </thead> </tr> </td> </th> => {
1226
+ self.unexpected(&tag);
1227
+ if self.in_scope_named(table_scope, tag.name.clone()) {
1228
+ self.pop_until_named(local_name!("select"));
1229
+ ProcessResult::Reprocess(self.reset_insertion_mode(), Token::Tag(tag))
1230
+ } else {
1231
+ ProcessResult::Done
1232
+ }
1233
+ }
1234
+
1235
+ token => self.step(InsertionMode::InSelect, token),
1236
+ }),
1237
+
1238
+ //§ parsing-main-intemplate
1239
+ InsertionMode::InTemplate => match_token!(token {
1240
+ Token::Characters(_, _) => self.step(InsertionMode::InBody, token),
1241
+ Token::Comment(_) => self.step(InsertionMode::InBody, token),
1242
+
1243
+ <base> <basefont> <bgsound> <link> <meta> <noframes> <script>
1244
+ <style> <template> <title> </template> => {
1245
+ self.step(InsertionMode::InHead, token)
1246
+ }
1247
+
1248
+ <caption> <colgroup> <tbody> <tfoot> <thead> => {
1249
+ self.template_modes.borrow_mut().pop();
1250
+ self.template_modes.borrow_mut().push(InsertionMode::InTable);
1251
+ ProcessResult::Reprocess(InsertionMode::InTable, token)
1252
+ }
1253
+
1254
+ <col> => {
1255
+ self.template_modes.borrow_mut().pop();
1256
+ self.template_modes.borrow_mut().push(InsertionMode::InColumnGroup);
1257
+ ProcessResult::Reprocess(InsertionMode::InColumnGroup, token)
1258
+ }
1259
+
1260
+ <tr> => {
1261
+ self.template_modes.borrow_mut().pop();
1262
+ self.template_modes.borrow_mut().push(InsertionMode::InTableBody);
1263
+ ProcessResult::Reprocess(InsertionMode::InTableBody, token)
1264
+ }
1265
+
1266
+ <td> <th> => {
1267
+ self.template_modes.borrow_mut().pop();
1268
+ self.template_modes.borrow_mut().push(InsertionMode::InRow);
1269
+ ProcessResult::Reprocess(InsertionMode::InRow, token)
1270
+ }
1271
+
1272
+ Token::Eof => {
1273
+ if !self.in_html_elem_named(local_name!("template")) {
1274
+ self.stop_parsing()
1275
+ } else {
1276
+ self.unexpected(&token);
1277
+ self.pop_until_named(local_name!("template"));
1278
+ self.clear_active_formatting_to_marker();
1279
+ self.template_modes.borrow_mut().pop();
1280
+ self.mode.set(self.reset_insertion_mode());
1281
+ ProcessResult::Reprocess(self.reset_insertion_mode(), token)
1282
+ }
1283
+ }
1284
+
1285
+ tag @ <_> => {
1286
+ self.template_modes.borrow_mut().pop();
1287
+ self.template_modes.borrow_mut().push(InsertionMode::InBody);
1288
+ ProcessResult::Reprocess(InsertionMode::InBody, Token::Tag(tag))
1289
+ }
1290
+
1291
+ token => self.unexpected(&token),
1292
+ }),
1293
+
1294
+ //§ parsing-main-afterbody
1295
+ InsertionMode::AfterBody => match_token!(token {
1296
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
1297
+ Token::Characters(SplitStatus::Whitespace, _) => self.step(InsertionMode::InBody, token),
1298
+ Token::Comment(text) => self.append_comment_to_html(text),
1299
+
1300
+ <html> => self.step(InsertionMode::InBody, token),
1301
+
1302
+ </html> => {
1303
+ if self.is_fragment() {
1304
+ self.unexpected(&token);
1305
+ } else {
1306
+ self.mode.set(InsertionMode::AfterAfterBody);
1307
+ }
1308
+ ProcessResult::Done
1309
+ }
1310
+
1311
+ Token::Eof => self.stop_parsing(),
1312
+
1313
+ token => {
1314
+ self.unexpected(&token);
1315
+ ProcessResult::Reprocess(InsertionMode::InBody, token)
1316
+ }
1317
+ }),
1318
+
1319
+ //§ parsing-main-inframeset
1320
+ InsertionMode::InFrameset => match_token!(token {
1321
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
1322
+ Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
1323
+ Token::Comment(text) => self.append_comment(text),
1324
+
1325
+ <html> => self.step(InsertionMode::InBody, token),
1326
+
1327
+ tag @ <frameset> => {
1328
+ self.insert_element_for(tag);
1329
+ ProcessResult::Done
1330
+ }
1331
+
1332
+ </frameset> => {
1333
+ if self.open_elems.borrow().len() == 1 {
1334
+ self.unexpected(&token);
1335
+ } else {
1336
+ self.pop();
1337
+ if !self.is_fragment() && !self.current_node_named(local_name!("frameset")) {
1338
+ self.mode.set(InsertionMode::AfterFrameset);
1339
+ }
1340
+ }
1341
+ ProcessResult::Done
1342
+ }
1343
+
1344
+ tag @ <frame> => {
1345
+ self.insert_and_pop_element_for(tag);
1346
+ ProcessResult::DoneAckSelfClosing
1347
+ }
1348
+
1349
+ <noframes> => self.step(InsertionMode::InHead, token),
1350
+
1351
+ Token::Eof => {
1352
+ if self.open_elems.borrow().len() != 1 {
1353
+ self.unexpected(&token);
1354
+ }
1355
+ self.stop_parsing()
1356
+ }
1357
+
1358
+ token => self.unexpected(&token),
1359
+ }),
1360
+
1361
+ //§ parsing-main-afterframeset
1362
+ InsertionMode::AfterFrameset => match_token!(token {
1363
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
1364
+ Token::Characters(SplitStatus::Whitespace, text) => self.append_text(text),
1365
+ Token::Comment(text) => self.append_comment(text),
1366
+
1367
+ <html> => self.step(InsertionMode::InBody, token),
1368
+
1369
+ </html> => {
1370
+ self.mode.set(InsertionMode::AfterAfterFrameset);
1371
+ ProcessResult::Done
1372
+ }
1373
+
1374
+ <noframes> => self.step(InsertionMode::InHead, token),
1375
+
1376
+ Token::Eof => self.stop_parsing(),
1377
+
1378
+ token => self.unexpected(&token),
1379
+ }),
1380
+
1381
+ //§ the-after-after-body-insertion-mode
1382
+ InsertionMode::AfterAfterBody => match_token!(token {
1383
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
1384
+ Token::Characters(SplitStatus::Whitespace, _) => self.step(InsertionMode::InBody, token),
1385
+ Token::Comment(text) => self.append_comment_to_doc(text),
1386
+
1387
+ <html> => self.step(InsertionMode::InBody, token),
1388
+
1389
+ Token::Eof => self.stop_parsing(),
1390
+
1391
+ token => {
1392
+ self.unexpected(&token);
1393
+ ProcessResult::Reprocess(InsertionMode::InBody, token)
1394
+ }
1395
+ }),
1396
+
1397
+ //§ the-after-after-frameset-insertion-mode
1398
+ InsertionMode::AfterAfterFrameset => match_token!(token {
1399
+ Token::Characters(SplitStatus::NotSplit, text) => ProcessResult::SplitWhitespace(text),
1400
+ Token::Characters(SplitStatus::Whitespace, _) => self.step(InsertionMode::InBody, token),
1401
+ Token::Comment(text) => self.append_comment_to_doc(text),
1402
+
1403
+ <html> => self.step(InsertionMode::InBody, token),
1404
+
1405
+ Token::Eof => self.stop_parsing(),
1406
+
1407
+ <noframes> => self.step(InsertionMode::InHead, token),
1408
+
1409
+ token => self.unexpected(&token),
1410
+ }),
1411
+ //§ END
1412
+ }
1413
+ }
1414
+
1415
+ pub(crate) fn step_foreign(&self, token: Token) -> ProcessResult<Handle> {
1416
+ match_token!(token {
1417
+ Token::NullCharacter => {
1418
+ self.unexpected(&token);
1419
+ self.append_text("\u{fffd}".to_tendril())
1420
+ }
1421
+
1422
+ Token::Characters(_, text) => {
1423
+ if any_not_whitespace(&text) {
1424
+ self.frameset_ok.set(false);
1425
+ }
1426
+ self.append_text(text)
1427
+ }
1428
+
1429
+ Token::Comment(text) => self.append_comment(text),
1430
+
1431
+ tag @ <b> <big> <blockquote> <body> <br> <center> <code> <dd> <div> <dl>
1432
+ <dt> <em> <embed> <h1> <h2> <h3> <h4> <h5> <h6> <head> <hr> <i>
1433
+ <img> <li> <listing> <menu> <meta> <nobr> <ol> <p> <pre> <ruby>
1434
+ <s> <small> <span> <strong> <strike> <sub> <sup> <table> <tt>
1435
+ <u> <ul> <var> </br> </p> => self.unexpected_start_tag_in_foreign_content(tag),
1436
+
1437
+ tag @ <font> => {
1438
+ let unexpected = tag.attrs.iter().any(|attr| {
1439
+ matches!(attr.name.expanded(),
1440
+ expanded_name!("", "color") |
1441
+ expanded_name!("", "face") |
1442
+ expanded_name!("", "size"))
1443
+ });
1444
+ if unexpected {
1445
+ self.unexpected_start_tag_in_foreign_content(tag)
1446
+ } else {
1447
+ self.foreign_start_tag(tag)
1448
+ }
1449
+ }
1450
+
1451
+ tag @ <_> => self.foreign_start_tag(tag),
1452
+
1453
+ // FIXME(#118): </script> in SVG
1454
+
1455
+ tag @ </_> => {
1456
+ let mut first = true;
1457
+ let mut stack_idx = self.open_elems.borrow().len() - 1;
1458
+ loop {
1459
+ if stack_idx == 0 {
1460
+ return ProcessResult::Done;
1461
+ }
1462
+
1463
+ let html;
1464
+ let eq;
1465
+ {
1466
+ let open_elems = self.open_elems.borrow();
1467
+ let node_name = self.sink.elem_name(&open_elems[stack_idx]);
1468
+ html = *node_name.ns() == ns!(html);
1469
+ eq = node_name.local_name().eq_ignore_ascii_case(&tag.name);
1470
+ }
1471
+ if !first && html {
1472
+ let mode = self.mode.get();
1473
+ return self.step(mode, Token::Tag(tag));
1474
+ }
1475
+
1476
+ if eq {
1477
+ self.truncate_stack(stack_idx);
1478
+ return ProcessResult::Done;
1479
+ }
1480
+
1481
+ if first {
1482
+ self.unexpected(&tag);
1483
+ first = false;
1484
+ }
1485
+ stack_idx -= 1;
1486
+ }
1487
+ }
1488
+
1489
+ // FIXME: This should be unreachable, but match_token requires a
1490
+ // catch-all case.
1491
+ _ => panic!("impossible case in foreign content"),
1492
+ })
1493
+ }
1494
+ }