| 869 |
$self->{document}->manakai_is_html (1); # MUST |
$self->{document}->manakai_is_html (1); # MUST |
| 870 |
$self->{document}->set_user_data (manakai_source_line => 1); |
$self->{document}->set_user_data (manakai_source_line => 1); |
| 871 |
$self->{document}->set_user_data (manakai_source_column => 1); |
$self->{document}->set_user_data (manakai_source_column => 1); |
| 872 |
|
|
| 873 |
|
$self->{frameset_ok} = 1; |
| 874 |
} # _initialize_tree_constructor |
} # _initialize_tree_constructor |
| 875 |
|
|
| 876 |
sub _terminate_tree_constructor ($) { |
sub _terminate_tree_constructor ($) { |
| 2491 |
## reprocess |
## reprocess |
| 2492 |
!!!ack-later; |
!!!ack-later; |
| 2493 |
next B; |
next B; |
| 2494 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 2495 |
if ($token->{tag_name} eq 'head') { |
## "Before head", "in head", and "after head" insertion modes |
| 2496 |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
## ignore most of end tags. Exceptions are "body", "html", |
| 2497 |
!!!cp ('t132'); |
## and "br" end tags. "Before head" and "in head" insertion |
| 2498 |
## As if <head> |
## modes also recognize "head" end tag. "In head noscript" |
| 2499 |
!!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token); |
## insertion modes ignore end tags except for "noscript" and |
| 2500 |
$self->{open_elements}->[-1]->[0]->append_child ($self->{head_element}); |
## "br". |
|
push @{$self->{open_elements}}, |
|
|
[$self->{head_element}, $el_category->{head}]; |
|
| 2501 |
|
|
| 2502 |
## Reprocess in the "in head" insertion mode... |
if ($token->{tag_name} eq 'head') { |
| 2503 |
pop @{$self->{open_elements}}; |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 2504 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
!!!cp ('t132'); |
| 2505 |
!!!next-token; |
## As if <head> |
| 2506 |
next B; |
!!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token); |
| 2507 |
} elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
$self->{open_elements}->[-1]->[0]->append_child ($self->{head_element}); |
| 2508 |
!!!cp ('t133'); |
push @{$self->{open_elements}}, |
| 2509 |
## As if </noscript> |
[$self->{head_element}, $el_category->{head}]; |
| 2510 |
pop @{$self->{open_elements}}; |
|
| 2511 |
!!!parse-error (type => 'in noscript:/', |
## Reprocess in the "in head" insertion mode... |
| 2512 |
text => 'head', token => $token); |
pop @{$self->{open_elements}}; |
| 2513 |
|
$self->{insertion_mode} = AFTER_HEAD_IM; |
| 2514 |
## Reprocess in the "in head" insertion mode... |
!!!next-token; |
| 2515 |
pop @{$self->{open_elements}}; |
next B; |
| 2516 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
} elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
| 2517 |
!!!next-token; |
!!!cp ('t133'); |
| 2518 |
next B; |
# |
| 2519 |
} elsif ($self->{insertion_mode} == IN_HEAD_IM) { |
} elsif ($self->{insertion_mode} == IN_HEAD_IM) { |
| 2520 |
!!!cp ('t134'); |
!!!cp ('t134'); |
| 2521 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 2522 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
$self->{insertion_mode} = AFTER_HEAD_IM; |
| 2523 |
!!!next-token; |
!!!next-token; |
| 2524 |
next B; |
next B; |
| 2525 |
} elsif ($self->{insertion_mode} == AFTER_HEAD_IM) { |
} elsif ($self->{insertion_mode} == AFTER_HEAD_IM) { |
| 2526 |
!!!cp ('t134.1'); |
!!!cp ('t134.1'); |
| 2527 |
!!!parse-error (type => 'unmatched end tag', text => 'head', |
# |
| 2528 |
token => $token); |
} else { |
| 2529 |
## Ignore the token |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
| 2530 |
!!!next-token; |
} |
| 2531 |
next B; |
} elsif ($token->{tag_name} eq 'noscript') { |
| 2532 |
} else { |
if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
| 2533 |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
!!!cp ('t136'); |
| 2534 |
} |
pop @{$self->{open_elements}}; |
| 2535 |
} elsif ($token->{tag_name} eq 'noscript') { |
$self->{insertion_mode} = IN_HEAD_IM; |
| 2536 |
if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
!!!next-token; |
| 2537 |
!!!cp ('t136'); |
next B; |
| 2538 |
pop @{$self->{open_elements}}; |
} else { |
| 2539 |
$self->{insertion_mode} = IN_HEAD_IM; |
!!!cp ('t138'); |
| 2540 |
!!!next-token; |
# |
| 2541 |
next B; |
} |
| 2542 |
} elsif ($self->{insertion_mode} == BEFORE_HEAD_IM or |
} elsif ({ |
| 2543 |
$self->{insertion_mode} == AFTER_HEAD_IM) { |
body => ($self->{insertion_mode} != IN_HEAD_NOSCRIPT_IM), |
| 2544 |
!!!cp ('t137'); |
html => ($self->{insertion_mode} != IN_HEAD_NOSCRIPT_IM), |
| 2545 |
!!!parse-error (type => 'unmatched end tag', |
br => 1, |
| 2546 |
text => 'noscript', token => $token); |
}->{$token->{tag_name}}) { |
|
## Ignore the token ## ISSUE: An issue in the spec. |
|
|
!!!next-token; |
|
|
next B; |
|
|
} else { |
|
|
!!!cp ('t138'); |
|
|
# |
|
|
} |
|
|
} elsif ({ |
|
|
body => 1, html => 1, |
|
|
}->{$token->{tag_name}}) { |
|
|
## TODO: This branch is entirely redundant. |
|
|
if ($self->{insertion_mode} == BEFORE_HEAD_IM or |
|
|
$self->{insertion_mode} == IN_HEAD_IM or |
|
|
$self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
|
|
!!!cp ('t140'); |
|
|
!!!parse-error (type => 'unmatched end tag', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
## Ignore the token |
|
|
!!!next-token; |
|
|
next B; |
|
|
} elsif ($self->{insertion_mode} == AFTER_HEAD_IM) { |
|
|
!!!cp ('t140.1'); |
|
|
!!!parse-error (type => 'unmatched end tag', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
## Ignore the token |
|
|
!!!next-token; |
|
|
next B; |
|
|
} else { |
|
|
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
|
|
} |
|
|
} elsif ($token->{tag_name} eq 'p') { |
|
|
!!!cp ('t142'); |
|
|
!!!parse-error (type => 'unmatched end tag', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
## Ignore the token |
|
|
!!!next-token; |
|
|
next B; |
|
|
} elsif ($token->{tag_name} eq 'br') { |
|
| 2547 |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 2548 |
!!!cp ('t142.2'); |
!!!cp ('t142.2'); |
| 2549 |
## (before head) as if <head>, (in head) as if </head> |
## (before head) as if <head>, (in head) as if </head> |
| 2563 |
!!!cp ('t143.3'); |
!!!cp ('t143.3'); |
| 2564 |
## NOTE: Two parse errors for <head><noscript></br> |
## NOTE: Two parse errors for <head><noscript></br> |
| 2565 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 2566 |
text => 'br', token => $token); |
text => $token->{tag_name}, token => $token); |
| 2567 |
## As if </noscript> |
## As if </noscript> |
| 2568 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 2569 |
$self->{insertion_mode} = IN_HEAD_IM; |
$self->{insertion_mode} = IN_HEAD_IM; |
| 2581 |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
| 2582 |
} |
} |
| 2583 |
|
|
| 2584 |
# |
## "after head" insertion mode |
| 2585 |
} else { ## Other end tags |
## As if <body> |
| 2586 |
!!!cp ('t145'); |
!!!insert-element ('body',, $token); |
| 2587 |
!!!parse-error (type => 'unmatched end tag', |
$self->{insertion_mode} = IN_BODY_IM; |
| 2588 |
text => $token->{tag_name}, token => $token); |
## Reprocess. |
| 2589 |
## Ignore the token |
next B; |
| 2590 |
!!!next-token; |
} |
|
next B; |
|
|
} |
|
|
|
|
|
if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
|
|
!!!cp ('t146'); |
|
|
## As if </noscript> |
|
|
pop @{$self->{open_elements}}; |
|
|
!!!parse-error (type => 'in noscript:/', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
|
|
|
## Reprocess in the "in head" insertion mode... |
|
|
## As if </head> |
|
|
pop @{$self->{open_elements}}; |
|
|
|
|
|
## Reprocess in the "after head" insertion mode... |
|
|
} elsif ($self->{insertion_mode} == IN_HEAD_IM) { |
|
|
!!!cp ('t147'); |
|
|
## As if </head> |
|
|
pop @{$self->{open_elements}}; |
|
|
|
|
|
## Reprocess in the "after head" insertion mode... |
|
|
} elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
|
|
## ISSUE: This case cannot be reached? |
|
|
!!!cp ('t148'); |
|
|
!!!parse-error (type => 'unmatched end tag', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
## Ignore the token ## ISSUE: An issue in the spec. |
|
|
!!!next-token; |
|
|
next B; |
|
|
} else { |
|
|
!!!cp ('t149'); |
|
|
} |
|
| 2591 |
|
|
| 2592 |
## "after head" insertion mode |
## End tags are ignored by default. |
| 2593 |
## As if <body> |
!!!cp ('t145'); |
| 2594 |
!!!insert-element ('body',, $token); |
!!!parse-error (type => 'unmatched end tag', |
| 2595 |
$self->{insertion_mode} = IN_BODY_IM; |
text => $token->{tag_name}, token => $token); |
| 2596 |
## reprocess |
## Ignore the token. |
| 2597 |
|
!!!next-token; |
| 2598 |
next B; |
next B; |
| 2599 |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
| 2600 |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 4339 |
!!!nack ('t343.1'); |
!!!nack ('t343.1'); |
| 4340 |
!!!next-token; |
!!!next-token; |
| 4341 |
next B; |
next B; |
| 4342 |
|
} elsif ($token->{tag_nane} eq 'frameset') { |
| 4343 |
|
!!!parse-error (type => 'in body', text => $token->{tag_name}, |
| 4344 |
|
token => $token); |
| 4345 |
|
|
| 4346 |
|
if (@{$self->{open_elements}} == 1 or |
| 4347 |
|
not ($self->{open_elements}->[1]->[1] != BODY_EL)) { |
| 4348 |
|
!!!cp ('t343.2'); |
| 4349 |
|
## Ignore the token. |
| 4350 |
|
} elsif (not $self->{frameset_ok}) { |
| 4351 |
|
!!!cp ('t343.3'); |
| 4352 |
|
## Ignore the token. |
| 4353 |
|
} else { |
| 4354 |
|
!!!cp ('t343.4'); |
| 4355 |
|
|
| 4356 |
|
## 1. Remove the second element. |
| 4357 |
|
my $body = $self->{open_elements}->[1]->[0]; |
| 4358 |
|
my $body_parent = $body->parent_node; |
| 4359 |
|
$body_parent->remove_child ($body) if $body_parent; |
| 4360 |
|
|
| 4361 |
|
## 2. Pop nodes. |
| 4362 |
|
splice @{$self->{open_elements}}, 1; |
| 4363 |
|
|
| 4364 |
|
## 3. Insert. |
| 4365 |
|
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
| 4366 |
|
|
| 4367 |
|
## 4. Switch. |
| 4368 |
|
$self->{insertion_mode} = IN_FRAMESET_IM; |
| 4369 |
|
} |
| 4370 |
|
|
| 4371 |
|
!!!nack ('t343.5'); |
| 4372 |
|
!!!next-token; |
| 4373 |
|
next B; |
| 4374 |
} elsif ({ |
} elsif ({ |
| 4375 |
## NOTE: Start tags for non-phrasing flow content elements |
## NOTE: Start tags for non-phrasing flow content elements |
| 4376 |
|
|
| 4464 |
!!!cp ('t386'); |
!!!cp ('t386'); |
| 4465 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 4466 |
|
|
| 4467 |
!!!nack ('t386.1'); |
!!!ack ('t386.1'); |
| 4468 |
!!!next-token; |
!!!next-token; |
| 4469 |
} else { |
} else { |
| 4470 |
!!!nack ('t347.1'); |
!!!nack ('t347.1'); |
| 5020 |
next B; |
next B; |
| 5021 |
} |
} |
| 5022 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 5023 |
if ($token->{tag_name} eq 'body') { |
if ($token->{tag_name} eq 'body' or $token->{tag_name} eq 'html') { |
| 5024 |
|
|
| 5025 |
## 1. If not "have an element in scope": |
## 1. If not "have an element in scope": |
| 5026 |
## "has a |body| element in scope" |
## "has a |body| element in scope" |
| 5037 |
} |
} |
| 5038 |
} |
} |
| 5039 |
|
|
| 5040 |
## NOTE: |<marquee></body>|, |<svg><foreignobject></body>| |
## NOTE: |<marquee></body>|, |<svg><foreignobject></body>|, |
| 5041 |
|
## and fragment cases. |
| 5042 |
|
|
| 5043 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 5044 |
text => $token->{tag_name}, token => $token); |
text => $token->{tag_name}, token => $token); |
| 5045 |
## NOTE: Ignore the token. |
## Ignore the token. (</body> or </html>) |
| 5046 |
!!!next-token; |
!!!next-token; |
| 5047 |
next B; |
next B; |
| 5048 |
} # INSCOPE |
} # INSCOPE |
| 5065 |
|
|
| 5066 |
## 3. Switch the insertion mode. |
## 3. Switch the insertion mode. |
| 5067 |
$self->{insertion_mode} = AFTER_BODY_IM; |
$self->{insertion_mode} = AFTER_BODY_IM; |
| 5068 |
!!!next-token; |
if ($token->{tag_name} eq 'body') { |
|
next B; |
|
|
} elsif ($token->{tag_name} eq 'html') { |
|
|
## TODO: Update this code. It seems that the code below is not |
|
|
## up-to-date, though it has same effect as speced. |
|
|
if (@{$self->{open_elements}} > 1 and |
|
|
$self->{open_elements}->[1]->[1] == BODY_EL) { |
|
|
unless ($self->{open_elements}->[-1]->[1] == BODY_EL) { |
|
|
!!!cp ('t406'); |
|
|
!!!parse-error (type => 'not closed', |
|
|
text => $self->{open_elements}->[1]->[0] |
|
|
->manakai_local_name, |
|
|
token => $token); |
|
|
} else { |
|
|
!!!cp ('t407'); |
|
|
} |
|
|
$self->{insertion_mode} = AFTER_BODY_IM; |
|
|
## reprocess |
|
|
next B; |
|
|
} else { |
|
|
!!!cp ('t408'); |
|
|
!!!parse-error (type => 'unmatched end tag', |
|
|
text => $token->{tag_name}, token => $token); |
|
|
## Ignore the token |
|
| 5069 |
!!!next-token; |
!!!next-token; |
| 5070 |
next B; |
} else { # html |
| 5071 |
|
## Reprocess. |
| 5072 |
} |
} |
| 5073 |
|
next B; |
| 5074 |
} elsif ({ |
} elsif ({ |
| 5075 |
## NOTE: End tags for non-phrasing flow content elements |
## NOTE: End tags for non-phrasing flow content elements |
| 5076 |
|
|