| 179 |
dt => DTDD_EL, |
dt => DTDD_EL, |
| 180 |
em => FORMATTING_EL, |
em => FORMATTING_EL, |
| 181 |
embed => MISC_SPECIAL_EL, |
embed => MISC_SPECIAL_EL, |
|
eventsource => MISC_SPECIAL_EL, |
|
| 182 |
fieldset => MISC_SPECIAL_EL, |
fieldset => MISC_SPECIAL_EL, |
| 183 |
figure => MISC_SPECIAL_EL, |
figure => MISC_SPECIAL_EL, |
| 184 |
font => FORMATTING_EL, |
font => FORMATTING_EL, |
| 202 |
#image => MISC_SPECIAL_EL, ## NOTE: Commented out in the spec. |
#image => MISC_SPECIAL_EL, ## NOTE: Commented out in the spec. |
| 203 |
input => MISC_SPECIAL_EL, |
input => MISC_SPECIAL_EL, |
| 204 |
isindex => MISC_SPECIAL_EL, |
isindex => MISC_SPECIAL_EL, |
| 205 |
|
## XXX keygen? (Whether a void element is in Special or not does not |
| 206 |
|
## affect to the processing, however.) |
| 207 |
li => LI_EL, |
li => LI_EL, |
| 208 |
link => MISC_SPECIAL_EL, |
link => MISC_SPECIAL_EL, |
| 209 |
listing => MISC_SPECIAL_EL, |
listing => MISC_SPECIAL_EL, |
| 526 |
|
|
| 527 |
if ($char_stream) { # if supported |
if ($char_stream) { # if supported |
| 528 |
## "Change the encoding" algorithm: |
## "Change the encoding" algorithm: |
|
|
|
|
## Step 1 |
|
|
if ($charset->{category} & |
|
|
Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) { |
|
|
$charset = Message::Charset::Info->get_by_html_name ('utf-8'); |
|
|
($char_stream, $e_status) = $charset->get_decode_handle |
|
|
($byte_stream, |
|
|
byte_buffer => \ $buffer->{buffer}); |
|
|
} |
|
|
$charset_name = $charset->get_iana_name; |
|
| 529 |
|
|
| 530 |
## Step 2 |
## Step 1 |
| 531 |
if (defined $self->{input_encoding} and |
if (defined $self->{input_encoding} and |
| 532 |
$self->{input_encoding} eq $charset_name) { |
$self->{input_encoding} eq $charset_name) { |
| 533 |
!!!parse-error (type => 'charset label:matching', |
!!!parse-error (type => 'charset label:matching', |
| 537 |
return; |
return; |
| 538 |
} |
} |
| 539 |
|
|
| 540 |
|
## Step 2 (HTML5 revision 3205) |
| 541 |
|
if (defined $self->{input_encoding} and |
| 542 |
|
Message::Charset::Info->get_by_html_name ($self->{input_encoding}) |
| 543 |
|
->{category} & Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) { |
| 544 |
|
$self->{confident} = 1; |
| 545 |
|
return; |
| 546 |
|
} |
| 547 |
|
|
| 548 |
|
## Step 3 |
| 549 |
|
if ($charset->{category} & |
| 550 |
|
Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) { |
| 551 |
|
$charset = Message::Charset::Info->get_by_html_name ('utf-8'); |
| 552 |
|
($char_stream, $e_status) = $charset->get_decode_handle |
| 553 |
|
($byte_stream, |
| 554 |
|
byte_buffer => \ $buffer->{buffer}); |
| 555 |
|
} |
| 556 |
|
$charset_name = $charset->get_iana_name; |
| 557 |
|
|
| 558 |
!!!parse-error (type => 'charset label detected', |
!!!parse-error (type => 'charset label detected', |
| 559 |
text => $self->{input_encoding}, |
text => $self->{input_encoding}, |
| 560 |
value => $charset_name, |
value => $charset_name, |
| 561 |
level => $self->{level}->{warn}, |
level => $self->{level}->{warn}, |
| 562 |
token => $token); |
token => $token); |
| 563 |
|
|
| 564 |
## Step 3 |
## Step 4 |
| 565 |
# if (can) { |
# if (can) { |
| 566 |
## change the encoding on the fly. |
## change the encoding on the fly. |
| 567 |
#$self->{confident} = 1; |
#$self->{confident} = 1; |
| 568 |
#return; |
#return; |
| 569 |
# } |
# } |
| 570 |
|
|
| 571 |
## Step 4 |
## Step 5 |
| 572 |
throw Whatpm::HTML::RestartParser (); |
throw Whatpm::HTML::RestartParser (); |
| 573 |
} |
} |
| 574 |
}; # $self->{change_encoding} |
}; # $self->{change_encoding} |
| 829 |
## combined with the original insertion mode. In thie parser, |
## combined with the original insertion mode. In thie parser, |
| 830 |
## they are stored together in the bit-or'ed form. |
## they are stored together in the bit-or'ed form. |
| 831 |
|
|
| 832 |
|
sub IM_MASK () { 0b11111111111 } |
| 833 |
|
|
| 834 |
## NOTE: "initial" and "before html" insertion modes have no constants. |
## NOTE: "initial" and "before html" insertion modes have no constants. |
| 835 |
|
|
| 836 |
## NOTE: "after after body" insertion mode. |
## NOTE: "after after body" insertion mode. |
| 912 |
|
|
| 913 |
INITIAL: { |
INITIAL: { |
| 914 |
if ($token->{type} == DOCTYPE_TOKEN) { |
if ($token->{type} == DOCTYPE_TOKEN) { |
| 915 |
## NOTE: Conformance checkers MAY, instead of reporting "not HTML5" |
## NOTE: Conformance checkers MAY, instead of reporting "not |
| 916 |
## error, switch to a conformance checking mode for another |
## HTML5" error, switch to a conformance checking mode for |
| 917 |
## language. |
## another language. (We don't support such mode switchings; it |
| 918 |
|
## is nonsense to do anything different from what browsers do.) |
| 919 |
my $doctype_name = $token->{name}; |
my $doctype_name = $token->{name}; |
| 920 |
$doctype_name = '' unless defined $doctype_name; |
$doctype_name = '' unless defined $doctype_name; |
| 921 |
$doctype_name =~ tr/a-z/A-Z/; # ASCII case-insensitive |
my $doctype = $self->{document}->create_document_type_definition |
| 922 |
if (not defined $token->{name} or # <!DOCTYPE> |
($doctype_name); |
| 923 |
defined $token->{sysid}) { |
|
| 924 |
|
$doctype_name =~ tr/A-Z/a-z/; # ASCII case-insensitive |
| 925 |
|
if ($doctype_name ne 'html') { |
| 926 |
!!!cp ('t1'); |
!!!cp ('t1'); |
| 927 |
!!!parse-error (type => 'not HTML5', token => $token); |
!!!parse-error (type => 'not HTML5', token => $token); |
| 928 |
} elsif ($doctype_name ne 'HTML') { |
} elsif (defined $token->{pubid}) { |
| 929 |
!!!cp ('t2'); |
!!!cp ('t2'); |
| 930 |
|
## XXX Obsolete permitted DOCTYPEs |
| 931 |
!!!parse-error (type => 'not HTML5', token => $token); |
!!!parse-error (type => 'not HTML5', token => $token); |
| 932 |
} elsif (defined $token->{pubid}) { |
} elsif (defined $token->{sysid}) { |
| 933 |
if ($token->{pubid} eq 'XSLT-compat') { |
if ($token->{sysid} eq 'about:legacy-compat') { |
| 934 |
!!!cp ('t1.2'); |
!!!cp ('t1.2'); ## <!DOCTYPE HTML SYSTEM "about:legacy-compat"> |
| 935 |
!!!parse-error (type => 'XSLT-compat', token => $token, |
!!!parse-error (type => 'XSLT-compat', token => $token, |
| 936 |
level => $self->{level}->{should}); |
level => $self->{level}->{should}); |
| 937 |
} else { |
} else { |
| 938 |
!!!parse-error (type => 'not HTML5', token => $token); |
!!!parse-error (type => 'not HTML5', token => $token); |
| 939 |
} |
} |
| 940 |
} else { |
} else { ## <!DOCTYPE HTML> |
| 941 |
!!!cp ('t3'); |
!!!cp ('t3'); |
| 942 |
# |
# |
| 943 |
} |
} |
| 944 |
|
|
|
my $doctype = $self->{document}->create_document_type_definition |
|
|
($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)? |
|
| 945 |
## NOTE: Default value for both |public_id| and |system_id| attributes |
## NOTE: Default value for both |public_id| and |system_id| attributes |
| 946 |
## are empty strings, so that we don't set any value in missing cases. |
## are empty strings, so that we don't set any value in missing cases. |
| 947 |
$doctype->public_id ($token->{pubid}) if defined $token->{pubid}; |
$doctype->public_id ($token->{pubid}) if defined $token->{pubid}; |
| 948 |
$doctype->system_id ($token->{sysid}) if defined $token->{sysid}; |
$doctype->system_id ($token->{sysid}) if defined $token->{sysid}; |
| 949 |
|
|
| 950 |
## NOTE: Other DocumentType attributes are null or empty lists. |
## NOTE: Other DocumentType attributes are null or empty lists. |
| 951 |
## ISSUE: internalSubset = null?? |
## In Firefox3, |internalSubset| attribute is set to the empty |
| 952 |
|
## string, while |null| is an allowed value for the attribute |
| 953 |
|
## according to DOM3 Core. |
| 954 |
$self->{document}->append_child ($doctype); |
$self->{document}->append_child ($doctype); |
| 955 |
|
|
| 956 |
if ($token->{quirks} or $doctype_name ne 'HTML') { |
if ($token->{quirks} or $doctype_name ne 'html') { |
| 957 |
!!!cp ('t4'); |
!!!cp ('t4'); |
| 958 |
$self->{document}->manakai_compat_mode ('quirks'); |
$self->{document}->manakai_compat_mode ('quirks'); |
| 959 |
} elsif (defined $token->{pubid}) { |
} elsif (defined $token->{pubid}) { |
| 1423 |
## Step 3 |
## Step 3 |
| 1424 |
## TODO: Mark as "already executed", if ... |
## TODO: Mark as "already executed", if ... |
| 1425 |
|
|
| 1426 |
## Step 4 |
## Step 4 (HTML5 revision 2702) |
| 1427 |
$insert->($script_el); |
$insert->($script_el); |
|
|
|
|
## ISSUE: $script_el is not put into the stack |
|
| 1428 |
push @{$self->{open_elements}}, [$script_el, $el_category->{script}]; |
push @{$self->{open_elements}}, [$script_el, $el_category->{script}]; |
| 1429 |
|
|
| 1430 |
## Step 5 |
## Step 5 |
| 1439 |
}; # $script_start_tag |
}; # $script_start_tag |
| 1440 |
|
|
| 1441 |
## NOTE: $open_tables->[-1]->[0] is the "current table" element node. |
## NOTE: $open_tables->[-1]->[0] is the "current table" element node. |
| 1442 |
## NOTE: $open_tables->[-1]->[1] is the "tainted" flag. |
## NOTE: $open_tables->[-1]->[1] is the "tainted" flag (OBSOLETE; unused). |
| 1443 |
## NOTE: $open_tables->[-1]->[2] is set false when non-Text node inserted. |
## NOTE: $open_tables->[-1]->[2] is set false when non-Text node inserted. |
| 1444 |
my $open_tables = [[$self->{open_elements}->[0]->[0]]]; |
my $open_tables = [[$self->{open_elements}->[0]->[0]]]; |
| 1445 |
|
|
| 1735 |
## document.write ("b")</script>| |
## document.write ("b")</script>| |
| 1736 |
|
|
| 1737 |
B: while (1) { |
B: while (1) { |
| 1738 |
|
|
| 1739 |
|
## The "in table text" insertion mode. |
| 1740 |
|
if ($self->{insertion_mode} & TABLE_IMS and |
| 1741 |
|
not $self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and |
| 1742 |
|
not $self->{insertion_mode} & IN_CDATA_RCDATA_IM) { |
| 1743 |
|
C: { |
| 1744 |
|
my $s; |
| 1745 |
|
if ($token->{type} == CHARACTER_TOKEN) { |
| 1746 |
|
!!!cp ('t194'); |
| 1747 |
|
$self->{pending_chars} ||= []; |
| 1748 |
|
push @{$self->{pending_chars}}, $token; |
| 1749 |
|
!!!next-token; |
| 1750 |
|
next B; |
| 1751 |
|
} else { |
| 1752 |
|
if ($self->{pending_chars}) { |
| 1753 |
|
$s = join '', map { $_->{data} } @{$self->{pending_chars}}; |
| 1754 |
|
delete $self->{pending_chars}; |
| 1755 |
|
if ($s =~ /[^\x09\x0A\x0C\x0D\x20]/) { |
| 1756 |
|
!!!cp ('t195'); |
| 1757 |
|
# |
| 1758 |
|
} else { |
| 1759 |
|
!!!cp ('t195.1'); |
| 1760 |
|
#$self->{open_elements}->[-1]->[0]->manakai_append_text ($s); |
| 1761 |
|
$self->{open_elements}->[-1]->[0]->append_child |
| 1762 |
|
($self->{document}->create_text_node ($s)); |
| 1763 |
|
last C; |
| 1764 |
|
} |
| 1765 |
|
} else { |
| 1766 |
|
!!!cp ('t195.2'); |
| 1767 |
|
last C; |
| 1768 |
|
} |
| 1769 |
|
} |
| 1770 |
|
|
| 1771 |
|
## Foster parenting |
| 1772 |
|
!!!parse-error (type => 'in table:#text', token => $token); |
| 1773 |
|
|
| 1774 |
|
## NOTE: As if in body, but insert into the foster parent element. |
| 1775 |
|
$reconstruct_active_formatting_elements->($insert_to_foster); |
| 1776 |
|
|
| 1777 |
|
if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) { |
| 1778 |
|
# MUST |
| 1779 |
|
my $foster_parent_element; |
| 1780 |
|
my $next_sibling; |
| 1781 |
|
#my $prev_sibling; |
| 1782 |
|
OE: for (reverse 0..$#{$self->{open_elements}}) { |
| 1783 |
|
if ($self->{open_elements}->[$_]->[1] == TABLE_EL) { |
| 1784 |
|
my $parent = $self->{open_elements}->[$_]->[0]->parent_node; |
| 1785 |
|
if (defined $parent and $parent->node_type == 1) { |
| 1786 |
|
$foster_parent_element = $parent; |
| 1787 |
|
!!!cp ('t196'); |
| 1788 |
|
$next_sibling = $self->{open_elements}->[$_]->[0]; |
| 1789 |
|
# $prev_sibling = $next_sibling->previous_sibling; |
| 1790 |
|
# |
| 1791 |
|
} else { |
| 1792 |
|
!!!cp ('t197'); |
| 1793 |
|
$foster_parent_element = $self->{open_elements}->[$_ - 1]->[0]; |
| 1794 |
|
# $prev_sibling = $foster_parent_element->last_child; |
| 1795 |
|
# |
| 1796 |
|
} |
| 1797 |
|
last OE; |
| 1798 |
|
} |
| 1799 |
|
} # OE |
| 1800 |
|
$foster_parent_element = $self->{open_elements}->[0]->[0] #and |
| 1801 |
|
#$prev_sibling = $foster_parent_element->last_child |
| 1802 |
|
unless defined $foster_parent_element; |
| 1803 |
|
#undef $prev_sibling unless $open_tables->[-1]->[2]; # ~node inserted |
| 1804 |
|
#if (defined $prev_sibling and |
| 1805 |
|
# $prev_sibling->node_type == 3) { |
| 1806 |
|
# !!! cp ('t198'); |
| 1807 |
|
# $prev_sibling->manakai_append_text ($s); |
| 1808 |
|
#} else { |
| 1809 |
|
!!!cp ('t199'); |
| 1810 |
|
$foster_parent_element->insert_before |
| 1811 |
|
($self->{document}->create_text_node ($s), $next_sibling); |
| 1812 |
|
#} |
| 1813 |
|
$open_tables->[-1]->[1] = 1; # tainted |
| 1814 |
|
$open_tables->[-1]->[2] = 1; # ~node inserted |
| 1815 |
|
} else { |
| 1816 |
|
## NOTE: Fragment case or in a foster parent'ed element |
| 1817 |
|
## (e.g. |<table><span>a|). In fragment case, whether the |
| 1818 |
|
## character is appended to existing node or a new node is |
| 1819 |
|
## created is irrelevant, since the foster parent'ed nodes |
| 1820 |
|
## are discarded and fragment parsing does not invoke any |
| 1821 |
|
## script. |
| 1822 |
|
!!!cp ('t200'); |
| 1823 |
|
$self->{open_elements}->[-1]->[0]->manakai_append_text ($s); |
| 1824 |
|
} |
| 1825 |
|
} # C |
| 1826 |
|
} # TABLE_IMS |
| 1827 |
|
|
| 1828 |
if ($token->{type} == DOCTYPE_TOKEN) { |
if ($token->{type} == DOCTYPE_TOKEN) { |
| 1829 |
!!!cp ('t73'); |
!!!cp ('t73'); |
| 1830 |
!!!parse-error (type => 'in html:#DOCTYPE', token => $token); |
!!!parse-error (type => 'in html:#DOCTYPE', token => $token); |
| 1966 |
} elsif ({ |
} elsif ({ |
| 1967 |
b => 1, big => 1, blockquote => 1, body => 1, br => 1, |
b => 1, big => 1, blockquote => 1, body => 1, br => 1, |
| 1968 |
center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1, |
center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1, |
| 1969 |
em => 1, embed => 1, font => 1, h1 => 1, h2 => 1, h3 => 1, |
em => 1, embed => 1, h1 => 1, h2 => 1, h3 => 1, |
| 1970 |
h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1, |
h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1, |
| 1971 |
img => 1, li => 1, listing => 1, menu => 1, meta => 1, |
img => 1, li => 1, listing => 1, menu => 1, meta => 1, |
| 1972 |
nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1, |
nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1, |
| 1973 |
small => 1, span => 1, strong => 1, strike => 1, sub => 1, |
small => 1, span => 1, strong => 1, strike => 1, sub => 1, |
| 1974 |
sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1, |
sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1, |
| 1975 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}} or |
| 1976 |
|
($token->{tag_name} eq 'font' and |
| 1977 |
|
($token->{attributes}->{color} or |
| 1978 |
|
$token->{attributes}->{face} or |
| 1979 |
|
$token->{attributes}->{size}))) { |
| 1980 |
!!!cp ('t87.2'); |
!!!cp ('t87.2'); |
| 1981 |
!!!parse-error (type => 'not closed', |
!!!parse-error (type => 'not closed', |
| 1982 |
text => $self->{open_elements}->[-1]->[0] |
text => $self->{open_elements}->[-1]->[0] |
| 2052 |
} |
} |
| 2053 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 2054 |
## NOTE: "using the rules for secondary insertion mode" then "continue" |
## NOTE: "using the rules for secondary insertion mode" then "continue" |
| 2055 |
!!!cp ('t87.5'); |
if ($token->{tag_name} eq 'script') { |
| 2056 |
# |
!!!cp ('t87.41'); |
| 2057 |
|
# |
| 2058 |
|
## XXXscript: Execute script here. |
| 2059 |
|
} else { |
| 2060 |
|
!!!cp ('t87.5'); |
| 2061 |
|
# |
| 2062 |
|
} |
| 2063 |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
| 2064 |
!!!cp ('t87.6'); |
!!!cp ('t87.6'); |
| 2065 |
!!!parse-error (type => 'not closed', |
!!!parse-error (type => 'not closed', |
| 2243 |
!!!ack ('t103.1'); |
!!!ack ('t103.1'); |
| 2244 |
!!!next-token; |
!!!next-token; |
| 2245 |
next B; |
next B; |
| 2246 |
} elsif ($token->{tag_name} eq 'command' or |
} elsif ($token->{tag_name} eq 'command') { |
|
$token->{tag_name} eq 'eventsource') { |
|
| 2247 |
if ($self->{insertion_mode} == IN_HEAD_IM) { |
if ($self->{insertion_mode} == IN_HEAD_IM) { |
| 2248 |
## NOTE: If the insertion mode at the time of the emission |
## NOTE: If the insertion mode at the time of the emission |
| 2249 |
## of the token was "before head", $self->{insertion_mode} |
## of the token was "before head", $self->{insertion_mode} |
| 2358 |
|
|
| 2359 |
## NOTE: There is a "as if in head" code clone. |
## NOTE: There is a "as if in head" code clone. |
| 2360 |
$parse_rcdata->(RCDATA_CONTENT_MODEL); |
$parse_rcdata->(RCDATA_CONTENT_MODEL); |
| 2361 |
## ISSUE: A spec bug [Bug 6038] |
|
| 2362 |
|
## NOTE: At this point the stack of open elements contain |
| 2363 |
|
## the |head| element (index == -2) and the |script| element |
| 2364 |
|
## (index == -1). In the "after head" insertion mode the |
| 2365 |
|
## |head| element is inserted only for the purpose of |
| 2366 |
|
## providing the context for the |script| element, and |
| 2367 |
|
## therefore we can now and have to remove the element from |
| 2368 |
|
## the stack. |
| 2369 |
splice @{$self->{open_elements}}, -2, 1, () # <head> |
splice @{$self->{open_elements}}, -2, 1, () # <head> |
| 2370 |
if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM; |
if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM; |
| 2371 |
next B; |
next B; |
| 2372 |
} elsif ($token->{tag_name} eq 'style' or |
} elsif ($token->{tag_name} eq 'style' or |
| 2373 |
$token->{tag_name} eq 'noframes') { |
$token->{tag_name} eq 'noframes') { |
| 2387 |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
| 2388 |
## ISSUE: A spec bug [Bug 6038] |
## ISSUE: A spec bug [Bug 6038] |
| 2389 |
splice @{$self->{open_elements}}, -2, 1, () # <head> |
splice @{$self->{open_elements}}, -2, 1, () # <head> |
| 2390 |
if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM; |
if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM; |
| 2391 |
next B; |
next B; |
| 2392 |
} elsif ($token->{tag_name} eq 'noscript') { |
} elsif ($token->{tag_name} eq 'noscript') { |
| 2393 |
if ($self->{insertion_mode} == IN_HEAD_IM) { |
if ($self->{insertion_mode} == IN_HEAD_IM) { |
| 2435 |
$script_start_tag->(); |
$script_start_tag->(); |
| 2436 |
## ISSUE: A spec bug [Bug 6038] |
## ISSUE: A spec bug [Bug 6038] |
| 2437 |
splice @{$self->{open_elements}}, -2, 1 # <head> |
splice @{$self->{open_elements}}, -2, 1 # <head> |
| 2438 |
if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM; |
if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM; |
| 2439 |
next B; |
next B; |
| 2440 |
} elsif ($token->{tag_name} eq 'body' or |
} elsif ($token->{tag_name} eq 'body' or |
| 2441 |
$token->{tag_name} eq 'frameset') { |
$token->{tag_name} eq 'frameset') { |
| 2600 |
## Ignore the token |
## Ignore the token |
| 2601 |
!!!next-token; |
!!!next-token; |
| 2602 |
next B; |
next B; |
| 2603 |
} elsif ($token->{tag_name} eq 'br') { |
} elsif ($token->{tag_name} eq 'br') { |
| 2604 |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 2605 |
!!!cp ('t142.2'); |
!!!cp ('t142.2'); |
| 2606 |
## (before head) as if <head>, (in head) as if </head> |
## (before head) as if <head>, (in head) as if </head> |
| 2607 |
!!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token); |
!!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token); |
| 2608 |
$self->{open_elements}->[-1]->[0]->append_child ($self->{head_element}); |
$self->{open_elements}->[-1]->[0]->append_child ($self->{head_element}); |
| 2609 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
$self->{insertion_mode} = AFTER_HEAD_IM; |
| 2610 |
|
|
| 2611 |
## Reprocess in the "after head" insertion mode... |
## Reprocess in the "after head" insertion mode... |
| 2612 |
} elsif ($self->{insertion_mode} == IN_HEAD_IM) { |
} elsif ($self->{insertion_mode} == IN_HEAD_IM) { |
| 2613 |
!!!cp ('t143.2'); |
!!!cp ('t143.2'); |
| 2614 |
## As if </head> |
## As if </head> |
| 2615 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 2616 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
$self->{insertion_mode} = AFTER_HEAD_IM; |
| 2617 |
|
|
| 2618 |
## Reprocess in the "after head" insertion mode... |
## Reprocess in the "after head" insertion mode... |
| 2619 |
} elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
} elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) { |
| 2620 |
!!!cp ('t143.3'); |
!!!cp ('t143.3'); |
| 2621 |
## ISSUE: Two parse errors for <head><noscript></br> |
## NOTE: Two parse errors for <head><noscript></br> |
| 2622 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 2623 |
text => 'br', token => $token); |
text => 'br', token => $token); |
| 2624 |
## As if </noscript> |
## As if </noscript> |
| 2625 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 2626 |
$self->{insertion_mode} = IN_HEAD_IM; |
$self->{insertion_mode} = IN_HEAD_IM; |
| 2627 |
|
|
| 2628 |
## Reprocess in the "in head" insertion mode... |
## Reprocess in the "in head" insertion mode... |
| 2629 |
## As if </head> |
## As if </head> |
| 2630 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 2631 |
$self->{insertion_mode} = AFTER_HEAD_IM; |
$self->{insertion_mode} = AFTER_HEAD_IM; |
| 2632 |
|
|
| 2633 |
## Reprocess in the "after head" insertion mode... |
## Reprocess in the "after head" insertion mode... |
| 2634 |
} elsif ($self->{insertion_mode} == AFTER_HEAD_IM) { |
} elsif ($self->{insertion_mode} == AFTER_HEAD_IM) { |
| 2635 |
!!!cp ('t143.4'); |
!!!cp ('t143.4'); |
| 2636 |
# |
# |
| 2637 |
} else { |
} else { |
| 2638 |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
die "$0: $self->{insertion_mode}: Unknown insertion mode"; |
| 2639 |
} |
} |
| 2640 |
|
|
| 2641 |
## ISSUE: does not agree with IE7 - it doesn't ignore </br>. |
# |
| 2642 |
!!!parse-error (type => 'unmatched end tag', |
} else { ## Other end tags |
|
text => 'br', token => $token); |
|
|
## Ignore the token |
|
|
!!!next-token; |
|
|
next B; |
|
|
} else { |
|
| 2643 |
!!!cp ('t145'); |
!!!cp ('t145'); |
| 2644 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 2645 |
text => $token->{tag_name}, token => $token); |
text => $token->{tag_name}, token => $token); |
| 2683 |
!!!insert-element ('body',, $token); |
!!!insert-element ('body',, $token); |
| 2684 |
$self->{insertion_mode} = IN_BODY_IM; |
$self->{insertion_mode} = IN_BODY_IM; |
| 2685 |
## reprocess |
## reprocess |
| 2686 |
next B; |
next B; |
| 2687 |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
| 2688 |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
if ($self->{insertion_mode} == BEFORE_HEAD_IM) { |
| 2689 |
!!!cp ('t149.1'); |
!!!cp ('t149.1'); |
| 2756 |
caption => 1, col => 1, colgroup => 1, tbody => 1, |
caption => 1, col => 1, colgroup => 1, tbody => 1, |
| 2757 |
td => 1, tfoot => 1, th => 1, thead => 1, tr => 1, |
td => 1, tfoot => 1, th => 1, thead => 1, tr => 1, |
| 2758 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 2759 |
if ($self->{insertion_mode} == IN_CELL_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) { |
| 2760 |
## have an element in table scope |
## have an element in table scope |
| 2761 |
for (reverse 0..$#{$self->{open_elements}}) { |
for (reverse 0..$#{$self->{open_elements}}) { |
| 2762 |
my $node = $self->{open_elements}->[$_]; |
my $node = $self->{open_elements}->[$_]; |
| 2784 |
!!!nack ('t153.1'); |
!!!nack ('t153.1'); |
| 2785 |
!!!next-token; |
!!!next-token; |
| 2786 |
next B; |
next B; |
| 2787 |
} elsif ($self->{insertion_mode} == IN_CAPTION_IM) { |
} elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) { |
| 2788 |
!!!parse-error (type => 'not closed', text => 'caption', |
!!!parse-error (type => 'not closed', text => 'caption', |
| 2789 |
token => $token); |
token => $token); |
| 2790 |
|
|
| 2849 |
} |
} |
| 2850 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 2851 |
if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') { |
if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') { |
| 2852 |
if ($self->{insertion_mode} == IN_CELL_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) { |
| 2853 |
## have an element in table scope |
## have an element in table scope |
| 2854 |
my $i; |
my $i; |
| 2855 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 2899 |
|
|
| 2900 |
!!!next-token; |
!!!next-token; |
| 2901 |
next B; |
next B; |
| 2902 |
} elsif ($self->{insertion_mode} == IN_CAPTION_IM) { |
} elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) { |
| 2903 |
!!!cp ('t169'); |
!!!cp ('t169'); |
| 2904 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 2905 |
text => $token->{tag_name}, token => $token); |
text => $token->{tag_name}, token => $token); |
| 2911 |
# |
# |
| 2912 |
} |
} |
| 2913 |
} elsif ($token->{tag_name} eq 'caption') { |
} elsif ($token->{tag_name} eq 'caption') { |
| 2914 |
if ($self->{insertion_mode} == IN_CAPTION_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) { |
| 2915 |
## have a table element in table scope |
## have a table element in table scope |
| 2916 |
my $i; |
my $i; |
| 2917 |
INSCOPE: { |
INSCOPE: { |
| 2960 |
|
|
| 2961 |
!!!next-token; |
!!!next-token; |
| 2962 |
next B; |
next B; |
| 2963 |
} elsif ($self->{insertion_mode} == IN_CELL_IM) { |
} elsif (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) { |
| 2964 |
!!!cp ('t177'); |
!!!cp ('t177'); |
| 2965 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 2966 |
text => $token->{tag_name}, token => $token); |
text => $token->{tag_name}, token => $token); |
| 2975 |
table => 1, tbody => 1, tfoot => 1, |
table => 1, tbody => 1, tfoot => 1, |
| 2976 |
thead => 1, tr => 1, |
thead => 1, tr => 1, |
| 2977 |
}->{$token->{tag_name}} and |
}->{$token->{tag_name}} and |
| 2978 |
$self->{insertion_mode} == IN_CELL_IM) { |
($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) { |
| 2979 |
## have an element in table scope |
## have an element in table scope |
| 2980 |
my $i; |
my $i; |
| 2981 |
my $tn; |
my $tn; |
| 3012 |
next B; |
next B; |
| 3013 |
} # INSCOPE |
} # INSCOPE |
| 3014 |
} elsif ($token->{tag_name} eq 'table' and |
} elsif ($token->{tag_name} eq 'table' and |
| 3015 |
$self->{insertion_mode} == IN_CAPTION_IM) { |
($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) { |
| 3016 |
!!!parse-error (type => 'not closed', text => 'caption', |
!!!parse-error (type => 'not closed', text => 'caption', |
| 3017 |
token => $token); |
token => $token); |
| 3018 |
|
|
| 3032 |
} # INSCOPE |
} # INSCOPE |
| 3033 |
unless (defined $i) { |
unless (defined $i) { |
| 3034 |
!!!cp ('t186'); |
!!!cp ('t186'); |
| 3035 |
|
## TODO: Wrong error type? |
| 3036 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 3037 |
text => 'caption', token => $token); |
text => 'caption', token => $token); |
| 3038 |
## Ignore the token |
## Ignore the token |
| 3078 |
!!!cp ('t191'); |
!!!cp ('t191'); |
| 3079 |
# |
# |
| 3080 |
} |
} |
| 3081 |
} elsif ({ |
} elsif ({ |
| 3082 |
tbody => 1, tfoot => 1, |
tbody => 1, tfoot => 1, |
| 3083 |
thead => 1, tr => 1, |
thead => 1, tr => 1, |
| 3084 |
}->{$token->{tag_name}} and |
}->{$token->{tag_name}} and |
| 3085 |
$self->{insertion_mode} == IN_CAPTION_IM) { |
($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) { |
| 3086 |
!!!cp ('t192'); |
!!!cp ('t192'); |
| 3087 |
!!!parse-error (type => 'unmatched end tag', |
!!!parse-error (type => 'unmatched end tag', |
| 3088 |
text => $token->{tag_name}, token => $token); |
text => $token->{tag_name}, token => $token); |
| 3089 |
## Ignore the token |
## Ignore the token |
| 3090 |
!!!next-token; |
!!!next-token; |
| 3091 |
next B; |
next B; |
| 3092 |
} else { |
} else { |
| 3093 |
!!!cp ('t193'); |
!!!cp ('t193'); |
| 3094 |
# |
# |
| 3095 |
} |
} |
| 3096 |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
} elsif ($token->{type} == END_OF_FILE_TOKEN) { |
| 3097 |
for my $entry (@{$self->{open_elements}}) { |
for my $entry (@{$self->{open_elements}}) { |
| 3098 |
unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) { |
unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) { |
| 3111 |
$insert = $insert_to_current; |
$insert = $insert_to_current; |
| 3112 |
# |
# |
| 3113 |
} elsif ($self->{insertion_mode} & TABLE_IMS) { |
} elsif ($self->{insertion_mode} & TABLE_IMS) { |
| 3114 |
if ($token->{type} == CHARACTER_TOKEN) { |
if ($token->{type} == START_TAG_TOKEN) { |
|
if (not $open_tables->[-1]->[1] and # tainted |
|
|
$token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) { |
|
|
$self->{open_elements}->[-1]->[0]->manakai_append_text ($1); |
|
|
|
|
|
unless (length $token->{data}) { |
|
|
!!!cp ('t194'); |
|
|
!!!next-token; |
|
|
next B; |
|
|
} else { |
|
|
!!!cp ('t195'); |
|
|
} |
|
|
} |
|
|
|
|
|
!!!parse-error (type => 'in table:#text', token => $token); |
|
|
|
|
|
## NOTE: As if in body, but insert into the foster parent element. |
|
|
$reconstruct_active_formatting_elements->($insert_to_foster); |
|
|
|
|
|
if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) { |
|
|
# MUST |
|
|
my $foster_parent_element; |
|
|
my $next_sibling; |
|
|
my $prev_sibling; |
|
|
OE: for (reverse 0..$#{$self->{open_elements}}) { |
|
|
if ($self->{open_elements}->[$_]->[1] == TABLE_EL) { |
|
|
my $parent = $self->{open_elements}->[$_]->[0]->parent_node; |
|
|
if (defined $parent and $parent->node_type == 1) { |
|
|
$foster_parent_element = $parent; |
|
|
!!!cp ('t196'); |
|
|
$next_sibling = $self->{open_elements}->[$_]->[0]; |
|
|
$prev_sibling = $next_sibling->previous_sibling; |
|
|
# |
|
|
} else { |
|
|
!!!cp ('t197'); |
|
|
$foster_parent_element = $self->{open_elements}->[$_ - 1]->[0]; |
|
|
$prev_sibling = $foster_parent_element->last_child; |
|
|
# |
|
|
} |
|
|
last OE; |
|
|
} |
|
|
} # OE |
|
|
$foster_parent_element = $self->{open_elements}->[0]->[0] and |
|
|
$prev_sibling = $foster_parent_element->last_child |
|
|
unless defined $foster_parent_element; |
|
|
undef $prev_sibling unless $open_tables->[-1]->[2]; # ~node inserted |
|
|
if (defined $prev_sibling and |
|
|
$prev_sibling->node_type == 3) { |
|
|
!!!cp ('t198'); |
|
|
$prev_sibling->manakai_append_text ($token->{data}); |
|
|
} else { |
|
|
!!!cp ('t199'); |
|
|
$foster_parent_element->insert_before |
|
|
($self->{document}->create_text_node ($token->{data}), |
|
|
$next_sibling); |
|
|
} |
|
|
$open_tables->[-1]->[1] = 1; # tainted |
|
|
$open_tables->[-1]->[2] = 1; # ~node inserted |
|
|
} else { |
|
|
## NOTE: Fragment case or in a foster parent'ed element |
|
|
## (e.g. |<table><span>a|). In fragment case, whether the |
|
|
## character is appended to existing node or a new node is |
|
|
## created is irrelevant, since the foster parent'ed nodes |
|
|
## are discarded and fragment parsing does not invoke any |
|
|
## script. |
|
|
!!!cp ('t200'); |
|
|
$self->{open_elements}->[-1]->[0]->manakai_append_text |
|
|
($token->{data}); |
|
|
} |
|
|
|
|
|
!!!next-token; |
|
|
next B; |
|
|
} elsif ($token->{type} == START_TAG_TOKEN) { |
|
| 3115 |
if ({ |
if ({ |
| 3116 |
tr => ($self->{insertion_mode} != IN_ROW_IM), |
tr => (($self->{insertion_mode} & IM_MASK) != IN_ROW_IM), |
| 3117 |
th => 1, td => 1, |
th => 1, td => 1, |
| 3118 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 3119 |
if ($self->{insertion_mode} == IN_TABLE_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_IM) { |
| 3120 |
## Clear back to table context |
## Clear back to table context |
| 3121 |
while (not ($self->{open_elements}->[-1]->[1] |
while (not ($self->{open_elements}->[-1]->[1] |
| 3122 |
& TABLE_SCOPING_EL)) { |
& TABLE_SCOPING_EL)) { |
| 3129 |
## reprocess in the "in table body" insertion mode... |
## reprocess in the "in table body" insertion mode... |
| 3130 |
} |
} |
| 3131 |
|
|
| 3132 |
if ($self->{insertion_mode} == IN_TABLE_BODY_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) { |
| 3133 |
unless ($token->{tag_name} eq 'tr') { |
unless ($token->{tag_name} eq 'tr') { |
| 3134 |
!!!cp ('t202'); |
!!!cp ('t202'); |
| 3135 |
!!!parse-error (type => 'missing start tag:tr', token => $token); |
!!!parse-error (type => 'missing start tag:tr', token => $token); |
| 3181 |
tbody => 1, tfoot => 1, thead => 1, |
tbody => 1, tfoot => 1, thead => 1, |
| 3182 |
tr => 1, # $self->{insertion_mode} == IN_ROW_IM |
tr => 1, # $self->{insertion_mode} == IN_ROW_IM |
| 3183 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 3184 |
if ($self->{insertion_mode} == IN_ROW_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) { |
| 3185 |
## As if </tr> |
## As if </tr> |
| 3186 |
## have an element in table scope |
## have an element in table scope |
| 3187 |
my $i; |
my $i; |
| 3228 |
} |
} |
| 3229 |
} |
} |
| 3230 |
|
|
| 3231 |
if ($self->{insertion_mode} == IN_TABLE_BODY_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) { |
| 3232 |
## have an element in table scope |
## have an element in table scope |
| 3233 |
my $i; |
my $i; |
| 3234 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3442 |
$insert = $insert_to_foster; |
$insert = $insert_to_foster; |
| 3443 |
# |
# |
| 3444 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 3445 |
if ($token->{tag_name} eq 'tr' and |
if ($token->{tag_name} eq 'tr' and |
| 3446 |
$self->{insertion_mode} == IN_ROW_IM) { |
($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) { |
| 3447 |
## have an element in table scope |
## have an element in table scope |
| 3448 |
my $i; |
my $i; |
| 3449 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3450 |
my $node = $self->{open_elements}->[$_]; |
my $node = $self->{open_elements}->[$_]; |
| 3483 |
!!!nack ('t231.1'); |
!!!nack ('t231.1'); |
| 3484 |
next B; |
next B; |
| 3485 |
} elsif ($token->{tag_name} eq 'table') { |
} elsif ($token->{tag_name} eq 'table') { |
| 3486 |
if ($self->{insertion_mode} == IN_ROW_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) { |
| 3487 |
## As if </tr> |
## As if </tr> |
| 3488 |
## have an element in table scope |
## have an element in table scope |
| 3489 |
my $i; |
my $i; |
| 3522 |
## reprocess in the "in table body" insertion mode... |
## reprocess in the "in table body" insertion mode... |
| 3523 |
} |
} |
| 3524 |
|
|
| 3525 |
if ($self->{insertion_mode} == IN_TABLE_BODY_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) { |
| 3526 |
## have an element in table scope |
## have an element in table scope |
| 3527 |
my $i; |
my $i; |
| 3528 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3604 |
tbody => 1, tfoot => 1, thead => 1, |
tbody => 1, tfoot => 1, thead => 1, |
| 3605 |
}->{$token->{tag_name}} and |
}->{$token->{tag_name}} and |
| 3606 |
$self->{insertion_mode} & ROW_IMS) { |
$self->{insertion_mode} & ROW_IMS) { |
| 3607 |
if ($self->{insertion_mode} == IN_ROW_IM) { |
if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) { |
| 3608 |
## have an element in table scope |
## have an element in table scope |
| 3609 |
my $i; |
my $i; |
| 3610 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3738 |
} else { |
} else { |
| 3739 |
die "$0: $token->{type}: Unknown token type"; |
die "$0: $token->{type}: Unknown token type"; |
| 3740 |
} |
} |
| 3741 |
} elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) { |
} elsif (($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) { |
| 3742 |
if ($token->{type} == CHARACTER_TOKEN) { |
if ($token->{type} == CHARACTER_TOKEN) { |
| 3743 |
if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) { |
if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) { |
| 3744 |
$self->{open_elements}->[-1]->[0]->manakai_append_text ($1); |
$self->{open_elements}->[-1]->[0]->manakai_append_text ($1); |
| 3868 |
!!!next-token; |
!!!next-token; |
| 3869 |
next B; |
next B; |
| 3870 |
} elsif ({ |
} elsif ({ |
| 3871 |
select => 1, input => 1, textarea => 1, |
select => 1, input => 1, textarea => 1, keygen => 1, |
| 3872 |
}->{$token->{tag_name}} or |
}->{$token->{tag_name}} or |
| 3873 |
($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and |
(($self->{insertion_mode} & IM_MASK) |
| 3874 |
|
== IN_SELECT_IN_TABLE_IM and |
| 3875 |
{ |
{ |
| 3876 |
caption => 1, table => 1, |
caption => 1, table => 1, |
| 3877 |
tbody => 1, tfoot => 1, thead => 1, |
tbody => 1, tfoot => 1, thead => 1, |
| 3878 |
tr => 1, td => 1, th => 1, |
tr => 1, td => 1, th => 1, |
| 3879 |
}->{$token->{tag_name}})) { |
}->{$token->{tag_name}})) { |
| 3880 |
## TODO: The type below is not good - <select> is replaced by </select> |
|
| 3881 |
!!!parse-error (type => 'not closed', text => 'select', |
## 1. Parse error. |
| 3882 |
token => $token); |
if ($token->{tag_name} eq 'select') { |
| 3883 |
## NOTE: As if the token were </select> (<select> case) or |
!!!parse-error (type => 'select in select', ## XXX: documentation |
| 3884 |
## as if there were </select> (otherwise). |
token => $token); |
| 3885 |
## have an element in table scope |
} else { |
| 3886 |
|
!!!parse-error (type => 'not closed', text => 'select', |
| 3887 |
|
token => $token); |
| 3888 |
|
} |
| 3889 |
|
|
| 3890 |
|
## 2./<select>-1. Unless "have an element in table scope" (select): |
| 3891 |
my $i; |
my $i; |
| 3892 |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
INSCOPE: for (reverse 0..$#{$self->{open_elements}}) { |
| 3893 |
my $node = $self->{open_elements}->[$_]; |
my $node = $self->{open_elements}->[$_]; |
| 3902 |
} # INSCOPE |
} # INSCOPE |
| 3903 |
unless (defined $i) { |
unless (defined $i) { |
| 3904 |
!!!cp ('t280'); |
!!!cp ('t280'); |
| 3905 |
!!!parse-error (type => 'unmatched end tag', |
if ($token->{tag_name} eq 'select') { |
| 3906 |
text => 'select', token => $token); |
## NOTE: This error would be raised when |
| 3907 |
## Ignore the token |
## |select.innerHTML = '<select>'| is executed; in this |
| 3908 |
|
## case two errors, "select in select" and "unmatched |
| 3909 |
|
## end tags" are reported to the user, the latter might |
| 3910 |
|
## be confusing but this is what the spec requires. |
| 3911 |
|
!!!parse-error (type => 'unmatched end tag', |
| 3912 |
|
text => 'select', |
| 3913 |
|
token => $token); |
| 3914 |
|
} |
| 3915 |
|
## Ignore the token. |
| 3916 |
!!!nack ('t280.1'); |
!!!nack ('t280.1'); |
| 3917 |
!!!next-token; |
!!!next-token; |
| 3918 |
next B; |
next B; |
| 3919 |
} |
} |
| 3920 |
|
|
| 3921 |
|
## 3. Otherwise, as if there were <select>: |
| 3922 |
|
|
| 3923 |
!!!cp ('t281'); |
!!!cp ('t281'); |
| 3924 |
splice @{$self->{open_elements}}, $i; |
splice @{$self->{open_elements}}, $i; |
| 3935 |
## Reprocess the token. |
## Reprocess the token. |
| 3936 |
next B; |
next B; |
| 3937 |
} |
} |
| 3938 |
|
} elsif ($token->{tag_name} eq 'script') { |
| 3939 |
|
!!!cp ('t281.3'); |
| 3940 |
|
## NOTE: This is an "as if in head" code clone |
| 3941 |
|
$script_start_tag->(); |
| 3942 |
|
next B; |
| 3943 |
} else { |
} else { |
| 3944 |
!!!cp ('t282'); |
!!!cp ('t282'); |
| 3945 |
!!!parse-error (type => 'in select', |
!!!parse-error (type => 'in select', |
| 4013 |
!!!nack ('t291.1'); |
!!!nack ('t291.1'); |
| 4014 |
!!!next-token; |
!!!next-token; |
| 4015 |
next B; |
next B; |
| 4016 |
} elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and |
} elsif (($self->{insertion_mode} & IM_MASK) |
| 4017 |
|
== IN_SELECT_IN_TABLE_IM and |
| 4018 |
{ |
{ |
| 4019 |
caption => 1, table => 1, tbody => 1, |
caption => 1, table => 1, tbody => 1, |
| 4020 |
tfoot => 1, thead => 1, tr => 1, td => 1, th => 1, |
tfoot => 1, thead => 1, tr => 1, td => 1, th => 1, |
| 4351 |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
$parse_rcdata->(CDATA_CONTENT_MODEL); |
| 4352 |
next B; |
next B; |
| 4353 |
} elsif ({ |
} elsif ({ |
| 4354 |
base => 1, command => 1, eventsource => 1, link => 1, |
base => 1, command => 1, link => 1, |
| 4355 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 4356 |
!!!cp ('t334'); |
!!!cp ('t334'); |
| 4357 |
## NOTE: This is an "as if in head" code clone, only "-t" differs |
## NOTE: This is an "as if in head" code clone, only "-t" differs |
| 4459 |
table => 1, |
table => 1, |
| 4460 |
hr => 1, |
hr => 1, |
| 4461 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 4462 |
|
|
| 4463 |
|
## 1. When there is an opening |form| element: |
| 4464 |
if ($token->{tag_name} eq 'form' and defined $self->{form_element}) { |
if ($token->{tag_name} eq 'form' and defined $self->{form_element}) { |
| 4465 |
!!!cp ('t350'); |
!!!cp ('t350'); |
| 4466 |
!!!parse-error (type => 'in form:form', token => $token); |
!!!parse-error (type => 'in form:form', token => $token); |
| 4470 |
next B; |
next B; |
| 4471 |
} |
} |
| 4472 |
|
|
| 4473 |
## has a p element in scope |
## 2. Close the |p| element, if any. |
| 4474 |
INSCOPE: for (reverse @{$self->{open_elements}}) { |
if ($token->{tag_name} ne 'table' or # The Hixie Quirk |
| 4475 |
if ($_->[1] == P_EL) { |
$self->{document}->manakai_compat_mode ne 'quirks') { |
| 4476 |
!!!cp ('t344'); |
## has a p element in scope |
| 4477 |
!!!back-token; # <form> |
INSCOPE: for (reverse @{$self->{open_elements}}) { |
| 4478 |
$token = {type => END_TAG_TOKEN, tag_name => 'p', |
if ($_->[1] == P_EL) { |
| 4479 |
line => $token->{line}, column => $token->{column}}; |
!!!cp ('t344'); |
| 4480 |
next B; |
!!!back-token; # <form> |
| 4481 |
} elsif ($_->[1] & SCOPING_EL) { |
$token = {type => END_TAG_TOKEN, tag_name => 'p', |
| 4482 |
!!!cp ('t345'); |
line => $token->{line}, column => $token->{column}}; |
| 4483 |
last INSCOPE; |
next B; |
| 4484 |
|
} elsif ($_->[1] & SCOPING_EL) { |
| 4485 |
|
!!!cp ('t345'); |
| 4486 |
|
last INSCOPE; |
| 4487 |
|
} |
| 4488 |
|
} # INSCOPE |
| 4489 |
|
} |
| 4490 |
|
|
| 4491 |
|
## 3. Close the opening <hn> element, if any. |
| 4492 |
|
if ({h1 => 1, h2 => 1, h3 => 1, |
| 4493 |
|
h4 => 1, h5 => 1, h6 => 1}->{$token->{tag_name}}) { |
| 4494 |
|
if ($self->{open_elements}->[-1]->[1] == HEADING_EL) { |
| 4495 |
|
!!!parse-error (type => 'not closed', |
| 4496 |
|
text => $self->{open_elements}->[-1]->[0]->manakai_local_name, |
| 4497 |
|
token => $token); |
| 4498 |
|
pop @{$self->{open_elements}}; |
| 4499 |
} |
} |
| 4500 |
} # INSCOPE |
} |
| 4501 |
|
|
| 4502 |
|
## 4. Insertion. |
| 4503 |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
| 4504 |
if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') { |
if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') { |
| 4505 |
!!!nack ('t346.1'); |
!!!nack ('t346.1'); |
| 4543 |
} elsif ($token->{tag_name} eq 'li') { |
} elsif ($token->{tag_name} eq 'li') { |
| 4544 |
## NOTE: As normal, but imply </li> when there's another <li> ... |
## NOTE: As normal, but imply </li> when there's another <li> ... |
| 4545 |
|
|
| 4546 |
## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>) |
## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>):: |
| 4547 |
## Interpreted as <li><foo/></li><li/> (non-conforming) |
## Interpreted as <li><foo/></li><li/> (non-conforming): |
| 4548 |
## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7), |
## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7), |
| 4549 |
## dt (Fx, O, S, IE), dl (O), fieldset (O, S, IE), form (Fx, O, S), |
## dt (Fx, O, S, IE), dl (O), fieldset (O, S, IE), form (Fx, O, S), |
| 4550 |
## hn (O), pre (O), applet (O, S), button (O, S), marquee (Fx, O, S), |
## hn (O), pre (O), applet (O, S), button (O, S), marquee (Fx, O, S), |
| 4551 |
## object (Fx) |
## object (Fx) |
| 4552 |
## Generate non-tree (non-conforming) |
## Generate non-tree (non-conforming): |
| 4553 |
## basefont (IE7 (where basefont is non-void)), center (IE), |
## basefont (IE7 (where basefont is non-void)), center (IE), |
| 4554 |
## form (IE), hn (IE) |
## form (IE), hn (IE) |
| 4555 |
## address, div, p (<li><foo><li> == <li><foo/></li><li/>) |
## address, div, p (<li><foo><li> == <li><foo/></li><li/>):: |
| 4556 |
## Interpreted as <li><foo><li/></foo></li> (non-conforming) |
## Interpreted as <li><foo><li/></foo></li> (non-conforming): |
| 4557 |
## div (Fx, S) |
## div (Fx, S) |
| 4558 |
|
|
| 4559 |
my $non_optional; |
my $non_optional; |
| 4869 |
line => $token->{line}, column => $token->{column}}, |
line => $token->{line}, column => $token->{column}}, |
| 4870 |
{type => START_TAG_TOKEN, tag_name => 'hr', |
{type => START_TAG_TOKEN, tag_name => 'hr', |
| 4871 |
line => $token->{line}, column => $token->{column}}, |
line => $token->{line}, column => $token->{column}}, |
|
{type => START_TAG_TOKEN, tag_name => 'p', |
|
|
line => $token->{line}, column => $token->{column}}, |
|
| 4872 |
{type => START_TAG_TOKEN, tag_name => 'label', |
{type => START_TAG_TOKEN, tag_name => 'label', |
| 4873 |
line => $token->{line}, column => $token->{column}}, |
line => $token->{line}, column => $token->{column}}, |
| 4874 |
); |
); |
| 4891 |
#{type => CHARACTER_TOKEN, data => ''}, # SHOULD |
#{type => CHARACTER_TOKEN, data => ''}, # SHOULD |
| 4892 |
{type => END_TAG_TOKEN, tag_name => 'label', |
{type => END_TAG_TOKEN, tag_name => 'label', |
| 4893 |
line => $token->{line}, column => $token->{column}}, |
line => $token->{line}, column => $token->{column}}, |
|
{type => END_TAG_TOKEN, tag_name => 'p', |
|
|
line => $token->{line}, column => $token->{column}}, |
|
| 4894 |
{type => START_TAG_TOKEN, tag_name => 'hr', |
{type => START_TAG_TOKEN, tag_name => 'hr', |
| 4895 |
line => $token->{line}, column => $token->{column}}, |
line => $token->{line}, column => $token->{column}}, |
| 4896 |
{type => END_TAG_TOKEN, tag_name => 'form', |
{type => END_TAG_TOKEN, tag_name => 'form', |
| 4900 |
next B; |
next B; |
| 4901 |
} |
} |
| 4902 |
} elsif ($token->{tag_name} eq 'textarea') { |
} elsif ($token->{tag_name} eq 'textarea') { |
| 4903 |
## Step 1 |
## 1. Insert |
| 4904 |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
| 4905 |
|
|
| 4906 |
## Step 2 |
## Step 2 # XXX |
| 4907 |
## TODO: $self->{form_element} if defined |
## TODO: $self->{form_element} if defined |
| 4908 |
|
|
| 4909 |
## Step 3 |
## 2. Drop U+000A LINE FEED |
| 4910 |
$self->{ignore_newline} = 1; |
$self->{ignore_newline} = 1; |
| 4911 |
|
|
| 4912 |
## Step 4 |
## 3. RCDATA |
|
## ISSUE: This step is wrong. (r2302 enbugged) |
|
|
|
|
|
## Step 5 |
|
| 4913 |
$self->{content_model} = RCDATA_CONTENT_MODEL; |
$self->{content_model} = RCDATA_CONTENT_MODEL; |
| 4914 |
delete $self->{escape}; # MUST |
delete $self->{escape}; # MUST |
| 4915 |
|
|
| 4916 |
## Step 6-7 |
## 4., 6. Insertion mode |
| 4917 |
$self->{insertion_mode} |= IN_CDATA_RCDATA_IM; |
$self->{insertion_mode} |= IN_CDATA_RCDATA_IM; |
| 4918 |
|
|
| 4919 |
|
## XXX: 5. frameset-ok flag |
| 4920 |
|
|
| 4921 |
!!!nack ('t392.1'); |
!!!nack ('t392.1'); |
| 4922 |
!!!next-token; |
!!!next-token; |
| 4923 |
next B; |
next B; |
| 4973 |
last INSCOPE; |
last INSCOPE; |
| 4974 |
} |
} |
| 4975 |
} # INSCOPE |
} # INSCOPE |
| 4976 |
|
|
| 4977 |
|
## TODO: <non-ruby><rt> is not allowed. |
| 4978 |
|
|
| 4979 |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
!!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token); |
| 4980 |
|
|
| 5063 |
} elsif ({ |
} elsif ({ |
| 5064 |
area => 1, basefont => 1, bgsound => 1, br => 1, |
area => 1, basefont => 1, bgsound => 1, br => 1, |
| 5065 |
embed => 1, img => 1, spacer => 1, wbr => 1, |
embed => 1, img => 1, spacer => 1, wbr => 1, |
| 5066 |
|
keygen => 1, |
| 5067 |
}->{$token->{tag_name}}) { |
}->{$token->{tag_name}}) { |
| 5068 |
!!!cp ('t388.1'); |
!!!cp ('t388.1'); |
| 5069 |
pop @{$self->{open_elements}}; |
pop @{$self->{open_elements}}; |
| 5073 |
|
|
| 5074 |
if ($self->{insertion_mode} & TABLE_IMS or |
if ($self->{insertion_mode} & TABLE_IMS or |
| 5075 |
$self->{insertion_mode} & BODY_TABLE_IMS or |
$self->{insertion_mode} & BODY_TABLE_IMS or |
| 5076 |
$self->{insertion_mode} == IN_COLUMN_GROUP_IM) { |
($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) { |
| 5077 |
!!!cp ('t400.1'); |
!!!cp ('t400.1'); |
| 5078 |
$self->{insertion_mode} = IN_SELECT_IN_TABLE_IM; |
$self->{insertion_mode} = IN_SELECT_IN_TABLE_IM; |
| 5079 |
} else { |
} else { |
| 5090 |
} |
} |
| 5091 |
} elsif ($token->{type} == END_TAG_TOKEN) { |
} elsif ($token->{type} == END_TAG_TOKEN) { |
| 5092 |
if ($token->{tag_name} eq 'body') { |
if ($token->{tag_name} eq 'body') { |
| 5093 |
## has a |body| element in scope |
|
| 5094 |
|
## 1. If not "have an element in scope": |
| 5095 |
|
## "has a |body| element in scope" |
| 5096 |
my $i; |
my $i; |
| 5097 |
INSCOPE: { |
INSCOPE: { |
| 5098 |
for (reverse @{$self->{open_elements}}) { |
for (reverse @{$self->{open_elements}}) { |
| 5115 |
next B; |
next B; |
| 5116 |
} # INSCOPE |
} # INSCOPE |
| 5117 |
|
|
| 5118 |
|
## 2. If unclosed elements: |
| 5119 |
for (@{$self->{open_elements}}) { |
for (@{$self->{open_elements}}) { |
| 5120 |
unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL) { |
unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL || |
| 5121 |
|
$_->[1] == OPTGROUP_EL || |
| 5122 |
|
$_->[1] == OPTION_EL || |
| 5123 |
|
$_->[1] == RUBY_COMPONENT_EL) { |
| 5124 |
!!!cp ('t403'); |
!!!cp ('t403'); |
| 5125 |
!!!parse-error (type => 'not closed', |
!!!parse-error (type => 'not closed', |
| 5126 |
text => $_->[0]->manakai_local_name, |
text => $_->[0]->manakai_local_name, |
| 5131 |
} |
} |
| 5132 |
} |
} |
| 5133 |
|
|
| 5134 |
|
## 3. Switch the insertion mode. |
| 5135 |
$self->{insertion_mode} = AFTER_BODY_IM; |
$self->{insertion_mode} = AFTER_BODY_IM; |
| 5136 |
!!!next-token; |
!!!next-token; |
| 5137 |
next B; |
next B; |
| 5518 |
## TODO: script stuffs |
## TODO: script stuffs |
| 5519 |
} # _tree_construct_main |
} # _tree_construct_main |
| 5520 |
|
|
| 5521 |
|
## XXX: How this method is organized is somewhat out of date, although |
| 5522 |
|
## it still does what the current spec documents. |
| 5523 |
sub set_inner_html ($$$$;$) { |
sub set_inner_html ($$$$;$) { |
| 5524 |
my $class = shift; |
my $class = shift; |
| 5525 |
my $node = shift; |
my $node = shift; # /context/ |
| 5526 |
#my $s = \$_[0]; |
#my $s = \$_[0]; |
| 5527 |
my $onerror = $_[1]; |
my $onerror = $_[1]; |
| 5528 |
my $get_wrapper = $_[2] || sub ($) { return $_[0] }; |
my $get_wrapper = $_[2] || sub ($) { return $_[0] }; |
| 5530 |
## ISSUE: Should {confident} be true? |
## ISSUE: Should {confident} be true? |
| 5531 |
|
|
| 5532 |
my $nt = $node->node_type; |
my $nt = $node->node_type; |
| 5533 |
if ($nt == 9) { |
if ($nt == 9) { # Document (invoke the algorithm with no /context/ element) |
| 5534 |
# MUST |
# MUST |
| 5535 |
|
|
| 5536 |
## Step 1 # MUST |
## Step 1 # MUST |
| 5545 |
|
|
| 5546 |
## Step 3, 4, 5 # MUST |
## Step 3, 4, 5 # MUST |
| 5547 |
$class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper); |
$class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper); |
| 5548 |
} elsif ($nt == 1) { |
} elsif ($nt == 1) { # Element (invoke the algorithm with /context/ element) |
| 5549 |
## TODO: If non-html element |
## TODO: If non-html element |
| 5550 |
|
|
| 5551 |
## NOTE: Most of this code is copied from |parse_string| |
## NOTE: Most of this code is copied from |parse_string| |
| 5552 |
|
|
| 5553 |
## TODO: Support for $get_wrapper |
## TODO: Support for $get_wrapper |
| 5554 |
|
|
| 5555 |
## Step 1 # MUST |
## F1. Create an HTML document. |
| 5556 |
my $this_doc = $node->owner_document; |
my $this_doc = $node->owner_document; |
| 5557 |
my $doc = $this_doc->implementation->create_document; |
my $doc = $this_doc->implementation->create_document; |
| 5558 |
$doc->manakai_is_html (1); |
$doc->manakai_is_html (1); |
| 5559 |
|
|
| 5560 |
|
## F2. Propagate quirkness flag |
| 5561 |
|
my $node_doc = $node->owner_document; |
| 5562 |
|
$doc->manakai_compat_mode ($node_doc->manakai_compat_mode); |
| 5563 |
|
|
| 5564 |
|
## F3. Create an HTML parser |
| 5565 |
my $p = $class->new; |
my $p = $class->new; |
| 5566 |
$p->{document} = $doc; |
$p->{document} = $doc; |
| 5567 |
|
|
| 5689 |
$p->_initialize_tokenizer; |
$p->_initialize_tokenizer; |
| 5690 |
$p->_initialize_tree_constructor; |
$p->_initialize_tree_constructor; |
| 5691 |
|
|
| 5692 |
## Step 2 |
## F4. If /context/ is not undef... |
| 5693 |
|
|
| 5694 |
|
## F4.1. content model flag |
| 5695 |
my $node_ln = $node->manakai_local_name; |
my $node_ln = $node->manakai_local_name; |
| 5696 |
$p->{content_model} = { |
$p->{content_model} = { |
| 5697 |
title => RCDATA_CONTENT_MODEL, |
title => RCDATA_CONTENT_MODEL, |
| 5707 |
}->{$node_ln}; |
}->{$node_ln}; |
| 5708 |
$p->{content_model} = PCDATA_CONTENT_MODEL |
$p->{content_model} = PCDATA_CONTENT_MODEL |
| 5709 |
unless defined $p->{content_model}; |
unless defined $p->{content_model}; |
|
## ISSUE: What is "the name of the element"? local name? |
|
| 5710 |
|
|
| 5711 |
$p->{inner_html_node} = [$node, $el_category->{$node_ln}]; |
$p->{inner_html_node} = [$node, $el_category->{$node_ln}]; |
| 5712 |
## TODO: Foreign element OK? |
## TODO: Foreign element OK? |
| 5713 |
|
|
| 5714 |
## Step 3 |
## F4.2. Root |html| element |
| 5715 |
my $root = $doc->create_element_ns |
my $root = $doc->create_element_ns |
| 5716 |
('http://www.w3.org/1999/xhtml', [undef, 'html']); |
('http://www.w3.org/1999/xhtml', [undef, 'html']); |
| 5717 |
|
|
| 5718 |
## Step 4 # MUST |
## F4.3. |
| 5719 |
$doc->append_child ($root); |
$doc->append_child ($root); |
| 5720 |
|
|
| 5721 |
## Step 5 # MUST |
## F4.4. |
| 5722 |
push @{$p->{open_elements}}, [$root, $el_category->{html}]; |
push @{$p->{open_elements}}, [$root, $el_category->{html}]; |
| 5723 |
|
|
| 5724 |
undef $p->{head_element}; |
undef $p->{head_element}; |
| 5725 |
undef $p->{head_element_inserted}; |
undef $p->{head_element_inserted}; |
| 5726 |
|
|
| 5727 |
## Step 6 # MUST |
## F4.5. |
| 5728 |
$p->_reset_insertion_mode; |
$p->_reset_insertion_mode; |
| 5729 |
|
|
| 5730 |
## Step 7 # MUST |
## F4.6. |
| 5731 |
my $anode = $node; |
my $anode = $node; |
| 5732 |
AN: while (defined $anode) { |
AN: while (defined $anode) { |
| 5733 |
if ($anode->node_type == 1) { |
if ($anode->node_type == 1) { |
| 5742 |
} |
} |
| 5743 |
$anode = $anode->parent_node; |
$anode = $anode->parent_node; |
| 5744 |
} # AN |
} # AN |
| 5745 |
|
|
| 5746 |
## Step 9 # MUST |
## F.6. Start the parser. |
| 5747 |
{ |
{ |
| 5748 |
my $self = $p; |
my $self = $p; |
| 5749 |
!!!next-token; |
!!!next-token; |
| 5750 |
} |
} |
| 5751 |
$p->_tree_construction_main; |
$p->_tree_construction_main; |
| 5752 |
|
|
| 5753 |
## Step 10 # MUST |
## F.7. |
| 5754 |
my @cn = @{$node->child_nodes}; |
my @cn = @{$node->child_nodes}; |
| 5755 |
for (@cn) { |
for (@cn) { |
| 5756 |
$node->remove_child ($_); |
$node->remove_child ($_); |