/[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.201 by wakaba, Sat Oct 4 12:20:35 2008 UTC revision 1.240 by wakaba, Sun Sep 6 10:21:14 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 |  
   
   ## ISSUE: option, optgroup, rt, rp?  
   
   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    SELECT_EL |    TABLE_ROWS_EL |
128    TABLE_ROW_EL |    TABLE_SCOPING_EL |
129    TABLE_ROW_GROUP_EL |    0b001
130    MISC_SPECIAL_EL  }
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 185  my $el_category = { Line 194  my $el_category = {
194    h6 => HEADING_EL,    h6 => HEADING_EL,
195    head => MISC_SPECIAL_EL,    head => MISC_SPECIAL_EL,
196    header => MISC_SPECIAL_EL,    header => MISC_SPECIAL_EL,
197      hgroup => MISC_SPECIAL_EL,
198    hr => MISC_SPECIAL_EL,    hr => MISC_SPECIAL_EL,
199    html => HTML_EL,    html => HTML_EL,
200    i => FORMATTING_EL,    i => FORMATTING_EL,
# Line 193  my $el_category = { Line 203  my $el_category = {
203    #image => MISC_SPECIAL_EL, ## NOTE: Commented out in the spec.    #image => MISC_SPECIAL_EL, ## NOTE: Commented out in the spec.
204    input => MISC_SPECIAL_EL,    input => MISC_SPECIAL_EL,
205    isindex => MISC_SPECIAL_EL,    isindex => MISC_SPECIAL_EL,
206      ## XXX keygen? (Whether a void element is in Special or not does not
207      ## affect to the processing, however.)
208    li => LI_EL,    li => LI_EL,
209    link => MISC_SPECIAL_EL,    link => MISC_SPECIAL_EL,
210    listing => MISC_SPECIAL_EL,    listing => MISC_SPECIAL_EL,
# Line 200  my $el_category = { Line 212  my $el_category = {
212    menu => MISC_SPECIAL_EL,    menu => MISC_SPECIAL_EL,
213    meta => MISC_SPECIAL_EL,    meta => MISC_SPECIAL_EL,
214    nav => MISC_SPECIAL_EL,    nav => MISC_SPECIAL_EL,
215    nobr => NOBR_EL | FORMATTING_EL,    nobr => NOBR_EL,
216    noembed => MISC_SPECIAL_EL,    noembed => MISC_SPECIAL_EL,
217    noframes => MISC_SPECIAL_EL,    noframes => MISC_SPECIAL_EL,
218    noscript => MISC_SPECIAL_EL,    noscript => MISC_SPECIAL_EL,
# Line 237  my $el_category = { Line 249  my $el_category = {
249    u => FORMATTING_EL,    u => FORMATTING_EL,
250    ul => MISC_SPECIAL_EL,    ul => MISC_SPECIAL_EL,
251    wbr => MISC_SPECIAL_EL,    wbr => MISC_SPECIAL_EL,
252      xmp => MISC_SPECIAL_EL,
253  };  };
254    
255  my $el_category_f = {  my $el_category_f = {
256    $MML_NS => {    $MML_NS => {
257      'annotation-xml' => MML_AXML_EL,      'annotation-xml' => MML_AXML_EL,
258      mi => FOREIGN_FLOW_CONTENT_EL,      mi => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
259      mo => FOREIGN_FLOW_CONTENT_EL,      mo => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
260      mn => FOREIGN_FLOW_CONTENT_EL,      mn => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
261      ms => FOREIGN_FLOW_CONTENT_EL,      ms => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
262      mtext => FOREIGN_FLOW_CONTENT_EL,      mtext => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
263    },    },
264    $SVG_NS => {    $SVG_NS => {
265      foreignObject => FOREIGN_FLOW_CONTENT_EL | MISC_SCOPING_EL,      foreignObject => SCOPING_EL | FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
266      desc => FOREIGN_FLOW_CONTENT_EL,      desc => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
267      title => FOREIGN_FLOW_CONTENT_EL,      title => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
268    },    },
269    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.
270  };  };
# Line 338  my $foreign_attr_xname = { Line 351  my $foreign_attr_xname = {
351    
352  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.
353    
 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;  
   
354  ## TODO: Invoke the reset algorithm when a resettable element is  ## TODO: Invoke the reset algorithm when a resettable element is
355  ## created (cf. HTML5 revision 2259).  ## created (cf. HTML5 revision 2259).
356    
# Line 559  sub parse_byte_stream ($$$$;$$) { Line 528  sub parse_byte_stream ($$$$;$$) {
528            
529      if ($char_stream) { # if supported      if ($char_stream) { # if supported
530        ## "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;  
531                
532        ## Step 2        ## Step 1
533        if (defined $self->{input_encoding} and        if (defined $self->{input_encoding} and
534            $self->{input_encoding} eq $charset_name) {            $self->{input_encoding} eq $charset_name) {
535          !!!parse-error (type => 'charset label:matching',          !!!parse-error (type => 'charset label:matching',
# Line 580  sub parse_byte_stream ($$$$;$$) { Line 539  sub parse_byte_stream ($$$$;$$) {
539          return;          return;
540        }        }
541    
542          ## Step 2 (HTML5 revision 3205)
543          if (defined $self->{input_encoding} and
544              Message::Charset::Info->get_by_html_name ($self->{input_encoding})
545              ->{category} & Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) {
546            $self->{confident} = 1;
547            return;
548          }
549    
550          ## Step 3
551          if ($charset->{category} &
552              Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) {
553            $charset = Message::Charset::Info->get_by_html_name ('utf-8');
554            ($char_stream, $e_status) = $charset->get_decode_handle
555                ($byte_stream,
556                 byte_buffer => \ $buffer->{buffer});
557          }
558          $charset_name = $charset->get_iana_name;
559    
560        !!!parse-error (type => 'charset label detected',        !!!parse-error (type => 'charset label detected',
561                        text => $self->{input_encoding},                        text => $self->{input_encoding},
562                        value => $charset_name,                        value => $charset_name,
563                        level => $self->{level}->{warn},                        level => $self->{level}->{warn},
564                        token => $token);                        token => $token);
565                
566        ## Step 3        ## Step 4
567        # if (can) {        # if (can) {
568          ## change the encoding on the fly.          ## change the encoding on the fly.
569          #$self->{confident} = 1;          #$self->{confident} = 1;
570          #return;          #return;
571        # }        # }
572                
573        ## Step 4        ## Step 5
574        throw Whatpm::HTML::RestartParser ();        throw Whatpm::HTML::RestartParser ();
575      }      }
576    }; # $self->{change_encoding}    }; # $self->{change_encoding}
# Line 673  sub parse_char_stream ($$$;$$) { Line 650  sub parse_char_stream ($$$;$$) {
650    
651    ## NOTE: |set_inner_html| copies most of this method's code    ## NOTE: |set_inner_html| copies most of this method's code
652    
653      ## Confidence: irrelevant.
654    $self->{confident} = 1 unless exists $self->{confident};    $self->{confident} = 1 unless exists $self->{confident};
655    
656    $self->{document}->input_encoding ($self->{input_encoding})    $self->{document}->input_encoding ($self->{input_encoding})
657        if defined $self->{input_encoding};        if defined $self->{input_encoding};
658  ## TODO: |{input_encoding}| is needless?  ## TODO: |{input_encoding}| is needless?
# Line 834  sub new ($) { Line 813  sub new ($) {
813    return $self;    return $self;
814  } # new  } # new
815    
816  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 }  
817    
818  sub AFTER_HTML_IMS () { 0b100 }  sub AFTER_HTML_IMS () { 0b100 }
819  sub HEAD_IMS ()       { 0b1000 }  sub HEAD_IMS ()       { 0b1000 }
# Line 914  sub ROW_IMS ()        { 0b10000000 } Line 824  sub ROW_IMS ()        { 0b10000000 }
824  sub BODY_AFTER_IMS () { 0b100000000 }  sub BODY_AFTER_IMS () { 0b100000000 }
825  sub FRAME_IMS ()      { 0b1000000000 }  sub FRAME_IMS ()      { 0b1000000000 }
826  sub SELECT_IMS ()     { 0b10000000000 }  sub SELECT_IMS ()     { 0b10000000000 }
827  sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 }  #sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 } # see Whatpm::HTML::Tokenizer
828      ## NOTE: "in foreign content" insertion mode is special; it is combined      ## NOTE: "in foreign content" insertion mode is special; it is combined
829      ## with the secondary insertion mode.  In this parser, they are stored      ## with the secondary insertion mode.  In this parser, they are stored
830      ## together in the bit-or'ed form.      ## together in the bit-or'ed form.
831    sub IN_CDATA_RCDATA_IM () { 0b1000000000000 }
832        ## NOTE: "in CDATA/RCDATA" insertion mode is also special; it is
833        ## combined with the original insertion mode.  In thie parser,
834        ## they are stored together in the bit-or'ed form.
835    
836    sub IM_MASK () { 0b11111111111 }
837    
838  ## NOTE: "initial" and "before html" insertion modes have no constants.  ## NOTE: "initial" and "before html" insertion modes have no constants.
839    
# Line 944  sub IN_SELECT_IM () { SELECT_IMS | 0b01 Line 860  sub IN_SELECT_IM () { SELECT_IMS | 0b01
860  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }
861  sub IN_COLUMN_GROUP_IM () { 0b10 }  sub IN_COLUMN_GROUP_IM () { 0b10 }
862    
 ## 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};  
         $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  
   
863  sub _initialize_tree_constructor ($) {  sub _initialize_tree_constructor ($) {
864    my $self = shift;    my $self = shift;
865    ## NOTE: $self->{document} MUST be specified before this method is called    ## NOTE: $self->{document} MUST be specified before this method is called
# Line 3467  sub _construct_tree ($) { Line 888  sub _construct_tree ($) {
888    ## When an interactive UA render the $self->{document} available    ## When an interactive UA render the $self->{document} available
889    ## to the user, or when it begin accepting user input, are    ## to the user, or when it begin accepting user input, are
890    ## 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  
891        
892    !!!next-token;    !!!next-token;
893    
894    undef $self->{form_element};    undef $self->{form_element};
895    undef $self->{head_element};    undef $self->{head_element};
896      undef $self->{head_element_inserted};
897    $self->{open_elements} = [];    $self->{open_elements} = [];
898    undef $self->{inner_html_node};    undef $self->{inner_html_node};
899      undef $self->{ignore_newline};
900    
901    ## NOTE: The "initial" insertion mode.    ## NOTE: The "initial" insertion mode.
902    $self->_tree_construction_initial; # MUST    $self->_tree_construction_initial; # MUST
# Line 3497  sub _tree_construction_initial ($) { Line 916  sub _tree_construction_initial ($) {
916    
917    INITIAL: {    INITIAL: {
918      if ($token->{type} == DOCTYPE_TOKEN) {      if ($token->{type} == DOCTYPE_TOKEN) {
919        ## NOTE: Conformance checkers MAY, instead of reporting "not HTML5"        ## NOTE: Conformance checkers MAY, instead of reporting "not
920        ## error, switch to a conformance checking mode for another        ## HTML5" error, switch to a conformance checking mode for
921        ## language.        ## another language.  (We don't support such mode switchings; it
922          ## is nonsense to do anything different from what browsers do.)
923        my $doctype_name = $token->{name};        my $doctype_name = $token->{name};
924        $doctype_name = '' unless defined $doctype_name;        $doctype_name = '' unless defined $doctype_name;
925        $doctype_name =~ tr/a-z/A-Z/; # ASCII case-insensitive        my $doctype = $self->{document}->create_document_type_definition
926        if (not defined $token->{name} or # <!DOCTYPE>            ($doctype_name);
927            defined $token->{sysid}) {  
928          $doctype_name =~ tr/A-Z/a-z/; # ASCII case-insensitive
929          if ($doctype_name ne 'html') {
930          !!!cp ('t1');          !!!cp ('t1');
931          !!!parse-error (type => 'not HTML5', token => $token);          !!!parse-error (type => 'not HTML5', token => $token);
932        } elsif ($doctype_name ne 'HTML') {        } elsif (defined $token->{pubid}) {
933          !!!cp ('t2');          !!!cp ('t2');
934            ## XXX Obsolete permitted DOCTYPEs
935          !!!parse-error (type => 'not HTML5', token => $token);          !!!parse-error (type => 'not HTML5', token => $token);
936        } elsif (defined $token->{pubid}) {        } elsif (defined $token->{sysid}) {
937          if ($token->{pubid} eq 'XSLT-compat') {          if ($token->{sysid} eq 'about:legacy-compat') {
938            !!!cp ('t1.2');            !!!cp ('t1.2'); ## <!DOCTYPE HTML SYSTEM "about:legacy-compat">
939            !!!parse-error (type => 'XSLT-compat', token => $token,            !!!parse-error (type => 'XSLT-compat', token => $token,
940                            level => $self->{level}->{should});                            level => $self->{level}->{should});
941          } else {          } else {
942            !!!parse-error (type => 'not HTML5', token => $token);            !!!parse-error (type => 'not HTML5', token => $token);
943          }          }
944        } else {        } else { ## <!DOCTYPE HTML>
945          !!!cp ('t3');          !!!cp ('t3');
946          #          #
947        }        }
948                
       my $doctype = $self->{document}->create_document_type_definition  
         ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?  
949        ## NOTE: Default value for both |public_id| and |system_id| attributes        ## NOTE: Default value for both |public_id| and |system_id| attributes
950        ## 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.
951        $doctype->public_id ($token->{pubid}) if defined $token->{pubid};        $doctype->public_id ($token->{pubid}) if defined $token->{pubid};
952        $doctype->system_id ($token->{sysid}) if defined $token->{sysid};        $doctype->system_id ($token->{sysid}) if defined $token->{sysid};
953    
954        ## NOTE: Other DocumentType attributes are null or empty lists.        ## NOTE: Other DocumentType attributes are null or empty lists.
955        ## ISSUE: internalSubset = null??        ## In Firefox3, |internalSubset| attribute is set to the empty
956          ## string, while |null| is an allowed value for the attribute
957          ## according to DOM3 Core.
958        $self->{document}->append_child ($doctype);        $self->{document}->append_child ($doctype);
959                
960        if ($token->{quirks} or $doctype_name ne 'HTML') {        if ($token->{quirks} or $doctype_name ne 'html') {
961          !!!cp ('t4');          !!!cp ('t4');
962          $self->{document}->manakai_compat_mode ('quirks');          $self->{document}->manakai_compat_mode ('quirks');
963        } elsif (defined $token->{pubid}) {        } elsif (defined $token->{pubid}) {
# Line 3818  sub _reset_insertion_mode ($) { Line 1242  sub _reset_insertion_mode ($) {
1242          ## SVG elements.  Currently the HTML syntax supports only MathML and          ## SVG elements.  Currently the HTML syntax supports only MathML and
1243          ## SVG elements as foreigners.          ## SVG elements as foreigners.
1244          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;
1245        } elsif ($node->[1] & TABLE_CELL_EL) {        } elsif ($node->[1] == TABLE_CELL_EL) {
1246          if ($last) {          if ($last) {
1247            !!!cp ('t28.2');            !!!cp ('t28.2');
1248            #            #
# Line 3847  sub _reset_insertion_mode ($) { Line 1271  sub _reset_insertion_mode ($) {
1271        $self->{insertion_mode} = $new_mode and return if defined $new_mode;        $self->{insertion_mode} = $new_mode and return if defined $new_mode;
1272                
1273        ## Step 15        ## Step 15
1274        if ($node->[1] & HTML_EL) {        if ($node->[1] == HTML_EL) {
1275          unless (defined $self->{head_element}) {          unless (defined $self->{head_element}) {
1276            !!!cp ('t29');            !!!cp ('t29');
1277            $self->{insertion_mode} = BEFORE_HEAD_IM;            $self->{insertion_mode} = BEFORE_HEAD_IM;
# Line 3979  sub _tree_construction_main ($) { Line 1403  sub _tree_construction_main ($) {
1403    
1404      ## Step 1      ## Step 1
1405      my $start_tag_name = $token->{tag_name};      my $start_tag_name = $token->{tag_name};
1406      my $el;      !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
     !!!create-element ($el, $HTML_NS, $start_tag_name, $token->{attributes}, $token);  
1407    
1408      ## Step 2      ## Step 2
     $insert->($el);  
   
     ## Step 3  
1409      $self->{content_model} = $content_model_flag; # CDATA or RCDATA      $self->{content_model} = $content_model_flag; # CDATA or RCDATA
1410      delete $self->{escape}; # MUST      delete $self->{escape}; # MUST
1411    
1412      ## Step 4      ## Step 3, 4
1413      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;  
     }  
   
     ## Step 5  
     if (length $text) {  
       !!!cp ('t41');  
       my $text = $self->{document}->create_text_node ($text);  
       $el->append_child ($text);  
     }  
1414    
1415      ## Step 6      !!!nack ('t40.1');
     $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";  
       }  
     }  
1416      !!!next-token;      !!!next-token;
1417    }; # $parse_rcdata    }; # $parse_rcdata
1418    
1419    my $script_start_tag = sub () {    my $script_start_tag = sub () {
1420        ## Step 1
1421      my $script_el;      my $script_el;
1422      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);
1423    
1424        ## Step 2
1425      ## TODO: mark as "parser-inserted"      ## TODO: mark as "parser-inserted"
1426    
1427        ## Step 3
1428        ## TODO: Mark as "already executed", if ...
1429    
1430        ## Step 4 (HTML5 revision 2702)
1431        $insert->($script_el);
1432        push @{$self->{open_elements}}, [$script_el, $el_category->{script}];
1433    
1434        ## Step 5
1435      $self->{content_model} = CDATA_CONTENT_MODEL;      $self->{content_model} = CDATA_CONTENT_MODEL;
1436      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;  
1437    
1438      if ($token->{type} == END_TAG_TOKEN and      ## Step 6-7
1439          $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  
1440    
1441        $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...  
     }  
       
1442      !!!next-token;      !!!next-token;
1443    }; # $script_start_tag    }; # $script_start_tag
1444    
1445    ## NOTE: $open_tables->[-1]->[0] is the "current table" element node.    ## NOTE: $open_tables->[-1]->[0] is the "current table" element node.
1446    ## NOTE: $open_tables->[-1]->[1] is the "tainted" flag.    ## NOTE: $open_tables->[-1]->[1] is the "tainted" flag (OBSOLETE; unused).
1447      ## NOTE: $open_tables->[-1]->[2] is set false when non-Text node inserted.
1448    my $open_tables = [[$self->{open_elements}->[0]->[0]]];    my $open_tables = [[$self->{open_elements}->[0]->[0]]];
1449    
1450    my $formatting_end_tag = sub {    my $formatting_end_tag = sub {
# Line 4167  sub _tree_construction_main ($) { Line 1529  sub _tree_construction_main ($) {
1529            !!!cp ('t59');            !!!cp ('t59');
1530            $furthest_block = $node;            $furthest_block = $node;
1531            $furthest_block_i_in_open = $_;            $furthest_block_i_in_open = $_;
1532              ## NOTE: The topmost (eldest) node.
1533          } elsif ($node->[0] eq $formatting_element->[0]) {          } elsif ($node->[0] eq $formatting_element->[0]) {
1534            !!!cp ('t60');            !!!cp ('t60');
1535            last OE;            last OE;
# Line 4250  sub _tree_construction_main ($) { Line 1613  sub _tree_construction_main ($) {
1613                
1614        ## Step 8        ## Step 8
1615        if ($common_ancestor_node->[1] & TABLE_ROWS_EL) {        if ($common_ancestor_node->[1] & TABLE_ROWS_EL) {
1616            ## Foster parenting.
1617          my $foster_parent_element;          my $foster_parent_element;
1618          my $next_sibling;          my $next_sibling;
1619          OE: for (reverse 0..$#{$self->{open_elements}}) {          OE: for (reverse 0..$#{$self->{open_elements}}) {
1620            if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {            if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1621                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;              !!!cp ('t65.2');
1622                               if (defined $parent and $parent->node_type == 1) {              $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1623                                 !!!cp ('t65.1');              $next_sibling = $self->{open_elements}->[$_]->[0];
1624                                 $foster_parent_element = $parent;              undef $next_sibling
1625                                 $next_sibling = $self->{open_elements}->[$_]->[0];                  unless $next_sibling->parent_node eq $foster_parent_element;
1626                               } else {              last OE;
1627                                 !!!cp ('t65.2');            }
1628                                 $foster_parent_element          } # OE
1629                                   = $self->{open_elements}->[$_ - 1]->[0];          $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1630                               }  
                              last OE;  
                            }  
                          } # OE  
                          $foster_parent_element = $self->{open_elements}->[0]->[0]  
                            unless defined $foster_parent_element;  
1631          $foster_parent_element->insert_before ($last_node->[0], $next_sibling);          $foster_parent_element->insert_before ($last_node->[0], $next_sibling);
1632          $open_tables->[-1]->[1] = 1; # tainted          $open_tables->[-1]->[1] = 1; # tainted
1633        } else {        } else {
# Line 4313  sub _tree_construction_main ($) { Line 1672  sub _tree_construction_main ($) {
1672            $i = $_;            $i = $_;
1673          }          }
1674        } # OE        } # OE
1675        splice @{$self->{open_elements}}, $i + 1, 1, $clone;        splice @{$self->{open_elements}}, $i + 1, 0, $clone;
1676                
1677        ## Step 14        ## Step 14
1678        redo FET;        redo FET;
# Line 4324  sub _tree_construction_main ($) { Line 1683  sub _tree_construction_main ($) {
1683      $self->{open_elements}->[-1]->[0]->append_child ($_[0]);      $self->{open_elements}->[-1]->[0]->append_child ($_[0]);
1684    }; # $insert_to_current    }; # $insert_to_current
1685    
1686      ## Foster parenting.  Note that there are three "foster parenting"
1687      ## code in the parser: for elements (this one), for texts, and for
1688      ## elements in the AAA code.
1689    my $insert_to_foster = sub {    my $insert_to_foster = sub {
1690      my $child = shift;      my $child = shift;
1691      if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {      if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
# Line 4331  sub _tree_construction_main ($) { Line 1693  sub _tree_construction_main ($) {
1693        my $foster_parent_element;        my $foster_parent_element;
1694        my $next_sibling;        my $next_sibling;
1695        OE: for (reverse 0..$#{$self->{open_elements}}) {        OE: for (reverse 0..$#{$self->{open_elements}}) {
1696          if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {          if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1697                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;            !!!cp ('t71');
1698                               if (defined $parent and $parent->node_type == 1) {            $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1699                                 !!!cp ('t70');            $next_sibling = $self->{open_elements}->[$_]->[0];
1700                                 $foster_parent_element = $parent;            undef $next_sibling
1701                                 $next_sibling = $self->{open_elements}->[$_]->[0];                unless $next_sibling->parent_node eq $foster_parent_element;
1702                               } else {            last OE;
1703                                 !!!cp ('t71');          }
1704                                 $foster_parent_element        } # OE
1705                                   = $self->{open_elements}->[$_ - 1]->[0];        $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1706                               }  
1707                               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);  
1708        $open_tables->[-1]->[1] = 1; # tainted        $open_tables->[-1]->[1] = 1; # tainted
1709      } else {      } else {
1710        !!!cp ('t72');        !!!cp ('t72');
# Line 4356  sub _tree_construction_main ($) { Line 1712  sub _tree_construction_main ($) {
1712      }      }
1713    }; # $insert_to_foster    }; # $insert_to_foster
1714    
1715      ## NOTE: Insert a character (MUST): When a character is inserted, if
1716      ## the last node that was inserted by the parser is a Text node and
1717      ## the character has to be inserted after that node, then the
1718      ## character is appended to the Text node.  However, if any other
1719      ## node is inserted by the parser, then a new Text node is created
1720      ## and the character is appended as that Text node.  If I'm not
1721      ## wrong, for a parser with scripting disabled, there are only two
1722      ## cases where this occurs.  One is the case where an element node
1723      ## is inserted to the |head| element.  This is covered by using the
1724      ## |$self->{head_element_inserted}| flag.  Another is the case where
1725      ## an element or comment is inserted into the |table| subtree while
1726      ## foster parenting happens.  This is covered by using the [2] flag
1727      ## of the |$open_tables| structure.  All other cases are handled
1728      ## simply by calling |manakai_append_text| method.
1729    
1730      ## TODO: |<body><script>document.write("a<br>");
1731      ## document.body.removeChild (document.body.lastChild);
1732      ## document.write ("b")</script>|
1733    
1734    B: while (1) {    B: while (1) {
1735    
1736        ## The "in table text" insertion mode.
1737        if ($self->{insertion_mode} & TABLE_IMS and
1738            not $self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and
1739            not $self->{insertion_mode} & IN_CDATA_RCDATA_IM) {
1740          C: {
1741            my $s;
1742            if ($token->{type} == CHARACTER_TOKEN) {
1743              !!!cp ('t194');
1744              $self->{pending_chars} ||= [];
1745              push @{$self->{pending_chars}}, $token;
1746              !!!next-token;
1747              next B;
1748            } else {
1749              if ($self->{pending_chars}) {
1750                $s = join '', map { $_->{data} } @{$self->{pending_chars}};
1751                delete $self->{pending_chars};
1752                if ($s =~ /[^\x09\x0A\x0C\x0D\x20]/) {
1753                  !!!cp ('t195');
1754                  #
1755                } else {
1756                  !!!cp ('t195.1');
1757                  #$self->{open_elements}->[-1]->[0]->manakai_append_text ($s);
1758                  $self->{open_elements}->[-1]->[0]->append_child
1759                      ($self->{document}->create_text_node ($s));
1760                  last C;
1761                }
1762              } else {
1763                !!!cp ('t195.2');
1764                last C;
1765              }
1766            }
1767    
1768            ## Foster parenting.
1769            !!!parse-error (type => 'in table:#text', token => $token);
1770    
1771            ## NOTE: As if in body, but insert into the foster parent element.
1772            $reconstruct_active_formatting_elements->($insert_to_foster);
1773                
1774            if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
1775              # MUST
1776              my $foster_parent_element;
1777              my $next_sibling;
1778              OE: for (reverse 0..$#{$self->{open_elements}}) {
1779                if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1780                  !!!cp ('t197');
1781                  $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
1782                  $next_sibling = $self->{open_elements}->[$_]->[0];
1783                  undef $next_sibling
1784                    unless $next_sibling->parent_node eq $foster_parent_element;
1785                  last OE;
1786                }
1787              } # OE
1788              $foster_parent_element ||= $self->{open_elements}->[0]->[0];
1789    
1790              !!!cp ('t199');
1791              $foster_parent_element->insert_before
1792                  ($self->{document}->create_text_node ($s), $next_sibling);
1793    
1794              $open_tables->[-1]->[1] = 1; # tainted
1795              $open_tables->[-1]->[2] = 1; # ~node inserted
1796            } else {
1797              ## NOTE: Fragment case or in a foster parent'ed element
1798              ## (e.g. |<table><span>a|).  In fragment case, whether the
1799              ## character is appended to existing node or a new node is
1800              ## created is irrelevant, since the foster parent'ed nodes
1801              ## are discarded and fragment parsing does not invoke any
1802              ## script.
1803              !!!cp ('t200');
1804              $self->{open_elements}->[-1]->[0]->manakai_append_text ($s);
1805            }
1806          } # C
1807        } # TABLE_IMS
1808    
1809      if ($token->{type} == DOCTYPE_TOKEN) {      if ($token->{type} == DOCTYPE_TOKEN) {
1810        !!!cp ('t73');        !!!cp ('t73');
1811        !!!parse-error (type => 'in html:#DOCTYPE', token => $token);        !!!parse-error (type => 'in html:#DOCTYPE', token => $token);
# Line 4403  sub _tree_construction_main ($) { Line 1852  sub _tree_construction_main ($) {
1852        } else {        } else {
1853          !!!cp ('t87');          !!!cp ('t87');
1854          $self->{open_elements}->[-1]->[0]->append_child ($comment);          $self->{open_elements}->[-1]->[0]->append_child ($comment);
1855            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
1856        }        }
1857        !!!next-token;        !!!next-token;
1858        next B;        next B;
1859        } elsif ($self->{insertion_mode} & IN_CDATA_RCDATA_IM) {
1860          if ($token->{type} == CHARACTER_TOKEN) {
1861            $token->{data} =~ s/^\x0A// if $self->{ignore_newline};
1862            delete $self->{ignore_newline};
1863    
1864            if (length $token->{data}) {
1865              !!!cp ('t43');
1866              $self->{open_elements}->[-1]->[0]->manakai_append_text
1867                  ($token->{data});
1868            } else {
1869              !!!cp ('t43.1');
1870            }
1871            !!!next-token;
1872            next B;
1873          } elsif ($token->{type} == END_TAG_TOKEN) {
1874            delete $self->{ignore_newline};
1875    
1876            if ($token->{tag_name} eq 'script') {
1877              !!!cp ('t50');
1878              
1879              ## Para 1-2
1880              my $script = pop @{$self->{open_elements}};
1881              
1882              ## Para 3
1883              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1884    
1885              ## Para 4
1886              ## TODO: $old_insertion_point = $current_insertion_point;
1887              ## TODO: $current_insertion_point = just before $self->{nc};
1888    
1889              ## Para 5
1890              ## TODO: Run the $script->[0].
1891    
1892              ## Para 6
1893              ## TODO: $current_insertion_point = $old_insertion_point;
1894    
1895              ## Para 7
1896              ## TODO: if ($pending_external_script) {
1897                ## TODO: ...
1898              ## TODO: }
1899    
1900              !!!next-token;
1901              next B;
1902            } else {
1903              !!!cp ('t42');
1904    
1905              pop @{$self->{open_elements}};
1906    
1907              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1908              !!!next-token;
1909              next B;
1910            }
1911          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
1912            delete $self->{ignore_newline};
1913    
1914            !!!cp ('t44');
1915            !!!parse-error (type => 'not closed',
1916                            text => $self->{open_elements}->[-1]->[0]
1917                                ->manakai_local_name,
1918                            token => $token);
1919    
1920            #if ($self->{open_elements}->[-1]->[1] == SCRIPT_EL) {
1921            #  ## TODO: Mark as "already executed"
1922            #}
1923    
1924            pop @{$self->{open_elements}};
1925    
1926            $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1927            ## Reprocess.
1928            next B;
1929          } else {
1930            die "$0: $token->{type}: In CDATA/RCDATA: Unknown token type";        
1931          }
1932      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {
1933        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
1934          !!!cp ('t87.1');          !!!cp ('t87.1');
# Line 4417  sub _tree_construction_main ($) { Line 1940  sub _tree_construction_main ($) {
1940               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or
1941              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or
1942              ($token->{tag_name} eq 'svg' and              ($token->{tag_name} eq 'svg' and
1943               $self->{open_elements}->[-1]->[1] & MML_AXML_EL)) {               $self->{open_elements}->[-1]->[1] == MML_AXML_EL)) {
1944            ## NOTE: "using the rules for secondary insertion mode"then"continue"            ## NOTE: "using the rules for secondary insertion mode"then"continue"
1945            !!!cp ('t87.2');            !!!cp ('t87.2');
1946            #            #
1947          } elsif ({          } elsif ({
1948                    b => 1, big => 1, blockquote => 1, body => 1, br => 1,                    b => 1, big => 1, blockquote => 1, body => 1, br => 1,
1949                    center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1,                    center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1,
1950                    em => 1, embed => 1, font => 1, h1 => 1, h2 => 1, h3 => 1,                    em => 1, embed => 1, h1 => 1, h2 => 1, h3 => 1,
1951                    h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1,                    h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1,
1952                    img => 1, li => 1, listing => 1, menu => 1, meta => 1,                    img => 1, li => 1, listing => 1, menu => 1, meta => 1,
1953                    nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1,                    nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1,
1954                    small => 1, span => 1, strong => 1, strike => 1, sub => 1,                    small => 1, span => 1, strong => 1, strike => 1, sub => 1,
1955                    sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1,                    sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1,
1956                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}} or
1957                     ($token->{tag_name} eq 'font' and
1958                      ($token->{attributes}->{color} or
1959                       $token->{attributes}->{face} or
1960                       $token->{attributes}->{size}))) {
1961            !!!cp ('t87.2');            !!!cp ('t87.2');
1962            !!!parse-error (type => 'not closed',            !!!parse-error (type => 'not closed',
1963                            text => $self->{open_elements}->[-1]->[0]                            text => $self->{open_elements}->[-1]->[0]
# Line 4506  sub _tree_construction_main ($) { Line 2033  sub _tree_construction_main ($) {
2033          }          }
2034        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
2035          ## NOTE: "using the rules for secondary insertion mode" then "continue"          ## NOTE: "using the rules for secondary insertion mode" then "continue"
2036          !!!cp ('t87.5');          if ($token->{tag_name} eq 'script') {
2037          #            !!!cp ('t87.41');
2038              #
2039              ## XXXscript: Execute script here.
2040            } else {
2041              !!!cp ('t87.5');
2042              #
2043            }
2044        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
2045          !!!cp ('t87.6');          !!!cp ('t87.6');
2046          !!!parse-error (type => 'not closed',          !!!parse-error (type => 'not closed',
# Line 4532  sub _tree_construction_main ($) { Line 2065  sub _tree_construction_main ($) {
2065        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
2066          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {
2067            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2068              !!!cp ('t88.2');              if ($self->{head_element_inserted}) {
2069              $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                !!!cp ('t88.3');
2070              #                $self->{open_elements}->[-1]->[0]->append_child
2071                    ($self->{document}->create_text_node ($1));
2072                  delete $self->{head_element_inserted};
2073                  ## NOTE: |</head> <link> |
2074                  #
2075                } else {
2076                  !!!cp ('t88.2');
2077                  $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
2078                  ## NOTE: |</head> &#x20;|
2079                  #
2080                }
2081            } else {            } else {
2082              !!!cp ('t88.1');              !!!cp ('t88.1');
2083              ## Ignore the token.              ## Ignore the token.
# Line 4630  sub _tree_construction_main ($) { Line 2173  sub _tree_construction_main ($) {
2173            !!!cp ('t97');            !!!cp ('t97');
2174          }          }
2175    
2176              if ($token->{tag_name} eq 'base') {          if ($token->{tag_name} eq 'base') {
2177                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2178                  !!!cp ('t98');              !!!cp ('t98');
2179                  ## As if </noscript>              ## As if </noscript>
2180                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2181                  !!!parse-error (type => 'in noscript', text => 'base',              !!!parse-error (type => 'in noscript', text => 'base',
2182                                  token => $token);                              token => $token);
2183                            
2184                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2185                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2186                } else {            } else {
2187                  !!!cp ('t99');              !!!cp ('t99');
2188                }            }
2189    
2190                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2191                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2192                  !!!cp ('t100');              !!!cp ('t100');
2193                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2194                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2195                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2196                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2197                } else {              $self->{head_element_inserted} = 1;
2198                  !!!cp ('t101');            } else {
2199                }              !!!cp ('t101');
2200                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2201                pop @{$self->{open_elements}};            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2202                pop @{$self->{open_elements}} # <head>            pop @{$self->{open_elements}};
2203                    if $self->{insertion_mode} == AFTER_HEAD_IM;            pop @{$self->{open_elements}} # <head>
2204                !!!nack ('t101.1');                if $self->{insertion_mode} == AFTER_HEAD_IM;
2205                !!!next-token;            !!!nack ('t101.1');
2206                next B;            !!!next-token;
2207              next B;
2208          } elsif ($token->{tag_name} eq 'link') {          } elsif ($token->{tag_name} eq 'link') {
2209            ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2210            if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
# Line 4669  sub _tree_construction_main ($) { Line 2213  sub _tree_construction_main ($) {
2213                              text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2214              push @{$self->{open_elements}},              push @{$self->{open_elements}},
2215                  [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2216                $self->{head_element_inserted} = 1;
2217            } else {            } else {
2218              !!!cp ('t103');              !!!cp ('t103');
2219            }            }
# Line 4679  sub _tree_construction_main ($) { Line 2224  sub _tree_construction_main ($) {
2224            !!!ack ('t103.1');            !!!ack ('t103.1');
2225            !!!next-token;            !!!next-token;
2226            next B;            next B;
2227          } elsif ($token->{tag_name} eq 'command' or          } elsif ($token->{tag_name} eq 'command') {
                  $token->{tag_name} eq 'eventsource') {  
2228            if ($self->{insertion_mode} == IN_HEAD_IM) {            if ($self->{insertion_mode} == IN_HEAD_IM) {
2229              ## NOTE: If the insertion mode at the time of the emission              ## NOTE: If the insertion mode at the time of the emission
2230              ## of the token was "before head", $self->{insertion_mode}              ## of the token was "before head", $self->{insertion_mode}
# Line 4701  sub _tree_construction_main ($) { Line 2245  sub _tree_construction_main ($) {
2245              !!!cp ('t103.3');              !!!cp ('t103.3');
2246              #              #
2247            }            }
2248              } elsif ($token->{tag_name} eq 'meta') {          } elsif ($token->{tag_name} eq 'meta') {
2249                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2250                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2251                  !!!cp ('t104');              !!!cp ('t104');
2252                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2253                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2254                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2255                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2256                } else {              $self->{head_element_inserted} = 1;
2257                  !!!cp ('t105');            } else {
2258                }              !!!cp ('t105');
2259                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2260                my $meta_el = pop @{$self->{open_elements}};            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2261              my $meta_el = pop @{$self->{open_elements}};
2262    
2263                unless ($self->{confident}) {                unless ($self->{confident}) {
2264                  if ($token->{attributes}->{charset}) {                  if ($token->{attributes}->{charset}) {
# Line 4771  sub _tree_construction_main ($) { Line 2316  sub _tree_construction_main ($) {
2316                !!!ack ('t110.1');                !!!ack ('t110.1');
2317                !!!next-token;                !!!next-token;
2318                next B;                next B;
2319              } elsif ($token->{tag_name} eq 'title') {          } elsif ($token->{tag_name} eq 'title') {
2320                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2321                  !!!cp ('t111');              !!!cp ('t111');
2322                  ## As if </noscript>              ## As if </noscript>
2323                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2324                  !!!parse-error (type => 'in noscript', text => 'title',              !!!parse-error (type => 'in noscript', text => 'title',
2325                                  token => $token);                              token => $token);
2326                            
2327                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2328                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2329                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2330                  !!!cp ('t112');              !!!cp ('t112');
2331                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2332                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2333                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2334                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2335                } else {              $self->{head_element_inserted} = 1;
2336                  !!!cp ('t113');            } else {
2337                }              !!!cp ('t113');
2338              }
2339    
2340                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2341                my $parent = defined $self->{head_element} ? $self->{head_element}            $parse_rcdata->(RCDATA_CONTENT_MODEL);
2342                    : $self->{open_elements}->[-1]->[0];  
2343                $parse_rcdata->(RCDATA_CONTENT_MODEL);            ## NOTE: At this point the stack of open elements contain
2344                pop @{$self->{open_elements}} # <head>            ## the |head| element (index == -2) and the |script| element
2345                    if $self->{insertion_mode} == AFTER_HEAD_IM;            ## (index == -1).  In the "after head" insertion mode the
2346                next B;            ## |head| element is inserted only for the purpose of
2347              } elsif ($token->{tag_name} eq 'style' or            ## providing the context for the |script| element, and
2348                       $token->{tag_name} eq 'noframes') {            ## therefore we can now and have to remove the element from
2349                ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and            ## the stack.
2350                ## insertion mode IN_HEAD_IM)            splice @{$self->{open_elements}}, -2, 1, () # <head>
2351                ## NOTE: There is a "as if in head" code clone.                if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2352                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            next B;
2353                  !!!cp ('t114');          } elsif ($token->{tag_name} eq 'style' or
2354                  !!!parse-error (type => 'after head',                   $token->{tag_name} eq 'noframes') {
2355                                  text => $token->{tag_name}, token => $token);            ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
2356                  push @{$self->{open_elements}},            ## insertion mode IN_HEAD_IM)
2357                      [$self->{head_element}, $el_category->{head}];            ## NOTE: There is a "as if in head" code clone.
2358                } else {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2359                  !!!cp ('t115');              !!!cp ('t114');
2360                }              !!!parse-error (type => 'after head',
2361                $parse_rcdata->(CDATA_CONTENT_MODEL);                              text => $token->{tag_name}, token => $token);
2362                pop @{$self->{open_elements}} # <head>              push @{$self->{open_elements}},
2363                    if $self->{insertion_mode} == AFTER_HEAD_IM;                  [$self->{head_element}, $el_category->{head}];
2364                next B;              $self->{head_element_inserted} = 1;
2365              } elsif ($token->{tag_name} eq 'noscript') {            } else {
2366                !!!cp ('t115');
2367              }
2368              $parse_rcdata->(CDATA_CONTENT_MODEL);
2369              ## ISSUE: A spec bug [Bug 6038]
2370              splice @{$self->{open_elements}}, -2, 1, () # <head>
2371                  if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2372              next B;
2373            } elsif ($token->{tag_name} eq 'noscript') {
2374                if ($self->{insertion_mode} == IN_HEAD_IM) {                if ($self->{insertion_mode} == IN_HEAD_IM) {
2375                  !!!cp ('t116');                  !!!cp ('t116');
2376                  ## NOTE: and scripting is disalbed                  ## NOTE: and scripting is disalbed
# Line 4837  sub _tree_construction_main ($) { Line 2391  sub _tree_construction_main ($) {
2391                  !!!cp ('t118');                  !!!cp ('t118');
2392                  #                  #
2393                }                }
2394              } elsif ($token->{tag_name} eq 'script') {          } elsif ($token->{tag_name} eq 'script') {
2395                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2396                  !!!cp ('t119');              !!!cp ('t119');
2397                  ## As if </noscript>              ## As if </noscript>
2398                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2399                  !!!parse-error (type => 'in noscript', text => 'script',              !!!parse-error (type => 'in noscript', text => 'script',
2400                                  token => $token);                              token => $token);
2401                            
2402                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2403                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2404                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2405                  !!!cp ('t120');              !!!cp ('t120');
2406                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2407                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2408                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2409                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2410                } else {              $self->{head_element_inserted} = 1;
2411                  !!!cp ('t121');            } else {
2412                }              !!!cp ('t121');
2413              }
2414    
2415                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2416                $script_start_tag->();            $script_start_tag->();
2417                pop @{$self->{open_elements}} # <head>            ## ISSUE: A spec bug  [Bug 6038]
2418                    if $self->{insertion_mode} == AFTER_HEAD_IM;            splice @{$self->{open_elements}}, -2, 1 # <head>
2419                next B;                if ($self->{insertion_mode} & IM_MASK) == AFTER_HEAD_IM;
2420              } elsif ($token->{tag_name} eq 'body' or            next B;
2421                       $token->{tag_name} eq 'frameset') {          } elsif ($token->{tag_name} eq 'body' or
2422                     $token->{tag_name} eq 'frameset') {
2423                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2424                  !!!cp ('t122');                  !!!cp ('t122');
2425                  ## As if </noscript>                  ## As if </noscript>
# Line 4933  sub _tree_construction_main ($) { Line 2489  sub _tree_construction_main ($) {
2489              ## reprocess              ## reprocess
2490              !!!ack-later;              !!!ack-later;
2491              next B;              next B;
2492            } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
2493              if ($token->{tag_name} eq 'head') {          ## "Before head", "in head", and "after head" insertion modes
2494                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {          ## ignore most of end tags.  Exceptions are "body", "html",
2495                  !!!cp ('t132');          ## and "br" end tags.  "Before head" and "in head" insertion
2496                  ## As if <head>          ## modes also recognize "head" end tag.  "In head noscript"
2497                  !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);          ## insertion modes ignore end tags except for "noscript" and
2498                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});          ## "br".
                 push @{$self->{open_elements}},  
                     [$self->{head_element}, $el_category->{head}];  
2499    
2500                  ## Reprocess in the "in head" insertion mode...          if ($token->{tag_name} eq 'head') {
2501                  pop @{$self->{open_elements}};            if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2502                  $self->{insertion_mode} = AFTER_HEAD_IM;              !!!cp ('t132');
2503                  !!!next-token;              ## As if <head>
2504                  next B;              !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);
2505                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {              $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
2506                  !!!cp ('t133');              push @{$self->{open_elements}},
2507                  ## As if </noscript>                  [$self->{head_element}, $el_category->{head}];
2508                  pop @{$self->{open_elements}};  
2509                  !!!parse-error (type => 'in noscript:/',              ## Reprocess in the "in head" insertion mode...
2510                                  text => 'head', token => $token);              pop @{$self->{open_elements}};
2511                                $self->{insertion_mode} = AFTER_HEAD_IM;
2512                  ## Reprocess in the "in head" insertion mode...              !!!next-token;
2513                  pop @{$self->{open_elements}};              next B;
2514                  $self->{insertion_mode} = AFTER_HEAD_IM;            } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2515                  !!!next-token;              !!!cp ('t133');
2516                  next B;              #
2517                } elsif ($self->{insertion_mode} == IN_HEAD_IM) {            } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
2518                  !!!cp ('t134');              !!!cp ('t134');
2519                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2520                  $self->{insertion_mode} = AFTER_HEAD_IM;              $self->{insertion_mode} = AFTER_HEAD_IM;
2521                  !!!next-token;              !!!next-token;
2522                  next B;              next B;
2523                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2524                  !!!cp ('t134.1');              !!!cp ('t134.1');
2525                  !!!parse-error (type => 'unmatched end tag', text => 'head',              #
2526                                  token => $token);            } else {
2527                  ## Ignore the token              die "$0: $self->{insertion_mode}: Unknown insertion mode";
2528                  !!!next-token;            }
2529                  next B;          } elsif ($token->{tag_name} eq 'noscript') {
2530                } else {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2531                  die "$0: $self->{insertion_mode}: Unknown insertion mode";              !!!cp ('t136');
2532                }              pop @{$self->{open_elements}};
2533              } elsif ($token->{tag_name} eq 'noscript') {              $self->{insertion_mode} = IN_HEAD_IM;
2534                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {              !!!next-token;
2535                  !!!cp ('t136');              next B;
2536                  pop @{$self->{open_elements}};            } else {
2537                  $self->{insertion_mode} = IN_HEAD_IM;              !!!cp ('t138');
2538                  !!!next-token;              #
2539                  next B;            }
2540                } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM or          } elsif ({
2541                         $self->{insertion_mode} == AFTER_HEAD_IM) {              body => ($self->{insertion_mode} != IN_HEAD_NOSCRIPT_IM),
2542                  !!!cp ('t137');              html => ($self->{insertion_mode} != IN_HEAD_NOSCRIPT_IM),
2543                  !!!parse-error (type => 'unmatched end tag',              br => 1,
2544                                  text => 'noscript', token => $token);          }->{$token->{tag_name}}) {
2545                  ## Ignore the token ## ISSUE: An issue in the spec.            if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2546                  !!!next-token;              !!!cp ('t142.2');
2547                  next B;              ## (before head) as if <head>, (in head) as if </head>
2548                } else {              !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);
2549                  !!!cp ('t138');              $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
2550                  #              $self->{insertion_mode} = AFTER_HEAD_IM;
               }  
             } elsif ({  
                       body => 1, html => 1,  
                      }->{$token->{tag_name}}) {  
               if ($self->{insertion_mode} == BEFORE_HEAD_IM or  
                   $self->{insertion_mode} == IN_HEAD_IM or  
                   $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {  
                 !!!cp ('t140');  
                 !!!parse-error (type => 'unmatched end tag',  
                                 text => $token->{tag_name}, token => $token);  
                 ## Ignore the token  
                 !!!next-token;  
                 next B;  
               } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {  
                 !!!cp ('t140.1');  
                 !!!parse-error (type => 'unmatched end tag',  
                                 text => $token->{tag_name}, token => $token);  
                 ## Ignore the token  
                 !!!next-token;  
                 next B;  
               } else {  
                 die "$0: $self->{insertion_mode}: Unknown insertion mode";  
               }  
             } elsif ($token->{tag_name} eq 'p') {  
               !!!cp ('t142');  
               !!!parse-error (type => 'unmatched end tag',  
                               text => $token->{tag_name}, token => $token);  
               ## Ignore the token  
               !!!next-token;  
               next B;  
             } elsif ($token->{tag_name} eq 'br') {  
               if ($self->{insertion_mode} == BEFORE_HEAD_IM) {  
                 !!!cp ('t142.2');  
                 ## (before head) as if <head>, (in head) as if </head>  
                 !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);  
                 $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});  
                 $self->{insertion_mode} = AFTER_HEAD_IM;  
2551        
2552                  ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2553                } elsif ($self->{insertion_mode} == IN_HEAD_IM) {            } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
2554                  !!!cp ('t143.2');              !!!cp ('t143.2');
2555                  ## As if </head>              ## As if </head>
2556                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2557                  $self->{insertion_mode} = AFTER_HEAD_IM;              $self->{insertion_mode} = AFTER_HEAD_IM;
2558        
2559                  ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2560                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2561                  !!!cp ('t143.3');              !!!cp ('t143.3');
2562                  ## ISSUE: Two parse errors for <head><noscript></br>              ## NOTE: Two parse errors for <head><noscript></br>
2563                  !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
2564                                  text => 'br', token => $token);                              text => $token->{tag_name}, token => $token);
2565                  ## As if </noscript>              ## As if </noscript>
2566                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2567                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
   
                 ## Reprocess in the "in head" insertion mode...  
                 ## As if </head>  
                 pop @{$self->{open_elements}};  
                 $self->{insertion_mode} = AFTER_HEAD_IM;  
   
                 ## Reprocess in the "after head" insertion mode...  
               } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {  
                 !!!cp ('t143.4');  
                 #  
               } else {  
                 die "$0: $self->{insertion_mode}: Unknown insertion mode";  
               }  
   
               ## ISSUE: does not agree with IE7 - it doesn't ignore </br>.  
               !!!parse-error (type => 'unmatched end tag',  
                               text => 'br', token => $token);  
               ## Ignore the token  
               !!!next-token;  
               next B;  
             } else {  
               !!!cp ('t145');  
               !!!parse-error (type => 'unmatched end tag',  
                               text => $token->{tag_name}, token => $token);  
               ## Ignore the token  
               !!!next-token;  
               next B;  
             }  
2568    
2569              if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {              ## Reprocess in the "in head" insertion mode...
2570                !!!cp ('t146');              ## As if </head>
2571                ## As if </noscript>              pop @{$self->{open_elements}};
2572                pop @{$self->{open_elements}};              $self->{insertion_mode} = AFTER_HEAD_IM;
               !!!parse-error (type => 'in noscript:/',  
                               text => $token->{tag_name}, token => $token);  
                 
               ## Reprocess in the "in head" insertion mode...  
               ## As if </head>  
               pop @{$self->{open_elements}};  
2573    
2574                ## Reprocess in the "after head" insertion mode...              ## Reprocess in the "after head" insertion mode...
2575              } elsif ($self->{insertion_mode} == IN_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2576                !!!cp ('t147');              !!!cp ('t143.4');
2577                ## As if </head>              #
2578                pop @{$self->{open_elements}};            } else {
2579                die "$0: $self->{insertion_mode}: Unknown insertion mode";
2580              }
2581    
2582                ## Reprocess in the "after head" insertion mode...            ## "after head" insertion mode
2583              } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {            ## As if <body>
2584  ## ISSUE: This case cannot be reached?            !!!insert-element ('body',, $token);
2585                !!!cp ('t148');            $self->{insertion_mode} = IN_BODY_IM;
2586                !!!parse-error (type => 'unmatched end tag',            ## Reprocess.
2587                                text => $token->{tag_name}, token => $token);            next B;
2588                ## Ignore the token ## ISSUE: An issue in the spec.          }
               !!!next-token;  
               next B;  
             } else {  
               !!!cp ('t149');  
             }  
2589    
2590              ## "after head" insertion mode          ## End tags are ignored by default.
2591              ## As if <body>          !!!cp ('t145');
2592              !!!insert-element ('body',, $token);          !!!parse-error (type => 'unmatched end tag',
2593              $self->{insertion_mode} = IN_BODY_IM;                          text => $token->{tag_name}, token => $token);
2594              ## reprocess          ## Ignore the token.
2595              next B;          !!!next-token;
2596            next B;
2597        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
2598          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
2599            !!!cp ('t149.1');            !!!cp ('t149.1');
# Line 5185  sub _tree_construction_main ($) { Line 2666  sub _tree_construction_main ($) {
2666                   caption => 1, col => 1, colgroup => 1, tbody => 1,                   caption => 1, col => 1, colgroup => 1, tbody => 1,
2667                   td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,                   td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,
2668                  }->{$token->{tag_name}}) {                  }->{$token->{tag_name}}) {
2669                if ($self->{insertion_mode} == IN_CELL_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2670                  ## have an element in table scope                  ## have an element in table scope
2671                  for (reverse 0..$#{$self->{open_elements}}) {                  for (reverse 0..$#{$self->{open_elements}}) {
2672                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
2673                    if ($node->[1] & TABLE_CELL_EL) {                    if ($node->[1] == TABLE_CELL_EL) {
2674                      !!!cp ('t151');                      !!!cp ('t151');
2675    
2676                      ## Close the cell                      ## Close the cell
# Line 5213  sub _tree_construction_main ($) { Line 2694  sub _tree_construction_main ($) {
2694                  !!!nack ('t153.1');                  !!!nack ('t153.1');
2695                  !!!next-token;                  !!!next-token;
2696                  next B;                  next B;
2697                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2698                  !!!parse-error (type => 'not closed', text => 'caption',                  !!!parse-error (type => 'not closed', text => 'caption',
2699                                  token => $token);                                  token => $token);
2700                                    
# Line 5223  sub _tree_construction_main ($) { Line 2704  sub _tree_construction_main ($) {
2704                  INSCOPE: {                  INSCOPE: {
2705                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2706                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2707                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2708                        !!!cp ('t155');                        !!!cp ('t155');
2709                        $i = $_;                        $i = $_;
2710                        last INSCOPE;                        last INSCOPE;
# Line 5249  sub _tree_construction_main ($) { Line 2730  sub _tree_construction_main ($) {
2730                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2731                  }                  }
2732    
2733                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2734                    !!!cp ('t159');                    !!!cp ('t159');
2735                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2736                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5278  sub _tree_construction_main ($) { Line 2759  sub _tree_construction_main ($) {
2759              }              }
2760            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
2761              if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {              if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {
2762                if ($self->{insertion_mode} == IN_CELL_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2763                  ## have an element in table scope                  ## have an element in table scope
2764                  my $i;                  my $i;
2765                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 5328  sub _tree_construction_main ($) { Line 2809  sub _tree_construction_main ($) {
2809                                    
2810                  !!!next-token;                  !!!next-token;
2811                  next B;                  next B;
2812                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2813                  !!!cp ('t169');                  !!!cp ('t169');
2814                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2815                                  text => $token->{tag_name}, token => $token);                                  text => $token->{tag_name}, token => $token);
# Line 5340  sub _tree_construction_main ($) { Line 2821  sub _tree_construction_main ($) {
2821                  #                  #
2822                }                }
2823              } elsif ($token->{tag_name} eq 'caption') {              } elsif ($token->{tag_name} eq 'caption') {
2824                if ($self->{insertion_mode} == IN_CAPTION_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2825                  ## have a table element in table scope                  ## have a table element in table scope
2826                  my $i;                  my $i;
2827                  INSCOPE: {                  INSCOPE: {
2828                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2829                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2830                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2831                        !!!cp ('t171');                        !!!cp ('t171');
2832                        $i = $_;                        $i = $_;
2833                        last INSCOPE;                        last INSCOPE;
# Line 5371  sub _tree_construction_main ($) { Line 2852  sub _tree_construction_main ($) {
2852                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2853                  }                  }
2854                                    
2855                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2856                    !!!cp ('t175');                    !!!cp ('t175');
2857                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2858                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5389  sub _tree_construction_main ($) { Line 2870  sub _tree_construction_main ($) {
2870                                    
2871                  !!!next-token;                  !!!next-token;
2872                  next B;                  next B;
2873                } elsif ($self->{insertion_mode} == IN_CELL_IM) {                } elsif (($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2874                  !!!cp ('t177');                  !!!cp ('t177');
2875                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2876                                  text => $token->{tag_name}, token => $token);                                  text => $token->{tag_name}, token => $token);
# Line 5404  sub _tree_construction_main ($) { Line 2885  sub _tree_construction_main ($) {
2885                        table => 1, tbody => 1, tfoot => 1,                        table => 1, tbody => 1, tfoot => 1,
2886                        thead => 1, tr => 1,                        thead => 1, tr => 1,
2887                       }->{$token->{tag_name}} and                       }->{$token->{tag_name}} and
2888                       $self->{insertion_mode} == IN_CELL_IM) {                       ($self->{insertion_mode} & IM_MASK) == IN_CELL_IM) {
2889                ## have an element in table scope                ## have an element in table scope
2890                my $i;                my $i;
2891                my $tn;                my $tn;
# Line 5421  sub _tree_construction_main ($) { Line 2902  sub _tree_construction_main ($) {
2902                                line => $token->{line},                                line => $token->{line},
2903                                column => $token->{column}};                                column => $token->{column}};
2904                      next B;                      next B;
2905                    } elsif ($node->[1] & TABLE_CELL_EL) {                    } elsif ($node->[1] == TABLE_CELL_EL) {
2906                      !!!cp ('t180');                      !!!cp ('t180');
2907                      $tn = $node->[0]->manakai_local_name;                      $tn = $node->[0]->manakai_local_name;
2908                      ## NOTE: There is exactly one |td| or |th| element                      ## NOTE: There is exactly one |td| or |th| element
# Line 5441  sub _tree_construction_main ($) { Line 2922  sub _tree_construction_main ($) {
2922                  next B;                  next B;
2923                } # INSCOPE                } # INSCOPE
2924              } elsif ($token->{tag_name} eq 'table' and              } elsif ($token->{tag_name} eq 'table' and
2925                       $self->{insertion_mode} == IN_CAPTION_IM) {                       ($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2926                !!!parse-error (type => 'not closed', text => 'caption',                !!!parse-error (type => 'not closed', text => 'caption',
2927                                token => $token);                                token => $token);
2928    
# Line 5450  sub _tree_construction_main ($) { Line 2931  sub _tree_construction_main ($) {
2931                my $i;                my $i;
2932                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
2933                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
2934                  if ($node->[1] & CAPTION_EL) {                  if ($node->[1] == CAPTION_EL) {
2935                    !!!cp ('t184');                    !!!cp ('t184');
2936                    $i = $_;                    $i = $_;
2937                    last INSCOPE;                    last INSCOPE;
# Line 5461  sub _tree_construction_main ($) { Line 2942  sub _tree_construction_main ($) {
2942                } # INSCOPE                } # INSCOPE
2943                unless (defined $i) {                unless (defined $i) {
2944                  !!!cp ('t186');                  !!!cp ('t186');
2945            ## TODO: Wrong error type?
2946                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2947                                  text => 'caption', token => $token);                                  text => 'caption', token => $token);
2948                  ## Ignore the token                  ## Ignore the token
# Line 5474  sub _tree_construction_main ($) { Line 2956  sub _tree_construction_main ($) {
2956                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
2957                }                }
2958    
2959                unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2960                  !!!cp ('t188');                  !!!cp ('t188');
2961                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
2962                                  text => $self->{open_elements}->[-1]->[0]                                  text => $self->{open_elements}->[-1]->[0]
# Line 5506  sub _tree_construction_main ($) { Line 2988  sub _tree_construction_main ($) {
2988                  !!!cp ('t191');                  !!!cp ('t191');
2989                  #                  #
2990                }                }
2991              } elsif ({          } elsif ({
2992                        tbody => 1, tfoot => 1,                    tbody => 1, tfoot => 1,
2993                        thead => 1, tr => 1,                    thead => 1, tr => 1,
2994                       }->{$token->{tag_name}} and                   }->{$token->{tag_name}} and
2995                       $self->{insertion_mode} == IN_CAPTION_IM) {                   ($self->{insertion_mode} & IM_MASK) == IN_CAPTION_IM) {
2996                !!!cp ('t192');            !!!cp ('t192');
2997                !!!parse-error (type => 'unmatched end tag',            !!!parse-error (type => 'unmatched end tag',
2998                                text => $token->{tag_name}, token => $token);                            text => $token->{tag_name}, token => $token);
2999                ## Ignore the token            ## Ignore the token
3000                !!!next-token;            !!!next-token;
3001                next B;            next B;
3002              } else {          } else {
3003                !!!cp ('t193');            !!!cp ('t193');
3004                #            #
3005              }          }
3006        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3007          for my $entry (@{$self->{open_elements}}) {          for my $entry (@{$self->{open_elements}}) {
3008            unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) {            unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) {
# Line 5539  sub _tree_construction_main ($) { Line 3021  sub _tree_construction_main ($) {
3021        $insert = $insert_to_current;        $insert = $insert_to_current;
3022        #        #
3023      } elsif ($self->{insertion_mode} & TABLE_IMS) {      } elsif ($self->{insertion_mode} & TABLE_IMS) {
3024        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) {  
3025          if ({          if ({
3026               tr => ($self->{insertion_mode} != IN_ROW_IM),               tr => (($self->{insertion_mode} & IM_MASK) != IN_ROW_IM),
3027               th => 1, td => 1,               th => 1, td => 1,
3028              }->{$token->{tag_name}}) {              }->{$token->{tag_name}}) {
3029            if ($self->{insertion_mode} == IN_TABLE_IM) {            if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_IM) {
3030              ## Clear back to table context              ## Clear back to table context
3031              while (not ($self->{open_elements}->[-1]->[1]              while (not ($self->{open_elements}->[-1]->[1]
3032                              & TABLE_SCOPING_EL)) {                              & TABLE_SCOPING_EL)) {
# Line 5621  sub _tree_construction_main ($) { Line 3039  sub _tree_construction_main ($) {
3039              ## reprocess in the "in table body" insertion mode...              ## reprocess in the "in table body" insertion mode...
3040            }            }
3041                        
3042            if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {            if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3043              unless ($token->{tag_name} eq 'tr') {              unless ($token->{tag_name} eq 'tr') {
3044                !!!cp ('t202');                !!!cp ('t202');
3045                !!!parse-error (type => 'missing start tag:tr', token => $token);                !!!parse-error (type => 'missing start tag:tr', token => $token);
# Line 5635  sub _tree_construction_main ($) { Line 3053  sub _tree_construction_main ($) {
3053                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3054              }              }
3055                                    
3056                  $self->{insertion_mode} = IN_ROW_IM;              $self->{insertion_mode} = IN_ROW_IM;
3057                  if ($token->{tag_name} eq 'tr') {              if ($token->{tag_name} eq 'tr') {
3058                    !!!cp ('t204');                !!!cp ('t204');
3059                    !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3060                    !!!nack ('t204');                $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3061                    !!!next-token;                !!!nack ('t204');
3062                    next B;                !!!next-token;
3063                  } else {                next B;
3064                    !!!cp ('t205');              } else {
3065                    !!!insert-element ('tr',, $token);                !!!cp ('t205');
3066                    ## reprocess in the "in row" insertion mode                !!!insert-element ('tr',, $token);
3067                  }                ## reprocess in the "in row" insertion mode
3068                } else {              }
3069                  !!!cp ('t206');            } else {
3070                }              !!!cp ('t206');
3071              }
3072    
3073                ## Clear back to table row context                ## Clear back to table row context
3074                while (not ($self->{open_elements}->[-1]->[1]                while (not ($self->{open_elements}->[-1]->[1]
# Line 5658  sub _tree_construction_main ($) { Line 3077  sub _tree_construction_main ($) {
3077                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3078                }                }
3079                                
3080                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3081                $self->{insertion_mode} = IN_CELL_IM;            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3082              $self->{insertion_mode} = IN_CELL_IM;
3083    
3084                push @$active_formatting_elements, ['#marker', ''];            push @$active_formatting_elements, ['#marker', ''];
3085                                
3086                !!!nack ('t207.1');            !!!nack ('t207.1');
3087              !!!next-token;
3088              next B;
3089            } elsif ({
3090                      caption => 1, col => 1, colgroup => 1,
3091                      tbody => 1, tfoot => 1, thead => 1,
3092                      tr => 1, # $self->{insertion_mode} == IN_ROW_IM
3093                     }->{$token->{tag_name}}) {
3094              if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3095                ## As if </tr>
3096                ## have an element in table scope
3097                my $i;
3098                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3099                  my $node = $self->{open_elements}->[$_];
3100                  if ($node->[1] == TABLE_ROW_EL) {
3101                    !!!cp ('t208');
3102                    $i = $_;
3103                    last INSCOPE;
3104                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
3105                    !!!cp ('t209');
3106                    last INSCOPE;
3107                  }
3108                } # INSCOPE
3109                unless (defined $i) {
3110                  !!!cp ('t210');
3111                  ## TODO: This type is wrong.
3112                  !!!parse-error (type => 'unmacthed end tag',
3113                                  text => $token->{tag_name}, token => $token);
3114                  ## Ignore the token
3115                  !!!nack ('t210.1');
3116                !!!next-token;                !!!next-token;
3117                next B;                next B;
3118              } 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;  
                 }  
3119                                    
3120                  ## Clear back to table row context                  ## Clear back to table row context
3121                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
# Line 5718  sub _tree_construction_main ($) { Line 3138  sub _tree_construction_main ($) {
3138                  }                  }
3139                }                }
3140    
3141                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3142                  ## have an element in table scope                  ## have an element in table scope
3143                  my $i;                  my $i;
3144                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3145                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3146                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3147                      !!!cp ('t214');                      !!!cp ('t214');
3148                      $i = $_;                      $i = $_;
3149                      last INSCOPE;                      last INSCOPE;
# Line 5765  sub _tree_construction_main ($) { Line 3185  sub _tree_construction_main ($) {
3185                  !!!cp ('t218');                  !!!cp ('t218');
3186                }                }
3187    
3188                if ($token->{tag_name} eq 'col') {            if ($token->{tag_name} eq 'col') {
3189                  ## Clear back to table context              ## Clear back to table context
3190                  while (not ($self->{open_elements}->[-1]->[1]              while (not ($self->{open_elements}->[-1]->[1]
3191                                  & TABLE_SCOPING_EL)) {                              & TABLE_SCOPING_EL)) {
3192                    !!!cp ('t219');                !!!cp ('t219');
3193                    ## ISSUE: Can this state be reached?                ## ISSUE: Can this state be reached?
3194                    pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3195                  }              }
3196                                
3197                  !!!insert-element ('colgroup',, $token);              !!!insert-element ('colgroup',, $token);
3198                  $self->{insertion_mode} = IN_COLUMN_GROUP_IM;              $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
3199                  ## reprocess              ## reprocess
3200                  !!!ack-later;              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3201                  next B;              !!!ack-later;
3202                } elsif ({              next B;
3203                          caption => 1,            } elsif ({
3204                          colgroup => 1,                      caption => 1,
3205                          tbody => 1, tfoot => 1, thead => 1,                      colgroup => 1,
3206                         }->{$token->{tag_name}}) {                      tbody => 1, tfoot => 1, thead => 1,
3207                  ## Clear back to table context                     }->{$token->{tag_name}}) {
3208                ## Clear back to table context
3209                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
3210                                  & TABLE_SCOPING_EL)) {                                  & TABLE_SCOPING_EL)) {
3211                    !!!cp ('t220');                    !!!cp ('t220');
# Line 5792  sub _tree_construction_main ($) { Line 3213  sub _tree_construction_main ($) {
3213                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
3214                  }                  }
3215                                    
3216                  push @$active_formatting_elements, ['#marker', '']              push @$active_formatting_elements, ['#marker', '']
3217                      if $token->{tag_name} eq 'caption';                  if $token->{tag_name} eq 'caption';
3218                                    
3219                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);              !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3220                  $self->{insertion_mode} = {              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3221                                             caption => IN_CAPTION_IM,              $self->{insertion_mode} = {
3222                                             colgroup => IN_COLUMN_GROUP_IM,                                         caption => IN_CAPTION_IM,
3223                                             tbody => IN_TABLE_BODY_IM,                                         colgroup => IN_COLUMN_GROUP_IM,
3224                                             tfoot => IN_TABLE_BODY_IM,                                         tbody => IN_TABLE_BODY_IM,
3225                                             thead => IN_TABLE_BODY_IM,                                         tfoot => IN_TABLE_BODY_IM,
3226                                            }->{$token->{tag_name}};                                         thead => IN_TABLE_BODY_IM,
3227                  !!!next-token;                                        }->{$token->{tag_name}};
3228                  !!!nack ('t220.1');              !!!next-token;
3229                  next B;              !!!nack ('t220.1');
3230                } else {              next B;
3231                  die "$0: in table: <>: $token->{tag_name}";            } else {
3232                }              die "$0: in table: <>: $token->{tag_name}";
3233              }
3234              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
3235                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
3236                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
# Line 5820  sub _tree_construction_main ($) { Line 3242  sub _tree_construction_main ($) {
3242                my $i;                my $i;
3243                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3244                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3245                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3246                    !!!cp ('t221');                    !!!cp ('t221');
3247                    $i = $_;                    $i = $_;
3248                    last INSCOPE;                    last INSCOPE;
# Line 5847  sub _tree_construction_main ($) { Line 3269  sub _tree_construction_main ($) {
3269                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3270                }                }
3271    
3272                unless ($self->{open_elements}->[-1]->[1] & TABLE_EL) {                unless ($self->{open_elements}->[-1]->[1] == TABLE_EL) {
3273                  !!!cp ('t225');                  !!!cp ('t225');
3274                  ## NOTE: |<table><tr><table>|                  ## NOTE: |<table><tr><table>|
3275                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
# Line 5867  sub _tree_construction_main ($) { Line 3289  sub _tree_construction_main ($) {
3289            !!!ack-later;            !!!ack-later;
3290            next B;            next B;
3291          } elsif ($token->{tag_name} eq 'style') {          } elsif ($token->{tag_name} eq 'style') {
3292            if (not $open_tables->[-1]->[1]) { # tainted            !!!cp ('t227.8');
3293              !!!cp ('t227.8');            ## NOTE: This is a "as if in head" code clone.
3294              ## NOTE: This is a "as if in head" code clone.            $parse_rcdata->(CDATA_CONTENT_MODEL);
3295              $parse_rcdata->(CDATA_CONTENT_MODEL);            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3296              next B;            next B;
           } else {  
             !!!cp ('t227.7');  
             #  
           }  
3297          } elsif ($token->{tag_name} eq 'script') {          } elsif ($token->{tag_name} eq 'script') {
3298            if (not $open_tables->[-1]->[1]) { # tainted            !!!cp ('t227.6');
3299              !!!cp ('t227.6');            ## NOTE: This is a "as if in head" code clone.
3300              ## NOTE: This is a "as if in head" code clone.            $script_start_tag->();
3301              $script_start_tag->();            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3302              next B;            next B;
           } else {  
             !!!cp ('t227.5');  
             #  
           }  
3303          } elsif ($token->{tag_name} eq 'input') {          } elsif ($token->{tag_name} eq 'input') {
3304            if (not $open_tables->[-1]->[1]) { # tainted            if ($token->{attributes}->{type}) {
3305              if ($token->{attributes}->{type}) { ## TODO: case              my $type = $token->{attributes}->{type}->{value};
3306                my $type = lc $token->{attributes}->{type}->{value};              $type =~ tr/A-Z/a-z/; ## ASCII case-insensitive.
3307                if ($type eq 'hidden') {              if ($type eq 'hidden') {
3308                  !!!cp ('t227.3');                !!!cp ('t227.3');
3309                  !!!parse-error (type => 'in table',                !!!parse-error (type => 'in table',
3310                                  text => $token->{tag_name}, token => $token);                                text => $token->{tag_name}, token => $token);
3311    
3312                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3313                  $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3314    
3315                  ## TODO: form element pointer                ## TODO: form element pointer
3316    
3317                  pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3318    
3319                  !!!next-token;                !!!next-token;
3320                  !!!ack ('t227.2.1');                !!!ack ('t227.2.1');
3321                  next B;                next B;
               } else {  
                 !!!cp ('t227.2');  
                 #  
               }  
3322              } else {              } else {
3323                !!!cp ('t227.1');                !!!cp ('t227.1');
3324                #                #
# Line 5927  sub _tree_construction_main ($) { Line 3338  sub _tree_construction_main ($) {
3338          $insert = $insert_to_foster;          $insert = $insert_to_foster;
3339          #          #
3340        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
3341              if ($token->{tag_name} eq 'tr' and          if ($token->{tag_name} eq 'tr' and
3342                  $self->{insertion_mode} == IN_ROW_IM) {              ($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3343                ## have an element in table scope            ## have an element in table scope
3344                my $i;                my $i;
3345                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3346                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3347                  if ($node->[1] & TABLE_ROW_EL) {                  if ($node->[1] == TABLE_ROW_EL) {
3348                    !!!cp ('t228');                    !!!cp ('t228');
3349                    $i = $_;                    $i = $_;
3350                    last INSCOPE;                    last INSCOPE;
# Line 5968  sub _tree_construction_main ($) { Line 3379  sub _tree_construction_main ($) {
3379                !!!nack ('t231.1');                !!!nack ('t231.1');
3380                next B;                next B;
3381              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
3382                if ($self->{insertion_mode} == IN_ROW_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3383                  ## As if </tr>                  ## As if </tr>
3384                  ## have an element in table scope                  ## have an element in table scope
3385                  my $i;                  my $i;
3386                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3387                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3388                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3389                      !!!cp ('t233');                      !!!cp ('t233');
3390                      $i = $_;                      $i = $_;
3391                      last INSCOPE;                      last INSCOPE;
# Line 6007  sub _tree_construction_main ($) { Line 3418  sub _tree_construction_main ($) {
3418                  ## reprocess in the "in table body" insertion mode...                  ## reprocess in the "in table body" insertion mode...
3419                }                }
3420    
3421                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_TABLE_BODY_IM) {
3422                  ## have an element in table scope                  ## have an element in table scope
3423                  my $i;                  my $i;
3424                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3425                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3426                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3427                      !!!cp ('t237');                      !!!cp ('t237');
3428                      $i = $_;                      $i = $_;
3429                      last INSCOPE;                      last INSCOPE;
# Line 6059  sub _tree_construction_main ($) { Line 3470  sub _tree_construction_main ($) {
3470                my $i;                my $i;
3471                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3472                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3473                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3474                    !!!cp ('t241');                    !!!cp ('t241');
3475                    $i = $_;                    $i = $_;
3476                    last INSCOPE;                    last INSCOPE;
# Line 6089  sub _tree_construction_main ($) { Line 3500  sub _tree_construction_main ($) {
3500                        tbody => 1, tfoot => 1, thead => 1,                        tbody => 1, tfoot => 1, thead => 1,
3501                       }->{$token->{tag_name}} and                       }->{$token->{tag_name}} and
3502                       $self->{insertion_mode} & ROW_IMS) {                       $self->{insertion_mode} & ROW_IMS) {
3503                if ($self->{insertion_mode} == IN_ROW_IM) {                if (($self->{insertion_mode} & IM_MASK) == IN_ROW_IM) {
3504                  ## have an element in table scope                  ## have an element in table scope
3505                  my $i;                  my $i;
3506                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 6118  sub _tree_construction_main ($) { Line 3529  sub _tree_construction_main ($) {
3529                  my $i;                  my $i;
3530                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3531                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3532                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3533                      !!!cp ('t250');                      !!!cp ('t250');
3534                      $i = $_;                      $i = $_;
3535                      last INSCOPE;                      last INSCOPE;
# Line 6208  sub _tree_construction_main ($) { Line 3619  sub _tree_construction_main ($) {
3619            #            #
3620          }          }
3621        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3622          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
3623                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
3624            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
3625            !!!cp ('t259.1');            !!!cp ('t259.1');
# Line 6223  sub _tree_construction_main ($) { Line 3634  sub _tree_construction_main ($) {
3634        } else {        } else {
3635          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
3636        }        }
3637      } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {      } elsif (($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) {
3638            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
3639              if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {              if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {
3640                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
# Line 6250  sub _tree_construction_main ($) { Line 3661  sub _tree_construction_main ($) {
3661              }              }
3662            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
3663              if ($token->{tag_name} eq 'colgroup') {              if ($token->{tag_name} eq 'colgroup') {
3664                if ($self->{open_elements}->[-1]->[1] & HTML_EL) {                if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3665                  !!!cp ('t264');                  !!!cp ('t264');
3666                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
3667                                  text => 'colgroup', token => $token);                                  text => 'colgroup', token => $token);
# Line 6276  sub _tree_construction_main ($) { Line 3687  sub _tree_construction_main ($) {
3687                #                #
3688              }              }
3689        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3690          if ($self->{open_elements}->[-1]->[1] & HTML_EL and          if ($self->{open_elements}->[-1]->[1] == HTML_EL and
3691              @{$self->{open_elements}} == 1) { # redundant, maybe              @{$self->{open_elements}} == 1) { # redundant, maybe
3692            !!!cp ('t270.2');            !!!cp ('t270.2');
3693            ## Stop parsing.            ## Stop parsing.
# Line 6294  sub _tree_construction_main ($) { Line 3705  sub _tree_construction_main ($) {
3705        }        }
3706    
3707            ## As if </colgroup>            ## As if </colgroup>
3708            if ($self->{open_elements}->[-1]->[1] & HTML_EL) {            if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3709              !!!cp ('t269');              !!!cp ('t269');
3710  ## TODO: Wrong error type?  ## TODO: Wrong error type?
3711              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6319  sub _tree_construction_main ($) { Line 3730  sub _tree_construction_main ($) {
3730          next B;          next B;
3731        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
3732          if ($token->{tag_name} eq 'option') {          if ($token->{tag_name} eq 'option') {
3733            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3734              !!!cp ('t272');              !!!cp ('t272');
3735              ## As if </option>              ## As if </option>
3736              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6332  sub _tree_construction_main ($) { Line 3743  sub _tree_construction_main ($) {
3743            !!!next-token;            !!!next-token;
3744            next B;            next B;
3745          } elsif ($token->{tag_name} eq 'optgroup') {          } elsif ($token->{tag_name} eq 'optgroup') {
3746            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3747              !!!cp ('t274');              !!!cp ('t274');
3748              ## As if </option>              ## As if </option>
3749              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6340  sub _tree_construction_main ($) { Line 3751  sub _tree_construction_main ($) {
3751              !!!cp ('t275');              !!!cp ('t275');
3752            }            }
3753    
3754            if ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3755              !!!cp ('t276');              !!!cp ('t276');
3756              ## As if </optgroup>              ## As if </optgroup>
3757              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6353  sub _tree_construction_main ($) { Line 3764  sub _tree_construction_main ($) {
3764            !!!next-token;            !!!next-token;
3765            next B;            next B;
3766          } elsif ({          } elsif ({
3767                     select => 1, input => 1, textarea => 1,                     select => 1, input => 1, textarea => 1, keygen => 1,
3768                   }->{$token->{tag_name}} or                   }->{$token->{tag_name}} or
3769                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and                   (($self->{insertion_mode} & IM_MASK)
3770                          == IN_SELECT_IN_TABLE_IM and
3771                    {                    {
3772                     caption => 1, table => 1,                     caption => 1, table => 1,
3773                     tbody => 1, tfoot => 1, thead => 1,                     tbody => 1, tfoot => 1, thead => 1,
3774                     tr => 1, td => 1, th => 1,                     tr => 1, td => 1, th => 1,
3775                    }->{$token->{tag_name}})) {                    }->{$token->{tag_name}})) {
3776            ## TODO: The type below is not good - <select> is replaced by </select>  
3777            !!!parse-error (type => 'not closed', text => 'select',            ## 1. Parse error.
3778                            token => $token);            if ($token->{tag_name} eq 'select') {
3779            ## NOTE: As if the token were </select> (<select> case) or                !!!parse-error (type => 'select in select', ## XXX: documentation
3780            ## as if there were </select> (otherwise).                                token => $token);
3781            ## have an element in table scope            } else {
3782                !!!parse-error (type => 'not closed', text => 'select',
3783                                token => $token);
3784              }
3785    
3786              ## 2./<select>-1. Unless "have an element in table scope" (select):
3787            my $i;            my $i;
3788            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3789              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3790              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3791                !!!cp ('t278');                !!!cp ('t278');
3792                $i = $_;                $i = $_;
3793                last INSCOPE;                last INSCOPE;
# Line 6381  sub _tree_construction_main ($) { Line 3798  sub _tree_construction_main ($) {
3798            } # INSCOPE            } # INSCOPE
3799            unless (defined $i) {            unless (defined $i) {
3800              !!!cp ('t280');              !!!cp ('t280');
3801              !!!parse-error (type => 'unmatched end tag',              if ($token->{tag_name} eq 'select') {
3802                              text => 'select', token => $token);                ## NOTE: This error would be raised when
3803              ## Ignore the token                ## |select.innerHTML = '<select>'| is executed; in this
3804                  ## case two errors, "select in select" and "unmatched
3805                  ## end tags" are reported to the user, the latter might
3806                  ## be confusing but this is what the spec requires.
3807                  !!!parse-error (type => 'unmatched end tag',
3808                                  text => 'select',
3809                                  token => $token);
3810                }
3811                ## Ignore the token.
3812              !!!nack ('t280.1');              !!!nack ('t280.1');
3813              !!!next-token;              !!!next-token;
3814              next B;              next B;
3815            }            }
3816    
3817              ## 3. Otherwise, as if there were <select>:
3818                                
3819            !!!cp ('t281');            !!!cp ('t281');
3820            splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
# Line 6404  sub _tree_construction_main ($) { Line 3831  sub _tree_construction_main ($) {
3831              ## Reprocess the token.              ## Reprocess the token.
3832              next B;              next B;
3833            }            }
3834            } elsif ($token->{tag_name} eq 'script') {
3835              !!!cp ('t281.3');
3836              ## NOTE: This is an "as if in head" code clone
3837              $script_start_tag->();
3838              next B;
3839          } else {          } else {
3840            !!!cp ('t282');            !!!cp ('t282');
3841            !!!parse-error (type => 'in select',            !!!parse-error (type => 'in select',
# Line 6415  sub _tree_construction_main ($) { Line 3847  sub _tree_construction_main ($) {
3847          }          }
3848        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
3849          if ($token->{tag_name} eq 'optgroup') {          if ($token->{tag_name} eq 'optgroup') {
3850            if ($self->{open_elements}->[-1]->[1] & OPTION_EL and            if ($self->{open_elements}->[-1]->[1] == OPTION_EL and
3851                $self->{open_elements}->[-2]->[1] & OPTGROUP_EL) {                $self->{open_elements}->[-2]->[1] == OPTGROUP_EL) {
3852              !!!cp ('t283');              !!!cp ('t283');
3853              ## As if </option>              ## As if </option>
3854              splice @{$self->{open_elements}}, -2;              splice @{$self->{open_elements}}, -2;
3855            } elsif ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            } elsif ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3856              !!!cp ('t284');              !!!cp ('t284');
3857              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3858            } else {            } else {
# Line 6433  sub _tree_construction_main ($) { Line 3865  sub _tree_construction_main ($) {
3865            !!!next-token;            !!!next-token;
3866            next B;            next B;
3867          } elsif ($token->{tag_name} eq 'option') {          } elsif ($token->{tag_name} eq 'option') {
3868            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3869              !!!cp ('t286');              !!!cp ('t286');
3870              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3871            } else {            } else {
# Line 6450  sub _tree_construction_main ($) { Line 3882  sub _tree_construction_main ($) {
3882            my $i;            my $i;
3883            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3884              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3885              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3886                !!!cp ('t288');                !!!cp ('t288');
3887                $i = $_;                $i = $_;
3888                last INSCOPE;                last INSCOPE;
# Line 6477  sub _tree_construction_main ($) { Line 3909  sub _tree_construction_main ($) {
3909            !!!nack ('t291.1');            !!!nack ('t291.1');
3910            !!!next-token;            !!!next-token;
3911            next B;            next B;
3912          } elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and          } elsif (($self->{insertion_mode} & IM_MASK)
3913                         == IN_SELECT_IN_TABLE_IM and
3914                   {                   {
3915                    caption => 1, table => 1, tbody => 1,                    caption => 1, table => 1, tbody => 1,
3916                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
# Line 6512  sub _tree_construction_main ($) { Line 3945  sub _tree_construction_main ($) {
3945            undef $i;            undef $i;
3946            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3947              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3948              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3949                !!!cp ('t295');                !!!cp ('t295');
3950                $i = $_;                $i = $_;
3951                last INSCOPE;                last INSCOPE;
# Line 6551  sub _tree_construction_main ($) { Line 3984  sub _tree_construction_main ($) {
3984            next B;            next B;
3985          }          }
3986        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3987          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
3988                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
3989            !!!cp ('t299.1');            !!!cp ('t299.1');
3990            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6738  sub _tree_construction_main ($) { Line 4171  sub _tree_construction_main ($) {
4171        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
4172          if ($token->{tag_name} eq 'frameset' and          if ($token->{tag_name} eq 'frameset' and
4173              $self->{insertion_mode} == IN_FRAMESET_IM) {              $self->{insertion_mode} == IN_FRAMESET_IM) {
4174            if ($self->{open_elements}->[-1]->[1] & HTML_EL and            if ($self->{open_elements}->[-1]->[1] == HTML_EL and
4175                @{$self->{open_elements}} == 1) {                @{$self->{open_elements}} == 1) {
4176              !!!cp ('t325');              !!!cp ('t325');
4177              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6752  sub _tree_construction_main ($) { Line 4185  sub _tree_construction_main ($) {
4185            }            }
4186    
4187            if (not defined $self->{inner_html_node} and            if (not defined $self->{inner_html_node} and
4188                not ($self->{open_elements}->[-1]->[1] & FRAMESET_EL)) {                not ($self->{open_elements}->[-1]->[1] == FRAMESET_EL)) {
4189              !!!cp ('t327');              !!!cp ('t327');
4190              $self->{insertion_mode} = AFTER_FRAMESET_IM;              $self->{insertion_mode} = AFTER_FRAMESET_IM;
4191            } else {            } else {
# Line 6784  sub _tree_construction_main ($) { Line 4217  sub _tree_construction_main ($) {
4217            next B;            next B;
4218          }          }
4219        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4220          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
4221                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
4222            !!!cp ('t331.1');            !!!cp ('t331.1');
4223            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6814  sub _tree_construction_main ($) { Line 4247  sub _tree_construction_main ($) {
4247          $parse_rcdata->(CDATA_CONTENT_MODEL);          $parse_rcdata->(CDATA_CONTENT_MODEL);
4248          next B;          next B;
4249        } elsif ({        } elsif ({
4250                  base => 1, command => 1, eventsource => 1, link => 1,                  base => 1, command => 1, link => 1,
4251                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
4252          !!!cp ('t334');          !!!cp ('t334');
4253          ## 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 6887  sub _tree_construction_main ($) { Line 4320  sub _tree_construction_main ($) {
4320          !!!parse-error (type => 'in body', text => 'body', token => $token);          !!!parse-error (type => 'in body', text => 'body', token => $token);
4321                                
4322          if (@{$self->{open_elements}} == 1 or          if (@{$self->{open_elements}} == 1 or
4323              not ($self->{open_elements}->[1]->[1] & BODY_EL)) {              not ($self->{open_elements}->[1]->[1] == BODY_EL)) {
4324            !!!cp ('t342');            !!!cp ('t342');
4325            ## Ignore the token            ## Ignore the token
4326          } else {          } else {
# Line 6912  sub _tree_construction_main ($) { Line 4345  sub _tree_construction_main ($) {
4345                  center => 1, datagrid => 1, details => 1, dialog => 1,                  center => 1, datagrid => 1, details => 1, dialog => 1,
4346                  dir => 1, div => 1, dl => 1, fieldset => 1, figure => 1,                  dir => 1, div => 1, dl => 1, fieldset => 1, figure => 1,
4347                  footer => 1, h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1,                  footer => 1, h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1,
4348                  h6 => 1, header => 1, menu => 1, nav => 1, ol => 1, p => 1,                  h6 => 1, header => 1, hgroup => 1,
4349                    menu => 1, nav => 1, ol => 1, p => 1,
4350                  section => 1, ul => 1,                  section => 1, ul => 1,
4351                  ## NOTE: As normal, but drops leading newline                  ## NOTE: As normal, but drops leading newline
4352                  pre => 1, listing => 1,                  pre => 1, listing => 1,
# Line 6922  sub _tree_construction_main ($) { Line 4356  sub _tree_construction_main ($) {
4356                  table => 1,                  table => 1,
4357                  hr => 1,                  hr => 1,
4358                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
4359    
4360            ## 1. When there is an opening |form| element:
4361          if ($token->{tag_name} eq 'form' and defined $self->{form_element}) {          if ($token->{tag_name} eq 'form' and defined $self->{form_element}) {
4362            !!!cp ('t350');            !!!cp ('t350');
4363            !!!parse-error (type => 'in form:form', token => $token);            !!!parse-error (type => 'in form:form', token => $token);
# Line 6931  sub _tree_construction_main ($) { Line 4367  sub _tree_construction_main ($) {
4367            next B;            next B;
4368          }          }
4369    
4370          ## has a p element in scope          ## 2. Close the |p| element, if any.
4371          INSCOPE: for (reverse @{$self->{open_elements}}) {          if ($token->{tag_name} ne 'table' or # The Hixie Quirk
4372            if ($_->[1] & P_EL) {              $self->{document}->manakai_compat_mode ne 'quirks') {
4373              !!!cp ('t344');            ## has a p element in scope
4374              !!!back-token; # <form>            INSCOPE: for (reverse @{$self->{open_elements}}) {
4375              $token = {type => END_TAG_TOKEN, tag_name => 'p',              if ($_->[1] == P_EL) {
4376                        line => $token->{line}, column => $token->{column}};                !!!cp ('t344');
4377              next B;                !!!back-token; # <form>
4378            } elsif ($_->[1] & SCOPING_EL) {                $token = {type => END_TAG_TOKEN, tag_name => 'p',
4379              !!!cp ('t345');                          line => $token->{line}, column => $token->{column}};
4380              last INSCOPE;                next B;
4381                } elsif ($_->[1] & SCOPING_EL) {
4382                  !!!cp ('t345');
4383                  last INSCOPE;
4384                }
4385              } # INSCOPE
4386            }
4387    
4388            ## 3. Close the opening <hn> element, if any.
4389            if ({h1 => 1, h2 => 1, h3 => 1,
4390                 h4 => 1, h5 => 1, h6 => 1}->{$token->{tag_name}}) {
4391              if ($self->{open_elements}->[-1]->[1] == HEADING_EL) {
4392                !!!parse-error (type => 'not closed',
4393                                text => $self->{open_elements}->[-1]->[0]->manakai_local_name,
4394                                token => $token);
4395                pop @{$self->{open_elements}};
4396            }            }
4397          } # INSCOPE          }
4398              
4399            ## 4. Insertion.
4400          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4401          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {
4402            !!!nack ('t346.1');            !!!nack ('t346.1');
# Line 6978  sub _tree_construction_main ($) { Line 4430  sub _tree_construction_main ($) {
4430            !!!cp ('t386');            !!!cp ('t386');
4431            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
4432                    
4433            !!!nack ('t386.1');            !!!ack ('t386.1');
4434            !!!next-token;            !!!next-token;
4435          } else {          } else {
4436            !!!nack ('t347.1');            !!!nack ('t347.1');
# Line 6988  sub _tree_construction_main ($) { Line 4440  sub _tree_construction_main ($) {
4440        } elsif ($token->{tag_name} eq 'li') {        } elsif ($token->{tag_name} eq 'li') {
4441          ## NOTE: As normal, but imply </li> when there's another <li> ...          ## NOTE: As normal, but imply </li> when there's another <li> ...
4442    
4443          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)::
4444            ## Interpreted as <li><foo/></li><li/> (non-conforming)            ## Interpreted as <li><foo/></li><li/> (non-conforming):
4445            ## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7),            ## blockquote (O9.27), center (O), dd (Fx3, O, S3.1.2, IE7),
4446            ## 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),
4447            ## 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),
4448            ## object (Fx)            ## object (Fx)
4449            ## Generate non-tree (non-conforming)            ## Generate non-tree (non-conforming):
4450            ## basefont (IE7 (where basefont is non-void)), center (IE),            ## basefont (IE7 (where basefont is non-void)), center (IE),
4451            ## form (IE), hn (IE)            ## form (IE), hn (IE)
4452          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)::
4453            ## Interpreted as <li><foo><li/></foo></li> (non-conforming)            ## Interpreted as <li><foo><li/></foo></li> (non-conforming):
4454            ## div (Fx, S)            ## div (Fx, S)
4455    
4456          my $non_optional;          my $non_optional;
# Line 7006  sub _tree_construction_main ($) { Line 4458  sub _tree_construction_main ($) {
4458    
4459          ## 1.          ## 1.
4460          for my $node (reverse @{$self->{open_elements}}) {          for my $node (reverse @{$self->{open_elements}}) {
4461            if ($node->[1] & LI_EL) {            if ($node->[1] == LI_EL) {
4462              ## 2. (a) As if </li>              ## 2. (a) As if </li>
4463              {              {
4464                ## If no </li> - not applied                ## If no </li> - not applied
# Line 7037  sub _tree_construction_main ($) { Line 4489  sub _tree_construction_main ($) {
4489                     ($node->[1] & SPECIAL_EL or                     ($node->[1] & SPECIAL_EL or
4490                      $node->[1] & SCOPING_EL) and                      $node->[1] & SCOPING_EL) and
4491                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4492                       (not $node->[1] & ADDRESS_DIV_P_EL)
4493                     (not $node->[1] & ADDRESS_EL) &                    ) {
                    (not $node->[1] & DIV_EL) &  
                    (not $node->[1] & P_EL)) {  
4494              ## 3.              ## 3.
4495              !!!cp ('t357');              !!!cp ('t357');
4496              last; ## goto 5.              last; ## goto 5.
# Line 7059  sub _tree_construction_main ($) { Line 4509  sub _tree_construction_main ($) {
4509    
4510          ## 5. (a) has a |p| element in scope          ## 5. (a) has a |p| element in scope
4511          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4512            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4513              !!!cp ('t353');              !!!cp ('t353');
4514    
4515              ## NOTE: |<p><li>|, for example.              ## NOTE: |<p><li>|, for example.
# Line 7088  sub _tree_construction_main ($) { Line 4538  sub _tree_construction_main ($) {
4538    
4539          ## 1.          ## 1.
4540          for my $node (reverse @{$self->{open_elements}}) {          for my $node (reverse @{$self->{open_elements}}) {
4541            if ($node->[1] & DT_EL or $node->[1] & DD_EL) {            if ($node->[1] == DTDD_EL) {
4542              ## 2. (a) As if </li>              ## 2. (a) As if </li>
4543              {              {
4544                ## If no </li> - not applied                ## If no </li> - not applied
# Line 7120  sub _tree_construction_main ($) { Line 4570  sub _tree_construction_main ($) {
4570                      $node->[1] & SCOPING_EL) and                      $node->[1] & SCOPING_EL) and
4571                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.                     ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4572    
4573                     (not $node->[1] & ADDRESS_EL) &                     (not $node->[1] & ADDRESS_DIV_P_EL)
4574                     (not $node->[1] & DIV_EL) &                    ) {
                    (not $node->[1] & P_EL)) {  
4575              ## 3.              ## 3.
4576              !!!cp ('t357.1');              !!!cp ('t357.1');
4577              last; ## goto 5.              last; ## goto 5.
# Line 7141  sub _tree_construction_main ($) { Line 4590  sub _tree_construction_main ($) {
4590    
4591          ## 5. (a) has a |p| element in scope          ## 5. (a) has a |p| element in scope
4592          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4593            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4594              !!!cp ('t353.1');              !!!cp ('t353.1');
4595              !!!back-token; # <x>              !!!back-token; # <x>
4596              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 7163  sub _tree_construction_main ($) { Line 4612  sub _tree_construction_main ($) {
4612    
4613          ## has a p element in scope          ## has a p element in scope
4614          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4615            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4616              !!!cp ('t367');              !!!cp ('t367');
4617              !!!back-token; # <plaintext>              !!!back-token; # <plaintext>
4618              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 7185  sub _tree_construction_main ($) { Line 4634  sub _tree_construction_main ($) {
4634        } elsif ($token->{tag_name} eq 'a') {        } elsif ($token->{tag_name} eq 'a') {
4635          AFE: for my $i (reverse 0..$#$active_formatting_elements) {          AFE: for my $i (reverse 0..$#$active_formatting_elements) {
4636            my $node = $active_formatting_elements->[$i];            my $node = $active_formatting_elements->[$i];
4637            if ($node->[1] & A_EL) {            if ($node->[1] == A_EL) {
4638              !!!cp ('t371');              !!!cp ('t371');
4639              !!!parse-error (type => 'in a:a', token => $token);              !!!parse-error (type => 'in a:a', token => $token);
4640                            
# Line 7229  sub _tree_construction_main ($) { Line 4678  sub _tree_construction_main ($) {
4678          ## has a |nobr| element in scope          ## has a |nobr| element in scope
4679          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4680            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4681            if ($node->[1] & NOBR_EL) {            if ($node->[1] == NOBR_EL) {
4682              !!!cp ('t376');              !!!cp ('t376');
4683              !!!parse-error (type => 'in nobr:nobr', token => $token);              !!!parse-error (type => 'in nobr:nobr', token => $token);
4684              !!!back-token; # <nobr>              !!!back-token; # <nobr>
# Line 7252  sub _tree_construction_main ($) { Line 4701  sub _tree_construction_main ($) {
4701          ## has a button element in scope          ## has a button element in scope
4702          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4703            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4704            if ($node->[1] & BUTTON_EL) {            if ($node->[1] == BUTTON_EL) {
4705              !!!cp ('t378');              !!!cp ('t378');
4706              !!!parse-error (type => 'in button:button', token => $token);              !!!parse-error (type => 'in button:button', token => $token);
4707              !!!back-token; # <button>              !!!back-token; # <button>
# Line 7317  sub _tree_construction_main ($) { Line 4766  sub _tree_construction_main ($) {
4766                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4767                          {type => START_TAG_TOKEN, tag_name => 'hr',                          {type => START_TAG_TOKEN, tag_name => 'hr',
4768                           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}},  
4769                          {type => START_TAG_TOKEN, tag_name => 'label',                          {type => START_TAG_TOKEN, tag_name => 'label',
4770                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4771                         );                         );
# Line 7341  sub _tree_construction_main ($) { Line 4788  sub _tree_construction_main ($) {
4788                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
4789                          {type => END_TAG_TOKEN, tag_name => 'label',                          {type => END_TAG_TOKEN, tag_name => 'label',
4790                           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}},  
4791                          {type => START_TAG_TOKEN, tag_name => 'hr',                          {type => START_TAG_TOKEN, tag_name => 'hr',
4792                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
4793                          {type => END_TAG_TOKEN, tag_name => 'form',                          {type => END_TAG_TOKEN, tag_name => 'form',
# Line 7352  sub _tree_construction_main ($) { Line 4797  sub _tree_construction_main ($) {
4797            next B;            next B;
4798          }          }
4799        } elsif ($token->{tag_name} eq 'textarea') {        } elsif ($token->{tag_name} eq 'textarea') {
4800          my $tag_name = $token->{tag_name};          ## 1. Insert
4801          my $el;          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
         !!!create-element ($el, $HTML_NS, $token->{tag_name}, $token->{attributes}, $token);  
4802                    
4803            ## Step 2 # XXX
4804          ## TODO: $self->{form_element} if defined          ## TODO: $self->{form_element} if defined
4805    
4806            ## 2. Drop U+000A LINE FEED
4807            $self->{ignore_newline} = 1;
4808    
4809            ## 3. RCDATA
4810          $self->{content_model} = RCDATA_CONTENT_MODEL;          $self->{content_model} = RCDATA_CONTENT_MODEL;
4811          delete $self->{escape}; # MUST          delete $self->{escape}; # MUST
4812            
4813          $insert->($el);          ## 4., 6. Insertion mode
4814                    $self->{insertion_mode} |= IN_CDATA_RCDATA_IM;
4815          my $text = '';  
4816            ## XXX: 5. frameset-ok flag
4817    
4818          !!!nack ('t392.1');          !!!nack ('t392.1');
4819          !!!next-token;          !!!next-token;
         if ($token->{type} == CHARACTER_TOKEN) {  
           $token->{data} =~ s/^\x0A//;  
           unless (length $token->{data}) {  
             !!!cp ('t392');  
             !!!next-token;  
           } else {  
             !!!cp ('t393');  
           }  
         } else {  
           !!!cp ('t394');  
         }  
         while ($token->{type} == CHARACTER_TOKEN) {  
           !!!cp ('t395');  
           $text .= $token->{data};  
           !!!next-token;  
         }  
         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);  
         }  
         !!!next-token;  
4820          next B;          next B;
4821        } elsif ($token->{tag_name} eq 'optgroup' or        } elsif ($token->{tag_name} eq 'optgroup' or
4822                 $token->{tag_name} eq 'option') {                 $token->{tag_name} eq 'option') {
4823          ## has an |option| element in scope          ## has an |option| element in scope
4824          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4825            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4826            if ($node->[1] & OPTION_EL) {            if ($node->[1] == OPTION_EL) {
4827              !!!cp ('t397.1');              !!!cp ('t397.1');
4828              ## NOTE: As if </option>              ## NOTE: As if </option>
4829              !!!back-token; # <option> or <optgroup>              !!!back-token; # <option> or <optgroup>
# Line 7428  sub _tree_construction_main ($) { Line 4848  sub _tree_construction_main ($) {
4848          ## has a |ruby| element in scope          ## has a |ruby| element in scope
4849          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4850            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4851            if ($node->[1] & RUBY_EL) {            if ($node->[1] == RUBY_EL) {
4852              !!!cp ('t398.1');              !!!cp ('t398.1');
4853              ## generate implied end tags              ## generate implied end tags
4854              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
4855                !!!cp ('t398.2');                !!!cp ('t398.2');
4856                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
4857              }              }
4858              unless ($self->{open_elements}->[-1]->[1] & RUBY_EL) {              unless ($self->{open_elements}->[-1]->[1] == RUBY_EL) {
4859                !!!cp ('t398.3');                !!!cp ('t398.3');
4860                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
4861                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
4862                                    ->manakai_local_name,                                    ->manakai_local_name,
4863                                token => $token);                                token => $token);
4864                pop @{$self->{open_elements}}                pop @{$self->{open_elements}}
4865                    while not $self->{open_elements}->[-1]->[1] & RUBY_EL;                    while not $self->{open_elements}->[-1]->[1] == RUBY_EL;
4866              }              }
4867              last INSCOPE;              last INSCOPE;
4868            } elsif ($node->[1] & SCOPING_EL) {            } elsif ($node->[1] & SCOPING_EL) {
# Line 7450  sub _tree_construction_main ($) { Line 4870  sub _tree_construction_main ($) {
4870              last INSCOPE;              last INSCOPE;
4871            }            }
4872          } # INSCOPE          } # INSCOPE
4873              
4874            ## TODO: <non-ruby><rt> is not allowed.
4875    
4876          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4877    
# Line 7538  sub _tree_construction_main ($) { Line 4960  sub _tree_construction_main ($) {
4960          } elsif ({          } elsif ({
4961                    area => 1, basefont => 1, bgsound => 1, br => 1,                    area => 1, basefont => 1, bgsound => 1, br => 1,
4962                    embed => 1, img => 1, spacer => 1, wbr => 1,                    embed => 1, img => 1, spacer => 1, wbr => 1,
4963                      keygen => 1,
4964                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}}) {
4965            !!!cp ('t388.1');            !!!cp ('t388.1');
4966            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
# Line 7547  sub _tree_construction_main ($) { Line 4970  sub _tree_construction_main ($) {
4970                    
4971            if ($self->{insertion_mode} & TABLE_IMS or            if ($self->{insertion_mode} & TABLE_IMS or
4972                $self->{insertion_mode} & BODY_TABLE_IMS or                $self->{insertion_mode} & BODY_TABLE_IMS or
4973                $self->{insertion_mode} == IN_COLUMN_GROUP_IM) {                ($self->{insertion_mode} & IM_MASK) == IN_COLUMN_GROUP_IM) {
4974              !!!cp ('t400.1');              !!!cp ('t400.1');
4975              $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;              $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;
4976            } else {            } else {
# Line 7563  sub _tree_construction_main ($) { Line 4986  sub _tree_construction_main ($) {
4986          next B;          next B;
4987        }        }
4988      } elsif ($token->{type} == END_TAG_TOKEN) {      } elsif ($token->{type} == END_TAG_TOKEN) {
4989        if ($token->{tag_name} eq 'body') {        if ($token->{tag_name} eq 'body' or $token->{tag_name} eq 'html') {
4990          ## has a |body| element in scope  
4991            ## 1. If not "have an element in scope":
4992            ## "has a |body| element in scope"
4993          my $i;          my $i;
4994          INSCOPE: {          INSCOPE: {
4995            for (reverse @{$self->{open_elements}}) {            for (reverse @{$self->{open_elements}}) {
4996              if ($_->[1] & BODY_EL) {              if ($_->[1] == BODY_EL) {
4997                !!!cp ('t405');                !!!cp ('t405');
4998                $i = $_;                $i = $_;
4999                last INSCOPE;                last INSCOPE;
# Line 7578  sub _tree_construction_main ($) { Line 5003  sub _tree_construction_main ($) {
5003              }              }
5004            }            }
5005    
5006            ## NOTE: |<marquee></body>|, |<svg><foreignobject></body>|            ## NOTE: |<marquee></body>|, |<svg><foreignobject></body>|,
5007              ## and fragment cases.
5008    
5009            !!!parse-error (type => 'unmatched end tag',            !!!parse-error (type => 'unmatched end tag',
5010                            text => $token->{tag_name}, token => $token);                            text => $token->{tag_name}, token => $token);
5011            ## NOTE: Ignore the token.            ## Ignore the token.  (</body> or </html>)
5012            !!!next-token;            !!!next-token;
5013            next B;            next B;
5014          } # INSCOPE          } # INSCOPE
5015    
5016            ## 2. If unclosed elements:
5017          for (@{$self->{open_elements}}) {          for (@{$self->{open_elements}}) {
5018            unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL) {            unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL ||
5019                      $_->[1] == OPTGROUP_EL ||
5020                      $_->[1] == OPTION_EL ||
5021                      $_->[1] == RUBY_COMPONENT_EL) {
5022              !!!cp ('t403');              !!!cp ('t403');
5023              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5024                              text => $_->[0]->manakai_local_name,                              text => $_->[0]->manakai_local_name,
# Line 7599  sub _tree_construction_main ($) { Line 5029  sub _tree_construction_main ($) {
5029            }            }
5030          }          }
5031    
5032            ## 3. Switch the insertion mode.
5033          $self->{insertion_mode} = AFTER_BODY_IM;          $self->{insertion_mode} = AFTER_BODY_IM;
5034          !!!next-token;          if ($token->{tag_name} eq 'body') {
         next B;  
       } elsif ($token->{tag_name} eq 'html') {  
         ## TODO: Update this code.  It seems that the code below is not  
         ## up-to-date, though it has same effect as speced.  
         if (@{$self->{open_elements}} > 1 and  
             $self->{open_elements}->[1]->[1] & BODY_EL) {  
           unless ($self->{open_elements}->[-1]->[1] & BODY_EL) {  
             !!!cp ('t406');  
             !!!parse-error (type => 'not closed',  
                             text => $self->{open_elements}->[1]->[0]  
                                 ->manakai_local_name,  
                             token => $token);  
           } else {  
             !!!cp ('t407');  
           }  
           $self->{insertion_mode} = AFTER_BODY_IM;  
           ## reprocess  
           next B;  
         } else {  
           !!!cp ('t408');  
           !!!parse-error (type => 'unmatched end tag',  
                           text => $token->{tag_name}, token => $token);  
           ## Ignore the token  
5035            !!!next-token;            !!!next-token;
5036            next B;          } else { # html
5037              ## Reprocess.
5038          }          }
5039            next B;
5040        } elsif ({        } elsif ({
5041                  ## NOTE: End tags for non-phrasing flow content elements                  ## NOTE: End tags for non-phrasing flow content elements
5042    
# Line 7634  sub _tree_construction_main ($) { Line 5044  sub _tree_construction_main ($) {
5044                  address => 1, article => 1, aside => 1, blockquote => 1,                  address => 1, article => 1, aside => 1, blockquote => 1,
5045                  center => 1, datagrid => 1, details => 1, dialog => 1,                  center => 1, datagrid => 1, details => 1, dialog => 1,
5046                  dir => 1, div => 1, dl => 1, fieldset => 1, figure => 1,                  dir => 1, div => 1, dl => 1, fieldset => 1, figure => 1,
5047                  footer => 1, header => 1, listing => 1, menu => 1, nav => 1,                  footer => 1, header => 1, hgroup => 1,
5048                    listing => 1, menu => 1, nav => 1,
5049                  ol => 1, pre => 1, section => 1, ul => 1,                  ol => 1, pre => 1, section => 1, ul => 1,
5050    
5051                  ## NOTE: As normal, but ... optional tags                  ## NOTE: As normal, but ... optional tags
# Line 7714  sub _tree_construction_main ($) { Line 5125  sub _tree_construction_main ($) {
5125          my $i;          my $i;
5126          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5127            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5128            if ($node->[1] & FORM_EL) {            if ($node->[1] == FORM_EL) {
5129              !!!cp ('t418');              !!!cp ('t418');
5130              $i = $_;              $i = $_;
5131              last INSCOPE;              last INSCOPE;
# Line 7762  sub _tree_construction_main ($) { Line 5173  sub _tree_construction_main ($) {
5173          my $i;          my $i;
5174          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5175            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5176            if ($node->[1] & HEADING_EL) {            if ($node->[1] == HEADING_EL) {
5177              !!!cp ('t423');              !!!cp ('t423');
5178              $i = $_;              $i = $_;
5179              last INSCOPE;              last INSCOPE;
# Line 7808  sub _tree_construction_main ($) { Line 5219  sub _tree_construction_main ($) {
5219          my $i;          my $i;
5220          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5221            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5222            if ($node->[1] & P_EL) {            if ($node->[1] == P_EL) {
5223              !!!cp ('t410.1');              !!!cp ('t410.1');
5224              $i = $_;              $i = $_;
5225              last INSCOPE;              last INSCOPE;
# Line 7985  sub _tree_construction_main ($) { Line 5396  sub _tree_construction_main ($) {
5396    ## TODO: script stuffs    ## TODO: script stuffs
5397  } # _tree_construct_main  } # _tree_construct_main
5398    
5399    ## XXX: How this method is organized is somewhat out of date, although
5400    ## it still does what the current spec documents.
5401  sub set_inner_html ($$$$;$) {  sub set_inner_html ($$$$;$) {
5402    my $class = shift;    my $class = shift;
5403    my $node = shift;    my $node = shift; # /context/
5404    #my $s = \$_[0];    #my $s = \$_[0];
5405    my $onerror = $_[1];    my $onerror = $_[1];
5406    my $get_wrapper = $_[2] || sub ($) { return $_[0] };    my $get_wrapper = $_[2] || sub ($) { return $_[0] };
5407    
   ## ISSUE: Should {confident} be true?  
   
5408    my $nt = $node->node_type;    my $nt = $node->node_type;
5409    if ($nt == 9) {    if ($nt == 9) { # Document (invoke the algorithm with no /context/ element)
5410      # MUST      # MUST
5411            
5412      ## Step 1 # MUST      ## Step 1 # MUST
# Line 8010  sub set_inner_html ($$$$;$) { Line 5421  sub set_inner_html ($$$$;$) {
5421    
5422      ## Step 3, 4, 5 # MUST      ## Step 3, 4, 5 # MUST
5423      $class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper);      $class->parse_char_string ($_[0] => $node, $onerror, $get_wrapper);
5424    } elsif ($nt == 1) {    } elsif ($nt == 1) { # Element (invoke the algorithm with /context/ element)
5425      ## TODO: If non-html element      ## TODO: If non-html element
5426    
5427      ## NOTE: Most of this code is copied from |parse_string|      ## NOTE: Most of this code is copied from |parse_string|
5428    
5429  ## TODO: Support for $get_wrapper  ## TODO: Support for $get_wrapper
5430    
5431      ## Step 1 # MUST      ## F1. Create an HTML document.
5432      my $this_doc = $node->owner_document;      my $this_doc = $node->owner_document;
5433      my $doc = $this_doc->implementation->create_document;      my $doc = $this_doc->implementation->create_document;
5434      $doc->manakai_is_html (1);      $doc->manakai_is_html (1);
5435    
5436        ## F2. Propagate quirkness flag
5437        my $node_doc = $node->owner_document;
5438        $doc->manakai_compat_mode ($node_doc->manakai_compat_mode);
5439    
5440        ## F3. Create an HTML parser
5441      my $p = $class->new;      my $p = $class->new;
5442      $p->{document} = $doc;      $p->{document} = $doc;
5443    
# Line 8148  sub set_inner_html ($$$$;$) { Line 5565  sub set_inner_html ($$$$;$) {
5565      $p->_initialize_tokenizer;      $p->_initialize_tokenizer;
5566      $p->_initialize_tree_constructor;      $p->_initialize_tree_constructor;
5567    
5568      ## Step 2      ## F4. If /context/ is not undef...
5569    
5570        ## F4.1. content model flag
5571      my $node_ln = $node->manakai_local_name;      my $node_ln = $node->manakai_local_name;
5572      $p->{content_model} = {      $p->{content_model} = {
5573        title => RCDATA_CONTENT_MODEL,        title => RCDATA_CONTENT_MODEL,
# Line 8164  sub set_inner_html ($$$$;$) { Line 5583  sub set_inner_html ($$$$;$) {
5583      }->{$node_ln};      }->{$node_ln};
5584      $p->{content_model} = PCDATA_CONTENT_MODEL      $p->{content_model} = PCDATA_CONTENT_MODEL
5585          unless defined $p->{content_model};          unless defined $p->{content_model};
         ## ISSUE: What is "the name of the element"? local name?  
5586    
5587      $p->{inner_html_node} = [$node, $el_category->{$node_ln}];      $p->{inner_html_node} = [$node, $el_category->{$node_ln}];
5588        ## TODO: Foreign element OK?        ## TODO: Foreign element OK?
5589    
5590      ## Step 3      ## F4.2. Root |html| element
5591      my $root = $doc->create_element_ns      my $root = $doc->create_element_ns
5592        ('http://www.w3.org/1999/xhtml', [undef, 'html']);        ('http://www.w3.org/1999/xhtml', [undef, 'html']);
5593    
5594      ## Step 4 # MUST      ## F4.3.
5595      $doc->append_child ($root);      $doc->append_child ($root);
5596    
5597      ## Step 5 # MUST      ## F4.4.
5598      push @{$p->{open_elements}}, [$root, $el_category->{html}];      push @{$p->{open_elements}}, [$root, $el_category->{html}];
5599    
5600      undef $p->{head_element};      undef $p->{head_element};
5601        undef $p->{head_element_inserted};
5602    
5603      ## Step 6 # MUST      ## F4.5.
5604      $p->_reset_insertion_mode;      $p->_reset_insertion_mode;
5605    
5606      ## Step 7 # MUST      ## F4.6.
5607      my $anode = $node;      my $anode = $node;
5608      AN: while (defined $anode) {      AN: while (defined $anode) {
5609        if ($anode->node_type == 1) {        if ($anode->node_type == 1) {
# Line 8199  sub set_inner_html ($$$$;$) { Line 5618  sub set_inner_html ($$$$;$) {
5618        }        }
5619        $anode = $anode->parent_node;        $anode = $anode->parent_node;
5620      } # AN      } # AN
5621        
5622      ## Step 9 # MUST      ## F.5. Set the input stream.
5623        $p->{confident} = 1; ## Confident: irrelevant.
5624    
5625        ## F.6. Start the parser.
5626      {      {
5627        my $self = $p;        my $self = $p;
5628        !!!next-token;        !!!next-token;
5629      }      }
5630      $p->_tree_construction_main;      $p->_tree_construction_main;
5631    
5632      ## Step 10 # MUST      ## F.7.
5633      my @cn = @{$node->child_nodes};      my @cn = @{$node->child_nodes};
5634      for (@cn) {      for (@cn) {
5635        $node->remove_child ($_);        $node->remove_child ($_);

Legend:
Removed from v.1.201  
changed lines
  Added in v.1.240

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24