@@ -55,9 +55,6 @@ void HTMLDocumentParser::run()
55
55
56
56
dbg () << " [" << insertion_mode_name () << " ] " << token.to_string ();
57
57
58
- if (token.type () == HTMLToken::Type::EndOfFile)
59
- return ;
60
-
61
58
switch (m_insertion_mode) {
62
59
case InsertionMode::Initial:
63
60
handle_initial (token);
@@ -80,6 +77,12 @@ void HTMLDocumentParser::run()
80
77
case InsertionMode::InBody:
81
78
handle_in_body (token);
82
79
break ;
80
+ case InsertionMode::AfterBody:
81
+ handle_after_body (token);
82
+ break ;
83
+ case InsertionMode::AfterAfterBody:
84
+ handle_after_after_body (token);
85
+ break ;
83
86
case InsertionMode::Text:
84
87
handle_text (token);
85
88
break ;
@@ -199,7 +202,10 @@ void HTMLDocumentParser::handle_after_head(HTMLToken& token)
199
202
}
200
203
201
204
if (token.is_start_tag () && token.tag_name () == " body" ) {
202
- ASSERT_NOT_REACHED ();
205
+ insert_html_element (token);
206
+ m_frameset_ok = false ;
207
+ m_insertion_mode = InsertionMode::InBody;
208
+ return ;
203
209
}
204
210
205
211
if (token.is_start_tag () && token.tag_name () == " frameset" ) {
@@ -231,10 +237,94 @@ void HTMLDocumentParser::handle_after_head(HTMLToken& token)
231
237
fake_body_token.m_tag .tag_name .append (" body" );
232
238
insert_html_element (fake_body_token);
233
239
m_insertion_mode = InsertionMode::InBody;
240
+ // FIXME: Reprocess the current token in InBody!
234
241
}
235
242
236
- void HTMLDocumentParser::handle_in_body (HTMLToken& )
243
+ void HTMLDocumentParser::generate_implied_end_tags ( )
237
244
{
245
+ Vector<String> names { " dd" , " dt" , " li" , " optgroup" , " option" , " p" , " rb" , " rp" , " rt" , " rtc" };
246
+ while (names.contains_slow (current_node ()->tag_name ()))
247
+ m_stack_of_open_elements.take_last ();
248
+ }
249
+
250
+ bool HTMLDocumentParser::stack_of_open_elements_has_element_with_tag_name_in_scope (const FlyString& tag_name)
251
+ {
252
+ Vector<String> list { " applet" , " caption" , " html" , " table" , " td" , " th" , " marquee" , " object" , " template" };
253
+ for (ssize_t i = m_stack_of_open_elements.size () - 1 ; i >= 0 ; --i) {
254
+ auto & node = m_stack_of_open_elements.at (i);
255
+ if (node.tag_name () == tag_name)
256
+ return true ;
257
+ if (list.contains_slow (node.tag_name ()))
258
+ return false ;
259
+ }
260
+ ASSERT_NOT_REACHED ();
261
+ }
262
+
263
+ void HTMLDocumentParser::handle_after_body (HTMLToken& token)
264
+ {
265
+ if (token.is_end_tag () && token.tag_name () == " html" ) {
266
+ if (m_parsing_fragment) {
267
+ ASSERT_NOT_REACHED ();
268
+ }
269
+ m_insertion_mode = InsertionMode::AfterAfterBody;
270
+ return ;
271
+ }
272
+ ASSERT_NOT_REACHED ();
273
+ }
274
+
275
+ void HTMLDocumentParser::handle_after_after_body (HTMLToken& token)
276
+ {
277
+ if (token.is_end_of_file ()) {
278
+ dbg () << " Stop parsing! :^)" ;
279
+ return ;
280
+ }
281
+ ASSERT_NOT_REACHED ();
282
+ }
283
+
284
+ void HTMLDocumentParser::handle_in_body (HTMLToken& token)
285
+ {
286
+ if (token.is_end_tag () && token.tag_name () == " body" ) {
287
+ if (!stack_of_open_elements_has_element_with_tag_name_in_scope (" body" )) {
288
+ ASSERT_NOT_REACHED ();
289
+ }
290
+
291
+ // FIXME: Otherwise, if there is a node in the stack of open elements that is
292
+ // not either a dd element, a dt element, an li element, an optgroup element,
293
+ // an option element, a p element, an rb element, an rp element, an rt element,
294
+ // an rtc element, a tbody element, a td element, a tfoot element, a th element,
295
+ // a thead element, a tr element, the body element, or the html element,
296
+ // then this is a parse error.
297
+
298
+ m_insertion_mode = InsertionMode::AfterBody;
299
+ return ;
300
+ }
301
+
302
+ {
303
+ Vector<String> names { " address" , " article" , " aside" , " blockquote" , " center" , " details" , " dialog" , " dir" , " div" , " dl" , " fieldset" , " figcaption" , " figure" , " footer" , " header" , " hgroup" , " main" , " menu" , " nav" , " ol" , " p" , " section" , " summary" , " ul" };
304
+ if (token.is_start_tag () && names.contains_slow (token.tag_name ())) {
305
+ // FIXME: If the stack of open elements has a p element in button scope, then close a p element.
306
+ insert_html_element (token);
307
+ return ;
308
+ }
309
+
310
+ if (token.is_end_tag () && names.contains_slow (token.tag_name ())) {
311
+ // FIXME: If the stack of open elements has a p element in button scope, then close a p element.
312
+
313
+ if (!stack_of_open_elements_has_element_with_tag_name_in_scope (token.tag_name ())) {
314
+ ASSERT_NOT_REACHED ();
315
+ }
316
+
317
+ generate_implied_end_tags ();
318
+
319
+ if (current_node ()->tag_name () != token.tag_name ()) {
320
+ ASSERT_NOT_REACHED ();
321
+ }
322
+
323
+ m_stack_of_open_elements.take_last ();
324
+ return ;
325
+ }
326
+ }
327
+
238
328
ASSERT_NOT_REACHED ();
239
329
}
240
330
0 commit comments