/[suikacvs]/markup/html/whatpm/Whatpm/HTML.pm.src
Suika

Diff of /markup/html/whatpm/Whatpm/HTML.pm.src

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.196 by wakaba, Sat Oct 4 07:58:58 2008 UTC revision 1.234 by wakaba, Sun Sep 6 02:20:52 2009 UTC
# Line 3  use strict; Line 3  use strict;
3  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4  use Error qw(:try);  use Error qw(:try);
5    
6    use Whatpm::HTML::Tokenizer;
7    
8  ## NOTE: This module don't check all HTML5 parse errors; character  ## NOTE: This module don't check all HTML5 parse errors; character
9  ## encoding related parse errors are expected to be handled by relevant  ## encoding related parse errors are expected to be handled by relevant
10  ## modules.  ## modules.
# Line 21  use Error qw(:try); Line 23  use Error qw(:try);
23    
24  require IO::Handle;  require IO::Handle;
25    
26    ## Namespace URLs
27    
28  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
29  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;
30  my $SVG_NS = q<http://www.w3.org/2000/svg>;  my $SVG_NS = q<http://www.w3.org/2000/svg>;
# Line 28  my $XLINK_NS = q<http://www.w3.org/1999/ Line 32  my $XLINK_NS = q<http://www.w3.org/1999/
32  my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;  my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;
33  my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;  my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;
34    
35  sub A_EL () { 0b1 }  ## Element categories
36  sub ADDRESS_EL () { 0b10 }  
37  sub BODY_EL () { 0b100 }  ## Bits 12-15
38  sub BUTTON_EL () { 0b1000 }  sub SPECIAL_EL () { 0b1_000000000000000 }
39  sub CAPTION_EL () { 0b10000 }  sub SCOPING_EL () { 0b1_00000000000000 }
40  sub DD_EL () { 0b100000 }  sub FORMATTING_EL () { 0b1_0000000000000 }
41  sub DIV_EL () { 0b1000000 }  sub PHRASING_EL () { 0b1_000000000000 }
42  sub DT_EL () { 0b10000000 }  
43  sub FORM_EL () { 0b100000000 }  ## Bits 10-11
44  sub FORMATTING_EL () { 0b1000000000 }  #sub FOREIGN_EL () { 0b1_00000000000 } # see Whatpm::HTML::Tokenizer
45  sub FRAMESET_EL () { 0b10000000000 }  sub FOREIGN_FLOW_CONTENT_EL () { 0b1_0000000000 }
46  sub HEADING_EL () { 0b100000000000 }  
47  sub HTML_EL () { 0b1000000000000 }  ## Bits 6-9
48  sub LI_EL () { 0b10000000000000 }  sub TABLE_SCOPING_EL () { 0b1_000000000 }
49  sub NOBR_EL () { 0b100000000000000 }  sub TABLE_ROWS_SCOPING_EL () { 0b1_00000000 }
50  sub OPTION_EL () { 0b1000000000000000 }  sub TABLE_ROW_SCOPING_EL () { 0b1_0000000 }
51  sub OPTGROUP_EL () { 0b10000000000000000 }  sub TABLE_ROWS_EL () { 0b1_000000 }
52  sub P_EL () { 0b100000000000000000 }  
53  sub SELECT_EL () { 0b1000000000000000000 }  ## Bit 5
54  sub TABLE_EL () { 0b10000000000000000000 }  sub ADDRESS_DIV_P_EL () { 0b1_00000 }
55  sub TABLE_CELL_EL () { 0b100000000000000000000 }  
56  sub TABLE_ROW_EL () { 0b1000000000000000000000 }  ## NOTE: Used in </body> and EOF algorithms.
57  sub TABLE_ROW_GROUP_EL () { 0b10000000000000000000000 }  ## Bit 4
58  sub MISC_SCOPING_EL () { 0b100000000000000000000000 }  sub ALL_END_TAG_OPTIONAL_EL () { 0b1_0000 }
 sub MISC_SPECIAL_EL () { 0b1000000000000000000000000 }  
 sub FOREIGN_EL () { 0b10000000000000000000000000 }  
 sub FOREIGN_FLOW_CONTENT_EL () { 0b100000000000000000000000000 }  
 sub MML_AXML_EL () { 0b1000000000000000000000000000 }  
 sub RUBY_EL () { 0b10000000000000000000000000000 }  
 sub RUBY_COMPONENT_EL () { 0b100000000000000000000000000000 }  
   
 sub TABLE_ROWS_EL () {  
   TABLE_EL |  
   TABLE_ROW_EL |  
   TABLE_ROW_GROUP_EL  
 }  
59    
60  ## NOTE: Used in "generate implied end tags" algorithm.  ## NOTE: Used in "generate implied end tags" algorithm.
61  ## NOTE: There is a code where a modified version of  ## NOTE: There is a code where a modified version of
62  ## END_TAG_OPTIONAL_EL is used in "generate implied end tags"  ## END_TAG_OPTIONAL_EL is used in "generate implied end tags"
63  ## implementation (search for the algorithm name).  ## implementation (search for the algorithm name).
64  sub END_TAG_OPTIONAL_EL () {  ## Bit 3
65    DD_EL |  sub END_TAG_OPTIONAL_EL () { 0b1_000 }
   DT_EL |  
   LI_EL |  
   OPTION_EL |  
   OPTGROUP_EL |  
   P_EL |  
   RUBY_COMPONENT_EL  
 }  
66    
67  ## NOTE: Used in </body> and EOF algorithms.  ## Bits 0-2
 sub ALL_END_TAG_OPTIONAL_EL () {  
   DD_EL |  
   DT_EL |  
   LI_EL |  
   P_EL |  
   
   BODY_EL |  
   HTML_EL |  
   TABLE_CELL_EL |  
   TABLE_ROW_EL |  
   TABLE_ROW_GROUP_EL  
 }  
68    
69  sub SCOPING_EL () {  sub MISC_SPECIAL_EL () { SPECIAL_EL | 0b000 }
70    BUTTON_EL |  sub FORM_EL () { SPECIAL_EL | 0b001 }
71    CAPTION_EL |  sub FRAMESET_EL () { SPECIAL_EL | 0b010 }
72    HTML_EL |  sub HEADING_EL () { SPECIAL_EL | 0b011 }
73    TABLE_EL |  sub SELECT_EL () { SPECIAL_EL | 0b100 }
74    TABLE_CELL_EL |  sub SCRIPT_EL () { SPECIAL_EL | 0b101 }
75    MISC_SCOPING_EL  
76    sub ADDRESS_DIV_EL () { SPECIAL_EL | ADDRESS_DIV_P_EL | 0b001 }
77    sub BODY_EL () { SPECIAL_EL | ALL_END_TAG_OPTIONAL_EL | 0b001 }
78    
79    sub DTDD_EL () {
80      SPECIAL_EL |
81      END_TAG_OPTIONAL_EL |
82      ALL_END_TAG_OPTIONAL_EL |
83      0b010
84  }  }
85    sub LI_EL () {
86  sub TABLE_SCOPING_EL () {    SPECIAL_EL |
87    HTML_EL |    END_TAG_OPTIONAL_EL |
88    TABLE_EL    ALL_END_TAG_OPTIONAL_EL |
89      0b100
90  }  }
91    sub P_EL () {
92  sub TABLE_ROWS_SCOPING_EL () {    SPECIAL_EL |
93    HTML_EL |    ADDRESS_DIV_P_EL |
94    TABLE_ROW_GROUP_EL    END_TAG_OPTIONAL_EL |
95      ALL_END_TAG_OPTIONAL_EL |
96      0b001
97  }  }
98    
99  sub TABLE_ROW_SCOPING_EL () {  sub TABLE_ROW_EL () {
100    HTML_EL |    SPECIAL_EL |
101    TABLE_ROW_EL    TABLE_ROWS_EL |
102      TABLE_ROW_SCOPING_EL |
103      ALL_END_TAG_OPTIONAL_EL |
104      0b001
105    }
106    sub TABLE_ROW_GROUP_EL () {
107      SPECIAL_EL |
108      TABLE_ROWS_EL |
109      TABLE_ROWS_SCOPING_EL |
110      ALL_END_TAG_OPTIONAL_EL |
111      0b001
112  }  }
113    
114  sub SPECIAL_EL () {  sub MISC_SCOPING_EL () { SCOPING_EL | 0b000 }
115    ADDRESS_EL |  sub BUTTON_EL () { SCOPING_EL | 0b001 }
116    BODY_EL |  sub CAPTION_EL () { SCOPING_EL | 0b010 }
117    DIV_EL |  sub HTML_EL () {
118      SCOPING_EL |
119    DD_EL |    TABLE_SCOPING_EL |
120    DT_EL |    TABLE_ROWS_SCOPING_EL |
121    LI_EL |    TABLE_ROW_SCOPING_EL |
122    P_EL |    ALL_END_TAG_OPTIONAL_EL |
123      0b001
124    FORM_EL |  }
125    FRAMESET_EL |  sub TABLE_EL () {
126    HEADING_EL |    SCOPING_EL |
127    OPTION_EL |    TABLE_ROWS_EL |
128    OPTGROUP_EL |    TABLE_SCOPING_EL |
129    SELECT_EL |    0b001
   TABLE_ROW_EL |  
   TABLE_ROW_GROUP_EL |  
   MISC_SPECIAL_EL  
130  }  }
131    sub TABLE_CELL_EL () {
132      SCOPING_EL |
133      TABLE_ROW_SCOPING_EL |
134      ALL_END_TAG_OPTIONAL_EL |
135      0b001
136    }
137    
138    sub MISC_FORMATTING_EL () { FORMATTING_EL | 0b000 }
139    sub A_EL () { FORMATTING_EL | 0b001 }
140    sub NOBR_EL () { FORMATTING_EL | 0b010 }
141    
142    sub RUBY_EL () { PHRASING_EL | 0b001 }
143    
144    ## ISSUE: ALL_END_TAG_OPTIONAL_EL?
145    sub OPTGROUP_EL () { PHRASING_EL | END_TAG_OPTIONAL_EL | 0b001 }
146    sub OPTION_EL () { PHRASING_EL | END_TAG_OPTIONAL_EL | 0b010 }
147    sub RUBY_COMPONENT_EL () { PHRASING_EL | END_TAG_OPTIONAL_EL | 0b100 }
148    
149    sub MML_AXML_EL () { PHRASING_EL | FOREIGN_EL | 0b001 }
150    
151  my $el_category = {  my $el_category = {
152    a => A_EL | FORMATTING_EL,    a => A_EL,
153    address => ADDRESS_EL,    address => ADDRESS_DIV_EL,
154    applet => MISC_SCOPING_EL,    applet => MISC_SCOPING_EL,
155    area => MISC_SPECIAL_EL,    area => MISC_SPECIAL_EL,
156    article => MISC_SPECIAL_EL,    article => MISC_SPECIAL_EL,
# Line 160  my $el_category = { Line 170  my $el_category = {
170    colgroup => MISC_SPECIAL_EL,    colgroup => MISC_SPECIAL_EL,
171    command => MISC_SPECIAL_EL,    command => MISC_SPECIAL_EL,
172    datagrid => MISC_SPECIAL_EL,    datagrid => MISC_SPECIAL_EL,
173    dd => DD_EL,    dd => DTDD_EL,
174    details => MISC_SPECIAL_EL,    details => MISC_SPECIAL_EL,
175    dialog => MISC_SPECIAL_EL,    dialog => MISC_SPECIAL_EL,
176    dir => MISC_SPECIAL_EL,    dir => MISC_SPECIAL_EL,
177    div => DIV_EL,    div => ADDRESS_DIV_EL,
178    dl => MISC_SPECIAL_EL,    dl => MISC_SPECIAL_EL,
179    dt => DT_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,
# Line 193  my $el_category = { Line 202  my $el_category = {
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,
# Line 200  my $el_category = { Line 211  my $el_category = {
211    menu => MISC_SPECIAL_EL,    menu => MISC_SPECIAL_EL,
212    meta => MISC_SPECIAL_EL,    meta => MISC_SPECIAL_EL,
213    nav => MISC_SPECIAL_EL,    nav => MISC_SPECIAL_EL,
214    nobr => NOBR_EL | FORMATTING_EL,    nobr => NOBR_EL,
215    noembed => MISC_SPECIAL_EL,    noembed => MISC_SPECIAL_EL,
216    noframes => MISC_SPECIAL_EL,    noframes => MISC_SPECIAL_EL,
217    noscript => MISC_SPECIAL_EL,    noscript => MISC_SPECIAL_EL,
# Line 242  my $el_category = { Line 253  my $el_category = {
253  my $el_category_f = {  my $el_category_f = {
254    $MML_NS => {    $MML_NS => {
255      'annotation-xml' => MML_AXML_EL,      'annotation-xml' => MML_AXML_EL,
256      mi => FOREIGN_FLOW_CONTENT_EL,      mi => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
257      mo => FOREIGN_FLOW_CONTENT_EL,      mo => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
258      mn => FOREIGN_FLOW_CONTENT_EL,      mn => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
259      ms => FOREIGN_FLOW_CONTENT_EL,      ms => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
260      mtext => FOREIGN_FLOW_CONTENT_EL,      mtext => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
261    },    },
262    $SVG_NS => {    $SVG_NS => {
263      foreignObject => FOREIGN_FLOW_CONTENT_EL,      foreignObject => SCOPING_EL | FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
264      desc => FOREIGN_FLOW_CONTENT_EL,      desc => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
265      title => FOREIGN_FLOW_CONTENT_EL,      title => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
266    },    },
267    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.
268  };  };
# Line 338  my $foreign_attr_xname = { Line 349  my $foreign_attr_xname = {
349    
350  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.
351    
 my $charref_map = {  
   0x0D => 0x000A,  
   0x80 => 0x20AC,  
   0x81 => 0xFFFD,  
   0x82 => 0x201A,  
   0x83 => 0x0192,  
   0x84 => 0x201E,  
   0x85 => 0x2026,  
   0x86 => 0x2020,  
   0x87 => 0x2021,  
   0x88 => 0x02C6,  
   0x89 => 0x2030,  
   0x8A => 0x0160,  
   0x8B => 0x2039,  
   0x8C => 0x0152,  
   0x8D => 0xFFFD,  
   0x8E => 0x017D,  
   0x8F => 0xFFFD,  
   0x90 => 0xFFFD,  
   0x91 => 0x2018,  
   0x92 => 0x2019,  
   0x93 => 0x201C,  
   0x94 => 0x201D,  
   0x95 => 0x2022,  
   0x96 => 0x2013,  
   0x97 => 0x2014,  
   0x98 => 0x02DC,  
   0x99 => 0x2122,  
   0x9A => 0x0161,  
   0x9B => 0x203A,  
   0x9C => 0x0153,  
   0x9D => 0xFFFD,  
   0x9E => 0x017E,  
   0x9F => 0x0178,  
 }; # $charref_map  
 $charref_map->{$_} = 0xFFFD  
     for 0x0000..0x0008, 0x000B, 0x000E..0x001F, 0x007F,  
         0xD800..0xDFFF, 0xFDD0..0xFDDF, ## ISSUE: 0xFDEF  
         0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF,  
         0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,  
         0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF,  
         0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, 0xDFFFF, 0xEFFFE,  
         0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE, 0x10FFFF;  
   
352  ## TODO: Invoke the reset algorithm when a resettable element is  ## TODO: Invoke the reset algorithm when a resettable element is
353  ## created (cf. HTML5 revision 2259).  ## created (cf. HTML5 revision 2259).
354    
# Line 488  sub parse_byte_stream ($$$$;$$) { Line 455  sub parse_byte_stream ($$$$;$$) {
455      if (defined $charset_name) {      if (defined $charset_name) {
456        $charset = Message::Charset::Info->get_by_html_name ($charset_name);        $charset = Message::Charset::Info->get_by_html_name ($charset_name);
457    
       ## ISSUE: Unsupported encoding is not ignored according to the spec.  
458        require Whatpm::Charset::DecodeHandle;        require Whatpm::Charset::DecodeHandle;
459        $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new        $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new
460            ($byte_stream);            ($byte_stream);
# Line 560  sub parse_byte_stream ($$$$;$$) { Line 526  sub parse_byte_stream ($$$$;$$) {
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',
# Line 581  sub parse_byte_stream ($$$$;$$) { Line 537  sub parse_byte_stream ($$$$;$$) {
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}
# Line 835  sub new ($) { Line 809  sub new ($) {
809    return $self;    return $self;
810  } # new  } # new
811    
812  sub CM_ENTITY () { 0b001 } # & markup in data  ## Insertion modes
 sub CM_LIMITED_MARKUP () { 0b010 } # < markup in data (limited)  
 sub CM_FULL_MARKUP () { 0b100 } # < markup in data (any)  
   
 sub PLAINTEXT_CONTENT_MODEL () { 0 }  
 sub CDATA_CONTENT_MODEL () { CM_LIMITED_MARKUP }  
 sub RCDATA_CONTENT_MODEL () { CM_ENTITY | CM_LIMITED_MARKUP }  
 sub PCDATA_CONTENT_MODEL () { CM_ENTITY | CM_FULL_MARKUP }  
   
 sub DATA_STATE () { 0 }  
 #sub ENTITY_DATA_STATE () { 1 }  
 sub TAG_OPEN_STATE () { 2 }  
 sub CLOSE_TAG_OPEN_STATE () { 3 }  
 sub TAG_NAME_STATE () { 4 }  
 sub BEFORE_ATTRIBUTE_NAME_STATE () { 5 }  
 sub ATTRIBUTE_NAME_STATE () { 6 }  
 sub AFTER_ATTRIBUTE_NAME_STATE () { 7 }  
 sub BEFORE_ATTRIBUTE_VALUE_STATE () { 8 }  
 sub ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE () { 9 }  
 sub ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE () { 10 }  
 sub ATTRIBUTE_VALUE_UNQUOTED_STATE () { 11 }  
 #sub ENTITY_IN_ATTRIBUTE_VALUE_STATE () { 12 }  
 sub MARKUP_DECLARATION_OPEN_STATE () { 13 }  
 sub COMMENT_START_STATE () { 14 }  
 sub COMMENT_START_DASH_STATE () { 15 }  
 sub COMMENT_STATE () { 16 }  
 sub COMMENT_END_STATE () { 17 }  
 sub COMMENT_END_DASH_STATE () { 18 }  
 sub BOGUS_COMMENT_STATE () { 19 }  
 sub DOCTYPE_STATE () { 20 }  
 sub BEFORE_DOCTYPE_NAME_STATE () { 21 }  
 sub DOCTYPE_NAME_STATE () { 22 }  
 sub AFTER_DOCTYPE_NAME_STATE () { 23 }  
 sub BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 24 }  
 sub DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE () { 25 }  
 sub DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE () { 26 }  
 sub AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 27 }  
 sub BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 28 }  
 sub DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE () { 29 }  
 sub DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE () { 30 }  
 sub AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 31 }  
 sub BOGUS_DOCTYPE_STATE () { 32 }  
 sub AFTER_ATTRIBUTE_VALUE_QUOTED_STATE () { 33 }  
 sub SELF_CLOSING_START_TAG_STATE () { 34 }  
 sub CDATA_SECTION_STATE () { 35 }  
 sub MD_HYPHEN_STATE () { 36 } # "markup declaration open state" in the spec  
 sub MD_DOCTYPE_STATE () { 37 } # "markup declaration open state" in the spec  
 sub MD_CDATA_STATE () { 38 } # "markup declaration open state" in the spec  
 sub CDATA_RCDATA_CLOSE_TAG_STATE () { 39 } # "close tag open state" in the spec  
 sub CDATA_SECTION_MSE1_STATE () { 40 } # "CDATA section state" in the spec  
 sub CDATA_SECTION_MSE2_STATE () { 41 } # "CDATA section state" in the spec  
 sub PUBLIC_STATE () { 42 } # "after DOCTYPE name state" in the spec  
 sub SYSTEM_STATE () { 43 } # "after DOCTYPE name state" in the spec  
 ## NOTE: "Entity data state", "entity in attribute value state", and  
 ## "consume a character reference" algorithm are jointly implemented  
 ## using the following six states:  
 sub ENTITY_STATE () { 44 }  
 sub ENTITY_HASH_STATE () { 45 }  
 sub NCR_NUM_STATE () { 46 }  
 sub HEXREF_X_STATE () { 47 }  
 sub HEXREF_HEX_STATE () { 48 }  
 sub ENTITY_NAME_STATE () { 49 }  
 sub PCDATA_STATE () { 50 } # "data state" in the spec  
   
 sub DOCTYPE_TOKEN () { 1 }  
 sub COMMENT_TOKEN () { 2 }  
 sub START_TAG_TOKEN () { 3 }  
 sub END_TAG_TOKEN () { 4 }  
 sub END_OF_FILE_TOKEN () { 5 }  
 sub CHARACTER_TOKEN () { 6 }  
813    
814  sub AFTER_HTML_IMS () { 0b100 }  sub AFTER_HTML_IMS () { 0b100 }
815  sub HEAD_IMS ()       { 0b1000 }  sub HEAD_IMS ()       { 0b1000 }
# Line 915  sub ROW_IMS ()        { 0b10000000 } Line 820  sub ROW_IMS ()        { 0b10000000 }
820  sub BODY_AFTER_IMS () { 0b100000000 }  sub BODY_AFTER_IMS () { 0b100000000 }
821  sub FRAME_IMS ()      { 0b1000000000 }  sub FRAME_IMS ()      { 0b1000000000 }
822  sub SELECT_IMS ()     { 0b10000000000 }  sub SELECT_IMS ()     { 0b10000000000 }
823  sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 }  #sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 } # see Whatpm::HTML::Tokenizer
824      ## NOTE: "in foreign content" insertion mode is special; it is combined      ## NOTE: "in foreign content" insertion mode is special; it is combined
825      ## with the secondary insertion mode.  In this parser, they are stored      ## with the secondary insertion mode.  In this parser, they are stored
826      ## together in the bit-or'ed form.      ## together in the bit-or'ed form.
827    sub IN_CDATA_RCDATA_IM () { 0b1000000000000 }
828        ## NOTE: "in CDATA/RCDATA" insertion mode is also special; it is
829        ## combined with the original insertion mode.  In thie parser,
830        ## 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    
# Line 945  sub IN_SELECT_IM () { SELECT_IMS | 0b01 Line 856  sub IN_SELECT_IM () { SELECT_IMS | 0b01
856  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }
857  sub IN_COLUMN_GROUP_IM () { 0b10 }  sub IN_COLUMN_GROUP_IM () { 0b10 }
858    
 ## Implementations MUST act as if state machine in the spec  
   
 sub _initialize_tokenizer ($) {  
   my $self = shift;  
   $self->{state} = DATA_STATE; # MUST  
   #$self->{s_kwd}; # state keyword - initialized when used  
   #$self->{entity__value}; # initialized when used  
   #$self->{entity__match}; # initialized when used  
   $self->{content_model} = PCDATA_CONTENT_MODEL; # be  
   undef $self->{ct}; # current token  
   undef $self->{ca}; # current attribute  
   undef $self->{last_stag_name}; # last emitted start tag name  
   #$self->{prev_state}; # initialized when used  
   delete $self->{self_closing};  
   $self->{char_buffer} = '';  
   $self->{char_buffer_pos} = 0;  
   $self->{nc} = -1; # next input character  
   #$self->{next_nc}  
   !!!next-input-character;  
   $self->{token} = [];  
   # $self->{escape}  
 } # _initialize_tokenizer  
   
 ## A token has:  
 ##   ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,  
 ##       CHARACTER_TOKEN, or END_OF_FILE_TOKEN  
 ##   ->{name} (DOCTYPE_TOKEN)  
 ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)  
 ##   ->{pubid} (DOCTYPE_TOKEN)  
 ##   ->{sysid} (DOCTYPE_TOKEN)  
 ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag  
 ##   ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)  
 ##        ->{name}  
 ##        ->{value}  
 ##        ->{has_reference} == 1 or 0  
 ##   ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN)  
 ## NOTE: The "self-closing flag" is hold as |$self->{self_closing}|.  
 ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|  
 ##     while the token is pushed back to the stack.  
   
 ## Emitted token MUST immediately be handled by the tree construction state.  
   
 ## Before each step, UA MAY check to see if either one of the scripts in  
 ## "list of scripts that will execute as soon as possible" or the first  
 ## script in the "list of scripts that will execute asynchronously",  
 ## has completed loading.  If one has, then it MUST be executed  
 ## and removed from the list.  
   
 ## TODO: Polytheistic slash SHOULD NOT be used. (Applied only to atheists.)  
 ## (This requirement was dropped from HTML5 spec, unfortunately.)  
   
 my $is_space = {  
   0x0009 => 1, # CHARACTER TABULATION (HT)  
   0x000A => 1, # LINE FEED (LF)  
   #0x000B => 0, # LINE TABULATION (VT)  
   0x000C => 1, # FORM FEED (FF)  
   #0x000D => 1, # CARRIAGE RETURN (CR)  
   0x0020 => 1, # SPACE (SP)  
 };  
   
 sub _get_next_token ($) {  
   my $self = shift;  
   
   if ($self->{self_closing}) {  
     !!!parse-error (type => 'nestc', token => $self->{ct});  
     ## NOTE: The |self_closing| flag is only set by start tag token.  
     ## In addition, when a start tag token is emitted, it is always set to  
     ## |ct|.  
     delete $self->{self_closing};  
   }  
   
   if (@{$self->{token}}) {  
     $self->{self_closing} = $self->{token}->[0]->{self_closing};  
     return shift @{$self->{token}};  
   }  
   
   A: {  
     if ($self->{state} == PCDATA_STATE) {  
       ## NOTE: Same as |DATA_STATE|, but only for |PCDATA| content model.  
   
       if ($self->{nc} == 0x0026) { # &  
         !!!cp (0.1);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity data state".  In this implementation, the tokenizer  
         ## is switched to the |ENTITY_STATE|, which is an implementation  
         ## of the "consume a character reference" algorithm.  
         $self->{entity_add} = -1;  
         $self->{prev_state} = DATA_STATE;  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003C) { # <  
         !!!cp (0.2);  
         $self->{state} = TAG_OPEN_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (0.3);  
         !!!emit ({type => END_OF_FILE_TOKEN,  
                   line => $self->{line}, column => $self->{column}});  
         last A; ## TODO: ok?  
       } else {  
         !!!cp (0.4);  
         #  
       }  
   
       # Anything else  
       my $token = {type => CHARACTER_TOKEN,  
                    data => chr $self->{nc},  
                    line => $self->{line}, column => $self->{column},  
                   };  
       $self->{read_until}->($token->{data}, q[<&], length $token->{data});  
   
       ## Stay in the state.  
       !!!next-input-character;  
       !!!emit ($token);  
       redo A;  
     } elsif ($self->{state} == DATA_STATE) {  
       $self->{s_kwd} = '' unless defined $self->{s_kwd};  
       if ($self->{nc} == 0x0026) { # &  
         $self->{s_kwd} = '';  
         if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA  
             not $self->{escape}) {  
           !!!cp (1);  
           ## NOTE: In the spec, the tokenizer is switched to the  
           ## "entity data state".  In this implementation, the tokenizer  
           ## is switched to the |ENTITY_STATE|, which is an implementation  
           ## of the "consume a character reference" algorithm.  
           $self->{entity_add} = -1;  
           $self->{prev_state} = DATA_STATE;  
           $self->{state} = ENTITY_STATE;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (2);  
           #  
         }  
       } elsif ($self->{nc} == 0x002D) { # -  
         if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
           $self->{s_kwd} .= '-';  
             
           if ($self->{s_kwd} eq '<!--') {  
             !!!cp (3);  
             $self->{escape} = 1; # unless $self->{escape};  
             $self->{s_kwd} = '--';  
             #  
           } elsif ($self->{s_kwd} eq '---') {  
             !!!cp (4);  
             $self->{s_kwd} = '--';  
             #  
           } else {  
             !!!cp (5);  
             #  
           }  
         }  
           
         #  
       } elsif ($self->{nc} == 0x0021) { # !  
         if (length $self->{s_kwd}) {  
           !!!cp (5.1);  
           $self->{s_kwd} .= '!';  
           #  
         } else {  
           !!!cp (5.2);  
           #$self->{s_kwd} = '';  
           #  
         }  
         #  
       } elsif ($self->{nc} == 0x003C) { # <  
         if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA  
             (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA  
              not $self->{escape})) {  
           !!!cp (6);  
           $self->{state} = TAG_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (7);  
           $self->{s_kwd} = '';  
           #  
         }  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{escape} and  
             ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA  
           if ($self->{s_kwd} eq '--') {  
             !!!cp (8);  
             delete $self->{escape};  
           } else {  
             !!!cp (9);  
           }  
         } else {  
           !!!cp (10);  
         }  
           
         $self->{s_kwd} = '';  
         #  
       } elsif ($self->{nc} == -1) {  
         !!!cp (11);  
         $self->{s_kwd} = '';  
         !!!emit ({type => END_OF_FILE_TOKEN,  
                   line => $self->{line}, column => $self->{column}});  
         last A; ## TODO: ok?  
       } else {  
         !!!cp (12);  
         $self->{s_kwd} = '';  
         #  
       }  
   
       # Anything else  
       my $token = {type => CHARACTER_TOKEN,  
                    data => chr $self->{nc},  
                    line => $self->{line}, column => $self->{column},  
                   };  
       if ($self->{read_until}->($token->{data}, q[-!<>&],  
                                 length $token->{data})) {  
         $self->{s_kwd} = '';  
       }  
   
       ## Stay in the data state.  
       if ($self->{content_model} == PCDATA_CONTENT_MODEL) {  
         !!!cp (13);  
         $self->{state} = PCDATA_STATE;  
       } else {  
         !!!cp (14);  
         ## Stay in the state.  
       }  
       !!!next-input-character;  
       !!!emit ($token);  
       redo A;  
     } elsif ($self->{state} == TAG_OPEN_STATE) {  
       if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
         if ($self->{nc} == 0x002F) { # /  
           !!!cp (15);  
           !!!next-input-character;  
           $self->{state} = CLOSE_TAG_OPEN_STATE;  
           redo A;  
         } elsif ($self->{nc} == 0x0021) { # !  
           !!!cp (15.1);  
           $self->{s_kwd} = '<' unless $self->{escape};  
           #  
         } else {  
           !!!cp (16);  
           #  
         }  
   
         ## reconsume  
         $self->{state} = DATA_STATE;  
         !!!emit ({type => CHARACTER_TOKEN, data => '<',  
                   line => $self->{line_prev},  
                   column => $self->{column_prev},  
                  });  
         redo A;  
       } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA  
         if ($self->{nc} == 0x0021) { # !  
           !!!cp (17);  
           $self->{state} = MARKUP_DECLARATION_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif ($self->{nc} == 0x002F) { # /  
           !!!cp (18);  
           $self->{state} = CLOSE_TAG_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif (0x0041 <= $self->{nc} and  
                  $self->{nc} <= 0x005A) { # A..Z  
           !!!cp (19);  
           $self->{ct}  
             = {type => START_TAG_TOKEN,  
                tag_name => chr ($self->{nc} + 0x0020),  
                line => $self->{line_prev},  
                column => $self->{column_prev}};  
           $self->{state} = TAG_NAME_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif (0x0061 <= $self->{nc} and  
                  $self->{nc} <= 0x007A) { # a..z  
           !!!cp (20);  
           $self->{ct} = {type => START_TAG_TOKEN,  
                                     tag_name => chr ($self->{nc}),  
                                     line => $self->{line_prev},  
                                     column => $self->{column_prev}};  
           $self->{state} = TAG_NAME_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif ($self->{nc} == 0x003E) { # >  
           !!!cp (21);  
           !!!parse-error (type => 'empty start tag',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = DATA_STATE;  
           !!!next-input-character;  
   
           !!!emit ({type => CHARACTER_TOKEN, data => '<>',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev},  
                    });  
   
           redo A;  
         } elsif ($self->{nc} == 0x003F) { # ?  
           !!!cp (22);  
           !!!parse-error (type => 'pio',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = BOGUS_COMMENT_STATE;  
           $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                     line => $self->{line_prev},  
                                     column => $self->{column_prev},  
                                    };  
           ## $self->{nc} is intentionally left as is  
           redo A;  
         } else {  
           !!!cp (23);  
           !!!parse-error (type => 'bare stago',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = DATA_STATE;  
           ## reconsume  
   
           !!!emit ({type => CHARACTER_TOKEN, data => '<',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev},  
                    });  
   
           redo A;  
         }  
       } else {  
         die "$0: $self->{content_model} in tag open";  
       }  
     } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {  
       ## NOTE: The "close tag open state" in the spec is implemented as  
       ## |CLOSE_TAG_OPEN_STATE| and |CDATA_RCDATA_CLOSE_TAG_STATE|.  
   
       my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"  
       if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
         if (defined $self->{last_stag_name}) {  
           $self->{state} = CDATA_RCDATA_CLOSE_TAG_STATE;  
           $self->{s_kwd} = '';  
           ## Reconsume.  
           redo A;  
         } else {  
           ## No start tag token has ever been emitted  
           ## NOTE: See <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>.  
           !!!cp (28);  
           $self->{state} = DATA_STATE;  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN, data => '</',  
                     line => $l, column => $c,  
                    });  
           redo A;  
         }  
       }  
   
       if (0x0041 <= $self->{nc} and  
           $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (29);  
         $self->{ct}  
             = {type => END_TAG_TOKEN,  
                tag_name => chr ($self->{nc} + 0x0020),  
                line => $l, column => $c};  
         $self->{state} = TAG_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0061 <= $self->{nc} and  
                $self->{nc} <= 0x007A) { # a..z  
         !!!cp (30);  
         $self->{ct} = {type => END_TAG_TOKEN,  
                                   tag_name => chr ($self->{nc}),  
                                   line => $l, column => $c};  
         $self->{state} = TAG_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (31);  
         !!!parse-error (type => 'empty end tag',  
                         line => $self->{line_prev}, ## "<" in "</>"  
                         column => $self->{column_prev} - 1);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (32);  
         !!!parse-error (type => 'bare etago');  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ({type => CHARACTER_TOKEN, data => '</',  
                   line => $l, column => $c,  
                  });  
   
         redo A;  
       } else {  
         !!!cp (33);  
         !!!parse-error (type => 'bogus end tag');  
         $self->{state} = BOGUS_COMMENT_STATE;  
         $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                   line => $self->{line_prev}, # "<" of "</"  
                                   column => $self->{column_prev} - 1,  
                                  };  
         ## NOTE: $self->{nc} is intentionally left as is.  
         ## Although the "anything else" case of the spec not explicitly  
         ## states that the next input character is to be reconsumed,  
         ## it will be included to the |data| of the comment token  
         ## generated from the bogus end tag, as defined in the  
         ## "bogus comment state" entry.  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_RCDATA_CLOSE_TAG_STATE) {  
       my $ch = substr $self->{last_stag_name}, length $self->{s_kwd}, 1;  
       if (length $ch) {  
         my $CH = $ch;  
         $ch =~ tr/a-z/A-Z/;  
         my $nch = chr $self->{nc};  
         if ($nch eq $ch or $nch eq $CH) {  
           !!!cp (24);  
           ## Stay in the state.  
           $self->{s_kwd} .= $nch;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (25);  
           $self->{state} = DATA_STATE;  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '</' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                    });  
           redo A;  
         }  
       } else { # after "<{tag-name}"  
         unless ($is_space->{$self->{nc}} or  
                 {  
                  0x003E => 1, # >  
                  0x002F => 1, # /  
                  -1 => 1, # EOF  
                 }->{$self->{nc}}) {  
           !!!cp (26);  
           ## Reconsume.  
           $self->{state} = DATA_STATE;  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '</' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                    });  
           redo A;  
         } else {  
           !!!cp (27);  
           $self->{ct}  
               = {type => END_TAG_TOKEN,  
                  tag_name => $self->{last_stag_name},  
                  line => $self->{line_prev},  
                  column => $self->{column_prev} - 1 - length $self->{s_kwd}};  
           $self->{state} = TAG_NAME_STATE;  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == TAG_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (34);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (35);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           #if ($self->{ct}->{attributes}) {  
           #  ## NOTE: This should never be reached.  
           #  !!! cp (36);  
           #  !!! parse-error (type => 'end tag attribute');  
           #} else {  
             !!!cp (37);  
           #}  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (38);  
         $self->{ct}->{tag_name} .= chr ($self->{nc} + 0x0020);  
           # start tag or end tag  
         ## Stay in this state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (39);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           #if ($self->{ct}->{attributes}) {  
           #  ## NOTE: This state should never be reached.  
           #  !!! cp (40);  
           #  !!! parse-error (type => 'end tag attribute');  
           #} else {  
             !!!cp (41);  
           #}  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (42);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (44);  
         $self->{ct}->{tag_name} .= chr $self->{nc};  
           # start tag or end tag  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (45);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (46);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (47);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp (48);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (49);  
         $self->{ca}  
             = {name => chr ($self->{nc} + 0x0020),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (50);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (52);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (53);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp (54);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ({  
              0x0022 => 1, # "  
              0x0027 => 1, # '  
              0x003D => 1, # =  
             }->{$self->{nc}}) {  
           !!!cp (55);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (56);  
         }  
         $self->{ca}  
             = {name => chr ($self->{nc}),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {  
       my $before_leave = sub {  
         if (exists $self->{ct}->{attributes} # start tag or end tag  
             ->{$self->{ca}->{name}}) { # MUST  
           !!!cp (57);  
           !!!parse-error (type => 'duplicate attribute', text => $self->{ca}->{name}, line => $self->{ca}->{line}, column => $self->{ca}->{column});  
           ## Discard $self->{ca} # MUST  
         } else {  
           !!!cp (58);  
           $self->{ct}->{attributes}->{$self->{ca}->{name}}  
             = $self->{ca};  
         }  
       }; # $before_leave  
   
       if ($is_space->{$self->{nc}}) {  
         !!!cp (59);  
         $before_leave->();  
         $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003D) { # =  
         !!!cp (60);  
         $before_leave->();  
         $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         $before_leave->();  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (61);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           !!!cp (62);  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!parse-error (type => 'end tag attribute');  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (63);  
         $self->{ca}->{name} .= chr ($self->{nc} + 0x0020);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (64);  
         $before_leave->();  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         $before_leave->();  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (66);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (67);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (68);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x0022 or # "  
             $self->{nc} == 0x0027) { # '  
           !!!cp (69);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (70);  
         }  
         $self->{ca}->{name} .= chr ($self->{nc});  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (71);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003D) { # =  
         !!!cp (72);  
         $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (73);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (74);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (75);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (76);  
         $self->{ca}  
             = {name => chr ($self->{nc} + 0x0020),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (77);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (79);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (80);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (81);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x0022 or # "  
             $self->{nc} == 0x0027) { # '  
           !!!cp (78);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (82);  
         }  
         $self->{ca}  
             = {name => chr ($self->{nc}),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;          
       }  
     } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (83);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (84);  
         $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (85);  
         $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;  
         ## reconsume  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (86);  
         $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!parse-error (type => 'empty unquoted attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (87);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (88);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (89);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (90);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (91);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (92);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x003D) { # =  
           !!!cp (93);  
           !!!parse-error (type => 'bad attribute value');  
         } else {  
           !!!cp (94);  
         }  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (95);  
         $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (96);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{prev_state} = $self->{state};  
         $self->{entity_add} = 0x0022; # "  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (97);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (98);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (99);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         !!!cp (100);  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q["&],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (101);  
         $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (102);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{entity_add} = 0x0027; # '  
         $self->{prev_state} = $self->{state};  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (103);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (104);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (105);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         !!!cp (106);  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q['&],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (107);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (108);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{entity_add} = -1;  
         $self->{prev_state} = $self->{state};  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (109);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (110);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (111);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (112);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (113);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (114);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ({  
              0x0022 => 1, # "  
              0x0027 => 1, # '  
              0x003D => 1, # =  
             }->{$self->{nc}}) {  
           !!!cp (115);  
           !!!parse-error (type => 'bad attribute value');  
         } else {  
           !!!cp (116);  
         }  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q["'=& >],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (118);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (119);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (120);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (121);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (122);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (122.3);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           if ($self->{ct}->{attributes}) {  
             !!!cp (122.1);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (122.2);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## Reconsume.  
         !!!emit ($self->{ct}); # start tag or end tag  
         redo A;  
       } else {  
         !!!cp ('124.1');  
         !!!parse-error (type => 'no space between attributes');  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         ## reconsume  
         redo A;  
       }  
     } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == END_TAG_TOKEN) {  
           !!!cp ('124.2');  
           !!!parse-error (type => 'nestc', token => $self->{ct});  
           ## TODO: Different type than slash in start tag  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp ('124.4');  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp ('124.5');  
           }  
           ## TODO: Test |<title></title/>|  
         } else {  
           !!!cp ('124.3');  
           $self->{self_closing} = 1;  
         }  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (124.7);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           if ($self->{ct}->{attributes}) {  
             !!!cp (124.5);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (124.6);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## Reconsume.  
         !!!emit ($self->{ct}); # start tag or end tag  
         redo A;  
       } else {  
         !!!cp ('124.4');  
         !!!parse-error (type => 'nestc');  
         ## TODO: This error type is wrong.  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == BOGUS_COMMENT_STATE) {  
       ## (only happen if PCDATA state)  
   
       ## NOTE: Unlike spec's "bogus comment state", this implementation  
       ## consumes characters one-by-one basis.  
         
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (124);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (125);  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
         redo A;  
       } else {  
         !!!cp (126);  
         $self->{ct}->{data} .= chr ($self->{nc}); # comment  
         $self->{read_until}->($self->{ct}->{data},  
                               q[>],  
                               length $self->{ct}->{data});  
   
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {  
       ## (only happen if PCDATA state)  
         
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (133);  
         $self->{state} = MD_HYPHEN_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0044 or # D  
                $self->{nc} == 0x0064) { # d  
         ## ASCII case-insensitive.  
         !!!cp (130);  
         $self->{state} = MD_DOCTYPE_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and  
                $self->{open_elements}->[-1]->[1] & FOREIGN_EL and  
                $self->{nc} == 0x005B) { # [  
         !!!cp (135.4);                  
         $self->{state} = MD_CDATA_STATE;  
         $self->{s_kwd} = '[';  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (136);  
       }  
   
       !!!parse-error (type => 'bogus comment',  
                       line => $self->{line_prev},  
                       column => $self->{column_prev} - 1);  
       ## Reconsume.  
       $self->{state} = BOGUS_COMMENT_STATE;  
       $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                 line => $self->{line_prev},  
                                 column => $self->{column_prev} - 1,  
                                };  
       redo A;  
     } elsif ($self->{state} == MD_HYPHEN_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (127);  
         $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 2,  
                                  };  
         $self->{state} = COMMENT_START_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (128);  
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 2);  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => '-',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 2,  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == MD_DOCTYPE_STATE) {  
       ## ASCII case-insensitive.  
       if ($self->{nc} == [  
             undef,  
             0x004F, # O  
             0x0043, # C  
             0x0054, # T  
             0x0059, # Y  
             0x0050, # P  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x006F, # o  
             0x0063, # c  
             0x0074, # t  
             0x0079, # y  
             0x0070, # p  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (131);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 6 and  
                ($self->{nc} == 0x0045 or # E  
                 $self->{nc} == 0x0065)) { # e  
         !!!cp (129);  
         $self->{state} = DOCTYPE_STATE;  
         $self->{ct} = {type => DOCTYPE_TOKEN,  
                                   quirks => 1,  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 7,  
                                  };  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (132);          
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1 - length $self->{s_kwd});  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => $self->{s_kwd},  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == MD_CDATA_STATE) {  
       if ($self->{nc} == {  
             '[' => 0x0043, # C  
             '[C' => 0x0044, # D  
             '[CD' => 0x0041, # A  
             '[CDA' => 0x0054, # T  
             '[CDAT' => 0x0041, # A  
           }->{$self->{s_kwd}}) {  
         !!!cp (135.1);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{s_kwd} eq '[CDATA' and  
                $self->{nc} == 0x005B) { # [  
         !!!cp (135.2);  
         $self->{ct} = {type => CHARACTER_TOKEN,  
                                   data => '',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 7};  
         $self->{state} = CDATA_SECTION_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (135.3);  
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1 - length $self->{s_kwd});  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => $self->{s_kwd},  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_START_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (137);  
         $self->{state} = COMMENT_START_DASH_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (138);  
         !!!parse-error (type => 'bogus comment');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (139);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (140);  
         $self->{ct}->{data} # comment  
             .= chr ($self->{nc});  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_START_DASH_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (141);  
         $self->{state} = COMMENT_END_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (142);  
         !!!parse-error (type => 'bogus comment');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (143);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (144);  
         $self->{ct}->{data} # comment  
             .= '-' . chr ($self->{nc});  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (145);  
         $self->{state} = COMMENT_END_DASH_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (146);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (147);  
         $self->{ct}->{data} .= chr ($self->{nc}); # comment  
         $self->{read_until}->($self->{ct}->{data},  
                               q[-],  
                               length $self->{ct}->{data});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_END_DASH_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (148);  
         $self->{state} = COMMENT_END_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (149);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (150);  
         $self->{ct}->{data} .= '-' . chr ($self->{nc}); # comment  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_END_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (151);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == 0x002D) { # -  
         !!!cp (152);  
         !!!parse-error (type => 'dash in comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev});  
         $self->{ct}->{data} .= '-'; # comment  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (153);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (154);  
         !!!parse-error (type => 'dash in comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev});  
         $self->{ct}->{data} .= '--' . chr ($self->{nc}); # comment  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (155);  
         $self->{state} = BEFORE_DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (156);  
         !!!parse-error (type => 'no space before DOCTYPE name');  
         $self->{state} = BEFORE_DOCTYPE_NAME_STATE;  
         ## reconsume  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (157);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (158);  
         !!!parse-error (type => 'no DOCTYPE name');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE (quirks)  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (159);  
         !!!parse-error (type => 'no DOCTYPE name');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # DOCTYPE (quirks)  
   
         redo A;  
       } else {  
         !!!cp (160);  
         $self->{ct}->{name} = chr $self->{nc};  
         delete $self->{ct}->{quirks};  
 ## ISSUE: "Set the token's name name to the" in the spec  
         $self->{state} = DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_NAME_STATE) {  
 ## ISSUE: Redundant "First," in the spec.  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (161);  
         $self->{state} = AFTER_DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (162);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (163);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (164);  
         $self->{ct}->{name}  
           .= chr ($self->{nc}); # DOCTYPE  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (165);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (166);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (167);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == 0x0050 or # P  
                $self->{nc} == 0x0070) { # p  
         $self->{state} = PUBLIC_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0053 or # S  
                $self->{nc} == 0x0073) { # s  
         $self->{state} = SYSTEM_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (180);  
         !!!parse-error (type => 'string after DOCTYPE name');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == PUBLIC_STATE) {  
       ## ASCII case-insensitive  
       if ($self->{nc} == [  
             undef,  
             0x0055, # U  
             0x0042, # B  
             0x004C, # L  
             0x0049, # I  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x0075, # u  
             0x0062, # b  
             0x006C, # l  
             0x0069, # i  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (175);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 5 and  
                ($self->{nc} == 0x0043 or # C  
                 $self->{nc} == 0x0063)) { # c  
         !!!cp (168);  
         $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (169);  
         !!!parse-error (type => 'string after DOCTYPE name',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} + 1 - length $self->{s_kwd});  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == SYSTEM_STATE) {  
       ## ASCII case-insensitive  
       if ($self->{nc} == [  
             undef,  
             0x0059, # Y  
             0x0053, # S  
             0x0054, # T  
             0x0045, # E  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x0079, # y  
             0x0073, # s  
             0x0074, # t  
             0x0065, # e  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (170);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 5 and  
                ($self->{nc} == 0x004D or # M  
                 $self->{nc} == 0x006D)) { # m  
         !!!cp (171);  
         $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (172);  
         !!!parse-error (type => 'string after DOCTYPE name',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} + 1 - length $self->{s_kwd});  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (181);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x0022) { # "  
         !!!cp (182);  
         $self->{ct}->{pubid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x0027) { # '  
         !!!cp (183);  
         $self->{ct}->{pubid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x003E) { # >  
         !!!cp (184);  
         !!!parse-error (type => 'no PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (185);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (186);  
         !!!parse-error (type => 'string after PUBLIC');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (187);  
         $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (188);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (189);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (190);  
         $self->{ct}->{pubid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{pubid}, q[">],  
                               length $self->{ct}->{pubid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (191);  
         $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (192);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (193);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (194);  
         $self->{ct}->{pubid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{pubid}, q['>],  
                               length $self->{ct}->{pubid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (195);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (196);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (197);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (198);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (199);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (200);  
         !!!parse-error (type => 'string after PUBLIC literal');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (201);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (202);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (203);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (204);  
         !!!parse-error (type => 'no SYSTEM literal');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (205);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (206);  
         !!!parse-error (type => 'string after SYSTEM');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (207);  
         $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (208);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (209);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (210);  
         $self->{ct}->{sysid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{sysid}, q[">],  
                               length $self->{ct}->{sysid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (211);  
         $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (212);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (213);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (214);  
         $self->{ct}->{sysid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{sysid}, q['>],  
                               length $self->{ct}->{sysid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (215);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (216);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (217);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (218);  
         !!!parse-error (type => 'string after SYSTEM literal');  
         #$self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (219);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (220);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (221);  
         my $s = '';  
         $self->{read_until}->($s, q[>], 0);  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_SECTION_STATE) {  
       ## NOTE: "CDATA section state" in the state is jointly implemented  
       ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,  
       ## and |CDATA_SECTION_MSE2_STATE|.  
         
       if ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.1);  
         $self->{state} = CDATA_SECTION_MSE1_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         if (length $self->{ct}->{data}) { # character  
           !!!cp (221.2);  
           !!!emit ($self->{ct}); # character  
         } else {  
           !!!cp (221.3);  
           ## No token to emit. $self->{ct} is discarded.  
         }          
         redo A;  
       } else {  
         !!!cp (221.4);  
         $self->{ct}->{data} .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{data},  
                               q<]>,  
                               length $self->{ct}->{data});  
   
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       }  
   
       ## ISSUE: "text tokens" in spec.  
     } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {  
       if ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.5);  
         $self->{state} = CDATA_SECTION_MSE2_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (221.6);  
         $self->{ct}->{data} .= ']';  
         $self->{state} = CDATA_SECTION_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         if (length $self->{ct}->{data}) { # character  
           !!!cp (221.7);  
           !!!emit ($self->{ct}); # character  
         } else {  
           !!!cp (221.8);  
           ## No token to emit. $self->{ct} is discarded.  
         }  
         redo A;  
       } elsif ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.9); # character  
         $self->{ct}->{data} .= ']'; ## Add first "]" of "]]]".  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (221.11);  
         $self->{ct}->{data} .= ']]'; # character  
         $self->{state} = CDATA_SECTION_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_STATE) {  
       if ($is_space->{$self->{nc}} or  
           {  
             0x003C => 1, 0x0026 => 1, -1 => 1, # <, &  
             $self->{entity_add} => 1,  
           }->{$self->{nc}}) {  
         !!!cp (1001);  
         ## Don't consume  
         ## No error  
         ## Return nothing.  
         #  
       } elsif ($self->{nc} == 0x0023) { # #  
         !!!cp (999);  
         $self->{state} = ENTITY_HASH_STATE;  
         $self->{s_kwd} = '#';  
         !!!next-input-character;  
         redo A;  
       } elsif ((0x0041 <= $self->{nc} and  
                 $self->{nc} <= 0x005A) or # A..Z  
                (0x0061 <= $self->{nc} and  
                 $self->{nc} <= 0x007A)) { # a..z  
         !!!cp (998);  
         require Whatpm::_NamedEntityList;  
         $self->{state} = ENTITY_NAME_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         $self->{entity__value} = $self->{s_kwd};  
         $self->{entity__match} = 0;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (1027);  
         !!!parse-error (type => 'bare ero');  
         ## Return nothing.  
         #  
       }  
   
       ## NOTE: No character is consumed by the "consume a character  
       ## reference" algorithm.  In other word, there is an "&" character  
       ## that does not introduce a character reference, which would be  
       ## appended to the parent element or the attribute value in later  
       ## process of the tokenizer.  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (997);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => '&',  
                   line => $self->{line_prev},  
                   column => $self->{column_prev},  
                  });  
         redo A;  
       } else {  
         !!!cp (996);  
         $self->{ca}->{value} .= '&';  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_HASH_STATE) {  
       if ($self->{nc} == 0x0078 or # x  
           $self->{nc} == 0x0058) { # X  
         !!!cp (995);  
         $self->{state} = HEXREF_X_STATE;  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0030 <= $self->{nc} and  
                $self->{nc} <= 0x0039) { # 0..9  
         !!!cp (994);  
         $self->{state} = NCR_NUM_STATE;  
         $self->{s_kwd} = $self->{nc} - 0x0030;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!parse-error (type => 'bare nero',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1);  
   
         ## NOTE: According to the spec algorithm, nothing is returned,  
         ## and then "&#" is appended to the parent element or the attribute  
         ## value in the later processing.  
   
         if ($self->{prev_state} == DATA_STATE) {  
           !!!cp (1019);  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '&#',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1,  
                    });  
           redo A;  
         } else {  
           !!!cp (993);  
           $self->{ca}->{value} .= '&#';  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == NCR_NUM_STATE) {  
       if (0x0030 <= $self->{nc} and  
           $self->{nc} <= 0x0039) { # 0..9  
         !!!cp (1012);  
         $self->{s_kwd} *= 10;  
         $self->{s_kwd} += $self->{nc} - 0x0030;  
           
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003B) { # ;  
         !!!cp (1013);  
         !!!next-input-character;  
         #  
       } else {  
         !!!cp (1014);  
         !!!parse-error (type => 'no refc');  
         ## Reconsume.  
         #  
       }  
   
       my $code = $self->{s_kwd};  
       my $l = $self->{line_prev};  
       my $c = $self->{column_prev};  
       if ($charref_map->{$code}) {  
         !!!cp (1015);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U+%04X', $code),  
                         line => $l, column => $c);  
         $code = $charref_map->{$code};  
       } elsif ($code > 0x10FFFF) {  
         !!!cp (1016);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U-%08X', $code),  
                         line => $l, column => $c);  
         $code = 0xFFFD;  
       }  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (992);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => chr $code,  
                   line => $l, column => $c,  
                  });  
         redo A;  
       } else {  
         !!!cp (991);  
         $self->{ca}->{value} .= chr $code;  
         $self->{ca}->{has_reference} = 1;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == HEXREF_X_STATE) {  
       if ((0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) or  
           (0x0041 <= $self->{nc} and $self->{nc} <= 0x0046) or  
           (0x0061 <= $self->{nc} and $self->{nc} <= 0x0066)) {  
         # 0..9, A..F, a..f  
         !!!cp (990);  
         $self->{state} = HEXREF_HEX_STATE;  
         $self->{s_kwd} = 0;  
         ## Reconsume.  
         redo A;  
       } else {  
         !!!parse-error (type => 'bare hcro',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 2);  
   
         ## NOTE: According to the spec algorithm, nothing is returned,  
         ## and then "&#" followed by "X" or "x" is appended to the parent  
         ## element or the attribute value in the later processing.  
   
         if ($self->{prev_state} == DATA_STATE) {  
           !!!cp (1005);  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '&' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - length $self->{s_kwd},  
                    });  
           redo A;  
         } else {  
           !!!cp (989);  
           $self->{ca}->{value} .= '&' . $self->{s_kwd};  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == HEXREF_HEX_STATE) {  
       if (0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) {  
         # 0..9  
         !!!cp (1002);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0030;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0061 <= $self->{nc} and  
                $self->{nc} <= 0x0066) { # a..f  
         !!!cp (1003);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0060 + 9;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x0046) { # A..F  
         !!!cp (1004);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0040 + 9;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003B) { # ;  
         !!!cp (1006);  
         !!!next-input-character;  
         #  
       } else {  
         !!!cp (1007);  
         !!!parse-error (type => 'no refc',  
                         line => $self->{line},  
                         column => $self->{column});  
         ## Reconsume.  
         #  
       }  
   
       my $code = $self->{s_kwd};  
       my $l = $self->{line_prev};  
       my $c = $self->{column_prev};  
       if ($charref_map->{$code}) {  
         !!!cp (1008);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U+%04X', $code),  
                         line => $l, column => $c);  
         $code = $charref_map->{$code};  
       } elsif ($code > 0x10FFFF) {  
         !!!cp (1009);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U-%08X', $code),  
                         line => $l, column => $c);  
         $code = 0xFFFD;  
       }  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (988);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => chr $code,  
                   line => $l, column => $c,  
                  });  
         redo A;  
       } else {  
         !!!cp (987);  
         $self->{ca}->{value} .= chr $code;  
         $self->{ca}->{has_reference} = 1;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_NAME_STATE) {  
       if (length $self->{s_kwd} < 30 and  
           ## NOTE: Some number greater than the maximum length of entity name  
           ((0x0041 <= $self->{nc} and # a  
             $self->{nc} <= 0x005A) or # x  
            (0x0061 <= $self->{nc} and # a  
             $self->{nc} <= 0x007A) or # z  
            (0x0030 <= $self->{nc} and # 0  
             $self->{nc} <= 0x0039) or # 9  
            $self->{nc} == 0x003B)) { # ;  
         our $EntityChar;  
         $self->{s_kwd} .= chr $self->{nc};  
         if (defined $EntityChar->{$self->{s_kwd}}) {  
           if ($self->{nc} == 0x003B) { # ;  
             !!!cp (1020);  
             $self->{entity__value} = $EntityChar->{$self->{s_kwd}};  
             $self->{entity__match} = 1;  
             !!!next-input-character;  
             #  
           } else {  
             !!!cp (1021);  
             $self->{entity__value} = $EntityChar->{$self->{s_kwd}};  
             $self->{entity__match} = -1;  
             ## Stay in the state.  
             !!!next-input-character;  
             redo A;  
           }  
         } else {  
           !!!cp (1022);  
           $self->{entity__value} .= chr $self->{nc};  
           $self->{entity__match} *= 2;  
           ## Stay in the state.  
           !!!next-input-character;  
           redo A;  
         }  
       }  
   
       my $data;  
       my $has_ref;  
       if ($self->{entity__match} > 0) {  
         !!!cp (1023);  
         $data = $self->{entity__value};  
         $has_ref = 1;  
         #  
       } elsif ($self->{entity__match} < 0) {  
         !!!parse-error (type => 'no refc');  
         if ($self->{prev_state} != DATA_STATE and # in attribute  
             $self->{entity__match} < -1) {  
           !!!cp (1024);  
           $data = '&' . $self->{s_kwd};  
           #  
         } else {  
           !!!cp (1025);  
           $data = $self->{entity__value};  
           $has_ref = 1;  
           #  
         }  
       } else {  
         !!!cp (1026);  
         !!!parse-error (type => 'bare ero',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - length $self->{s_kwd});  
         $data = '&' . $self->{s_kwd};  
         #  
       }  
     
       ## NOTE: In these cases, when a character reference is found,  
       ## it is consumed and a character token is returned, or, otherwise,  
       ## nothing is consumed and returned, according to the spec algorithm.  
       ## In this implementation, anything that has been examined by the  
       ## tokenizer is appended to the parent element or the attribute value  
       ## as string, either literal string when no character reference or  
       ## entity-replaced string otherwise, in this stage, since any characters  
       ## that would not be consumed are appended in the data state or in an  
       ## appropriate attribute value state anyway.  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (986);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN,  
                   data => $data,  
                   line => $self->{line_prev},  
                   column => $self->{column_prev} + 1 - length $self->{s_kwd},  
                  });  
         redo A;  
       } else {  
         !!!cp (985);  
         $self->{ca}->{value} .= $data;  
         $self->{ca}->{has_reference} = 1 if $has_ref;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } else {  
       die "$0: $self->{state}: Unknown state";  
     }  
   } # A    
   
   die "$0: _get_next_token: unexpected case";  
 } # _get_next_token  
   
859  sub _initialize_tree_constructor ($) {  sub _initialize_tree_constructor ($) {
860    my $self = shift;    my $self = shift;
861    ## NOTE: $self->{document} MUST be specified before this method is called    ## NOTE: $self->{document} MUST be specified before this method is called
# Line 3469  sub _construct_tree ($) { Line 884  sub _construct_tree ($) {
884    ## When an interactive UA render the $self->{document} available    ## When an interactive UA render the $self->{document} available
885    ## to the user, or when it begin accepting user input, are    ## to the user, or when it begin accepting user input, are
886    ## not defined.    ## not defined.
   
   ## Append a character: collect it and all subsequent consecutive  
   ## characters and insert one Text node whose data is concatenation  
   ## of all those characters. # MUST  
887        
888    !!!next-token;    !!!next-token;
889    
890    undef $self->{form_element};    undef $self->{form_element};
891    undef $self->{head_element};    undef $self->{head_element};
892      undef $self->{head_element_inserted};
893    $self->{open_elements} = [];    $self->{open_elements} = [];
894    undef $self->{inner_html_node};    undef $self->{inner_html_node};
895      undef $self->{ignore_newline};
896    
897    ## NOTE: The "initial" insertion mode.    ## NOTE: The "initial" insertion mode.
898    $self->_tree_construction_initial; # MUST    $self->_tree_construction_initial; # MUST
# Line 3499  sub _tree_construction_initial ($) { Line 912  sub _tree_construction_initial ($) {
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}) {
# Line 3785  sub _tree_construction_root_element ($) Line 1203  sub _tree_construction_root_element ($)
1203      ## NOTE: Reprocess the token.      ## NOTE: Reprocess the token.
1204      !!!ack-later;      !!!ack-later;
1205      return; ## Go to the "before head" insertion mode.      return; ## Go to the "before head" insertion mode.
   
     ## ISSUE: There is an issue in the spec  
1206    } # B    } # B
1207    
1208    die "$0: _tree_construction_root_element: This should never be reached";    die "$0: _tree_construction_root_element: This should never be reached";
# Line 3822  sub _reset_insertion_mode ($) { Line 1238  sub _reset_insertion_mode ($) {
1238          ## SVG elements.  Currently the HTML syntax supports only MathML and          ## SVG elements.  Currently the HTML syntax supports only MathML and
1239          ## SVG elements as foreigners.          ## SVG elements as foreigners.
1240          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;
1241        } elsif ($node->[1] & TABLE_CELL_EL) {        } elsif ($node->[1] == TABLE_CELL_EL) {
1242          if ($last) {          if ($last) {
1243            !!!cp ('t28.2');            !!!cp ('t28.2');
1244            #            #
# Line 3851  sub _reset_insertion_mode ($) { Line 1267  sub _reset_insertion_mode ($) {
1267        $self->{insertion_mode} = $new_mode and return if defined $new_mode;        $self->{insertion_mode} = $new_mode and return if defined $new_mode;
1268                
1269        ## Step 15        ## Step 15
1270        if ($node->[1] & HTML_EL) {        if ($node->[1] == HTML_EL) {
1271          unless (defined $self->{head_element}) {          unless (defined $self->{head_element}) {
1272            !!!cp ('t29');            !!!cp ('t29');
1273            $self->{insertion_mode} = BEFORE_HEAD_IM;            $self->{insertion_mode} = BEFORE_HEAD_IM;
# Line 3983  sub _tree_construction_main ($) { Line 1399  sub _tree_construction_main ($) {
1399    
1400      ## Step 1      ## Step 1
1401      my $start_tag_name = $token->{tag_name};      my $start_tag_name = $token->{tag_name};
1402      my $el;      !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
     !!!create-element ($el, $HTML_NS, $start_tag_name, $token->{attributes}, $token);  
1403    
1404      ## Step 2      ## Step 2
     $insert->($el);  
   
     ## Step 3  
1405      $self->{content_model} = $content_model_flag; # CDATA or RCDATA      $self->{content_model} = $content_model_flag; # CDATA or RCDATA
1406      delete $self->{escape}; # MUST      delete $self->{escape}; # MUST
1407    
1408      ## Step 4      ## Step 3, 4
1409      my $text = '';      $self->{insertion_mode} |= IN_CDATA_RCDATA_IM;
     !!!nack ('t40.1');  
     !!!next-token;  
     while ($token->{type} == CHARACTER_TOKEN) { # or until stop tokenizing  
       !!!cp ('t40');  
       $text .= $token->{data};  
       !!!next-token;  
     }  
1410    
1411      ## Step 5      !!!nack ('t40.1');
     if (length $text) {  
       !!!cp ('t41');  
       my $text = $self->{document}->create_text_node ($text);  
       $el->append_child ($text);  
     }  
   
     ## Step 6  
     $self->{content_model} = PCDATA_CONTENT_MODEL;  
   
     ## Step 7  
     if ($token->{type} == END_TAG_TOKEN and  
         $token->{tag_name} eq $start_tag_name) {  
       !!!cp ('t42');  
       ## Ignore the token  
     } else {  
       ## NOTE: An end-of-file token.  
       if ($content_model_flag == CDATA_CONTENT_MODEL) {  
         !!!cp ('t43');  
         !!!parse-error (type => 'in CDATA:#eof', token => $token);  
       } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {  
         !!!cp ('t44');  
         !!!parse-error (type => 'in RCDATA:#eof', token => $token);  
       } else {  
         die "$0: $content_model_flag in parse_rcdata";  
       }  
     }  
1412      !!!next-token;      !!!next-token;
1413    }; # $parse_rcdata    }; # $parse_rcdata
1414    
1415    my $script_start_tag = sub () {    my $script_start_tag = sub () {
1416        ## Step 1
1417      my $script_el;      my $script_el;
1418      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);
1419    
1420        ## Step 2
1421      ## TODO: mark as "parser-inserted"      ## TODO: mark as "parser-inserted"
1422    
1423        ## Step 3
1424        ## TODO: Mark as "already executed", if ...
1425    
1426        ## Step 4 (HTML5 revision 2702)
1427        $insert->($script_el);
1428        push @{$self->{open_elements}}, [$script_el, $el_category->{script}];
1429    
1430        ## Step 5
1431      $self->{content_model} = CDATA_CONTENT_MODEL;      $self->{content_model} = CDATA_CONTENT_MODEL;
1432      delete $self->{escape}; # MUST      delete $self->{escape}; # MUST
       
     my $text = '';  
     !!!nack ('t45.1');  
     !!!next-token;  
     while ($token->{type} == CHARACTER_TOKEN) {  
       !!!cp ('t45');  
       $text .= $token->{data};  
       !!!next-token;  
     } # stop if non-character token or tokenizer stops tokenising  
     if (length $text) {  
       !!!cp ('t46');  
       $script_el->manakai_append_text ($text);  
     }  
                 
     $self->{content_model} = PCDATA_CONTENT_MODEL;  
1433    
1434      if ($token->{type} == END_TAG_TOKEN and      ## Step 6-7
1435          $token->{tag_name} eq 'script') {      $self->{insertion_mode} |= IN_CDATA_RCDATA_IM;
       !!!cp ('t47');  
       ## Ignore the token  
     } else {  
       !!!cp ('t48');  
       !!!parse-error (type => 'in CDATA:#eof', token => $token);  
       ## ISSUE: And ignore?  
       ## TODO: mark as "already executed"  
     }  
       
     if (defined $self->{inner_html_node}) {  
       !!!cp ('t49');  
       ## TODO: mark as "already executed"  
     } else {  
       !!!cp ('t50');  
       ## TODO: $old_insertion_point = current insertion point  
       ## TODO: insertion point = just before the next input character  
1436    
1437        $insert->($script_el);      !!!nack ('t40.2');
         
       ## TODO: insertion point = $old_insertion_point (might be "undefined")  
         
       ## TODO: if there is a script that will execute as soon as the parser resume, then...  
     }  
       
1438      !!!next-token;      !!!next-token;
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.
1444    my $open_tables = [[$self->{open_elements}->[0]->[0]]];    my $open_tables = [[$self->{open_elements}->[0]->[0]]];
1445    
1446    my $formatting_end_tag = sub {    my $formatting_end_tag = sub {
# Line 4171  sub _tree_construction_main ($) { Line 1525  sub _tree_construction_main ($) {
1525            !!!cp ('t59');            !!!cp ('t59');
1526            $furthest_block = $node;            $furthest_block = $node;
1527            $furthest_block_i_in_open = $_;            $furthest_block_i_in_open = $_;
1528              ## NOTE: The topmost (eldest) node.
1529          } elsif ($node->[0] eq $formatting_element->[0]) {          } elsif ($node->[0] eq $formatting_element->[0]) {
1530            !!!cp ('t60');            !!!cp ('t60');
1531            last OE;            last OE;
# Line 4254  sub _tree_construction_main ($) { Line 1609  sub _tree_construction_main ($) {
1609                
1610        ## Step 8        ## Step 8
1611        if ($common_ancestor_node->[1] & TABLE_ROWS_EL) {        if ($common_ancestor_node->[1] & TABLE_ROWS_EL) {
1612            ## Foster parenting.
1613          my $foster_parent_element;          my $foster_parent_element;
1614          my $next_sibling;          my $next_sibling;
1615          OE: for (reverse 0..$#{$self->{open_elements}}) {          OE: for (reverse 0..$#{$self->{open_elements}}) {
1616            if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {            if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1617                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;              !!!cp ('t65.2');
1618                               if (defined $parent and $parent->node_type == 1) {              $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1619                                 !!!cp ('t65.1');              $next_sibling = $self->{open_elements}->[$_]->[0];
1620                                 $foster_parent_element = $parent;              undef $next_sibling
1621                                 $next_sibling = $self->{open_elements}->[$_]->[0];                  unless $next_sibling->parent_node eq $foster_parent_element;
1622                               } else {              last OE;
1623                                 !!!cp ('t65.2');            }
1624                                 $foster_parent_element          } # OE
1625                                   = $self->{open_elements}->[$_ - 1]->[0];          $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1626                               }  
                              last OE;  
                            }  
                          } # OE  
                          $foster_parent_element = $self->{open_elements}->[0]->[0]  
                            unless defined $foster_parent_element;  
1627          $foster_parent_element->insert_before ($last_node->[0], $next_sibling);          $foster_parent_element->insert_before ($last_node->[0], $next_sibling);
1628          $open_tables->[-1]->[1] = 1; # tainted          $open_tables->[-1]->[1] = 1; # tainted
1629        } else {        } else {
# Line 4317  sub _tree_construction_main ($) { Line 1668  sub _tree_construction_main ($) {
1668            $i = $_;            $i = $_;
1669          }          }
1670        } # OE        } # OE
1671        splice @{$self->{open_elements}}, $i + 1, 1, $clone;        splice @{$self->{open_elements}}, $i + 1, 0, $clone;
1672                
1673        ## Step 14        ## Step 14
1674        redo FET;        redo FET;
# Line 4328  sub _tree_construction_main ($) { Line 1679  sub _tree_construction_main ($) {
1679      $self->{open_elements}->[-1]->[0]->append_child ($_[0]);      $self->{open_elements}->[-1]->[0]->append_child ($_[0]);
1680    }; # $insert_to_current    }; # $insert_to_current
1681    
1682      ## Foster parenting.  Note that there are three "foster parenting"
1683      ## code in the parser: for elements (this one), for texts, and for
1684      ## elements in the AAA code.
1685    my $insert_to_foster = sub {    my $insert_to_foster = sub {
1686      my $child = shift;      my $child = shift;
1687      if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {      if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
# Line 4335  sub _tree_construction_main ($) { Line 1689  sub _tree_construction_main ($) {
1689        my $foster_parent_element;        my $foster_parent_element;
1690        my $next_sibling;        my $next_sibling;
1691        OE: for (reverse 0..$#{$self->{open_elements}}) {        OE: for (reverse 0..$#{$self->{open_elements}}) {
1692          if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {          if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1693                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;            !!!cp ('t71');
1694                               if (defined $parent and $parent->node_type == 1) {            $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1695                                 !!!cp ('t70');            $next_sibling = $self->{open_elements}->[$_]->[0];
1696                                 $foster_parent_element = $parent;            undef $next_sibling
1697                                 $next_sibling = $self->{open_elements}->[$_]->[0];                unless $next_sibling->parent_node eq $foster_parent_element;
1698                               } else {            last OE;
1699                                 !!!cp ('t71');          }
1700                                 $foster_parent_element        } # OE
1701                                   = $self->{open_elements}->[$_ - 1]->[0];        $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1702                               }  
1703                               last OE;        $foster_parent_element->insert_before ($child, $next_sibling);
                            }  
                          } # OE  
                          $foster_parent_element = $self->{open_elements}->[0]->[0]  
                            unless defined $foster_parent_element;  
                          $foster_parent_element->insert_before  
                            ($child, $next_sibling);  
1704        $open_tables->[-1]->[1] = 1; # tainted        $open_tables->[-1]->[1] = 1; # tainted
1705      } else {      } else {
1706        !!!cp ('t72');        !!!cp ('t72');
# Line 4360  sub _tree_construction_main ($) { Line 1708  sub _tree_construction_main ($) {
1708      }      }
1709    }; # $insert_to_foster    }; # $insert_to_foster
1710    
1711      ## NOTE: Insert a character (MUST): When a character is inserted, if
1712      ## the last node that was inserted by the parser is a Text node and
1713      ## the character has to be inserted after that node, then the
1714      ## character is appended to the Text node.  However, if any other
1715      ## node is inserted by the parser, then a new Text node is created
1716      ## and the character is appended as that Text node.  If I'm not
1717      ## wrong, for a parser with scripting disabled, there are only two
1718      ## cases where this occurs.  One is the case where an element node
1719      ## is inserted to the |head| element.  This is covered by using the
1720      ## |$self->{head_element_inserted}| flag.  Another is the case where
1721      ## an element or comment is inserted into the |table| subtree while
1722      ## foster parenting happens.  This is covered by using the [2] flag
1723      ## of the |$open_tables| structure.  All other cases are handled
1724      ## simply by calling |manakai_append_text| method.
1725    
1726      ## TODO: |<body><script>document.write("a<br>");
1727      ## document.body.removeChild (document.body.lastChild);
1728      ## document.write ("b")</script>|
1729    
1730    B: while (1) {    B: while (1) {
1731    
1732        ## The "in table text" insertion mode.
1733        if ($self->{insertion_mode} & TABLE_IMS and
1734            not $self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and
1735            not $self->{insertion_mode} & IN_CDATA_RCDATA_IM) {
1736          C: {
1737            my $s;
1738            if ($token->{type} == CHARACTER_TOKEN) {
1739              !!!cp ('t194');
1740              $self->{pending_chars} ||= [];
1741              push @{$self->{pending_chars}}, $token;
1742              !!!next-token;
1743              next B;
1744            } else {
1745              if ($self->{pending_chars}) {
1746                $s = join '', map { $_->{data} } @{$self->{pending_chars}};
1747                delete $self->{pending_chars};
1748                if ($s =~ /[^\x09\x0A\x0C\x0D\x20]/) {
1749                  !!!cp ('t195');
1750                  #
1751                } else {
1752                  !!!cp ('t195.1');
1753                  #$self->{open_elements}->[-1]->[0]->manakai_append_text ($s);
1754                  $self->{open_elements}->[-1]->[0]->append_child
1755                      ($self->{document}->create_text_node ($s));
1756                  last C;
1757                }
1758              } else {
1759                !!!cp ('t195.2');
1760                last C;
1761              }
1762            }
1763    
1764            ## Foster parenting.
1765            !!!parse-error (type => 'in table:#text', token => $token);
1766    
1767            ## NOTE: As if in body, but insert into the foster parent element.
1768            $reconstruct_active_formatting_elements->($insert_to_foster);
1769                
1770            if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
1771              # MUST
1772              my $foster_parent_element;
1773              my $next_sibling;
1774              OE: for (reverse 0..$#{$self->{open_elements}}) {
1775                if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1776                  !!!cp ('t197');
1777                  $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1778                  $next_sibling = $self->{open_elements}->[$_]->[0];
1779                  undef $next_sibling
1780                    unless $next_sibling->parent_node eq $foster_parent_element;
1781                  last OE;
1782                }
1783              } # OE
1784              $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1785    
1786              !!!cp ('t199');
1787              $foster_parent_element->insert_before
1788                  ($self->{document}->create_text_node ($s), $next_sibling);
1789    
1790              $open_tables->[-1]->[1] = 1; # tainted
1791              $open_tables->[-1]->[2] = 1; # ~node inserted
1792            } else {
1793              ## NOTE: Fragment case or in a foster parent'ed element
1794              ## (e.g. |<table><span>a|).  In fragment case, whether the
1795              ## character is appended to existing node or a new node is
1796              ## created is irrelevant, since the foster parent'ed nodes
1797              ## are discarded and fragment parsing does not invoke any
1798              ## script.
1799              !!!cp ('t200');
1800              $self->{open_elements}->[-1]->[0]->manakai_append_text ($s);
1801            }
1802          } # C
1803        } # TABLE_IMS
1804    
1805      if ($token->{type} == DOCTYPE_TOKEN) {      if ($token->{type} == DOCTYPE_TOKEN) {
1806        !!!cp ('t73');        !!!cp ('t73');
1807        !!!parse-error (type => 'in html:#DOCTYPE', token => $token);        !!!parse-error (type => 'in html:#DOCTYPE', token => $token);
# Line 4407  sub _tree_construction_main ($) { Line 1848  sub _tree_construction_main ($) {
1848        } else {        } else {
1849          !!!cp ('t87');          !!!cp ('t87');
1850          $self->{open_elements}->[-1]->[0]->append_child ($comment);          $self->{open_elements}->[-1]->[0]->append_child ($comment);
1851            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
1852        }        }
1853        !!!next-token;        !!!next-token;
1854        next B;        next B;
1855        } elsif ($self->{insertion_mode} & IN_CDATA_RCDATA_IM) {
1856          if ($token->{type} == CHARACTER_TOKEN) {
1857            $token->{data} =~ s/^\x0A// if $self->{ignore_newline};
1858            delete $self->{ignore_newline};
1859    
1860            if (length $token->{data}) {
1861              !!!cp ('t43');
1862              $self->{open_elements}->[-1]->[0]->manakai_append_text
1863                  ($token->{data});
1864            } else {
1865              !!!cp ('t43.1');
1866            }
1867            !!!next-token;
1868            next B;
1869          } elsif ($token->{type} == END_TAG_TOKEN) {
1870            delete $self->{ignore_newline};
1871    
1872            if ($token->{tag_name} eq 'script') {
1873              !!!cp ('t50');
1874              
1875              ## Para 1-2
1876              my $script = pop @{$self->{open_elements}};
1877              
1878              ## Para 3
1879              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1880    
1881              ## Para 4
1882              ## TODO: $old_insertion_point = $current_insertion_point;
1883              ## TODO: $current_insertion_point = just before $self->{nc};
1884    
1885              ## Para 5
1886              ## TODO: Run the $script->[0].
1887    
1888              ## Para 6
1889              ## TODO: $current_insertion_point = $old_insertion_point;
1890    
1891              ## Para 7
1892              ## TODO: if ($pending_external_script) {
1893                ## TODO: ...
1894              ## TODO: }
1895    
1896              !!!next-token;
1897              next B;
1898            } else {
1899              !!!cp ('t42');
1900    
1901              pop @{$self->{open_elements}};
1902    
1903              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1904              !!!next-token;
1905              next B;
1906            }
1907          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
1908            delete $self->{ignore_newline};
1909    
1910            !!!cp ('t44');
1911            !!!parse-error (type => 'not closed',
1912                            text => $self->{open_elements}->[-1]->[0]
1913                                ->manakai_local_name,
1914                            token => $token);
1915    
1916            #if ($self->{open_elements}->[-1]->[1] == SCRIPT_EL) {
1917            #  ## TODO: Mark as "already executed"
1918            #}
1919    
1920            pop @{$self->{open_elements}};
1921    
1922            $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1923            ## Reprocess.
1924            next B;
1925          } else {
1926            die "$0: $token->{type}: In CDATA/RCDATA: Unknown token type";        
1927          }
1928      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {
1929        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
1930          !!!cp ('t87.1');          !!!cp ('t87.1');
# Line 4421  sub _tree_construction_main ($) { Line 1936  sub _tree_construction_main ($) {
1936               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or
1937              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or
1938              ($token->{tag_name} eq 'svg' and              ($token->{tag_name} eq 'svg' and
1939               $self->{open_elements}->[-1]->[1] & MML_AXML_EL)) {               $self->{open_elements}->[-1]->[1] == MML_AXML_EL)) {
1940            ## NOTE: "using the rules for secondary insertion mode"then"continue"            ## NOTE: "using the rules for secondary insertion mode"then"continue"
1941            !!!cp ('t87.2');            !!!cp ('t87.2');
1942            #            #
1943          } elsif ({          } elsif ({
1944                    b => 1, big => 1, blockquote => 1, body => 1, br => 1,                    b => 1, big => 1, blockquote => 1, body => 1, br => 1,
1945                    center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1,                    center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1,
1946                    em => 1, embed => 1, font => 1, h1 => 1, h2 => 1, h3 => 1,                    em => 1, embed => 1, h1 => 1, h2 => 1, h3 => 1,
1947                    h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1,                    h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1,
1948                    img => 1, li => 1, listing => 1, menu => 1, meta => 1,                    img => 1, li => 1, listing => 1, menu => 1, meta => 1,
1949                    nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1,                    nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1,
1950                    small => 1, span => 1, strong => 1, strike => 1, sub => 1,                    small => 1, span => 1, strong => 1, strike => 1, sub => 1,
1951                    sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1,                    sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1,
1952                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}} or
1953                     ($token->{tag_name} eq 'font' and
1954                      ($token->{attributes}->{color} or
1955                       $token->{attributes}->{face} or
1956                       $token->{attributes}->{size}))) {
1957            !!!cp ('t87.2');            !!!cp ('t87.2');
1958            !!!parse-error (type => 'not closed',            !!!parse-error (type => 'not closed',
1959                            text => $self->{open_elements}->[-1]->[0]                            text => $self->{open_elements}->[-1]->[0]
# Line 4510  sub _tree_construction_main ($) { Line 2029  sub _tree_construction_main ($) {
2029          }          }
2030        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
2031          ## NOTE: "using the rules for secondary insertion mode" then "continue"          ## NOTE: "using the rules for secondary insertion mode" then "continue"
2032          !!!cp ('t87.5');          if ($token->{tag_name} eq 'script') {
2033          #            !!!cp ('t87.41');
2034              #
2035              ## XXXscript: Execute script here.
2036            } else {
2037              !!!cp ('t87.5');
2038              #
2039            }
2040        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
2041          !!!cp ('t87.6');          !!!cp ('t87.6');
2042          !!!parse-error (type => 'not closed',          !!!parse-error (type => 'not closed',
# Line 4522  sub _tree_construction_main ($) { Line 2047  sub _tree_construction_main ($) {
2047          pop @{$self->{open_elements}}          pop @{$self->{open_elements}}
2048              while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;              while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;
2049    
2050            ## NOTE: |<span><svg>| ... two parse errors, |<svg>| ... a parse error.
2051    
2052          $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;          $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;
2053          ## Reprocess.          ## Reprocess.
2054          next B;          next B;
# Line 4534  sub _tree_construction_main ($) { Line 2061  sub _tree_construction_main ($) {
2061        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
2062          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {
2063            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2064              !!!cp ('t88.2');              if ($self->{head_element_inserted}) {
2065              $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                !!!cp ('t88.3');
2066              #                $self->{open_elements}->[-1]->[0]->append_child
2067                    ($self->{document}->create_text_node ($1));
2068                  delete $self->{head_element_inserted};
2069                  ## NOTE: |</head> <link> |
2070                  #
2071                } else {
2072                  !!!cp ('t88.2');
2073                  $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
2074                  ## NOTE: |</head> &#x20;|
2075                  #
2076                }
2077            } else {            } else {
2078              !!!cp ('t88.1');              !!!cp ('t88.1');
2079              ## Ignore the token.              ## Ignore the token.
# Line 4632  sub _tree_construction_main ($) { Line 2169  sub _tree_construction_main ($) {
2169            !!!cp ('t97');            !!!cp ('t97');
2170          }          }
2171    
2172              if ($token->{tag_name} eq 'base') {          if ($token->{tag_name} eq 'base') {
2173                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2174                  !!!cp ('t98');              !!!cp ('t98');
2175                  ## As if </noscript>              ## As if </noscript>
2176                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2177                  !!!parse-error (type => 'in noscript', text => 'base',              !!!parse-error (type => 'in noscript', text => 'base',
2178                                  token => $token);                              token => $token);
2179                            
2180                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2181                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2182                } else {            } else {
2183                  !!!cp ('t99');              !!!cp ('t99');
2184                }            }
2185    
2186                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2187                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2188                  !!!cp ('t100');              !!!cp ('t100');
2189                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2190                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2191                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2192                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2193                } else {              $self->{head_element_inserted} = 1;
2194                  !!!cp ('t101');            } else {
2195                }              !!!cp ('t101');
2196                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2197                pop @{$self->{open_elements}};            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2198                pop @{$self->{open_elements}} # <head>            pop @{$self->{open_elements}};
2199                    if $self->{insertion_mode} == AFTER_HEAD_IM;            pop @{$self->{open_elements}} # <head>
2200                !!!nack ('t101.1');                if $self->{insertion_mode} == AFTER_HEAD_IM;
2201                !!!next-token;            !!!nack ('t101.1');
2202                next B;            !!!next-token;
2203              next B;
2204          } elsif ($token->{tag_name} eq 'link') {          } elsif ($token->{tag_name} eq 'link') {
2205            ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2206            if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
# Line 4671  sub _tree_construction_main ($) { Line 2209  sub _tree_construction_main ($) {
2209                              text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2210              push @{$self->{open_elements}},              push @{$self->{open_elements}},
2211                  [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2212                $self->{head_element_inserted} = 1;
2213            } else {            } else {
2214              !!!cp ('t103');              !!!cp ('t103');
2215            }            }
# Line 4681  sub _tree_construction_main ($) { Line 2220  sub _tree_construction_main ($) {
2220            !!!ack ('t103.1');            !!!ack ('t103.1');
2221            !!!next-token;            !!!next-token;
2222            next B;            next B;
2223          } elsif ($token->{tag_name} eq 'command' or          } elsif ($token->{tag_name} eq 'command') {
                  $token->{tag_name} eq 'eventsource') {  
2224            if ($self->{insertion_mode} == IN_HEAD_IM) {            if ($self->{insertion_mode} == IN_HEAD_IM) {
2225              ## NOTE: If the insertion mode at the time of the emission              ## NOTE: If the insertion mode at the time of the emission
2226              ## of the token was "before head", $self->{insertion_mode}              ## of the token was "before head", $self->{insertion_mode}
# Line 4703  sub _tree_construction_main ($) { Line 2241  sub _tree_construction_main ($) {
2241              !!!cp ('t103.3');              !!!cp ('t103.3');
2242              #              #
2243            }            }
2244              } elsif ($token->{tag_name} eq 'meta') {          } elsif ($token->{tag_name} eq 'meta') {
2245                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2246                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2247                  !!!cp ('t104');              !!!cp ('t104');
2248                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2249                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2250                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2251                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2252                } else {              $self->{head_element_inserted} = 1;
2253                  !!!cp ('t105');            } else {
2254                }              !!!cp ('t105');
2255                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2256                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2257              my $meta_el = pop @{$self->{open_elements}};
2258    
2259                unless ($self->{confident}) {                unless ($self->{confident}) {
2260                  if ($token->{attributes}->{charset}) {                  if ($token->{attributes}->{charset}) {
# Line 4773  sub _tree_construction_main ($) { Line 2312  sub _tree_construction_main ($) {
2312                !!!ack ('t110.1');                !!!ack ('t110.1');
2313                !!!next-token;                !!!next-token;
2314                next B;                next B;
2315              } elsif ($token->{tag_name} eq 'title') {          } elsif ($token->{tag_name} eq 'title') {
2316                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2317                  !!!cp ('t111');              !!!cp ('t111');
2318                  ## As if </noscript>              ## As if </noscript>
2319                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2320                  !!!parse-error (type => 'in noscript', text => 'title',              !!!parse-error (type => 'in noscript', text => 'title',
2321                                  token => $token);                              token => $token);
2322                            
2323                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2324                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2325                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2326                  !!!cp ('t112');              !!!cp ('t112');
2327                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2328                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2329                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2330                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2331                } else {              $self->{head_element_inserted} = 1;
2332                  !!!cp ('t113');            } else {
2333                }              !!!cp ('t113');
2334              }
2335    
2336                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2337                my $parent = defined $self->{head_element} ? $self->{head_element}            $parse_rcdata->(RCDATA_CONTENT_MODEL);
2338                    : $self->{open_elements}->[-1]->[0];  
2339                $parse_rcdata->(RCDATA_CONTENT_MODEL);            ## NOTE: At this point the stack of open elements contain
2340                pop @{$self->{open_elements}} # <head>            ## the |head| element (index == -2) and the |script| element
2341                    if $self->{insertion_mode} == AFTER_HEAD_IM;            ## (index == -1).  In the "after head" insertion mode the
2342                next B;            ## |head| element is inserted only for the purpose of
2343              } elsif ($token->{tag_name} eq 'style' or            ## providing the context for the |script| element, and
2344                       $token->{tag_name} eq 'noframes') {            ## therefore we can now and have to remove the element from
2345                ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and            ## the stack.
2346                ## insertion mode IN_HEAD_IM)            splice @{$self->{open_elements}}, -2, 1, () # <head>
2347                ## NOTE: There is a "as if in head" code clone.                if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2348                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            next B;
2349                  !!!cp ('t114');          } elsif ($token->{tag_name} eq 'style' or
2350                  !!!parse-error (type => 'after head',                   $token->{tag_name} eq 'noframes') {
2351                                  text => $token->{tag_name}, token => $token);            ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
2352                  push @{$self->{open_elements}},            ## insertion mode IN_HEAD_IM)
2353                      [$self->{head_element}, $el_category->{head}];            ## NOTE: There is a "as if in head" code clone.
2354                } else {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2355                  !!!cp ('t115');              !!!cp ('t114');
2356                }              !!!parse-error (type => 'after head',
2357                $parse_rcdata->(CDATA_CONTENT_MODEL);                              text => $token->{tag_name}, token => $token);
2358                pop @{$self->{open_elements}} # <head>              push @{$self->{open_elements}},
2359                    if $self->{insertion_mode} == AFTER_HEAD_IM;                  [$self->{head_element}, $el_category->{head}];
2360                next B;              $self->{head_element_inserted} = 1;
2361              } elsif ($token->{tag_name} eq 'noscript') {            } else {
2362                !!!cp ('t115');
2363              }
2364              $parse_rcdata->(CDATA_CONTENT_MODEL);
2365              ## ISSUE: A spec bug [Bug 6038]
2366              splice @{$self->{open_elements}}, -2, 1, () # <head>
2367                  if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2368              next B;
2369            } elsif ($token->{tag_name} eq 'noscript') {
2370                if ($self->{insertion_mode} == IN_HEAD_IM) {                if ($self->{insertion_mode} == IN_HEAD_IM) {
2371                  !!!cp ('t116');                  !!!cp ('t116');
2372                  ## NOTE: and scripting is disalbed                  ## NOTE: and scripting is disalbed
# Line 4839  sub _tree_construction_main ($) { Line 2387  sub _tree_construction_main ($) {
2387                  !!!cp ('t118');                  !!!cp ('t118');
2388                  #                  #
2389                }                }
2390              } elsif ($token->{tag_name} eq 'script') {          } elsif ($token->{tag_name} eq 'script') {
2391                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2392                  !!!cp ('t119');              !!!cp ('t119');
2393                  ## As if </noscript>              ## As if </noscript>
2394                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2395                  !!!parse-error (type => 'in noscript', text => 'script',              !!!parse-error (type => 'in noscript', text => 'script',
2396                                  token => $token);                              token => $token);
2397                            
2398                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2399                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2400                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2401                  !!!cp ('t120');              !!!cp ('t120');
2402                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2403                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2404                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2405                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2406                } else {              $self->{head_element_inserted} = 1;
2407                  !!!cp ('t121');            } else {
2408                }              !!!cp ('t121');
2409              }
2410    
2411                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2412                $script_start_tag->();            $script_start_tag->();
2413                pop @{$self->{open_elements}} # <head>            ## ISSUE: A spec bug  [Bug 6038]
2414                    if $self->{insertion_mode} == AFTER_HEAD_IM;            splice @{$self->{open_elements}}, -2, 1 # <head>
2415                next B;                if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2416              } elsif ($token->{tag_name} eq 'body' or            next B;
2417                       $token->{tag_name} eq 'frameset') {          } elsif ($token->{tag_name} eq 'body' or
2418                     $token->{tag_name} eq 'frameset') {
2419                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2420                  !!!cp ('t122');                  !!!cp ('t122');
2421                  ## As if </noscript>                  ## As if </noscript>
# Line 5000  sub _tree_construction_main ($) { Line 2550  sub _tree_construction_main ($) {
2550              } elsif ({              } elsif ({
2551                        body => 1, html => 1,                        body => 1, html => 1,
2552                       }->{$token->{tag_name}}) {                       }->{$token->{tag_name}}) {
2553                if ($self->{insertion_mode} == BEFORE_HEAD_IM or                ## TODO: This branch is entirely redundant.
2554                  if ($self->{insertion_mode} == BEFORE_HEAD_IM or
2555                    $self->{insertion_mode} == IN_HEAD_IM or                    $self->{insertion_mode} == IN_HEAD_IM or
2556                    $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                    $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2557                  !!!cp ('t140');                  !!!cp ('t140');
# Line 5026  sub _tree_construction_main ($) { Line 2577  sub _tree_construction_main ($) {
2577                ## Ignore the token                ## Ignore the token
2578                !!!next-token;                !!!next-token;
2579                next B;                next B;
2580              } elsif ($token->{tag_name} eq 'br') {          } elsif ($token->{tag_name} eq 'br') {
2581                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {            if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2582                  !!!cp ('t142.2');              !!!cp ('t142.2');
2583                  ## (before head) as if <head>, (in head) as if </head>              ## (before head) as if <head>, (in head) as if </head>
2584                  !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);              !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);
2585                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});              $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
2586                  $self->{insertion_mode} = AFTER_HEAD_IM;              $self->{insertion_mode} = AFTER_HEAD_IM;
2587        
2588                  ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2589                } elsif ($self->{insertion_mode} == IN_HEAD_IM) {            } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
2590                  !!!cp ('t143.2');              !!!cp ('t143.2');
2591                  ## As if </head>              ## As if </head>
2592                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2593                  $self->{insertion_mode} = AFTER_HEAD_IM;              $self->{insertion_mode} = AFTER_HEAD_IM;
2594        
2595                  ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2596                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2597                  !!!cp ('t143.3');              !!!cp ('t143.3');
2598                  ## ISSUE: Two parse errors for <head><noscript></br>              ## NOTE: Two parse errors for <head><noscript></br>
2599                  !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
2600                                  text => 'br', token => $token);                              text => 'br', token => $token);
2601                  ## As if </noscript>              ## As if </noscript>
2602                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2603                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2604    
2605                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2606                  ## As if </head>              ## As if </head>
2607                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2608                  $self->{insertion_mode} = AFTER_HEAD_IM;              $self->{insertion_mode} = AFTER_HEAD_IM;
2609    
2610                  ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2611                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2612                  !!!cp ('t143.4');              !!!cp ('t143.4');
2613                  #              #
2614                } else {            } else {
2615                  die "$0: $self->{insertion_mode}: Unknown insertion mode";              die "$0: $self->{insertion_mode}: Unknown insertion mode";
2616                }            }
2617    
2618                ## ISSUE: does not agree with IE7 - it doesn't ignore </br>.            #
2619                !!!parse-error (type => 'unmatched end tag',          } else { ## Other end tags
                               text => 'br', token => $token);  
               ## Ignore the token  
               !!!next-token;  
               next B;  
             } else {  
2620                !!!cp ('t145');                !!!cp ('t145');
2621                !!!parse-error (type => 'unmatched end tag',                !!!parse-error (type => 'unmatched end tag',
2622                                text => $token->{tag_name}, token => $token);                                text => $token->{tag_name}, token => $token);
# Line 5114  sub _tree_construction_main ($) { Line 2660  sub _tree_construction_main ($) {
2660              !!!insert-element ('body',, $token);              !!!insert-element ('body',, $token);
2661              $self->{insertion_mode} = IN_BODY_IM;              $self->{insertion_mode} = IN_BODY_IM;
2662              ## reprocess              ## reprocess
2663              next B;          next B;
2664        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
2665          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2666            !!!cp ('t149.1');            !!!cp ('t149.1');
# Line 5172  sub _tree_construction_main ($) { Line 2718  sub _tree_construction_main ($) {
2718        } else {        } else {
2719          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
2720        }        }
   
           ## ISSUE: An issue in the spec.  
2721      } elsif ($self->{insertion_mode} & BODY_IMS) {      } elsif ($self->{insertion_mode} & BODY_IMS) {
2722            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
2723              !!!cp ('t150');              !!!cp ('t150');
# Line 5189  sub _tree_construction_main ($) { Line 2733  sub _tree_construction_main ($) {
2733                   caption => 1, col => 1, colgroup => 1, tbody => 1,                   caption => 1, col => 1, colgroup => 1, tbody => 1,
2734                   td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,                   td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,
2735                  }->{$token->{tag_name}}) {                  }->{$token->{tag_name}}) {
2736                if ($self->{insertion_mode} == IN_CELL_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2737                  ## have an element in table scope                  ## have an element in table scope
2738                  for (reverse 0..$#{$self->{open_elements}}) {                  for (reverse 0..$#{$self->{open_elements}}) {
2739                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
2740                    if ($node->[1] & TABLE_CELL_EL) {                    if ($node->[1] == TABLE_CELL_EL) {
2741                      !!!cp ('t151');                      !!!cp ('t151');
2742    
2743                      ## Close the cell                      ## Close the cell
# Line 5217  sub _tree_construction_main ($) { Line 2761  sub _tree_construction_main ($) {
2761                  !!!nack ('t153.1');                  !!!nack ('t153.1');
2762                  !!!next-token;                  !!!next-token;
2763                  next B;                  next B;
2764                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2765                  !!!parse-error (type => 'not closed', text => 'caption',                  !!!parse-error (type => 'not closed', text => 'caption',
2766                                  token => $token);                                  token => $token);
2767                                    
# Line 5227  sub _tree_construction_main ($) { Line 2771  sub _tree_construction_main ($) {
2771                  INSCOPE: {                  INSCOPE: {
2772                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2773                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2774                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2775                        !!!cp ('t155');                        !!!cp ('t155');
2776                        $i = $_;                        $i = $_;
2777                        last INSCOPE;                        last INSCOPE;
# Line 5253  sub _tree_construction_main ($) { Line 2797  sub _tree_construction_main ($) {
2797                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2798                  }                  }
2799    
2800                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2801                    !!!cp ('t159');                    !!!cp ('t159');
2802                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2803                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5282  sub _tree_construction_main ($) { Line 2826  sub _tree_construction_main ($) {
2826              }              }
2827            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
2828              if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {              if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {
2829                if ($self->{insertion_mode} == IN_CELL_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2830                  ## have an element in table scope                  ## have an element in table scope
2831                  my $i;                  my $i;
2832                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 5332  sub _tree_construction_main ($) { Line 2876  sub _tree_construction_main ($) {
2876                                    
2877                  !!!next-token;                  !!!next-token;
2878                  next B;                  next B;
2879                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2880                  !!!cp ('t169');                  !!!cp ('t169');
2881                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2882                                  text => $token->{tag_name}, token => $token);                                  text => $token->{tag_name}, token => $token);
# Line 5344  sub _tree_construction_main ($) { Line 2888  sub _tree_construction_main ($) {
2888                  #                  #
2889                }                }
2890              } elsif ($token->{tag_name} eq 'caption') {              } elsif ($token->{tag_name} eq 'caption') {
2891                if ($self->{insertion_mode} == IN_CAPTION_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2892                  ## have a table element in table scope                  ## have a table element in table scope
2893                  my $i;                  my $i;
2894                  INSCOPE: {                  INSCOPE: {
2895                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2896                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2897                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2898                        !!!cp ('t171');                        !!!cp ('t171');
2899                        $i = $_;                        $i = $_;
2900                        last INSCOPE;                        last INSCOPE;
# Line 5375  sub _tree_construction_main ($) { Line 2919  sub _tree_construction_main ($) {
2919                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2920                  }                  }
2921                                    
2922                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2923                    !!!cp ('t175');                    !!!cp ('t175');
2924                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2925                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5393  sub _tree_construction_main ($) { Line 2937  sub _tree_construction_main ($) {
2937                                    
2938                  !!!next-token;                  !!!next-token;
2939                  next B;                  next B;
2940                } elsif ($self->{insertion_mode} == IN_CELL_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2941                  !!!cp ('t177');                  !!!cp ('t177');
2942                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2943                                  text => $token->{tag_name}, token => $token);                                  text => $token->{tag_name}, token => $token);
# Line 5408  sub _tree_construction_main ($) { Line 2952  sub _tree_construction_main ($) {
2952                        table => 1, tbody => 1, tfoot => 1,                        table => 1, tbody => 1, tfoot => 1,
2953                        thead => 1, tr => 1,                        thead => 1, tr => 1,
2954                       }->{$token->{tag_name}} and                       }->{$token->{tag_name}} and
2955                       $self->{insertion_mode} == IN_CELL_IM) {                       ($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2956                ## have an element in table scope                ## have an element in table scope
2957                my $i;                my $i;
2958                my $tn;                my $tn;
# Line 5425  sub _tree_construction_main ($) { Line 2969  sub _tree_construction_main ($) {
2969                                line => $token->{line},                                line => $token->{line},
2970                                column => $token->{column}};                                column => $token->{column}};
2971                      next B;                      next B;
2972                    } elsif ($node->[1] & TABLE_CELL_EL) {                    } elsif ($node->[1] == TABLE_CELL_EL) {
2973                      !!!cp ('t180');                      !!!cp ('t180');
2974                      $tn = $node->[0]->manakai_local_name;                      $tn = $node->[0]->manakai_local_name;
2975                      ## NOTE: There is exactly one |td| or |th| element                      ## NOTE: There is exactly one |td| or |th| element
# Line 5445  sub _tree_construction_main ($) { Line 2989  sub _tree_construction_main ($) {
2989                  next B;                  next B;
2990                } # INSCOPE                } # INSCOPE
2991              } elsif ($token->{tag_name} eq 'table' and              } elsif ($token->{tag_name} eq 'table' and
2992                       $self->{insertion_mode} == IN_CAPTION_IM) {                       ($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2993                !!!parse-error (type => 'not closed', text => 'caption',                !!!parse-error (type => 'not closed', text => 'caption',
2994                                token => $token);                                token => $token);
2995    
# Line 5454  sub _tree_construction_main ($) { Line 2998  sub _tree_construction_main ($) {
2998                my $i;                my $i;
2999                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3000                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3001                  if ($node->[1] & CAPTION_EL) {                  if ($node->[1] == CAPTION_EL) {
3002                    !!!cp ('t184');                    !!!cp ('t184');
3003                    $i = $_;                    $i = $_;
3004                    last INSCOPE;                    last INSCOPE;
# Line 5465  sub _tree_construction_main ($) { Line 3009  sub _tree_construction_main ($) {
3009                } # INSCOPE                } # INSCOPE
3010                unless (defined $i) {                unless (defined $i) {
3011                  !!!cp ('t186');                  !!!cp ('t186');
3012            ## TODO: Wrong error type?
3013                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
3014                                  text => 'caption', token => $token);                                  text => 'caption', token => $token);
3015                  ## Ignore the token                  ## Ignore the token
# Line 5478  sub _tree_construction_main ($) { Line 3023  sub _tree_construction_main ($) {
3023                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3024                }                }
3025    
3026                unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
3027                  !!!cp ('t188');                  !!!cp ('t188');
3028                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
3029                                  text => $self->{open_elements}->[-1]->[0]                                  text => $self->{open_elements}->[-1]->[0]
# Line 5510  sub _tree_construction_main ($) { Line 3055  sub _tree_construction_main ($) {
3055                  !!!cp ('t191');                  !!!cp ('t191');
3056                  #                  #
3057                }                }
3058              } elsif ({          } elsif ({
3059                        tbody => 1, tfoot => 1,                    tbody => 1, tfoot => 1,
3060                        thead => 1, tr => 1,                    thead => 1, tr => 1,
3061                       }->{$token->{tag_name}} and                   }->{$token->{tag_name}} and
3062                       $self->{insertion_mode} == IN_CAPTION_IM) {                   ($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
3063                !!!cp ('t192');            !!!cp ('t192');
3064                !!!parse-error (type => 'unmatched end tag',            !!!parse-error (type => 'unmatched end tag',
3065                                text => $token->{tag_name}, token => $token);                            text => $token->{tag_name}, token => $token);
3066                ## Ignore the token            ## Ignore the token
3067                !!!next-token;            !!!next-token;
3068                next B;            next B;
3069              } else {          } else {
3070                !!!cp ('t193');            !!!cp ('t193');
3071                #            #
3072              }          }
3073        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3074          for my $entry (@{$self->{open_elements}}) {          for my $entry (@{$self->{open_elements}}) {
3075            unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) {            unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) {
# Line 5543  sub _tree_construction_main ($) { Line 3088  sub _tree_construction_main ($) {
3088        $insert = $insert_to_current;        $insert = $insert_to_current;
3089        #        #
3090      } elsif ($self->{insertion_mode} & TABLE_IMS) {      } elsif ($self->{insertion_mode} & TABLE_IMS) {
3091        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);  
   
             ## As if in body, but insert into foster parent element  
             ## ISSUE: Spec says that "whenever a node would be inserted  
             ## into the current node" while characters might not be  
             ## result in a new Text node.  
             $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) {  
                     !!!cp ('t196');  
                     $foster_parent_element = $parent;  
                     $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;  
               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  
         } else {  
           !!!cp ('t200');  
           $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});  
         }  
               
         !!!next-token;  
         next B;  
       } elsif ($token->{type} == START_TAG_TOKEN) {  
3092          if ({          if ({
3093               tr => ($self->{insertion_mode} != IN_ROW_IM),               tr => (($self->{insertion_mode} & IM_MASK) != IN_ROW_IM),
3094               th => 1, td => 1,               th => 1, td => 1,
3095              }->{$token->{tag_name}}) {              }->{$token->{tag_name}}) {
3096            if ($self->{insertion_mode} == IN_TABLE_IM) {            if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_IM) {
3097              ## Clear back to table context              ## Clear back to table context
3098              while (not ($self->{open_elements}->[-1]->[1]              while (not ($self->{open_elements}->[-1]->[1]
3099                              & TABLE_SCOPING_EL)) {                              & TABLE_SCOPING_EL)) {
# Line 5625  sub _tree_construction_main ($) { Line 3106  sub _tree_construction_main ($) {
3106              ## reprocess in the "in table body" insertion mode...              ## reprocess in the "in table body" insertion mode...
3107            }            }
3108                        
3109            if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {            if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3110              unless ($token->{tag_name} eq 'tr') {              unless ($token->{tag_name} eq 'tr') {
3111                !!!cp ('t202');                !!!cp ('t202');
3112                !!!parse-error (type => 'missing start tag:tr', token => $token);                !!!parse-error (type => 'missing start tag:tr', token => $token);
# Line 5639  sub _tree_construction_main ($) { Line 3120  sub _tree_construction_main ($) {
3120                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3121              }              }
3122                                    
3123                  $self->{insertion_mode} = IN_ROW_IM;              $self->{insertion_mode} = IN_ROW_IM;
3124                  if ($token->{tag_name} eq 'tr') {              if ($token->{tag_name} eq 'tr') {
3125                    !!!cp ('t204');                !!!cp ('t204');
3126                    !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3127                    !!!nack ('t204');                $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3128                    !!!next-token;                !!!nack ('t204');
3129                    next B;                !!!next-token;
3130                  } else {                next B;
3131                    !!!cp ('t205');              } else {
3132                    !!!insert-element ('tr',, $token);                !!!cp ('t205');
3133                    ## reprocess in the "in row" insertion mode                !!!insert-element ('tr',, $token);
3134                  }                ## reprocess in the "in row" insertion mode
3135                } else {              }
3136                  !!!cp ('t206');            } else {
3137                }              !!!cp ('t206');
3138              }
3139    
3140                ## Clear back to table row context                ## Clear back to table row context
3141                while (not ($self->{open_elements}->[-1]->[1]                while (not ($self->{open_elements}->[-1]->[1]
# Line 5662  sub _tree_construction_main ($) { Line 3144  sub _tree_construction_main ($) {
3144                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3145                }                }
3146                                
3147                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3148                $self->{insertion_mode} = IN_CELL_IM;            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3149              $self->{insertion_mode} = IN_CELL_IM;
3150    
3151                push @$active_formatting_elements, ['#marker', ''];            push @$active_formatting_elements, ['#marker', ''];
3152                                
3153                !!!nack ('t207.1');            !!!nack ('t207.1');
3154              !!!next-token;
3155              next B;
3156            } elsif ({
3157                      caption => 1, col => 1, colgroup => 1,
3158                      tbody => 1, tfoot => 1, thead => 1,
3159                      tr => 1, # $self->{insertion_mode} == IN_ROW_IM
3160                     }->{$token->{tag_name}}) {
3161              if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3162                ## As if </tr>
3163                ## have an element in table scope
3164                my $i;
3165                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3166                  my $node = $self->{open_elements}->[$_];
3167                  if ($node->[1] == TABLE_ROW_EL) {
3168                    !!!cp ('t208');
3169                    $i = $_;
3170                    last INSCOPE;
3171                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
3172                    !!!cp ('t209');
3173                    last INSCOPE;
3174                  }
3175                } # INSCOPE
3176                unless (defined $i) {
3177                  !!!cp ('t210');
3178                  ## TODO: This type is wrong.
3179                  !!!parse-error (type => 'unmacthed end tag',
3180                                  text => $token->{tag_name}, token => $token);
3181                  ## Ignore the token
3182                  !!!nack ('t210.1');
3183                !!!next-token;                !!!next-token;
3184                next B;                next B;
3185              } elsif ({              }
                       caption => 1, col => 1, colgroup => 1,  
                       tbody => 1, tfoot => 1, thead => 1,  
                       tr => 1, # $self->{insertion_mode} == IN_ROW_IM  
                      }->{$token->{tag_name}}) {  
               if ($self->{insertion_mode} == IN_ROW_IM) {  
                 ## As if </tr>  
                 ## have an element in table scope  
                 my $i;  
                 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {  
                   my $node = $self->{open_elements}->[$_];  
                   if ($node->[1] & TABLE_ROW_EL) {  
                     !!!cp ('t208');  
                     $i = $_;  
                     last INSCOPE;  
                   } elsif ($node->[1] & TABLE_SCOPING_EL) {  
                     !!!cp ('t209');  
                     last INSCOPE;  
                   }  
                 } # INSCOPE  
                 unless (defined $i) {  
                   !!!cp ('t210');  
 ## TODO: This type is wrong.  
                   !!!parse-error (type => 'unmacthed end tag',  
                                   text => $token->{tag_name}, token => $token);  
                   ## Ignore the token  
                   !!!nack ('t210.1');  
                   !!!next-token;  
                   next B;  
                 }  
3186                                    
3187                  ## Clear back to table row context                  ## Clear back to table row context
3188                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
# Line 5722  sub _tree_construction_main ($) { Line 3205  sub _tree_construction_main ($) {
3205                  }                  }
3206                }                }
3207    
3208                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3209                  ## have an element in table scope                  ## have an element in table scope
3210                  my $i;                  my $i;
3211                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3212                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3213                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3214                      !!!cp ('t214');                      !!!cp ('t214');
3215                      $i = $_;                      $i = $_;
3216                      last INSCOPE;                      last INSCOPE;
# Line 5769  sub _tree_construction_main ($) { Line 3252  sub _tree_construction_main ($) {
3252                  !!!cp ('t218');                  !!!cp ('t218');
3253                }                }
3254    
3255                if ($token->{tag_name} eq 'col') {            if ($token->{tag_name} eq 'col') {
3256                  ## Clear back to table context              ## Clear back to table context
3257                  while (not ($self->{open_elements}->[-1]->[1]              while (not ($self->{open_elements}->[-1]->[1]
3258                                  & TABLE_SCOPING_EL)) {                              & TABLE_SCOPING_EL)) {
3259                    !!!cp ('t219');                !!!cp ('t219');
3260                    ## ISSUE: Can this state be reached?                ## ISSUE: Can this state be reached?
3261                    pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3262                  }              }
3263                                
3264                  !!!insert-element ('colgroup',, $token);              !!!insert-element ('colgroup',, $token);
3265                  $self->{insertion_mode} = IN_COLUMN_GROUP_IM;              $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
3266                  ## reprocess              ## reprocess
3267                  !!!ack-later;              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3268                  next B;              !!!ack-later;
3269                } elsif ({              next B;
3270                          caption => 1,            } elsif ({
3271                          colgroup => 1,                      caption => 1,
3272                          tbody => 1, tfoot => 1, thead => 1,                      colgroup => 1,
3273                         }->{$token->{tag_name}}) {                      tbody => 1, tfoot => 1, thead => 1,
3274                  ## Clear back to table context                     }->{$token->{tag_name}}) {
3275                ## Clear back to table context
3276                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
3277                                  & TABLE_SCOPING_EL)) {                                  & TABLE_SCOPING_EL)) {
3278                    !!!cp ('t220');                    !!!cp ('t220');
# Line 5796  sub _tree_construction_main ($) { Line 3280  sub _tree_construction_main ($) {
3280                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
3281                  }                  }
3282                                    
3283                  push @$active_formatting_elements, ['#marker', '']              push @$active_formatting_elements, ['#marker', '']
3284                      if $token->{tag_name} eq 'caption';                  if $token->{tag_name} eq 'caption';
3285                                    
3286                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);              !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3287                  $self->{insertion_mode} = {              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3288                                             caption => IN_CAPTION_IM,              $self->{insertion_mode} = {
3289                                             colgroup => IN_COLUMN_GROUP_IM,                                         caption => IN_CAPTION_IM,
3290                                             tbody => IN_TABLE_BODY_IM,                                         colgroup => IN_COLUMN_GROUP_IM,
3291                                             tfoot => IN_TABLE_BODY_IM,                                         tbody => IN_TABLE_BODY_IM,
3292                                             thead => IN_TABLE_BODY_IM,                                         tfoot => IN_TABLE_BODY_IM,
3293                                            }->{$token->{tag_name}};                                         thead => IN_TABLE_BODY_IM,
3294                  !!!next-token;                                        }->{$token->{tag_name}};
3295                  !!!nack ('t220.1');              !!!next-token;
3296                  next B;              !!!nack ('t220.1');
3297                } else {              next B;
3298                  die "$0: in table: <>: $token->{tag_name}";            } else {
3299                }              die "$0: in table: <>: $token->{tag_name}";
3300              }
3301              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
3302                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
3303                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
# Line 5824  sub _tree_construction_main ($) { Line 3309  sub _tree_construction_main ($) {
3309                my $i;                my $i;
3310                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3311                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3312                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3313                    !!!cp ('t221');                    !!!cp ('t221');
3314                    $i = $_;                    $i = $_;
3315                    last INSCOPE;                    last INSCOPE;
# Line 5851  sub _tree_construction_main ($) { Line 3336  sub _tree_construction_main ($) {
3336                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3337                }                }
3338    
3339                unless ($self->{open_elements}->[-1]->[1] & TABLE_EL) {                unless ($self->{open_elements}->[-1]->[1] == TABLE_EL) {
3340                  !!!cp ('t225');                  !!!cp ('t225');
3341                  ## NOTE: |<table><tr><table>|                  ## NOTE: |<table><tr><table>|
3342                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
# Line 5871  sub _tree_construction_main ($) { Line 3356  sub _tree_construction_main ($) {
3356            !!!ack-later;            !!!ack-later;
3357            next B;            next B;
3358          } elsif ($token->{tag_name} eq 'style') {          } elsif ($token->{tag_name} eq 'style') {
3359            if (not $open_tables->[-1]->[1]) { # tainted            !!!cp ('t227.8');
3360              !!!cp ('t227.8');            ## NOTE: This is a "as if in head" code clone.
3361              ## NOTE: This is a "as if in head" code clone.            $parse_rcdata->(CDATA_CONTENT_MODEL);
3362              $parse_rcdata->(CDATA_CONTENT_MODEL);            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3363              next B;            next B;
           } else {  
             !!!cp ('t227.7');  
             #  
           }  
3364          } elsif ($token->{tag_name} eq 'script') {          } elsif ($token->{tag_name} eq 'script') {
3365            if (not $open_tables->[-1]->[1]) { # tainted            !!!cp ('t227.6');
3366              !!!cp ('t227.6');            ## NOTE: This is a "as if in head" code clone.
3367              ## NOTE: This is a "as if in head" code clone.            $script_start_tag->();
3368              $script_start_tag->();            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3369              next B;            next B;
           } else {  
             !!!cp ('t227.5');  
             #  
           }  
3370          } elsif ($token->{tag_name} eq 'input') {          } elsif ($token->{tag_name} eq 'input') {
3371            if (not $open_tables->[-1]->[1]) { # tainted            if ($token->{attributes}->{type}) {
3372              if ($token->{attributes}->{type}) { ## TODO: case              my $type = $token->{attributes}->{type}->{value};
3373                my $type = lc $token->{attributes}->{type}->{value};              $type =~ tr/A-Z/a-z/; ## ASCII case-insensitive.
3374                if ($type eq 'hidden') {              if ($type eq 'hidden') {
3375                  !!!cp ('t227.3');                !!!cp ('t227.3');
3376                  !!!parse-error (type => 'in table',                !!!parse-error (type => 'in table',
3377                                  text => $token->{tag_name}, token => $token);                                text => $token->{tag_name}, token => $token);
3378    
3379                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3380                  $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3381    
3382                  ## TODO: form element pointer                ## TODO: form element pointer
3383    
3384                  pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3385    
3386                  !!!next-token;                !!!next-token;
3387                  !!!ack ('t227.2.1');                !!!ack ('t227.2.1');
3388                  next B;                next B;
               } else {  
                 !!!cp ('t227.2');  
                 #  
               }  
3389              } else {              } else {
3390                !!!cp ('t227.1');                !!!cp ('t227.1');
3391                #                #
# Line 5931  sub _tree_construction_main ($) { Line 3405  sub _tree_construction_main ($) {
3405          $insert = $insert_to_foster;          $insert = $insert_to_foster;
3406          #          #
3407        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
3408              if ($token->{tag_name} eq 'tr' and          if ($token->{tag_name} eq 'tr' and
3409                  $self->{insertion_mode} == IN_ROW_IM) {              ($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3410                ## have an element in table scope            ## have an element in table scope
3411                my $i;                my $i;
3412                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3413                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3414                  if ($node->[1] & TABLE_ROW_EL) {                  if ($node->[1] == TABLE_ROW_EL) {
3415                    !!!cp ('t228');                    !!!cp ('t228');
3416                    $i = $_;                    $i = $_;
3417                    last INSCOPE;                    last INSCOPE;
# Line 5972  sub _tree_construction_main ($) { Line 3446  sub _tree_construction_main ($) {
3446                !!!nack ('t231.1');                !!!nack ('t231.1');
3447                next B;                next B;
3448              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
3449                if ($self->{insertion_mode} == IN_ROW_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3450                  ## As if </tr>                  ## As if </tr>
3451                  ## have an element in table scope                  ## have an element in table scope
3452                  my $i;                  my $i;
3453                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3454                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3455                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3456                      !!!cp ('t233');                      !!!cp ('t233');
3457                      $i = $_;                      $i = $_;
3458                      last INSCOPE;                      last INSCOPE;
# Line 6011  sub _tree_construction_main ($) { Line 3485  sub _tree_construction_main ($) {
3485                  ## reprocess in the "in table body" insertion mode...                  ## reprocess in the "in table body" insertion mode...
3486                }                }
3487    
3488                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3489                  ## have an element in table scope                  ## have an element in table scope
3490                  my $i;                  my $i;
3491                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3492                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3493                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3494                      !!!cp ('t237');                      !!!cp ('t237');
3495                      $i = $_;                      $i = $_;
3496                      last INSCOPE;                      last INSCOPE;
# Line 6063  sub _tree_construction_main ($) { Line 3537  sub _tree_construction_main ($) {
3537                my $i;                my $i;
3538                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3539                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3540                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3541                    !!!cp ('t241');                    !!!cp ('t241');
3542                    $i = $_;                    $i = $_;
3543                    last INSCOPE;                    last INSCOPE;
# Line 6093  sub _tree_construction_main ($) { Line 3567  sub _tree_construction_main ($) {
3567                        tbody => 1, tfoot => 1, thead => 1,                        tbody => 1, tfoot => 1, thead => 1,
3568                       }->{$token->{tag_name}} and                       }->{$token->{tag_name}} and
3569                       $self->{insertion_mode} & ROW_IMS) {                       $self->{insertion_mode} & ROW_IMS) {
3570                if ($self->{insertion_mode} == IN_ROW_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3571                  ## have an element in table scope                  ## have an element in table scope
3572                  my $i;                  my $i;
3573                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 6122  sub _tree_construction_main ($) { Line 3596  sub _tree_construction_main ($) {
3596                  my $i;                  my $i;
3597                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3598                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3599                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3600                      !!!cp ('t250');                      !!!cp ('t250');
3601                      $i = $_;                      $i = $_;
3602                      last INSCOPE;                      last INSCOPE;
# Line 6212  sub _tree_construction_main ($) { Line 3686  sub _tree_construction_main ($) {
3686            #            #
3687          }          }
3688        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3689          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
3690                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
3691            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
3692            !!!cp ('t259.1');            !!!cp ('t259.1');
# Line 6227  sub _tree_construction_main ($) { Line 3701  sub _tree_construction_main ($) {
3701        } else {        } else {
3702          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
3703        }        }
3704      } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {      } elsif (($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) {
3705            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
3706              if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {              if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {
3707                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
# Line 6254  sub _tree_construction_main ($) { Line 3728  sub _tree_construction_main ($) {
3728              }              }
3729            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
3730              if ($token->{tag_name} eq 'colgroup') {              if ($token->{tag_name} eq 'colgroup') {
3731                if ($self->{open_elements}->[-1]->[1] & HTML_EL) {                if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3732                  !!!cp ('t264');                  !!!cp ('t264');
3733                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
3734                                  text => 'colgroup', token => $token);                                  text => 'colgroup', token => $token);
# Line 6280  sub _tree_construction_main ($) { Line 3754  sub _tree_construction_main ($) {
3754                #                #
3755              }              }
3756        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3757          if ($self->{open_elements}->[-1]->[1] & HTML_EL and          if ($self->{open_elements}->[-1]->[1] == HTML_EL and
3758              @{$self->{open_elements}} == 1) { # redundant, maybe              @{$self->{open_elements}} == 1) { # redundant, maybe
3759            !!!cp ('t270.2');            !!!cp ('t270.2');
3760            ## Stop parsing.            ## Stop parsing.
# Line 6298  sub _tree_construction_main ($) { Line 3772  sub _tree_construction_main ($) {
3772        }        }
3773    
3774            ## As if </colgroup>            ## As if </colgroup>
3775            if ($self->{open_elements}->[-1]->[1] & HTML_EL) {            if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3776              !!!cp ('t269');              !!!cp ('t269');
3777  ## TODO: Wrong error type?  ## TODO: Wrong error type?
3778              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6323  sub _tree_construction_main ($) { Line 3797  sub _tree_construction_main ($) {
3797          next B;          next B;
3798        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
3799          if ($token->{tag_name} eq 'option') {          if ($token->{tag_name} eq 'option') {
3800            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3801              !!!cp ('t272');              !!!cp ('t272');
3802              ## As if </option>              ## As if </option>
3803              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6336  sub _tree_construction_main ($) { Line 3810  sub _tree_construction_main ($) {
3810            !!!next-token;            !!!next-token;
3811            next B;            next B;
3812          } elsif ($token->{tag_name} eq 'optgroup') {          } elsif ($token->{tag_name} eq 'optgroup') {
3813            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3814              !!!cp ('t274');              !!!cp ('t274');
3815              ## As if </option>              ## As if </option>
3816              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6344  sub _tree_construction_main ($) { Line 3818  sub _tree_construction_main ($) {
3818              !!!cp ('t275');              !!!cp ('t275');
3819            }            }
3820    
3821            if ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3822              !!!cp ('t276');              !!!cp ('t276');
3823              ## As if </optgroup>              ## As if </optgroup>
3824              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6357  sub _tree_construction_main ($) { Line 3831  sub _tree_construction_main ($) {
3831            !!!next-token;            !!!next-token;
3832            next B;            next B;
3833          } elsif ({          } elsif ({
3834                     select => 1, input => 1, textarea => 1,                     select => 1, input => 1, textarea => 1, keygen => 1,
3835                   }->{$token->{tag_name}} or                   }->{$token->{tag_name}} or
3836                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and                   (($self->{insertion_mode} & IM_MASK)
3837                          == IN_SELECT_IN_TABLE_IM and
3838                    {                    {
3839                     caption => 1, table => 1,                     caption => 1, table => 1,
3840                     tbody => 1, tfoot => 1, thead => 1,                     tbody => 1, tfoot => 1, thead => 1,
3841                     tr => 1, td => 1, th => 1,                     tr => 1, td => 1, th => 1,
3842                    }->{$token->{tag_name}})) {                    }->{$token->{tag_name}})) {
3843            ## TODO: The type below is not good - <select> is replaced by </select>  
3844            !!!parse-error (type => 'not closed', text => 'select',            ## 1. Parse error.
3845                            token => $token);            if ($token->{tag_name} eq 'select') {
3846            ## NOTE: As if the token were </select> (<select> case) or                !!!parse-error (type => 'select in select', ## XXX: documentation
3847            ## as if there were </select> (otherwise).                                token => $token);
3848            ## have an element in table scope            } else {
3849                !!!parse-error (type => 'not closed', text => 'select',
3850                                token => $token);
3851              }
3852    
3853              ## 2./<select>-1. Unless "have an element in table scope" (select):
3854            my $i;            my $i;
3855            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3856              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3857              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3858                !!!cp ('t278');                !!!cp ('t278');
3859                $i = $_;                $i = $_;
3860                last INSCOPE;                last INSCOPE;
# Line 6385  sub _tree_construction_main ($) { Line 3865  sub _tree_construction_main ($) {
3865            } # INSCOPE            } # INSCOPE
3866            unless (defined $i) {            unless (defined $i) {
3867              !!!cp ('t280');              !!!cp ('t280');
3868              !!!parse-error (type => 'unmatched end tag',              if ($token->{tag_name} eq 'select') {
3869                              text => 'select', token => $token);                ## NOTE: This error would be raised when
3870              ## Ignore the token                ## |select.innerHTML = '<select>'| is executed; in this
3871                  ## case two errors, "select in select" and "unmatched
3872                  ## end tags" are reported to the user, the latter might
3873                  ## be confusing but this is what the spec requires.
3874                  !!!parse-error (type => 'unmatched end tag',
3875                                  text => 'select',
3876                                  token => $token);
3877                }
3878                ## Ignore the token.
3879              !!!nack ('t280.1');              !!!nack ('t280.1');
3880              !!!next-token;              !!!next-token;
3881              next B;              next B;
3882            }            }
3883    
3884              ## 3. Otherwise, as if there were <select>:
3885                                
3886            !!!cp ('t281');            !!!cp ('t281');
3887            splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
# Line 6408  sub _tree_construction_main ($) { Line 3898  sub _tree_construction_main ($) {
3898              ## Reprocess the token.              ## Reprocess the token.
3899              next B;              next B;
3900            }            }
3901            } elsif ($token->{tag_name} eq 'script') {
3902              !!!cp ('t281.3');
3903              ## NOTE: This is an "as if in head" code clone
3904              $script_start_tag->();
3905              next B;
3906          } else {          } else {
3907            !!!cp ('t282');            !!!cp ('t282');
3908            !!!parse-error (type => 'in select',            !!!parse-error (type => 'in select',
# Line 6419  sub _tree_construction_main ($) { Line 3914  sub _tree_construction_main ($) {
3914          }          }
3915        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
3916          if ($token->{tag_name} eq 'optgroup') {          if ($token->{tag_name} eq 'optgroup') {
3917            if ($self->{open_elements}->[-1]->[1] & OPTION_EL and            if ($self->{open_elements}->[-1]->[1] == OPTION_EL and
3918                $self->{open_elements}->[-2]->[1] & OPTGROUP_EL) {                $self->{open_elements}->[-2]->[1] == OPTGROUP_EL) {
3919              !!!cp ('t283');              !!!cp ('t283');
3920              ## As if </option>              ## As if </option>
3921              splice @{$self->{open_elements}}, -2;              splice @{$self->{open_elements}}, -2;
3922            } elsif ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            } elsif ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3923              !!!cp ('t284');              !!!cp ('t284');
3924              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3925            } else {            } else {
# Line 6437  sub _tree_construction_main ($) { Line 3932  sub _tree_construction_main ($) {
3932            !!!next-token;            !!!next-token;
3933            next B;            next B;
3934          } elsif ($token->{tag_name} eq 'option') {          } elsif ($token->{tag_name} eq 'option') {
3935            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3936              !!!cp ('t286');              !!!cp ('t286');
3937              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3938            } else {            } else {
# Line 6454  sub _tree_construction_main ($) { Line 3949  sub _tree_construction_main ($) {
3949            my $i;            my $i;
3950            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3951              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3952              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3953                !!!cp ('t288');                !!!cp ('t288');
3954                $i = $_;                $i = $_;
3955                last INSCOPE;                last INSCOPE;
# Line 6481  sub _tree_construction_main ($) { Line 3976  sub _tree_construction_main ($) {
3976            !!!nack ('t291.1');            !!!nack ('t291.1');
3977            !!!next-token;            !!!next-token;
3978            next B;            next B;
3979          } elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and          } elsif (($self->{insertion_mode} & IM_MASK)
3980                         == IN_SELECT_IN_TABLE_IM and
3981                   {                   {
3982                    caption => 1, table => 1, tbody => 1,                    caption => 1, table => 1, tbody => 1,
3983                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
# Line 6516  sub _tree_construction_main ($) { Line 4012  sub _tree_construction_main ($) {
4012            undef $i;            undef $i;
4013            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4014              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
4015              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
4016                !!!cp ('t295');                !!!cp ('t295');
4017                $i = $_;                $i = $_;
4018                last INSCOPE;                last INSCOPE;
# Line 6555  sub _tree_construction_main ($) { Line 4051  sub _tree_construction_main ($) {
4051            next B;            next B;
4052          }          }
4053        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4054          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
4055                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
4056            !!!cp ('t299.1');            !!!cp ('t299.1');
4057            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6742  sub _tree_construction_main ($) { Line 4238  sub _tree_construction_main ($) {
4238        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
4239          if ($token->{tag_name} eq 'frameset' and          if ($token->{tag_name} eq 'frameset' and
4240              $self->{insertion_mode} == IN_FRAMESET_IM) {              $self->{insertion_mode} == IN_FRAMESET_IM) {
4241            if ($self->{open_elements}->[-1]->[1] & HTML_EL and            if ($self->{open_elements}->[-1]->[1] == HTML_EL and
4242                @{$self->{open_elements}} == 1) {                @{$self->{open_elements}} == 1) {
4243              !!!cp ('t325');              !!!cp ('t325');
4244              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6756  sub _tree_construction_main ($) { Line 4252  sub _tree_construction_main ($) {
4252            }            }
4253    
4254            if (not defined $self->{inner_html_node} and            if (not defined $self->{inner_html_node} and
4255                not ($self->{open_elements}->[-1]->[1] & FRAMESET_EL)) {                not ($self->{open_elements}->[-1]->[1] == FRAMESET_EL)) {
4256              !!!cp ('t327');              !!!cp ('t327');
4257              $self->{insertion_mode} = AFTER_FRAMESET_IM;              $self->{insertion_mode} = AFTER_FRAMESET_IM;
4258            } else {            } else {
# Line 6788  sub _tree_construction_main ($) { Line 4284  sub _tree_construction_main ($) {
4284            next B;            next B;
4285          }          }
4286        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4287          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
4288                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
4289            !!!cp ('t331.1');            !!!cp ('t331.1');
4290            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6801  sub _tree_construction_main ($) { Line 4297  sub _tree_construction_main ($) {
4297        } else {        } else {
4298          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
4299        }        }
   
       ## ISSUE: An issue in spec here  
4300      } else {      } else {
4301        die "$0: $self->{insertion_mode}: Unknown insertion mode";        die "$0: $self->{insertion_mode}: Unknown insertion mode";
4302      }      }
# Line 6820  sub _tree_construction_main ($) { Line 4314  sub _tree_construction_main ($) {
4314          $parse_rcdata->(CDATA_CONTENT_MODEL);          $parse_rcdata->(CDATA_CONTENT_MODEL);
4315          next B;          next B;
4316        } elsif ({        } elsif ({
4317                  base => 1, command => 1, eventsource => 1, link => 1,                  base => 1, command => 1, link => 1,
4318                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
4319          !!!cp ('t334');          !!!cp ('t334');
4320          ## 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
# Line 6893  sub _tree_construction_main ($) { Line 4387  sub _tree_construction_main ($) {
4387          !!!parse-error (type => 'in body', text => 'body', token => $token);          !!!parse-error (type => 'in body', text => 'body', token => $token);
4388                                
4389          if (@{$self->{open_elements}} == 1 or          if (@{$self->{open_elements}} == 1 or
4390              not ($self->{open_elements}->[1]->[1] & BODY_EL)) {              not ($self->{open_elements}->[1]->[1] == BODY_EL)) {
4391            !!!cp ('t342');            !!!cp ('t342');
4392            ## Ignore the token            ## Ignore the token
4393          } else {          } else {
# Line 6928  sub _tree_construction_main ($) { Line 4422  sub _tree_construction_main ($) {
4422                  table => 1,                  table => 1,
4423                  hr => 1,                  hr => 1,
4424                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
4425    
4426            ## 1. When there is an opening |form| element:
4427          if ($token->{tag_name} eq 'form' and defined $self->{form_element}) {          if ($token->{tag_name} eq 'form' and defined $self->{form_element}) {
4428            !!!cp ('t350');            !!!cp ('t350');
4429            !!!parse-error (type => 'in form:form', token => $token);            !!!parse-error (type => 'in form:form', token => $token);
# Line 6937  sub _tree_construction_main ($) { Line 4433  sub _tree_construction_main ($) {
4433            next B;            next B;
4434          }          }
4435    
4436          ## has a p element in scope          ## 2. Close the |p| element, if any.
4437          INSCOPE: for (reverse @{$self->{open_elements}}) {          if ($token->{tag_name} ne 'table' or # The Hixie Quirk
4438            if ($_->[1] & P_EL) {              $self->{document}->manakai_compat_mode ne 'quirks') {
4439              !!!cp ('t344');            ## has a p element in scope
4440              !!!back-token; # <form>            INSCOPE: for (reverse @{$self->{open_elements}}) {
4441              $token = {type => END_TAG_TOKEN, tag_name => 'p',              if ($_->[1] == P_EL) {
4442                        line => $token->{line}, column => $token->{column}};                !!!cp ('t344');
4443              next B;                !!!back-token; # <form>
4444            } elsif ($_->[1] & SCOPING_EL) {                $token = {type => END_TAG_TOKEN, tag_name => 'p',
4445              !!!cp ('t345');                          line => $token->{line}, column => $token->{column}};
4446              last INSCOPE;                next B;
4447                } elsif ($_->[1] & SCOPING_EL) {
4448                  !!!cp ('t345');
4449                  last INSCOPE;
4450                }
4451              } # INSCOPE
4452            }
4453    
4454            ## 3. Close the opening <hn> element, if any.
4455            if ({h1 => 1, h2 => 1, h3 => 1,
4456                 h4 => 1, h5 => 1, h6 => 1}->{$token->{tag_name}}) {
4457              if ($self->{open_elements}->[-1]->[1] == HEADING_EL) {
4458                !!!parse-error (type => 'not closed',
4459                                text => $self->{open_elements}->[-1]->[0]->manakai_local_name,
4460                                token => $token);
4461                pop @{$self->{open_elements}};
4462            }            }
4463          } # INSCOPE          }
4464              
4465            ## 4. Insertion.
4466          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4467          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {
4468            !!!nack ('t346.1');            !!!nack ('t346.1');
# Line 6994  sub _tree_construction_main ($) { Line 4506  sub _tree_construction_main ($) {
4506        } elsif ($token->{tag_name} eq 'li') {        } elsif ($token->{tag_name} eq 'li') {
4507          ## NOTE: As normal, but imply </li> when there's another <li> ...          ## NOTE: As normal, but imply </li> when there's another <li> ...
4508    
4509          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)::
4510            ## Interpreted as <li><foo/></li><li/> (non-conforming)            ## Interpreted as <li><foo/></li><li/> (non-conforming):
4511            ## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7),            ## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7),
4512            ## 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),
4513            ## 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),
4514            ## object (Fx)            ## object (Fx)
4515            ## Generate non-tree (non-conforming)            ## Generate non-tree (non-conforming):
4516            ## basefont (IE7 (where basefont is non-void)), center (IE),            ## basefont (IE7 (where basefont is non-void)), center (IE),
4517            ## form (IE), hn (IE)            ## form (IE), hn (IE)
4518          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)::
4519            ## Interpreted as <li><foo><li/></foo></li> (non-conforming)            ## Interpreted as <li><foo><li/></foo></li> (non-conforming):
4520            ## div (Fx, S)            ## div (Fx, S)
4521    
4522          my $non_optional;          my $non_optional;
# Line 7012  sub _tree_construction_main ($) { Line 4524  sub _tree_construction_main ($) {
4524    
4525          ## 1.          ## 1.
4526          for my $node (reverse @{$self->{open_elements}}) {          for my $node (reverse @{$self->{open_elements}}) {
4527            if ($node->[1] & LI_EL) {            if ($node->[1] == LI_EL) {
4528              ## 2. (a) As if </li>              ## 2. (a) As if </li>
4529              {              {
4530                ## If no </li> - not applied                ## If no </li> - not applied
# Line 7043  sub _tree_construction_main ($) { Line 4555  sub _tree_construction_main ($) {
4555                     ($node->[1] & SPECIAL_EL or                     ($node->[1] & SPECIAL_EL or
4556                      $node->[1] & SCOPING_EL) and                      $node->[1] & SCOPING_EL) and
4557                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4558                       (not $node->[1] & ADDRESS_DIV_P_EL)
4559                     (not $node->[1] & ADDRESS_EL) &                    ) {
                    (not $node->[1] & DIV_EL) &  
                    (not $node->[1] & P_EL)) {  
4560              ## 3.              ## 3.
4561              !!!cp ('t357');              !!!cp ('t357');
4562              last; ## goto 5.              last; ## goto 5.
# Line 7064  sub _tree_construction_main ($) { Line 4574  sub _tree_construction_main ($) {
4574          }          }
4575    
4576          ## 5. (a) has a |p| element in scope          ## 5. (a) has a |p| element in scope
         ## ISSUE: Is this step really necessary?  
4577          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4578            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4579              !!!cp ('t353');              !!!cp ('t353');
4580    
4581                ## NOTE: |<p><li>|, for example.
4582    
4583              !!!back-token; # <x>              !!!back-token; # <x>
4584              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
4585                        line => $token->{line}, column => $token->{column}};                        line => $token->{line}, column => $token->{column}};
# Line 7092  sub _tree_construction_main ($) { Line 4604  sub _tree_construction_main ($) {
4604    
4605          ## 1.          ## 1.
4606          for my $node (reverse @{$self->{open_elements}}) {          for my $node (reverse @{$self->{open_elements}}) {
4607            if ($node->[1] & DT_EL or $node->[1] & DD_EL) {            if ($node->[1] == DTDD_EL) {
4608              ## 2. (a) As if </li>              ## 2. (a) As if </li>
4609              {              {
4610                ## If no </li> - not applied                ## If no </li> - not applied
# Line 7124  sub _tree_construction_main ($) { Line 4636  sub _tree_construction_main ($) {
4636                      $node->[1] & SCOPING_EL) and                      $node->[1] & SCOPING_EL) and
4637                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4638    
4639                     (not $node->[1] & ADDRESS_EL) &                     (not $node->[1] & ADDRESS_DIV_P_EL)
4640                     (not $node->[1] & DIV_EL) &                    ) {
                    (not $node->[1] & P_EL)) {  
4641              ## 3.              ## 3.
4642              !!!cp ('t357.1');              !!!cp ('t357.1');
4643              last; ## goto 5.              last; ## goto 5.
# Line 7144  sub _tree_construction_main ($) { Line 4655  sub _tree_construction_main ($) {
4655          }          }
4656    
4657          ## 5. (a) has a |p| element in scope          ## 5. (a) has a |p| element in scope
         ## ISSUE: Is this step really necessary?  
4658          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4659            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4660              !!!cp ('t353.1');              !!!cp ('t353.1');
4661              !!!back-token; # <x>              !!!back-token; # <x>
4662              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 7168  sub _tree_construction_main ($) { Line 4678  sub _tree_construction_main ($) {
4678    
4679          ## has a p element in scope          ## has a p element in scope
4680          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4681            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4682              !!!cp ('t367');              !!!cp ('t367');
4683              !!!back-token; # <plaintext>              !!!back-token; # <plaintext>
4684              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 7190  sub _tree_construction_main ($) { Line 4700  sub _tree_construction_main ($) {
4700        } elsif ($token->{tag_name} eq 'a') {        } elsif ($token->{tag_name} eq 'a') {
4701          AFE: for my $i (reverse 0..$#$active_formatting_elements) {          AFE: for my $i (reverse 0..$#$active_formatting_elements) {
4702            my $node = $active_formatting_elements->[$i];            my $node = $active_formatting_elements->[$i];
4703            if ($node->[1] & A_EL) {            if ($node->[1] == A_EL) {
4704              !!!cp ('t371');              !!!cp ('t371');
4705              !!!parse-error (type => 'in a:a', token => $token);              !!!parse-error (type => 'in a:a', token => $token);
4706                            
# Line 7234  sub _tree_construction_main ($) { Line 4744  sub _tree_construction_main ($) {
4744          ## has a |nobr| element in scope          ## has a |nobr| element in scope
4745          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4746            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4747            if ($node->[1] & NOBR_EL) {            if ($node->[1] == NOBR_EL) {
4748              !!!cp ('t376');              !!!cp ('t376');
4749              !!!parse-error (type => 'in nobr:nobr', token => $token);              !!!parse-error (type => 'in nobr:nobr', token => $token);
4750              !!!back-token; # <nobr>              !!!back-token; # <nobr>
# Line 7257  sub _tree_construction_main ($) { Line 4767  sub _tree_construction_main ($) {
4767          ## has a button element in scope          ## has a button element in scope
4768          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4769            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4770            if ($node->[1] & BUTTON_EL) {            if ($node->[1] == BUTTON_EL) {
4771              !!!cp ('t378');              !!!cp ('t378');
4772              !!!parse-error (type => 'in button:button', token => $token);              !!!parse-error (type => 'in button:button', token => $token);
4773              !!!back-token; # <button>              !!!back-token; # <button>
# Line 7322  sub _tree_construction_main ($) { Line 4832  sub _tree_construction_main ($) {
4832                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4833                          {type => START_TAG_TOKEN, tag_name => 'hr',                          {type => START_TAG_TOKEN, tag_name => 'hr',
4834                           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}},  
4835                          {type => START_TAG_TOKEN, tag_name => 'label',                          {type => START_TAG_TOKEN, tag_name => 'label',
4836                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4837                         );                         );
# Line 7346  sub _tree_construction_main ($) { Line 4854  sub _tree_construction_main ($) {
4854                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
4855                          {type => END_TAG_TOKEN, tag_name => 'label',                          {type => END_TAG_TOKEN, tag_name => 'label',
4856                           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}},  
4857                          {type => START_TAG_TOKEN, tag_name => 'hr',                          {type => START_TAG_TOKEN, tag_name => 'hr',
4858                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4859                          {type => END_TAG_TOKEN, tag_name => 'form',                          {type => END_TAG_TOKEN, tag_name => 'form',
# Line 7357  sub _tree_construction_main ($) { Line 4863  sub _tree_construction_main ($) {
4863            next B;            next B;
4864          }          }
4865        } elsif ($token->{tag_name} eq 'textarea') {        } elsif ($token->{tag_name} eq 'textarea') {
4866          my $tag_name = $token->{tag_name};          ## 1. Insert
4867          my $el;          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
         !!!create-element ($el, $HTML_NS, $token->{tag_name}, $token->{attributes}, $token);  
4868                    
4869            ## Step 2 # XXX
4870          ## TODO: $self->{form_element} if defined          ## TODO: $self->{form_element} if defined
4871    
4872            ## 2. Drop U+000A LINE FEED
4873            $self->{ignore_newline} = 1;
4874    
4875            ## 3. RCDATA
4876          $self->{content_model} = RCDATA_CONTENT_MODEL;          $self->{content_model} = RCDATA_CONTENT_MODEL;
4877          delete $self->{escape}; # MUST          delete $self->{escape}; # MUST
4878            
4879          $insert->($el);          ## 4., 6. Insertion mode
4880                    $self->{insertion_mode} |= IN_CDATA_RCDATA_IM;
4881          my $text = '';  
4882            ## XXX: 5. frameset-ok flag
4883    
4884          !!!nack ('t392.1');          !!!nack ('t392.1');
4885          !!!next-token;          !!!next-token;
4886          if ($token->{type} == CHARACTER_TOKEN) {          next B;
4887            $token->{data} =~ s/^\x0A//;        } elsif ($token->{tag_name} eq 'optgroup' or
4888            unless (length $token->{data}) {                 $token->{tag_name} eq 'option') {
4889              !!!cp ('t392');          ## has an |option| element in scope
4890              !!!next-token;          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4891            } else {            my $node = $self->{open_elements}->[$_];
4892              !!!cp ('t393');            if ($node->[1] == OPTION_EL) {
4893                !!!cp ('t397.1');
4894                ## NOTE: As if </option>
4895                !!!back-token; # <option> or <optgroup>
4896                $token = {type => END_TAG_TOKEN, tag_name => 'option',
4897                          line => $token->{line}, column => $token->{column}};
4898                next B;
4899              } elsif ($node->[1] & SCOPING_EL) {
4900                !!!cp ('t397.2');
4901                last INSCOPE;
4902            }            }
4903          } else {          } # INSCOPE
4904            !!!cp ('t394');  
4905          }          $reconstruct_active_formatting_elements->($insert_to_current);
4906          while ($token->{type} == CHARACTER_TOKEN) {  
4907            !!!cp ('t395');          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4908            $text .= $token->{data};  
4909            !!!next-token;          !!!nack ('t397.3');
         }  
         if (length $text) {  
           !!!cp ('t396');  
           $el->manakai_append_text ($text);  
         }  
           
         $self->{content_model} = PCDATA_CONTENT_MODEL;  
           
         if ($token->{type} == END_TAG_TOKEN and  
             $token->{tag_name} eq $tag_name) {  
           !!!cp ('t397');  
           ## Ignore the token  
         } else {  
           !!!cp ('t398');  
           !!!parse-error (type => 'in RCDATA:#eof', token => $token);  
         }  
4910          !!!next-token;          !!!next-token;
4911          next B;          redo B;
4912        } elsif ($token->{tag_name} eq 'rt' or        } elsif ($token->{tag_name} eq 'rt' or
4913                 $token->{tag_name} eq 'rp') {                 $token->{tag_name} eq 'rp') {
4914          ## has a |ruby| element in scope          ## has a |ruby| element in scope
4915          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4916            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4917            if ($node->[1] & RUBY_EL) {            if ($node->[1] == RUBY_EL) {
4918              !!!cp ('t398.1');              !!!cp ('t398.1');
4919              ## generate implied end tags              ## generate implied end tags
4920              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
4921                !!!cp ('t398.2');                !!!cp ('t398.2');
4922                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
4923              }              }
4924              unless ($self->{open_elements}->[-1]->[1] & RUBY_EL) {              unless ($self->{open_elements}->[-1]->[1] == RUBY_EL) {
4925                !!!cp ('t398.3');                !!!cp ('t398.3');
4926                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
4927                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
4928                                    ->manakai_local_name,                                    ->manakai_local_name,
4929                                token => $token);                                token => $token);
4930                pop @{$self->{open_elements}}                pop @{$self->{open_elements}}
4931                    while not $self->{open_elements}->[-1]->[1] & RUBY_EL;                    while not $self->{open_elements}->[-1]->[1] == RUBY_EL;
4932              }              }
4933              last INSCOPE;              last INSCOPE;
4934            } elsif ($node->[1] & SCOPING_EL) {            } elsif ($node->[1] & SCOPING_EL) {
# Line 7430  sub _tree_construction_main ($) { Line 4936  sub _tree_construction_main ($) {
4936              last INSCOPE;              last INSCOPE;
4937            }            }
4938          } # INSCOPE          } # INSCOPE
4939              
4940            ## TODO: <non-ruby><rt> is not allowed.
4941    
4942          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4943    
# Line 7450  sub _tree_construction_main ($) { Line 4958  sub _tree_construction_main ($) {
4958                    
4959          if ($self->{self_closing}) {          if ($self->{self_closing}) {
4960            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
4961            !!!ack ('t398.1');            !!!ack ('t398.6');
4962          } else {          } else {
4963            !!!cp ('t398.2');            !!!cp ('t398.7');
4964            $self->{insertion_mode} |= IN_FOREIGN_CONTENT_IM;            $self->{insertion_mode} |= IN_FOREIGN_CONTENT_IM;
4965            ## NOTE: |<body><math><mi><svg>| -> "in foreign content" insertion            ## NOTE: |<body><math><mi><svg>| -> "in foreign content" insertion
4966            ## mode, "in body" (not "in foreign content") secondary insertion            ## mode, "in body" (not "in foreign content") secondary insertion
# Line 7463  sub _tree_construction_main ($) { Line 4971  sub _tree_construction_main ($) {
4971          next B;          next B;
4972        } elsif ({        } elsif ({
4973                  caption => 1, col => 1, colgroup => 1, frame => 1,                  caption => 1, col => 1, colgroup => 1, frame => 1,
4974                  frameset => 1, head => 1, option => 1, optgroup => 1,                  frameset => 1, head => 1,
4975                  tbody => 1, td => 1, tfoot => 1, th => 1,                  tbody => 1, td => 1, tfoot => 1, th => 1,
4976                  thead => 1, tr => 1,                  thead => 1, tr => 1,
4977                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
# Line 7474  sub _tree_construction_main ($) { Line 4982  sub _tree_construction_main ($) {
4982          !!!nack ('t401.1'); ## NOTE: |<col/>| or |<frame/>| here is an error.          !!!nack ('t401.1'); ## NOTE: |<col/>| or |<frame/>| here is an error.
4983          !!!next-token;          !!!next-token;
4984          next B;          next B;
4985                  } elsif ($token->{tag_name} eq 'param' or
4986          ## ISSUE: An issue on HTML5 new elements in the spec.                 $token->{tag_name} eq 'source') {
4987            !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4988            pop @{$self->{open_elements}};
4989    
4990            !!!ack ('t398.5');
4991            !!!next-token;
4992            redo B;
4993        } else {        } else {
4994          if ($token->{tag_name} eq 'image') {          if ($token->{tag_name} eq 'image') {
4995            !!!cp ('t384');            !!!cp ('t384');
# Line 7511  sub _tree_construction_main ($) { Line 5025  sub _tree_construction_main ($) {
5025            !!!ack ('t388.2');            !!!ack ('t388.2');
5026          } elsif ({          } elsif ({
5027                    area => 1, basefont => 1, bgsound => 1, br => 1,                    area => 1, basefont => 1, bgsound => 1, br => 1,
5028                    embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,                    embed => 1, img => 1, spacer => 1, wbr => 1,
5029                    #image => 1,                    keygen => 1,
5030                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}}) {
5031            !!!cp ('t388.1');            !!!cp ('t388.1');
5032            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
# Line 7522  sub _tree_construction_main ($) { Line 5036  sub _tree_construction_main ($) {
5036                    
5037            if ($self->{insertion_mode} & TABLE_IMS or            if ($self->{insertion_mode} & TABLE_IMS or
5038                $self->{insertion_mode} & BODY_TABLE_IMS or                $self->{insertion_mode} & BODY_TABLE_IMS or
5039                $self->{insertion_mode} == IN_COLUMN_GROUP_IM) {                ($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) {
5040              !!!cp ('t400.1');              !!!cp ('t400.1');
5041              $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;              $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;
5042            } else {            } else {
# Line 7539  sub _tree_construction_main ($) { Line 5053  sub _tree_construction_main ($) {
5053        }        }
5054      } elsif ($token->{type} == END_TAG_TOKEN) {      } elsif ($token->{type} == END_TAG_TOKEN) {
5055        if ($token->{tag_name} eq 'body') {        if ($token->{tag_name} eq 'body') {
5056          ## has a |body| element in scope  
5057            ## 1. If not "have an element in scope":
5058            ## "has a |body| element in scope"
5059          my $i;          my $i;
5060          INSCOPE: {          INSCOPE: {
5061            for (reverse @{$self->{open_elements}}) {            for (reverse @{$self->{open_elements}}) {
5062              if ($_->[1] & BODY_EL) {              if ($_->[1] == BODY_EL) {
5063                !!!cp ('t405');                !!!cp ('t405');
5064                $i = $_;                $i = $_;
5065                last INSCOPE;                last INSCOPE;
# Line 7553  sub _tree_construction_main ($) { Line 5069  sub _tree_construction_main ($) {
5069              }              }
5070            }            }
5071    
5072            !!!parse-error (type => 'start tag not allowed',            ## NOTE: |<marquee></body>|, |<svg><foreignobject></body>|
5073    
5074              !!!parse-error (type => 'unmatched end tag',
5075                            text => $token->{tag_name}, token => $token);                            text => $token->{tag_name}, token => $token);
5076            ## NOTE: Ignore the token.            ## NOTE: Ignore the token.
5077            !!!next-token;            !!!next-token;
5078            next B;            next B;
5079          } # INSCOPE          } # INSCOPE
5080    
5081            ## 2. If unclosed elements:
5082          for (@{$self->{open_elements}}) {          for (@{$self->{open_elements}}) {
5083            unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL) {            unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL ||
5084                      $_->[1] == OPTGROUP_EL ||
5085                      $_->[1] == OPTION_EL ||
5086                      $_->[1] == RUBY_COMPONENT_EL) {
5087              !!!cp ('t403');              !!!cp ('t403');
5088              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5089                              text => $_->[0]->manakai_local_name,                              text => $_->[0]->manakai_local_name,
# Line 7572  sub _tree_construction_main ($) { Line 5094  sub _tree_construction_main ($) {
5094            }            }
5095          }          }
5096    
5097            ## 3. Switch the insertion mode.
5098          $self->{insertion_mode} = AFTER_BODY_IM;          $self->{insertion_mode} = AFTER_BODY_IM;
5099          !!!next-token;          !!!next-token;
5100          next B;          next B;
# Line 7579  sub _tree_construction_main ($) { Line 5102  sub _tree_construction_main ($) {
5102          ## TODO: Update this code.  It seems that the code below is not          ## TODO: Update this code.  It seems that the code below is not
5103          ## up-to-date, though it has same effect as speced.          ## up-to-date, though it has same effect as speced.
5104          if (@{$self->{open_elements}} > 1 and          if (@{$self->{open_elements}} > 1 and
5105              $self->{open_elements}->[1]->[1] & BODY_EL) {              $self->{open_elements}->[1]->[1] == BODY_EL) {
5106            ## ISSUE: There is an issue in the spec.            unless ($self->{open_elements}->[-1]->[1] == BODY_EL) {
           unless ($self->{open_elements}->[-1]->[1] & BODY_EL) {  
5107              !!!cp ('t406');              !!!cp ('t406');
5108              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5109                              text => $self->{open_elements}->[1]->[0]                              text => $self->{open_elements}->[1]->[0]
# Line 7616  sub _tree_construction_main ($) { Line 5138  sub _tree_construction_main ($) {
5138    
5139                  applet => 1, button => 1, marquee => 1, object => 1,                  applet => 1, button => 1, marquee => 1, object => 1,
5140                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
5141            ## NOTE: Code for <li> start tags includes "as if </li>" code.
5142            ## Code for <dt> or <dd> start tags includes "as if </dt> or
5143            ## </dd>" code.
5144    
5145          ## has an element in scope          ## has an element in scope
5146          my $i;          my $i;
5147          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 7684  sub _tree_construction_main ($) { Line 5210  sub _tree_construction_main ($) {
5210          my $i;          my $i;
5211          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5212            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5213            if ($node->[1] & FORM_EL) {            if ($node->[1] == FORM_EL) {
5214              !!!cp ('t418');              !!!cp ('t418');
5215              $i = $_;              $i = $_;
5216              last INSCOPE;              last INSCOPE;
# Line 7732  sub _tree_construction_main ($) { Line 5258  sub _tree_construction_main ($) {
5258          my $i;          my $i;
5259          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5260            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5261            if ($node->[1] & HEADING_EL) {            if ($node->[1] == HEADING_EL) {
5262              !!!cp ('t423');              !!!cp ('t423');
5263              $i = $_;              $i = $_;
5264              last INSCOPE;              last INSCOPE;
# Line 7774  sub _tree_construction_main ($) { Line 5300  sub _tree_construction_main ($) {
5300          ## NOTE: As normal, except </p> implies <p> and ...          ## NOTE: As normal, except </p> implies <p> and ...
5301    
5302          ## has an element in scope          ## has an element in scope
5303            my $non_optional;
5304          my $i;          my $i;
5305          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5306            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5307            if ($node->[1] & P_EL) {            if ($node->[1] == P_EL) {
5308              !!!cp ('t410.1');              !!!cp ('t410.1');
5309              $i = $_;              $i = $_;
5310              last INSCOPE;              last INSCOPE;
5311            } elsif ($node->[1] & SCOPING_EL) {            } elsif ($node->[1] & SCOPING_EL) {
5312              !!!cp ('t411.1');              !!!cp ('t411.1');
5313              last INSCOPE;              last INSCOPE;
5314              } elsif ($node->[1] & END_TAG_OPTIONAL_EL) {
5315                ## NOTE: |END_TAG_OPTIONAL_EL| includes "p"
5316                !!!cp ('t411.2');
5317                #
5318              } else {
5319                !!!cp ('t411.3');
5320                $non_optional ||= $node;
5321                #
5322            }            }
5323          } # INSCOPE          } # INSCOPE
5324    
5325          if (defined $i) {          if (defined $i) {
5326            if ($self->{open_elements}->[-1]->[0]->manakai_local_name            ## 1. Generate implied end tags
5327                    ne $token->{tag_name}) {            #
5328    
5329              ## 2. If current node != "p", parse error
5330              if ($non_optional) {
5331              !!!cp ('t412.1');              !!!cp ('t412.1');
5332              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5333                              text => $self->{open_elements}->[-1]->[0]                              text => $non_optional->[0]->manakai_local_name,
                                 ->manakai_local_name,  
5334                              token => $token);                              token => $token);
5335            } else {            } else {
5336              !!!cp ('t414.1');              !!!cp ('t414.1');
5337            }            }
5338    
5339              ## 3. Pop
5340            splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
5341          } else {          } else {
5342            !!!cp ('t413.1');            !!!cp ('t413.1');
# Line 7839  sub _tree_construction_main ($) { Line 5377  sub _tree_construction_main ($) {
5377          ## Ignore the token.          ## Ignore the token.
5378          !!!next-token;          !!!next-token;
5379          next B;          next B;
       } elsif ({  
                 caption => 1, col => 1, colgroup => 1, frame => 1,  
                 frameset => 1, head => 1, option => 1, optgroup => 1,  
                 tbody => 1, td => 1, tfoot => 1, th => 1,  
                 thead => 1, tr => 1,  
                 area => 1, basefont => 1, bgsound => 1,  
                 embed => 1, hr => 1, iframe => 1, image => 1,  
                 img => 1, input => 1, isindex => 1, noembed => 1,  
                 noframes => 1, param => 1, select => 1, spacer => 1,  
                 table => 1, textarea => 1, wbr => 1,  
                 noscript => 0, ## TODO: if scripting is enabled  
                }->{$token->{tag_name}}) {  
         !!!cp ('t429');  
         !!!parse-error (type => 'unmatched end tag',  
                         text => $token->{tag_name}, token => $token);  
         ## Ignore the token  
         !!!next-token;  
         next B;  
5380        } else {        } else {
5381          if ($token->{tag_name} eq 'sarcasm') {          if ($token->{tag_name} eq 'sarcasm') {
5382            sleep 0.001; # take a deep breath            sleep 0.001; # take a deep breath
# Line 7868  sub _tree_construction_main ($) { Line 5388  sub _tree_construction_main ($) {
5388    
5389          ## Step 2          ## Step 2
5390          S2: {          S2: {
5391            if ($node->[0]->manakai_local_name eq $token->{tag_name}) {            my $node_tag_name = $node->[0]->manakai_local_name;
5392              $node_tag_name =~ tr/A-Z/a-z/; # for SVG camelCase tag names
5393              if ($node_tag_name eq $token->{tag_name}) {
5394              ## Step 1              ## Step 1
5395              ## generate implied end tags              ## generate implied end tags
5396              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
# Line 7881  sub _tree_construction_main ($) { Line 5403  sub _tree_construction_main ($) {
5403              }              }
5404                    
5405              ## Step 2              ## Step 2
5406              if ($self->{open_elements}->[-1]->[0]->manakai_local_name              my $current_tag_name
5407                      ne $token->{tag_name}) {                  = $self->{open_elements}->[-1]->[0]->manakai_local_name;
5408                $current_tag_name =~ tr/A-Z/a-z/;
5409                if ($current_tag_name ne $token->{tag_name}) {
5410                !!!cp ('t431');                !!!cp ('t431');
5411                ## NOTE: <x><y></x>                ## NOTE: <x><y></x>
5412                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
# Line 7957  sub _tree_construction_main ($) { Line 5481  sub _tree_construction_main ($) {
5481    ## TODO: script stuffs    ## TODO: script stuffs
5482  } # _tree_construct_main  } # _tree_construct_main
5483    
5484    ## XXX: How this method is organized is somewhat out of date, although
5485    ## it still does what the current spec documents.
5486  sub set_inner_html ($$$$;$) {  sub set_inner_html ($$$$;$) {
5487    my $class = shift;    my $class = shift;
5488    my $node = shift;    my $node = shift; # /context/
5489    #my $s = \$_[0];    #my $s = \$_[0];
5490    my $onerror = $_[1];    my $onerror = $_[1];
5491    my $get_wrapper = $_[2] || sub ($) { return $_[0] };    my $get_wrapper = $_[2] || sub ($) { return $_[0] };
# Line 7967  sub set_inner_html ($$$$;$) { Line 5493  sub set_inner_html ($$$$;$) {
5493    ## ISSUE: Should {confident} be true?    ## ISSUE: Should {confident} be true?
5494    
5495    my $nt = $node->node_type;    my $nt = $node->node_type;
5496    if ($nt == 9) {    if ($nt == 9) { # Document (invoke the algorithm with no /context/ element)
5497      # MUST      # MUST
5498            
5499      ## Step 1 # MUST      ## Step 1 # MUST
# Line 7982  sub set_inner_html ($$$$;$) { Line 5508  sub set_inner_html ($$$$;$) {
5508    
5509      ## Step 3, 4, 5 # MUST      ## Step 3, 4, 5 # MUST
5510      $class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper);      $class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper);
5511    } elsif ($nt == 1) {    } elsif ($nt == 1) { # Element (invoke the algorithm with /context/ element)
5512      ## TODO: If non-html element      ## TODO: If non-html element
5513    
5514      ## NOTE: Most of this code is copied from |parse_string|      ## NOTE: Most of this code is copied from |parse_string|
5515    
5516  ## TODO: Support for $get_wrapper  ## TODO: Support for $get_wrapper
5517    
5518      ## Step 1 # MUST      ## F1. Create an HTML document.
5519      my $this_doc = $node->owner_document;      my $this_doc = $node->owner_document;
5520      my $doc = $this_doc->implementation->create_document;      my $doc = $this_doc->implementation->create_document;
5521      $doc->manakai_is_html (1);      $doc->manakai_is_html (1);
5522    
5523        ## F2. Propagate quirkness flag
5524        my $node_doc = $node->owner_document;
5525        $doc->manakai_compat_mode ($node_doc->manakai_compat_mode);
5526    
5527        ## F3. Create an HTML parser
5528      my $p = $class->new;      my $p = $class->new;
5529      $p->{document} = $doc;      $p->{document} = $doc;
5530    
# Line 8120  sub set_inner_html ($$$$;$) { Line 5652  sub set_inner_html ($$$$;$) {
5652      $p->_initialize_tokenizer;      $p->_initialize_tokenizer;
5653      $p->_initialize_tree_constructor;      $p->_initialize_tree_constructor;
5654    
5655      ## Step 2      ## F4. If /context/ is not undef...
5656    
5657        ## F4.1. content model flag
5658      my $node_ln = $node->manakai_local_name;      my $node_ln = $node->manakai_local_name;
5659      $p->{content_model} = {      $p->{content_model} = {
5660        title => RCDATA_CONTENT_MODEL,        title => RCDATA_CONTENT_MODEL,
# Line 8136  sub set_inner_html ($$$$;$) { Line 5670  sub set_inner_html ($$$$;$) {
5670      }->{$node_ln};      }->{$node_ln};
5671      $p->{content_model} = PCDATA_CONTENT_MODEL      $p->{content_model} = PCDATA_CONTENT_MODEL
5672          unless defined $p->{content_model};          unless defined $p->{content_model};
         ## ISSUE: What is "the name of the element"? local name?  
5673    
5674      $p->{inner_html_node} = [$node, $el_category->{$node_ln}];      $p->{inner_html_node} = [$node, $el_category->{$node_ln}];
5675        ## TODO: Foreign element OK?        ## TODO: Foreign element OK?
5676    
5677      ## Step 3      ## F4.2. Root |html| element
5678      my $root = $doc->create_element_ns      my $root = $doc->create_element_ns
5679        ('http://www.w3.org/1999/xhtml', [undef, 'html']);        ('http://www.w3.org/1999/xhtml', [undef, 'html']);
5680    
5681      ## Step 4 # MUST      ## F4.3.
5682      $doc->append_child ($root);      $doc->append_child ($root);
5683    
5684      ## Step 5 # MUST      ## F4.4.
5685      push @{$p->{open_elements}}, [$root, $el_category->{html}];      push @{$p->{open_elements}}, [$root, $el_category->{html}];
5686    
5687      undef $p->{head_element};      undef $p->{head_element};
5688        undef $p->{head_element_inserted};
5689    
5690      ## Step 6 # MUST      ## F4.5.
5691      $p->_reset_insertion_mode;      $p->_reset_insertion_mode;
5692    
5693      ## Step 7 # MUST      ## F4.6.
5694      my $anode = $node;      my $anode = $node;
5695      AN: while (defined $anode) {      AN: while (defined $anode) {
5696        if ($anode->node_type == 1) {        if ($anode->node_type == 1) {
# Line 8171  sub set_inner_html ($$$$;$) { Line 5705  sub set_inner_html ($$$$;$) {
5705        }        }
5706        $anode = $anode->parent_node;        $anode = $anode->parent_node;
5707      } # AN      } # AN
5708        
5709      ## Step 9 # MUST      ## F.6. Start the parser.
5710      {      {
5711        my $self = $p;        my $self = $p;
5712        !!!next-token;        !!!next-token;
5713      }      }
5714      $p->_tree_construction_main;      $p->_tree_construction_main;
5715    
5716      ## Step 10 # MUST      ## F.7.
5717      my @cn = @{$node->child_nodes};      my @cn = @{$node->child_nodes};
5718      for (@cn) {      for (@cn) {
5719        $node->remove_child ($_);        $node->remove_child ($_);

Legend:
Removed from v.1.196  
changed lines
  Added in v.1.234

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24