| 303 |
sub ROW_IMS () { 0b10000000 } |
sub ROW_IMS () { 0b10000000 } |
| 304 |
sub BODY_AFTER_IMS () { 0b100000000 } |
sub BODY_AFTER_IMS () { 0b100000000 } |
| 305 |
sub FRAME_IMS () { 0b1000000000 } |
sub FRAME_IMS () { 0b1000000000 } |
| 306 |
|
sub SELECT_IMS () { 0b10000000000 } |
| 307 |
|
|
| 308 |
## NOTE: "initial" and "before html" insertion modes have no constants. |
## NOTE: "initial" and "before html" insertion modes have no constants. |
| 309 |
|
|
| 326 |
sub AFTER_BODY_IM () { BODY_AFTER_IMS } |
sub AFTER_BODY_IM () { BODY_AFTER_IMS } |
| 327 |
sub IN_FRAMESET_IM () { FRAME_IMS | 0b01 } |
sub IN_FRAMESET_IM () { FRAME_IMS | 0b01 } |
| 328 |
sub AFTER_FRAMESET_IM () { FRAME_IMS | 0b10 } |
sub AFTER_FRAMESET_IM () { FRAME_IMS | 0b10 } |
| 329 |
sub IN_SELECT_IM () { 0b01 } |
sub IN_SELECT_IM () { SELECT_IMS | 0b01 } |
| 330 |
|
sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 } |
| 331 |
sub IN_COLUMN_GROUP_IM () { 0b10 } |
sub IN_COLUMN_GROUP_IM () { 0b10 } |
| 332 |
|
|
| 333 |
## Implementations MUST act as if state machine in the spec |
## Implementations MUST act as if state machine in the spec |
| 3012 |
!!!next-token; |
!!!next-token; |
| 3013 |
}; # $script_start_tag |
}; # $script_start_tag |
| 3014 |
|
|
| 3015 |
|
## NOTE: $open_tables->[-1]->[0] is the "current table" element node. |
| 3016 |
|
## NOTE: $open_tables->[-1]->[1] is the "tainted" flag. |
| 3017 |
|
my $open_tables = [[$self->{open_elements}->[0]->[0]]]; |
| 3018 |
|
|
| 3019 |
my $formatting_end_tag = sub { |
my $formatting_end_tag = sub { |
| 3020 |
my $tag_name = shift; |
my $tag_name = shift; |
| 3021 |
|
|
| 3022 |
|
## NOTE: The adoptioon agency algorithm (AAA). |
| 3023 |
|
|
| 3024 |
FET: { |
FET: { |
| 3025 |
## Step 1 |
## Step 1 |
| 3026 |
my $formatting_element; |
my $formatting_element; |
| 3174 |
} # S7 |
} # S7 |
| 3175 |
|
|
| 3176 |
## Step 8 |
## Step 8 |
| 3177 |
$common_ancestor_node->[0]->append_child ($last_node->[0]); |
if ({ |
| 3178 |
|
table => 1, tbody => 1, tfoot => 1, thead => 1, tr => 1, |
| 3179 |
|
}->{$common_ancestor_node->[1]}) { |
| 3180 |
|
my $foster_parent_element; |
| 3181 |
|
my $next_sibling; |
| 3182 |
|
OE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3183 |
|
if ($self->{open_elements}->[$_]->[1] eq 'table') { |
| 3184 |
|
my $parent = $self->{open_elements}->[$_]->[0]->parent_node; |
| 3185 |
|
if (defined $parent and $parent->node_type == 1) { |
| 3186 |
|
!!!cp ('t65.1'); |
| 3187 |
|
$foster_parent_element = $parent; |
| 3188 |
|
$next_sibling = $self->{open_elements}->[$_]->[0]; |
| 3189 |
|
} else { |
| 3190 |
|
!!!cp ('t65.2'); |
| 3191 |
|
$foster_parent_element |
| 3192 |
|
= $self->{open_elements}->[$_ - 1]->[0]; |
| 3193 |
|
} |
| 3194 |
|
last OE; |
| 3195 |
|
} |
| 3196 |
|
} # OE |
| 3197 |
|
$foster_parent_element = $self->{open_elements}->[0]->[0] |
| 3198 |
|
unless defined $foster_parent_element; |
| 3199 |
|
$foster_parent_element->insert_before ($last_node->[0], $next_sibling); |
| 3200 |
|
$open_tables->[-1]->[1] = 1; # tainted |
| 3201 |
|
} else { |
| 3202 |
|
!!!cp ('t65.3'); |
| 3203 |
|
$common_ancestor_node->[0]->append_child ($last_node->[0]); |
| 3204 |
|
} |
| 3205 |
|
|
| 3206 |
## Step 9 |
## Step 9 |
| 3207 |
my $clone = [$formatting_element->[0]->clone_node (0), |
my $clone = [$formatting_element->[0]->clone_node (0), |
| 3247 |
} # FET |
} # FET |
| 3248 |
}; # $formatting_end_tag |
}; # $formatting_end_tag |
| 3249 |
|
|
|
## NOTE: $open_tables->[-1]->[0] is the "current table". |
|
|
## NOTE: $open_tables->[-1]->[1] is the "tainted" flag. |
|
|
my $open_tables = [[$self->{open_elements}->[0]->[0]]]; |
|
|
|
|
| 3250 |
$insert = my $insert_to_current = sub { |
$insert = my $insert_to_current = sub { |
| 3251 |
$self->{open_elements}->[-1]->[0]->append_child ($_[0]); |
$self->{open_elements}->[-1]->[0]->append_child ($_[0]); |
| 3252 |
}; # $insert_to_current |
}; # $insert_to_current |
| 3369 |
} elsif ($self->{insertion_mode} & HEAD_IMS) { |
} elsif ($self->{insertion_mode} & HEAD_IMS) { |
| 3370 |
if ($token->{type} == CHARACTER_TOKEN) { |
if ($token->{type} == CHARACTER_TOKEN) { |
| 3371 |
if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { |
if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { |
| 3372 |
$self->{open_elements}->[-1]->[0]->manakai_append_text ($1); |
unless ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 3373 |
|
!!!cp ('t88.2'); |
| 3374 |
|
$self->{open_elements}->[-1]->[0]->manakai_append_text ($1); |
| 3375 |
|
} else { |
| 3376 |
|
!!!cp ('t88.1'); |
| 3377 |
|
## Ignore the token. |
| 3378 |
|
!!!next-token; |
| 3379 |
|
redo B; |
| 3380 |
|
} |
| 3381 |
unless (length $token->{data}) { |
unless (length $token->{data}) { |
| 3382 |
!!!cp ('t88'); |
!!!cp ('t88'); |
| 3383 |
!!!next-token; |
!!!next-token; |
| 3478 |
} |
} |
| 3479 |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
| 3480 |
pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec. |
pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec. |
| 3481 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3482 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3483 |
!!!next-token; |
!!!next-token; |
| 3484 |
redo B; |
redo B; |
| 3493 |
} |
} |
| 3494 |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
| 3495 |
pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec. |
pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec. |
| 3496 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3497 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3498 |
!!!next-token; |
!!!next-token; |
| 3499 |
redo B; |
redo B; |
| 3554 |
} |
} |
| 3555 |
} |
} |
| 3556 |
|
|
| 3557 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3558 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3559 |
!!!next-token; |
!!!next-token; |
| 3560 |
redo B; |
redo B; |
| 3579 |
my $parent = defined $self->{head_element} ? $self->{head_element} |
my $parent = defined $self->{head_element} ? $self->{head_element} |
| 3580 |
: $self->{open_elements}->[-1]->[0]; |
: $self->{open_elements}->[-1]->[0]; |
| 3581 |
$parse_rcdata->(RCDATA_CONTENT_MODEL); |
$parse_rcdata->(RCDATA_CONTENT_MODEL); |
| 3582 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3583 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3584 |
redo B; |
redo B; |
| 3585 |
} elsif ($token->{tag_name} eq 'style') { |
} elsif ($token->{tag_name} eq 'style') { |
| 3594 |
!!!cp ('t115'); |
!!!cp ('t115'); |
| 3595 |
} |
} |
| 3596 |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
| 3597 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3598 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3599 |
redo B; |
redo B; |
| 3600 |
} elsif ($token->{tag_name} eq 'noscript') { |
} elsif ($token->{tag_name} eq 'noscript') { |
| 3633 |
} |
} |
| 3634 |
|
|
| 3635 |
## NOTE: There is a "as if in head" code clone. |
## NOTE: There is a "as if in head" code clone. |
| 3636 |
$script_start_tag->($insert_to_current); |
$script_start_tag->(); |
| 3637 |
pop @{$self->{open_elements}} |
pop @{$self->{open_elements}} # <head> |
| 3638 |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
if $self->{insertion_mode} == AFTER_HEAD_IM; |
| 3639 |
redo B; |
redo B; |
| 3640 |
} elsif ($token->{tag_name} eq 'body' or |
} elsif ($token->{tag_name} eq 'body' or |
| 4523 |
|
|
| 4524 |
## reprocess |
## reprocess |
| 4525 |
redo B; |
redo B; |
| 4526 |
|
} elsif ($token->{tag_name} eq 'style') { |
| 4527 |
|
if (not $open_tables->[-1]->[1]) { # tainted |
| 4528 |
|
!!!cp ('t227.8'); |
| 4529 |
|
## NOTE: This is a "as if in head" code clone. |
| 4530 |
|
$parse_rcdata->(CDATA_CONTENT_MODEL); |
| 4531 |
|
redo B; |
| 4532 |
|
} else { |
| 4533 |
|
!!!cp ('t227.7'); |
| 4534 |
|
# |
| 4535 |
|
} |
| 4536 |
|
} elsif ($token->{tag_name} eq 'script') { |
| 4537 |
|
if (not $open_tables->[-1]->[1]) { # tainted |
| 4538 |
|
!!!cp ('t227.6'); |
| 4539 |
|
## NOTE: This is a "as if in head" code clone. |
| 4540 |
|
$script_start_tag->(); |
| 4541 |
|
redo B; |
| 4542 |
|
} else { |
| 4543 |
|
!!!cp ('t227.5'); |
| 4544 |
|
# |
| 4545 |
|
} |
| 4546 |
|
} elsif ($token->{tag_name} eq 'input') { |
| 4547 |
|
if (not $open_tables->[-1]->[1]) { # tainted |
| 4548 |
|
if ($token->{attributes}->{type}) { ## TODO: case |
| 4549 |
|
my $type = lc $token->{attributes}->{type}->{value}; |
| 4550 |
|
if ($type eq 'hidden') { |
| 4551 |
|
!!!cp ('t227.3'); |
| 4552 |
|
!!!parse-error (type => 'in table:'.$token->{tag_name}); |
| 4553 |
|
|
| 4554 |
|
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
| 4555 |
|
|
| 4556 |
|
## TODO: form element pointer |
| 4557 |
|
|
| 4558 |
|
pop @{$self->{open_elements}}; |
| 4559 |
|
|
| 4560 |
|
!!!next-token; |
| 4561 |
|
redo B; |
| 4562 |
|
} else { |
| 4563 |
|
!!!cp ('t227.2'); |
| 4564 |
|
# |
| 4565 |
|
} |
| 4566 |
|
} else { |
| 4567 |
|
!!!cp ('t227.1'); |
| 4568 |
|
# |
| 4569 |
|
} |
| 4570 |
|
} else { |
| 4571 |
|
!!!cp ('t227.4'); |
| 4572 |
|
# |
| 4573 |
|
} |
| 4574 |
} else { |
} else { |
| 4575 |
!!!cp ('t227'); |
!!!cp ('t227'); |
|
!!!parse-error (type => 'in table:'.$token->{tag_name}); |
|
|
|
|
|
$insert = $insert_to_foster; |
|
| 4576 |
# |
# |
| 4577 |
} |
} |
| 4578 |
|
|
| 4579 |
|
!!!parse-error (type => 'in table:'.$token->{tag_name}); |
| 4580 |
|
|
| 4581 |
|
$insert = $insert_to_foster; |
| 4582 |
|
# |
| 4583 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 4584 |
if ($token->{tag_name} eq 'tr' and |
if ($token->{tag_name} eq 'tr' and |
| 4585 |
$self->{insertion_mode} == IN_ROW_IM) { |
$self->{insertion_mode} == IN_ROW_IM) { |
| 4933 |
## reprocess |
## reprocess |
| 4934 |
redo B; |
redo B; |
| 4935 |
} |
} |
| 4936 |
} elsif ($self->{insertion_mode} == IN_SELECT_IM) { |
} elsif ($self->{insertion_mode} & SELECT_IMS) { |
| 4937 |
if ($token->{type} == CHARACTER_TOKEN) { |
if ($token->{type} == CHARACTER_TOKEN) { |
| 4938 |
!!!cp ('t271'); |
!!!cp ('t271'); |
| 4939 |
$self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data}); |
$self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data}); |
| 4972 |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
!!!insert-element ($token->{tag_name}, $token->{attributes}); |
| 4973 |
!!!next-token; |
!!!next-token; |
| 4974 |
redo B; |
redo B; |
| 4975 |
} elsif ($token->{tag_name} eq 'select') { |
} elsif ($token->{tag_name} eq 'select' or |
| 4976 |
## TODO: The type below is not good - <select> is replaced by </select> |
$token->{tag_name} eq 'input' or |
| 4977 |
!!!parse-error (type => 'not closed:select'); |
($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and |
| 4978 |
## As if </select> instead |
{ |
| 4979 |
|
caption => 1, table => 1, |
| 4980 |
|
tbody => 1, tfoot => 1, thead => 1, |
| 4981 |
|
tr => 1, td => 1, th => 1, |
| 4982 |
|
}->{$token->{tag_name}})) { |
| 4983 |
|
## TODO: The type below is not good - <select> is replaced by </select> |
| 4984 |
|
!!!parse-error (type => 'not closed:select'); |
| 4985 |
|
## NOTE: As if the token were </select> (<select> case) or |
| 4986 |
|
## as if there were </select> (otherwise). |
| 4987 |
## have an element in table scope |
## have an element in table scope |
| 4988 |
my $i; |
my $i; |
| 4989 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 4990 |
my $node = $self->{open_elements}->[$_]; |
my $node = $self->{open_elements}->[$_]; |
| 4991 |
if ($node->[1] eq $token->{tag_name}) { |
if ($node->[1] eq 'select') { |
| 4992 |
!!!cp ('t278'); |
!!!cp ('t278'); |
| 4993 |
$i = $_; |
$i = $_; |
| 4994 |
last INSCOPE; |
last INSCOPE; |
| 5012 |
|
|
| 5013 |
$self->_reset_insertion_mode; |
$self->_reset_insertion_mode; |
| 5014 |
|
|
| 5015 |
!!!next-token; |
if ($token->{tag_name} eq 'select') { |
| 5016 |
redo B; |
!!!cp ('t281.2'); |
| 5017 |
|
!!!next-token; |
| 5018 |
|
redo B; |
| 5019 |
|
} else { |
| 5020 |
|
!!!cp ('t281.1'); |
| 5021 |
|
## Reprocess the token. |
| 5022 |
|
redo B; |
| 5023 |
|
} |
| 5024 |
} else { |
} else { |
| 5025 |
!!!cp ('t282'); |
!!!cp ('t282'); |
| 5026 |
!!!parse-error (type => 'in select:'.$token->{tag_name}); |
!!!parse-error (type => 'in select:'.$token->{tag_name}); |
| 5087 |
|
|
| 5088 |
!!!next-token; |
!!!next-token; |
| 5089 |
redo B; |
redo B; |
| 5090 |
} elsif ({ |
} elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and |
| 5091 |
caption => 1, table => 1, tbody => 1, |
{ |
| 5092 |
tfoot => 1, thead => 1, tr => 1, td => 1, th => 1, |
caption => 1, table => 1, tbody => 1, |
| 5093 |
}->{$token->{tag_name}}) { |
tfoot => 1, thead => 1, tr => 1, td => 1, th => 1, |
| 5094 |
|
}->{$token->{tag_name}}) { |
| 5095 |
## TODO: The following is wrong? |
## TODO: The following is wrong? |
| 5096 |
!!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}); |
!!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}); |
| 5097 |
|
|
| 5389 |
if ($token->{tag_name} eq 'script') { |
if ($token->{tag_name} eq 'script') { |
| 5390 |
!!!cp ('t332'); |
!!!cp ('t332'); |
| 5391 |
## NOTE: This is an "as if in head" code clone |
## NOTE: This is an "as if in head" code clone |
| 5392 |
$script_start_tag->($insert); |
$script_start_tag->(); |
| 5393 |
redo B; |
redo B; |
| 5394 |
} elsif ($token->{tag_name} eq 'style') { |
} elsif ($token->{tag_name} eq 'style') { |
| 5395 |
!!!cp ('t333'); |
!!!cp ('t333'); |
| 5992 |
|
|
| 5993 |
## TODO: associate with $self->{form_element} if defined |
## TODO: associate with $self->{form_element} if defined |
| 5994 |
|
|
| 5995 |
$self->{insertion_mode} = IN_SELECT_IM; |
if ($self->{insertion_mode} & TABLE_IMS or |
| 5996 |
|
$self->{insertion_mode} & BODY_TABLE_IMS or |
| 5997 |
|
$self->{insertion_mode} == IN_COLUMN_GROUP_IM) { |
| 5998 |
|
!!!cp ('t400.1'); |
| 5999 |
|
$self->{insertion_mode} = IN_SELECT_IN_TABLE_IM; |
| 6000 |
|
} else { |
| 6001 |
|
!!!cp ('t400.2'); |
| 6002 |
|
$self->{insertion_mode} = IN_SELECT_IM; |
| 6003 |
|
} |
| 6004 |
!!!next-token; |
!!!next-token; |
| 6005 |
redo B; |
redo B; |
| 6006 |
} elsif ({ |
} elsif ({ |