/[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.195 by wakaba, Sat Oct 4 06:30:34 2008 UTC revision 1.209 by wakaba, Tue Oct 14 07:40:52 2008 UTC
# Line 3  use strict; Line 3  use strict;
3  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4  use Error qw(:try);  use Error qw(:try);
5    
6    use Whatpm::HTML::Tokenizer;
7    
8  ## NOTE: This module don't check all HTML5 parse errors; character  ## NOTE: This module don't check all HTML5 parse errors; character
9  ## encoding related parse errors are expected to be handled by relevant  ## encoding related parse errors are expected to be handled by relevant
10  ## modules.  ## modules.
# Line 21  use Error qw(:try); Line 23  use Error qw(:try);
23    
24  require IO::Handle;  require IO::Handle;
25    
26    ## Namespace URLs
27    
28  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
29  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;
30  my $SVG_NS = q<http://www.w3.org/2000/svg>;  my $SVG_NS = q<http://www.w3.org/2000/svg>;
# Line 28  my $XLINK_NS = q<http://www.w3.org/1999/ Line 32  my $XLINK_NS = q<http://www.w3.org/1999/
32  my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;  my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;
33  my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;  my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;
34    
35  sub A_EL () { 0b1 }  ## Element categories
36  sub ADDRESS_EL () { 0b10 }  
37  sub BODY_EL () { 0b100 }  ## Bits 12-15
38  sub BUTTON_EL () { 0b1000 }  sub SPECIAL_EL () { 0b1_000000000000000 }
39  sub CAPTION_EL () { 0b10000 }  sub SCOPING_EL () { 0b1_00000000000000 }
40  sub DD_EL () { 0b100000 }  sub FORMATTING_EL () { 0b1_0000000000000 }
41  sub DIV_EL () { 0b1000000 }  sub PHRASING_EL () { 0b1_000000000000 }
42  sub DT_EL () { 0b10000000 }  
43  sub FORM_EL () { 0b100000000 }  ## Bits 10-11
44  sub FORMATTING_EL () { 0b1000000000 }  #sub FOREIGN_EL () { 0b1_00000000000 } # see Whatpm::HTML::Tokenizer
45  sub FRAMESET_EL () { 0b10000000000 }  sub FOREIGN_FLOW_CONTENT_EL () { 0b1_0000000000 }
46  sub HEADING_EL () { 0b100000000000 }  
47  sub HTML_EL () { 0b1000000000000 }  ## Bits 6-9
48  sub LI_EL () { 0b10000000000000 }  sub TABLE_SCOPING_EL () { 0b1_000000000 }
49  sub NOBR_EL () { 0b100000000000000 }  sub TABLE_ROWS_SCOPING_EL () { 0b1_00000000 }
50  sub OPTION_EL () { 0b1000000000000000 }  sub TABLE_ROW_SCOPING_EL () { 0b1_0000000 }
51  sub OPTGROUP_EL () { 0b10000000000000000 }  sub TABLE_ROWS_EL () { 0b1_000000 }
52  sub P_EL () { 0b100000000000000000 }  
53  sub SELECT_EL () { 0b1000000000000000000 }  ## Bit 5
54  sub TABLE_EL () { 0b10000000000000000000 }  sub ADDRESS_DIV_P_EL () { 0b1_00000 }
55  sub TABLE_CELL_EL () { 0b100000000000000000000 }  
56  sub TABLE_ROW_EL () { 0b1000000000000000000000 }  ## NOTE: Used in </body> and EOF algorithms.
57  sub TABLE_ROW_GROUP_EL () { 0b10000000000000000000000 }  ## Bit 4
58  sub MISC_SCOPING_EL () { 0b100000000000000000000000 }  sub ALL_END_TAG_OPTIONAL_EL () { 0b1_0000 }
 sub MISC_SPECIAL_EL () { 0b1000000000000000000000000 }  
 sub FOREIGN_EL () { 0b10000000000000000000000000 }  
 sub FOREIGN_FLOW_CONTENT_EL () { 0b100000000000000000000000000 }  
 sub MML_AXML_EL () { 0b1000000000000000000000000000 }  
 sub RUBY_EL () { 0b10000000000000000000000000000 }  
 sub RUBY_COMPONENT_EL () { 0b100000000000000000000000000000 }  
   
 sub TABLE_ROWS_EL () {  
   TABLE_EL |  
   TABLE_ROW_EL |  
   TABLE_ROW_GROUP_EL  
 }  
59    
60  ## NOTE: Used in "generate implied end tags" algorithm.  ## NOTE: Used in "generate implied end tags" algorithm.
61  ## NOTE: There is a code where a modified version of  ## NOTE: There is a code where a modified version of
62  ## END_TAG_OPTIONAL_EL is used in "generate implied end tags"  ## END_TAG_OPTIONAL_EL is used in "generate implied end tags"
63  ## implementation (search for the algorithm name).  ## implementation (search for the algorithm name).
64  sub END_TAG_OPTIONAL_EL () {  ## Bit 3
65    DD_EL |  sub END_TAG_OPTIONAL_EL () { 0b1_000 }
   DT_EL |  
   LI_EL |  
   OPTION_EL |  
   OPTGROUP_EL |  
   P_EL |  
   RUBY_COMPONENT_EL  
 }  
66    
67  ## NOTE: Used in </body> and EOF algorithms.  ## Bits 0-2
 sub ALL_END_TAG_OPTIONAL_EL () {  
   DD_EL |  
   DT_EL |  
   LI_EL |  
   P_EL |  
   
   BODY_EL |  
   HTML_EL |  
   TABLE_CELL_EL |  
   TABLE_ROW_EL |  
   TABLE_ROW_GROUP_EL  
 }  
68    
69  sub SCOPING_EL () {  sub MISC_SPECIAL_EL () { SPECIAL_EL | 0b000 }
70    BUTTON_EL |  sub FORM_EL () { SPECIAL_EL | 0b001 }
71    CAPTION_EL |  sub FRAMESET_EL () { SPECIAL_EL | 0b010 }
72    HTML_EL |  sub HEADING_EL () { SPECIAL_EL | 0b011 }
73    TABLE_EL |  sub SELECT_EL () { SPECIAL_EL | 0b100 }
74    TABLE_CELL_EL |  sub SCRIPT_EL () { SPECIAL_EL | 0b101 }
75    MISC_SCOPING_EL  
76    sub ADDRESS_DIV_EL () { SPECIAL_EL | ADDRESS_DIV_P_EL | 0b001 }
77    sub BODY_EL () { SPECIAL_EL | ALL_END_TAG_OPTIONAL_EL | 0b001 }
78    
79    sub DTDD_EL () {
80      SPECIAL_EL |
81      END_TAG_OPTIONAL_EL |
82      ALL_END_TAG_OPTIONAL_EL |
83      0b010
84  }  }
85    sub LI_EL () {
86  sub TABLE_SCOPING_EL () {    SPECIAL_EL |
87    HTML_EL |    END_TAG_OPTIONAL_EL |
88    TABLE_EL    ALL_END_TAG_OPTIONAL_EL |
89      0b100
90  }  }
91    sub P_EL () {
92  sub TABLE_ROWS_SCOPING_EL () {    SPECIAL_EL |
93    HTML_EL |    ADDRESS_DIV_P_EL |
94    TABLE_ROW_GROUP_EL    END_TAG_OPTIONAL_EL |
95      ALL_END_TAG_OPTIONAL_EL |
96      0b001
97  }  }
98    
99  sub TABLE_ROW_SCOPING_EL () {  sub TABLE_ROW_EL () {
100    HTML_EL |    SPECIAL_EL |
101    TABLE_ROW_EL    TABLE_ROWS_EL |
102      TABLE_ROW_SCOPING_EL |
103      ALL_END_TAG_OPTIONAL_EL |
104      0b001
105    }
106    sub TABLE_ROW_GROUP_EL () {
107      SPECIAL_EL |
108      TABLE_ROWS_EL |
109      TABLE_ROWS_SCOPING_EL |
110      ALL_END_TAG_OPTIONAL_EL |
111      0b001
112  }  }
113    
114  sub SPECIAL_EL () {  sub MISC_SCOPING_EL () { SCOPING_EL | 0b000 }
115    ADDRESS_EL |  sub BUTTON_EL () { SCOPING_EL | 0b001 }
116    BODY_EL |  sub CAPTION_EL () { SCOPING_EL | 0b010 }
117    DIV_EL |  sub HTML_EL () {
118      SCOPING_EL |
119    DD_EL |    TABLE_SCOPING_EL |
120    DT_EL |    TABLE_ROWS_SCOPING_EL |
121    LI_EL |    TABLE_ROW_SCOPING_EL |
122    P_EL |    ALL_END_TAG_OPTIONAL_EL |
123      0b001
124    FORM_EL |  }
125    FRAMESET_EL |  sub TABLE_EL () {
126    HEADING_EL |    SCOPING_EL |
127    OPTION_EL |    TABLE_ROWS_EL |
128    OPTGROUP_EL |    TABLE_SCOPING_EL |
129    SELECT_EL |    0b001
130    TABLE_ROW_EL |  }
131    TABLE_ROW_GROUP_EL |  sub TABLE_CELL_EL () {
132    MISC_SPECIAL_EL    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,
182    eventsource => MISC_SPECIAL_EL,    eventsource => MISC_SPECIAL_EL,
# Line 200  my $el_category = { Line 210  my $el_category = {
210    menu => MISC_SPECIAL_EL,    menu => MISC_SPECIAL_EL,
211    meta => MISC_SPECIAL_EL,    meta => MISC_SPECIAL_EL,
212    nav => MISC_SPECIAL_EL,    nav => MISC_SPECIAL_EL,
213    nobr => NOBR_EL | FORMATTING_EL,    nobr => NOBR_EL,
214    noembed => MISC_SPECIAL_EL,    noembed => MISC_SPECIAL_EL,
215    noframes => MISC_SPECIAL_EL,    noframes => MISC_SPECIAL_EL,
216    noscript => MISC_SPECIAL_EL,    noscript => MISC_SPECIAL_EL,
# Line 242  my $el_category = { Line 252  my $el_category = {
252  my $el_category_f = {  my $el_category_f = {
253    $MML_NS => {    $MML_NS => {
254      'annotation-xml' => MML_AXML_EL,      'annotation-xml' => MML_AXML_EL,
255      mi => FOREIGN_FLOW_CONTENT_EL,      mi => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
256      mo => FOREIGN_FLOW_CONTENT_EL,      mo => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
257      mn => FOREIGN_FLOW_CONTENT_EL,      mn => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
258      ms => FOREIGN_FLOW_CONTENT_EL,      ms => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
259      mtext => FOREIGN_FLOW_CONTENT_EL,      mtext => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
260    },    },
261    $SVG_NS => {    $SVG_NS => {
262      foreignObject => FOREIGN_FLOW_CONTENT_EL,      foreignObject => SCOPING_EL | FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
263      desc => FOREIGN_FLOW_CONTENT_EL,      desc => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
264      title => FOREIGN_FLOW_CONTENT_EL,      title => FOREIGN_EL | FOREIGN_FLOW_CONTENT_EL,
265    },    },
266    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.
267  };  };
# Line 338  my $foreign_attr_xname = { Line 348  my $foreign_attr_xname = {
348    
349  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.  ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.
350    
 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;  
   
351  ## TODO: Invoke the reset algorithm when a resettable element is  ## TODO: Invoke the reset algorithm when a resettable element is
352  ## created (cf. HTML5 revision 2259).  ## created (cf. HTML5 revision 2259).
353    
# Line 488  sub parse_byte_stream ($$$$;$$) { Line 454  sub parse_byte_stream ($$$$;$$) {
454      if (defined $charset_name) {      if (defined $charset_name) {
455        $charset = Message::Charset::Info->get_by_html_name ($charset_name);        $charset = Message::Charset::Info->get_by_html_name ($charset_name);
456    
       ## ISSUE: Unsupported encoding is not ignored according to the spec.  
457        require Whatpm::Charset::DecodeHandle;        require Whatpm::Charset::DecodeHandle;
458        $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new        $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new
459            ($byte_stream);            ($byte_stream);
# Line 835  sub new ($) { Line 800  sub new ($) {
800    return $self;    return $self;
801  } # new  } # new
802    
803  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 }  
804    
805  sub AFTER_HTML_IMS () { 0b100 }  sub AFTER_HTML_IMS () { 0b100 }
806  sub HEAD_IMS ()       { 0b1000 }  sub HEAD_IMS ()       { 0b1000 }
# Line 915  sub ROW_IMS ()        { 0b10000000 } Line 811  sub ROW_IMS ()        { 0b10000000 }
811  sub BODY_AFTER_IMS () { 0b100000000 }  sub BODY_AFTER_IMS () { 0b100000000 }
812  sub FRAME_IMS ()      { 0b1000000000 }  sub FRAME_IMS ()      { 0b1000000000 }
813  sub SELECT_IMS ()     { 0b10000000000 }  sub SELECT_IMS ()     { 0b10000000000 }
814  sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 }  #sub IN_FOREIGN_CONTENT_IM () { 0b100000000000 } # see Whatpm::HTML::Tokenizer
815      ## NOTE: "in foreign content" insertion mode is special; it is combined      ## NOTE: "in foreign content" insertion mode is special; it is combined
816      ## with the secondary insertion mode.  In this parser, they are stored      ## with the secondary insertion mode.  In this parser, they are stored
817      ## together in the bit-or'ed form.      ## together in the bit-or'ed form.
818    sub IN_CDATA_RCDATA_IM () { 0b1000000000000 }
819        ## NOTE: "in CDATA/RCDATA" insertion mode is also special; it is
820        ## combined with the original insertion mode.  In thie parser,
821        ## they are stored together in the bit-or'ed form.
822    
823  ## NOTE: "initial" and "before html" insertion modes have no constants.  ## NOTE: "initial" and "before html" insertion modes have no constants.
824    
# Line 945  sub IN_SELECT_IM () { SELECT_IMS | 0b01 Line 845  sub IN_SELECT_IM () { SELECT_IMS | 0b01
845  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }  sub IN_SELECT_IN_TABLE_IM () { SELECT_IMS | 0b10 }
846  sub IN_COLUMN_GROUP_IM () { 0b10 }  sub IN_COLUMN_GROUP_IM () { 0b10 }
847    
 ## Implementations MUST act as if state machine in the spec  
   
 sub _initialize_tokenizer ($) {  
   my $self = shift;  
   $self->{state} = DATA_STATE; # MUST  
   #$self->{s_kwd}; # state keyword - initialized when used  
   #$self->{entity__value}; # initialized when used  
   #$self->{entity__match}; # initialized when used  
   $self->{content_model} = PCDATA_CONTENT_MODEL; # be  
   undef $self->{ct}; # current token  
   undef $self->{ca}; # current attribute  
   undef $self->{last_stag_name}; # last emitted start tag name  
   #$self->{prev_state}; # initialized when used  
   delete $self->{self_closing};  
   $self->{char_buffer} = '';  
   $self->{char_buffer_pos} = 0;  
   $self->{nc} = -1; # next input character  
   #$self->{next_nc}  
   !!!next-input-character;  
   $self->{token} = [];  
   # $self->{escape}  
 } # _initialize_tokenizer  
   
 ## A token has:  
 ##   ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,  
 ##       CHARACTER_TOKEN, or END_OF_FILE_TOKEN  
 ##   ->{name} (DOCTYPE_TOKEN)  
 ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)  
 ##   ->{pubid} (DOCTYPE_TOKEN)  
 ##   ->{sysid} (DOCTYPE_TOKEN)  
 ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag  
 ##   ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)  
 ##        ->{name}  
 ##        ->{value}  
 ##        ->{has_reference} == 1 or 0  
 ##   ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN)  
 ## NOTE: The "self-closing flag" is hold as |$self->{self_closing}|.  
 ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|  
 ##     while the token is pushed back to the stack.  
   
 ## Emitted token MUST immediately be handled by the tree construction state.  
   
 ## Before each step, UA MAY check to see if either one of the scripts in  
 ## "list of scripts that will execute as soon as possible" or the first  
 ## script in the "list of scripts that will execute asynchronously",  
 ## has completed loading.  If one has, then it MUST be executed  
 ## and removed from the list.  
   
 ## TODO: Polytheistic slash SHOULD NOT be used. (Applied only to atheists.)  
 ## (This requirement was dropped from HTML5 spec, unfortunately.)  
   
 my $is_space = {  
   0x0009 => 1, # CHARACTER TABULATION (HT)  
   0x000A => 1, # LINE FEED (LF)  
   #0x000B => 0, # LINE TABULATION (VT)  
   0x000C => 1, # FORM FEED (FF)  
   #0x000D => 1, # CARRIAGE RETURN (CR)  
   0x0020 => 1, # SPACE (SP)  
 };  
   
 sub _get_next_token ($) {  
   my $self = shift;  
   
   if ($self->{self_closing}) {  
     !!!parse-error (type => 'nestc', token => $self->{ct});  
     ## NOTE: The |self_closing| flag is only set by start tag token.  
     ## In addition, when a start tag token is emitted, it is always set to  
     ## |ct|.  
     delete $self->{self_closing};  
   }  
   
   if (@{$self->{token}}) {  
     $self->{self_closing} = $self->{token}->[0]->{self_closing};  
     return shift @{$self->{token}};  
   }  
   
   A: {  
     if ($self->{state} == PCDATA_STATE) {  
       ## NOTE: Same as |DATA_STATE|, but only for |PCDATA| content model.  
   
       if ($self->{nc} == 0x0026) { # &  
         !!!cp (0.1);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity data state".  In this implementation, the tokenizer  
         ## is switched to the |ENTITY_STATE|, which is an implementation  
         ## of the "consume a character reference" algorithm.  
         $self->{entity_add} = -1;  
         $self->{prev_state} = DATA_STATE;  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003C) { # <  
         !!!cp (0.2);  
         $self->{state} = TAG_OPEN_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (0.3);  
         !!!emit ({type => END_OF_FILE_TOKEN,  
                   line => $self->{line}, column => $self->{column}});  
         last A; ## TODO: ok?  
       } else {  
         !!!cp (0.4);  
         #  
       }  
   
       # Anything else  
       my $token = {type => CHARACTER_TOKEN,  
                    data => chr $self->{nc},  
                    line => $self->{line}, column => $self->{column},  
                   };  
       $self->{read_until}->($token->{data}, q[<&], length $token->{data});  
   
       ## Stay in the state.  
       !!!next-input-character;  
       !!!emit ($token);  
       redo A;  
     } elsif ($self->{state} == DATA_STATE) {  
       $self->{s_kwd} = '' unless defined $self->{s_kwd};  
       if ($self->{nc} == 0x0026) { # &  
         $self->{s_kwd} = '';  
         if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA  
             not $self->{escape}) {  
           !!!cp (1);  
           ## NOTE: In the spec, the tokenizer is switched to the  
           ## "entity data state".  In this implementation, the tokenizer  
           ## is switched to the |ENTITY_STATE|, which is an implementation  
           ## of the "consume a character reference" algorithm.  
           $self->{entity_add} = -1;  
           $self->{prev_state} = DATA_STATE;  
           $self->{state} = ENTITY_STATE;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (2);  
           #  
         }  
       } elsif ($self->{nc} == 0x002D) { # -  
         if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
           $self->{s_kwd} .= '-';  
             
           if ($self->{s_kwd} eq '<!--') {  
             !!!cp (3);  
             $self->{escape} = 1; # unless $self->{escape};  
             $self->{s_kwd} = '--';  
             #  
           } elsif ($self->{s_kwd} eq '---') {  
             !!!cp (4);  
             $self->{s_kwd} = '--';  
             #  
           } else {  
             !!!cp (5);  
             #  
           }  
         }  
           
         #  
       } elsif ($self->{nc} == 0x0021) { # !  
         if (length $self->{s_kwd}) {  
           !!!cp (5.1);  
           $self->{s_kwd} .= '!';  
           #  
         } else {  
           !!!cp (5.2);  
           #$self->{s_kwd} = '';  
           #  
         }  
         #  
       } elsif ($self->{nc} == 0x003C) { # <  
         if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA  
             (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA  
              not $self->{escape})) {  
           !!!cp (6);  
           $self->{state} = TAG_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (7);  
           $self->{s_kwd} = '';  
           #  
         }  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{escape} and  
             ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA  
           if ($self->{s_kwd} eq '--') {  
             !!!cp (8);  
             delete $self->{escape};  
           } else {  
             !!!cp (9);  
           }  
         } else {  
           !!!cp (10);  
         }  
           
         $self->{s_kwd} = '';  
         #  
       } elsif ($self->{nc} == -1) {  
         !!!cp (11);  
         $self->{s_kwd} = '';  
         !!!emit ({type => END_OF_FILE_TOKEN,  
                   line => $self->{line}, column => $self->{column}});  
         last A; ## TODO: ok?  
       } else {  
         !!!cp (12);  
         $self->{s_kwd} = '';  
         #  
       }  
   
       # Anything else  
       my $token = {type => CHARACTER_TOKEN,  
                    data => chr $self->{nc},  
                    line => $self->{line}, column => $self->{column},  
                   };  
       if ($self->{read_until}->($token->{data}, q[-!<>&],  
                                 length $token->{data})) {  
         $self->{s_kwd} = '';  
       }  
   
       ## Stay in the data state.  
       if ($self->{content_model} == PCDATA_CONTENT_MODEL) {  
         !!!cp (13);  
         $self->{state} = PCDATA_STATE;  
       } else {  
         !!!cp (14);  
         ## Stay in the state.  
       }  
       !!!next-input-character;  
       !!!emit ($token);  
       redo A;  
     } elsif ($self->{state} == TAG_OPEN_STATE) {  
       if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
         if ($self->{nc} == 0x002F) { # /  
           !!!cp (15);  
           !!!next-input-character;  
           $self->{state} = CLOSE_TAG_OPEN_STATE;  
           redo A;  
         } elsif ($self->{nc} == 0x0021) { # !  
           !!!cp (15.1);  
           $self->{s_kwd} = '<' unless $self->{escape};  
           #  
         } else {  
           !!!cp (16);  
           #  
         }  
   
         ## reconsume  
         $self->{state} = DATA_STATE;  
         !!!emit ({type => CHARACTER_TOKEN, data => '<',  
                   line => $self->{line_prev},  
                   column => $self->{column_prev},  
                  });  
         redo A;  
       } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA  
         if ($self->{nc} == 0x0021) { # !  
           !!!cp (17);  
           $self->{state} = MARKUP_DECLARATION_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif ($self->{nc} == 0x002F) { # /  
           !!!cp (18);  
           $self->{state} = CLOSE_TAG_OPEN_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif (0x0041 <= $self->{nc} and  
                  $self->{nc} <= 0x005A) { # A..Z  
           !!!cp (19);  
           $self->{ct}  
             = {type => START_TAG_TOKEN,  
                tag_name => chr ($self->{nc} + 0x0020),  
                line => $self->{line_prev},  
                column => $self->{column_prev}};  
           $self->{state} = TAG_NAME_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif (0x0061 <= $self->{nc} and  
                  $self->{nc} <= 0x007A) { # a..z  
           !!!cp (20);  
           $self->{ct} = {type => START_TAG_TOKEN,  
                                     tag_name => chr ($self->{nc}),  
                                     line => $self->{line_prev},  
                                     column => $self->{column_prev}};  
           $self->{state} = TAG_NAME_STATE;  
           !!!next-input-character;  
           redo A;  
         } elsif ($self->{nc} == 0x003E) { # >  
           !!!cp (21);  
           !!!parse-error (type => 'empty start tag',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = DATA_STATE;  
           !!!next-input-character;  
   
           !!!emit ({type => CHARACTER_TOKEN, data => '<>',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev},  
                    });  
   
           redo A;  
         } elsif ($self->{nc} == 0x003F) { # ?  
           !!!cp (22);  
           !!!parse-error (type => 'pio',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = BOGUS_COMMENT_STATE;  
           $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                     line => $self->{line_prev},  
                                     column => $self->{column_prev},  
                                    };  
           ## $self->{nc} is intentionally left as is  
           redo A;  
         } else {  
           !!!cp (23);  
           !!!parse-error (type => 'bare stago',  
                           line => $self->{line_prev},  
                           column => $self->{column_prev});  
           $self->{state} = DATA_STATE;  
           ## reconsume  
   
           !!!emit ({type => CHARACTER_TOKEN, data => '<',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev},  
                    });  
   
           redo A;  
         }  
       } else {  
         die "$0: $self->{content_model} in tag open";  
       }  
     } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {  
       ## NOTE: The "close tag open state" in the spec is implemented as  
       ## |CLOSE_TAG_OPEN_STATE| and |CDATA_RCDATA_CLOSE_TAG_STATE|.  
   
       my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"  
       if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA  
         if (defined $self->{last_stag_name}) {  
           $self->{state} = CDATA_RCDATA_CLOSE_TAG_STATE;  
           $self->{s_kwd} = '';  
           ## Reconsume.  
           redo A;  
         } else {  
           ## No start tag token has ever been emitted  
           ## NOTE: See <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>.  
           !!!cp (28);  
           $self->{state} = DATA_STATE;  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN, data => '</',  
                     line => $l, column => $c,  
                    });  
           redo A;  
         }  
       }  
   
       if (0x0041 <= $self->{nc} and  
           $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (29);  
         $self->{ct}  
             = {type => END_TAG_TOKEN,  
                tag_name => chr ($self->{nc} + 0x0020),  
                line => $l, column => $c};  
         $self->{state} = TAG_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0061 <= $self->{nc} and  
                $self->{nc} <= 0x007A) { # a..z  
         !!!cp (30);  
         $self->{ct} = {type => END_TAG_TOKEN,  
                                   tag_name => chr ($self->{nc}),  
                                   line => $l, column => $c};  
         $self->{state} = TAG_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (31);  
         !!!parse-error (type => 'empty end tag',  
                         line => $self->{line_prev}, ## "<" in "</>"  
                         column => $self->{column_prev} - 1);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (32);  
         !!!parse-error (type => 'bare etago');  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ({type => CHARACTER_TOKEN, data => '</',  
                   line => $l, column => $c,  
                  });  
   
         redo A;  
       } else {  
         !!!cp (33);  
         !!!parse-error (type => 'bogus end tag');  
         $self->{state} = BOGUS_COMMENT_STATE;  
         $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                   line => $self->{line_prev}, # "<" of "</"  
                                   column => $self->{column_prev} - 1,  
                                  };  
         ## NOTE: $self->{nc} is intentionally left as is.  
         ## Although the "anything else" case of the spec not explicitly  
         ## states that the next input character is to be reconsumed,  
         ## it will be included to the |data| of the comment token  
         ## generated from the bogus end tag, as defined in the  
         ## "bogus comment state" entry.  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_RCDATA_CLOSE_TAG_STATE) {  
       my $ch = substr $self->{last_stag_name}, length $self->{s_kwd}, 1;  
       if (length $ch) {  
         my $CH = $ch;  
         $ch =~ tr/a-z/A-Z/;  
         my $nch = chr $self->{nc};  
         if ($nch eq $ch or $nch eq $CH) {  
           !!!cp (24);  
           ## Stay in the state.  
           $self->{s_kwd} .= $nch;  
           !!!next-input-character;  
           redo A;  
         } else {  
           !!!cp (25);  
           $self->{state} = DATA_STATE;  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '</' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                    });  
           redo A;  
         }  
       } else { # after "<{tag-name}"  
         unless ($is_space->{$self->{nc}} or  
                 {  
                  0x003E => 1, # >  
                  0x002F => 1, # /  
                  -1 => 1, # EOF  
                 }->{$self->{nc}}) {  
           !!!cp (26);  
           ## Reconsume.  
           $self->{state} = DATA_STATE;  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '</' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                    });  
           redo A;  
         } else {  
           !!!cp (27);  
           $self->{ct}  
               = {type => END_TAG_TOKEN,  
                  tag_name => $self->{last_stag_name},  
                  line => $self->{line_prev},  
                  column => $self->{column_prev} - 1 - length $self->{s_kwd}};  
           $self->{state} = TAG_NAME_STATE;  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == TAG_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (34);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (35);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           #if ($self->{ct}->{attributes}) {  
           #  ## NOTE: This should never be reached.  
           #  !!! cp (36);  
           #  !!! parse-error (type => 'end tag attribute');  
           #} else {  
             !!!cp (37);  
           #}  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (38);  
         $self->{ct}->{tag_name} .= chr ($self->{nc} + 0x0020);  
           # start tag or end tag  
         ## Stay in this state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (39);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           #if ($self->{ct}->{attributes}) {  
           #  ## NOTE: This state should never be reached.  
           #  !!! cp (40);  
           #  !!! parse-error (type => 'end tag attribute');  
           #} else {  
             !!!cp (41);  
           #}  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (42);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (44);  
         $self->{ct}->{tag_name} .= chr $self->{nc};  
           # start tag or end tag  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (45);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (46);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (47);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp (48);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (49);  
         $self->{ca}  
             = {name => chr ($self->{nc} + 0x0020),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (50);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (52);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (53);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp (54);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ({  
              0x0022 => 1, # "  
              0x0027 => 1, # '  
              0x003D => 1, # =  
             }->{$self->{nc}}) {  
           !!!cp (55);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (56);  
         }  
         $self->{ca}  
             = {name => chr ($self->{nc}),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {  
       my $before_leave = sub {  
         if (exists $self->{ct}->{attributes} # start tag or end tag  
             ->{$self->{ca}->{name}}) { # MUST  
           !!!cp (57);  
           !!!parse-error (type => 'duplicate attribute', text => $self->{ca}->{name}, line => $self->{ca}->{line}, column => $self->{ca}->{column});  
           ## Discard $self->{ca} # MUST  
         } else {  
           !!!cp (58);  
           $self->{ct}->{attributes}->{$self->{ca}->{name}}  
             = $self->{ca};  
         }  
       }; # $before_leave  
   
       if ($is_space->{$self->{nc}}) {  
         !!!cp (59);  
         $before_leave->();  
         $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003D) { # =  
         !!!cp (60);  
         $before_leave->();  
         $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         $before_leave->();  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (61);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           !!!cp (62);  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!parse-error (type => 'end tag attribute');  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (63);  
         $self->{ca}->{name} .= chr ($self->{nc} + 0x0020);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (64);  
         $before_leave->();  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         $before_leave->();  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (66);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (67);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (68);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x0022 or # "  
             $self->{nc} == 0x0027) { # '  
           !!!cp (69);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (70);  
         }  
         $self->{ca}->{name} .= chr ($self->{nc});  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (71);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003D) { # =  
         !!!cp (72);  
         $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (73);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (74);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (75);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x005A) { # A..Z  
         !!!cp (76);  
         $self->{ca}  
             = {name => chr ($self->{nc} + 0x0020),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (77);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (79);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (80);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (81);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         # reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x0022 or # "  
             $self->{nc} == 0x0027) { # '  
           !!!cp (78);  
           !!!parse-error (type => 'bad attribute name');  
         } else {  
           !!!cp (82);  
         }  
         $self->{ca}  
             = {name => chr ($self->{nc}),  
                value => '',  
                line => $self->{line}, column => $self->{column}};  
         $self->{state} = ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;          
       }  
     } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (83);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (84);  
         $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (85);  
         $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;  
         ## reconsume  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (86);  
         $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!parse-error (type => 'empty unquoted attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (87);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (88);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (89);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (90);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (91);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (92);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ($self->{nc} == 0x003D) { # =  
           !!!cp (93);  
           !!!parse-error (type => 'bad attribute value');  
         } else {  
           !!!cp (94);  
         }  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (95);  
         $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (96);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{prev_state} = $self->{state};  
         $self->{entity_add} = 0x0022; # "  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (97);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (98);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (99);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         !!!cp (100);  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q["&],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (101);  
         $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (102);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{entity_add} = 0x0027; # '  
         $self->{prev_state} = $self->{state};  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed attribute value');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (103);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (104);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (105);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         !!!cp (106);  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q['&],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (107);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0026) { # &  
         !!!cp (108);  
         ## NOTE: In the spec, the tokenizer is switched to the  
         ## "entity in attribute value state".  In this implementation, the  
         ## tokenizer is switched to the |ENTITY_STATE|, which is an  
         ## implementation of the "consume a character reference" algorithm.  
         $self->{entity_add} = -1;  
         $self->{prev_state} = $self->{state};  
         $self->{state} = ENTITY_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (109);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (110);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (111);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (112);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (113);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (114);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } else {  
         if ({  
              0x0022 => 1, # "  
              0x0027 => 1, # '  
              0x003D => 1, # =  
             }->{$self->{nc}}) {  
           !!!cp (115);  
           !!!parse-error (type => 'bad attribute value');  
         } else {  
           !!!cp (116);  
         }  
         $self->{ca}->{value} .= chr ($self->{nc});  
         $self->{read_until}->($self->{ca}->{value},  
                               q["'=& >],  
                               length $self->{ca}->{value});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (118);  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (119);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp (120);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (121);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == 0x002F) { # /  
         !!!cp (122);  
         $self->{state} = SELF_CLOSING_START_TAG_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (122.3);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           if ($self->{ct}->{attributes}) {  
             !!!cp (122.1);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (122.2);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## Reconsume.  
         !!!emit ($self->{ct}); # start tag or end tag  
         redo A;  
       } else {  
         !!!cp ('124.1');  
         !!!parse-error (type => 'no space between attributes');  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         ## reconsume  
         redo A;  
       }  
     } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         if ($self->{ct}->{type} == END_TAG_TOKEN) {  
           !!!cp ('124.2');  
           !!!parse-error (type => 'nestc', token => $self->{ct});  
           ## TODO: Different type than slash in start tag  
           $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST  
           if ($self->{ct}->{attributes}) {  
             !!!cp ('124.4');  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             !!!cp ('124.5');  
           }  
           ## TODO: Test |<title></title/>|  
         } else {  
           !!!cp ('124.3');  
           $self->{self_closing} = 1;  
         }  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # start tag or end tag  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!parse-error (type => 'unclosed tag');  
         if ($self->{ct}->{type} == START_TAG_TOKEN) {  
           !!!cp (124.7);  
           $self->{last_stag_name} = $self->{ct}->{tag_name};  
         } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {  
           if ($self->{ct}->{attributes}) {  
             !!!cp (124.5);  
             !!!parse-error (type => 'end tag attribute');  
           } else {  
             ## NOTE: This state should never be reached.  
             !!!cp (124.6);  
           }  
         } else {  
           die "$0: $self->{ct}->{type}: Unknown token type";  
         }  
         $self->{state} = DATA_STATE;  
         ## Reconsume.  
         !!!emit ($self->{ct}); # start tag or end tag  
         redo A;  
       } else {  
         !!!cp ('124.4');  
         !!!parse-error (type => 'nestc');  
         ## TODO: This error type is wrong.  
         $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == BOGUS_COMMENT_STATE) {  
       ## (only happen if PCDATA state)  
   
       ## NOTE: Unlike spec's "bogus comment state", this implementation  
       ## consumes characters one-by-one basis.  
         
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (124);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (125);  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
         redo A;  
       } else {  
         !!!cp (126);  
         $self->{ct}->{data} .= chr ($self->{nc}); # comment  
         $self->{read_until}->($self->{ct}->{data},  
                               q[>],  
                               length $self->{ct}->{data});  
   
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {  
       ## (only happen if PCDATA state)  
         
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (133);  
         $self->{state} = MD_HYPHEN_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0044 or # D  
                $self->{nc} == 0x0064) { # d  
         ## ASCII case-insensitive.  
         !!!cp (130);  
         $self->{state} = MD_DOCTYPE_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and  
                $self->{open_elements}->[-1]->[1] & FOREIGN_EL and  
                $self->{nc} == 0x005B) { # [  
         !!!cp (135.4);                  
         $self->{state} = MD_CDATA_STATE;  
         $self->{s_kwd} = '[';  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (136);  
       }  
   
       !!!parse-error (type => 'bogus comment',  
                       line => $self->{line_prev},  
                       column => $self->{column_prev} - 1);  
       ## Reconsume.  
       $self->{state} = BOGUS_COMMENT_STATE;  
       $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                 line => $self->{line_prev},  
                                 column => $self->{column_prev} - 1,  
                                };  
       redo A;  
     } elsif ($self->{state} == MD_HYPHEN_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (127);  
         $self->{ct} = {type => COMMENT_TOKEN, data => '',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 2,  
                                  };  
         $self->{state} = COMMENT_START_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (128);  
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 2);  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => '-',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 2,  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == MD_DOCTYPE_STATE) {  
       ## ASCII case-insensitive.  
       if ($self->{nc} == [  
             undef,  
             0x004F, # O  
             0x0043, # C  
             0x0054, # T  
             0x0059, # Y  
             0x0050, # P  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x006F, # o  
             0x0063, # c  
             0x0074, # t  
             0x0079, # y  
             0x0070, # p  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (131);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 6 and  
                ($self->{nc} == 0x0045 or # E  
                 $self->{nc} == 0x0065)) { # e  
         !!!cp (129);  
         $self->{state} = DOCTYPE_STATE;  
         $self->{ct} = {type => DOCTYPE_TOKEN,  
                                   quirks => 1,  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 7,  
                                  };  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (132);          
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1 - length $self->{s_kwd});  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => $self->{s_kwd},  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == MD_CDATA_STATE) {  
       if ($self->{nc} == {  
             '[' => 0x0043, # C  
             '[C' => 0x0044, # D  
             '[CD' => 0x0041, # A  
             '[CDA' => 0x0054, # T  
             '[CDAT' => 0x0041, # A  
           }->{$self->{s_kwd}}) {  
         !!!cp (135.1);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{s_kwd} eq '[CDATA' and  
                $self->{nc} == 0x005B) { # [  
         !!!cp (135.2);  
         $self->{ct} = {type => CHARACTER_TOKEN,  
                                   data => '',  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 7};  
         $self->{state} = CDATA_SECTION_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (135.3);  
         !!!parse-error (type => 'bogus comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1 - length $self->{s_kwd});  
         $self->{state} = BOGUS_COMMENT_STATE;  
         ## Reconsume.  
         $self->{ct} = {type => COMMENT_TOKEN,  
                                   data => $self->{s_kwd},  
                                   line => $self->{line_prev},  
                                   column => $self->{column_prev} - 1 - length $self->{s_kwd},  
                                  };  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_START_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (137);  
         $self->{state} = COMMENT_START_DASH_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (138);  
         !!!parse-error (type => 'bogus comment');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (139);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (140);  
         $self->{ct}->{data} # comment  
             .= chr ($self->{nc});  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_START_DASH_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (141);  
         $self->{state} = COMMENT_END_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (142);  
         !!!parse-error (type => 'bogus comment');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (143);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (144);  
         $self->{ct}->{data} # comment  
             .= '-' . chr ($self->{nc});  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (145);  
         $self->{state} = COMMENT_END_DASH_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (146);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (147);  
         $self->{ct}->{data} .= chr ($self->{nc}); # comment  
         $self->{read_until}->($self->{ct}->{data},  
                               q[-],  
                               length $self->{ct}->{data});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_END_DASH_STATE) {  
       if ($self->{nc} == 0x002D) { # -  
         !!!cp (148);  
         $self->{state} = COMMENT_END_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (149);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (150);  
         $self->{ct}->{data} .= '-' . chr ($self->{nc}); # comment  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == COMMENT_END_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (151);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } elsif ($self->{nc} == 0x002D) { # -  
         !!!cp (152);  
         !!!parse-error (type => 'dash in comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev});  
         $self->{ct}->{data} .= '-'; # comment  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (153);  
         !!!parse-error (type => 'unclosed comment');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # comment  
   
         redo A;  
       } else {  
         !!!cp (154);  
         !!!parse-error (type => 'dash in comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev});  
         $self->{ct}->{data} .= '--' . chr ($self->{nc}); # comment  
         $self->{state} = COMMENT_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (155);  
         $self->{state} = BEFORE_DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (156);  
         !!!parse-error (type => 'no space before DOCTYPE name');  
         $self->{state} = BEFORE_DOCTYPE_NAME_STATE;  
         ## reconsume  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (157);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (158);  
         !!!parse-error (type => 'no DOCTYPE name');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE (quirks)  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (159);  
         !!!parse-error (type => 'no DOCTYPE name');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # DOCTYPE (quirks)  
   
         redo A;  
       } else {  
         !!!cp (160);  
         $self->{ct}->{name} = chr $self->{nc};  
         delete $self->{ct}->{quirks};  
 ## ISSUE: "Set the token's name name to the" in the spec  
         $self->{state} = DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_NAME_STATE) {  
 ## ISSUE: Redundant "First," in the spec.  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (161);  
         $self->{state} = AFTER_DOCTYPE_NAME_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (162);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (163);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (164);  
         $self->{ct}->{name}  
           .= chr ($self->{nc}); # DOCTYPE  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (165);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (166);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (167);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == 0x0050 or # P  
                $self->{nc} == 0x0070) { # p  
         $self->{state} = PUBLIC_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0053 or # S  
                $self->{nc} == 0x0073) { # s  
         $self->{state} = SYSTEM_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (180);  
         !!!parse-error (type => 'string after DOCTYPE name');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == PUBLIC_STATE) {  
       ## ASCII case-insensitive  
       if ($self->{nc} == [  
             undef,  
             0x0055, # U  
             0x0042, # B  
             0x004C, # L  
             0x0049, # I  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x0075, # u  
             0x0062, # b  
             0x006C, # l  
             0x0069, # i  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (175);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 5 and  
                ($self->{nc} == 0x0043 or # C  
                 $self->{nc} == 0x0063)) { # c  
         !!!cp (168);  
         $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (169);  
         !!!parse-error (type => 'string after DOCTYPE name',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} + 1 - length $self->{s_kwd});  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == SYSTEM_STATE) {  
       ## ASCII case-insensitive  
       if ($self->{nc} == [  
             undef,  
             0x0059, # Y  
             0x0053, # S  
             0x0054, # T  
             0x0045, # E  
           ]->[length $self->{s_kwd}] or  
           $self->{nc} == [  
             undef,  
             0x0079, # y  
             0x0073, # s  
             0x0074, # t  
             0x0065, # e  
           ]->[length $self->{s_kwd}]) {  
         !!!cp (170);  
         ## Stay in the state.  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif ((length $self->{s_kwd}) == 5 and  
                ($self->{nc} == 0x004D or # M  
                 $self->{nc} == 0x006D)) { # m  
         !!!cp (171);  
         $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (172);  
         !!!parse-error (type => 'string after DOCTYPE name',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} + 1 - length $self->{s_kwd});  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (181);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x0022) { # "  
         !!!cp (182);  
         $self->{ct}->{pubid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x0027) { # '  
         !!!cp (183);  
         $self->{ct}->{pubid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} eq 0x003E) { # >  
         !!!cp (184);  
         !!!parse-error (type => 'no PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (185);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (186);  
         !!!parse-error (type => 'string after PUBLIC');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (187);  
         $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (188);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (189);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (190);  
         $self->{ct}->{pubid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{pubid}, q[">],  
                               length $self->{ct}->{pubid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (191);  
         $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (192);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (193);  
         !!!parse-error (type => 'unclosed PUBLIC literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (194);  
         $self->{ct}->{pubid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{pubid}, q['>],  
                               length $self->{ct}->{pubid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (195);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (196);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (197);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (198);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (199);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (200);  
         !!!parse-error (type => 'string after PUBLIC literal');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (201);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0022) { # "  
         !!!cp (202);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x0027) { # '  
         !!!cp (203);  
         $self->{ct}->{sysid} = ''; # DOCTYPE  
         $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (204);  
         !!!parse-error (type => 'no SYSTEM literal');  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (205);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (206);  
         !!!parse-error (type => 'string after SYSTEM');  
         $self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0022) { # "  
         !!!cp (207);  
         $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (208);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (209);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (210);  
         $self->{ct}->{sysid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{sysid}, q[">],  
                               length $self->{ct}->{sysid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {  
       if ($self->{nc} == 0x0027) { # '  
         !!!cp (211);  
         $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (212);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (213);  
         !!!parse-error (type => 'unclosed SYSTEM literal');  
   
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (214);  
         $self->{ct}->{sysid} # DOCTYPE  
             .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{sysid}, q['>],  
                               length $self->{ct}->{sysid});  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {  
       if ($is_space->{$self->{nc}}) {  
         !!!cp (215);  
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003E) { # >  
         !!!cp (216);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (217);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (218);  
         !!!parse-error (type => 'string after SYSTEM literal');  
         #$self->{ct}->{quirks} = 1;  
   
         $self->{state} = BOGUS_DOCTYPE_STATE;  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         !!!cp (219);  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } elsif ($self->{nc} == -1) {  
         !!!cp (220);  
         !!!parse-error (type => 'unclosed DOCTYPE');  
         $self->{state} = DATA_STATE;  
         ## reconsume  
   
         !!!emit ($self->{ct}); # DOCTYPE  
   
         redo A;  
       } else {  
         !!!cp (221);  
         my $s = '';  
         $self->{read_until}->($s, q[>], 0);  
   
         ## Stay in the state  
         !!!next-input-character;  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_SECTION_STATE) {  
       ## NOTE: "CDATA section state" in the state is jointly implemented  
       ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,  
       ## and |CDATA_SECTION_MSE2_STATE|.  
         
       if ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.1);  
         $self->{state} = CDATA_SECTION_MSE1_STATE;  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == -1) {  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         if (length $self->{ct}->{data}) { # character  
           !!!cp (221.2);  
           !!!emit ($self->{ct}); # character  
         } else {  
           !!!cp (221.3);  
           ## No token to emit. $self->{ct} is discarded.  
         }          
         redo A;  
       } else {  
         !!!cp (221.4);  
         $self->{ct}->{data} .= chr $self->{nc};  
         $self->{read_until}->($self->{ct}->{data},  
                               q<]>,  
                               length $self->{ct}->{data});  
   
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       }  
   
       ## ISSUE: "text tokens" in spec.  
     } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {  
       if ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.5);  
         $self->{state} = CDATA_SECTION_MSE2_STATE;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (221.6);  
         $self->{ct}->{data} .= ']';  
         $self->{state} = CDATA_SECTION_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {  
       if ($self->{nc} == 0x003E) { # >  
         $self->{state} = DATA_STATE;  
         !!!next-input-character;  
         if (length $self->{ct}->{data}) { # character  
           !!!cp (221.7);  
           !!!emit ($self->{ct}); # character  
         } else {  
           !!!cp (221.8);  
           ## No token to emit. $self->{ct} is discarded.  
         }  
         redo A;  
       } elsif ($self->{nc} == 0x005D) { # ]  
         !!!cp (221.9); # character  
         $self->{ct}->{data} .= ']'; ## Add first "]" of "]]]".  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (221.11);  
         $self->{ct}->{data} .= ']]'; # character  
         $self->{state} = CDATA_SECTION_STATE;  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_STATE) {  
       if ($is_space->{$self->{nc}} or  
           {  
             0x003C => 1, 0x0026 => 1, -1 => 1, # <, &  
             $self->{entity_add} => 1,  
           }->{$self->{nc}}) {  
         !!!cp (1001);  
         ## Don't consume  
         ## No error  
         ## Return nothing.  
         #  
       } elsif ($self->{nc} == 0x0023) { # #  
         !!!cp (999);  
         $self->{state} = ENTITY_HASH_STATE;  
         $self->{s_kwd} = '#';  
         !!!next-input-character;  
         redo A;  
       } elsif ((0x0041 <= $self->{nc} and  
                 $self->{nc} <= 0x005A) or # A..Z  
                (0x0061 <= $self->{nc} and  
                 $self->{nc} <= 0x007A)) { # a..z  
         !!!cp (998);  
         require Whatpm::_NamedEntityList;  
         $self->{state} = ENTITY_NAME_STATE;  
         $self->{s_kwd} = chr $self->{nc};  
         $self->{entity__value} = $self->{s_kwd};  
         $self->{entity__match} = 0;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!cp (1027);  
         !!!parse-error (type => 'bare ero');  
         ## Return nothing.  
         #  
       }  
   
       ## NOTE: No character is consumed by the "consume a character  
       ## reference" algorithm.  In other word, there is an "&" character  
       ## that does not introduce a character reference, which would be  
       ## appended to the parent element or the attribute value in later  
       ## process of the tokenizer.  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (997);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => '&',  
                   line => $self->{line_prev},  
                   column => $self->{column_prev},  
                  });  
         redo A;  
       } else {  
         !!!cp (996);  
         $self->{ca}->{value} .= '&';  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_HASH_STATE) {  
       if ($self->{nc} == 0x0078 or # x  
           $self->{nc} == 0x0058) { # X  
         !!!cp (995);  
         $self->{state} = HEXREF_X_STATE;  
         $self->{s_kwd} .= chr $self->{nc};  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0030 <= $self->{nc} and  
                $self->{nc} <= 0x0039) { # 0..9  
         !!!cp (994);  
         $self->{state} = NCR_NUM_STATE;  
         $self->{s_kwd} = $self->{nc} - 0x0030;  
         !!!next-input-character;  
         redo A;  
       } else {  
         !!!parse-error (type => 'bare nero',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 1);  
   
         ## NOTE: According to the spec algorithm, nothing is returned,  
         ## and then "&#" is appended to the parent element or the attribute  
         ## value in the later processing.  
   
         if ($self->{prev_state} == DATA_STATE) {  
           !!!cp (1019);  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '&#',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - 1,  
                    });  
           redo A;  
         } else {  
           !!!cp (993);  
           $self->{ca}->{value} .= '&#';  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == NCR_NUM_STATE) {  
       if (0x0030 <= $self->{nc} and  
           $self->{nc} <= 0x0039) { # 0..9  
         !!!cp (1012);  
         $self->{s_kwd} *= 10;  
         $self->{s_kwd} += $self->{nc} - 0x0030;  
           
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003B) { # ;  
         !!!cp (1013);  
         !!!next-input-character;  
         #  
       } else {  
         !!!cp (1014);  
         !!!parse-error (type => 'no refc');  
         ## Reconsume.  
         #  
       }  
   
       my $code = $self->{s_kwd};  
       my $l = $self->{line_prev};  
       my $c = $self->{column_prev};  
       if ($charref_map->{$code}) {  
         !!!cp (1015);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U+%04X', $code),  
                         line => $l, column => $c);  
         $code = $charref_map->{$code};  
       } elsif ($code > 0x10FFFF) {  
         !!!cp (1016);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U-%08X', $code),  
                         line => $l, column => $c);  
         $code = 0xFFFD;  
       }  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (992);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => chr $code,  
                   line => $l, column => $c,  
                  });  
         redo A;  
       } else {  
         !!!cp (991);  
         $self->{ca}->{value} .= chr $code;  
         $self->{ca}->{has_reference} = 1;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == HEXREF_X_STATE) {  
       if ((0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) or  
           (0x0041 <= $self->{nc} and $self->{nc} <= 0x0046) or  
           (0x0061 <= $self->{nc} and $self->{nc} <= 0x0066)) {  
         # 0..9, A..F, a..f  
         !!!cp (990);  
         $self->{state} = HEXREF_HEX_STATE;  
         $self->{s_kwd} = 0;  
         ## Reconsume.  
         redo A;  
       } else {  
         !!!parse-error (type => 'bare hcro',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - 2);  
   
         ## NOTE: According to the spec algorithm, nothing is returned,  
         ## and then "&#" followed by "X" or "x" is appended to the parent  
         ## element or the attribute value in the later processing.  
   
         if ($self->{prev_state} == DATA_STATE) {  
           !!!cp (1005);  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           !!!emit ({type => CHARACTER_TOKEN,  
                     data => '&' . $self->{s_kwd},  
                     line => $self->{line_prev},  
                     column => $self->{column_prev} - length $self->{s_kwd},  
                    });  
           redo A;  
         } else {  
           !!!cp (989);  
           $self->{ca}->{value} .= '&' . $self->{s_kwd};  
           $self->{state} = $self->{prev_state};  
           ## Reconsume.  
           redo A;  
         }  
       }  
     } elsif ($self->{state} == HEXREF_HEX_STATE) {  
       if (0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) {  
         # 0..9  
         !!!cp (1002);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0030;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0061 <= $self->{nc} and  
                $self->{nc} <= 0x0066) { # a..f  
         !!!cp (1003);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0060 + 9;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif (0x0041 <= $self->{nc} and  
                $self->{nc} <= 0x0046) { # A..F  
         !!!cp (1004);  
         $self->{s_kwd} *= 0x10;  
         $self->{s_kwd} += $self->{nc} - 0x0040 + 9;  
         ## Stay in the state.  
         !!!next-input-character;  
         redo A;  
       } elsif ($self->{nc} == 0x003B) { # ;  
         !!!cp (1006);  
         !!!next-input-character;  
         #  
       } else {  
         !!!cp (1007);  
         !!!parse-error (type => 'no refc',  
                         line => $self->{line},  
                         column => $self->{column});  
         ## Reconsume.  
         #  
       }  
   
       my $code = $self->{s_kwd};  
       my $l = $self->{line_prev};  
       my $c = $self->{column_prev};  
       if ($charref_map->{$code}) {  
         !!!cp (1008);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U+%04X', $code),  
                         line => $l, column => $c);  
         $code = $charref_map->{$code};  
       } elsif ($code > 0x10FFFF) {  
         !!!cp (1009);  
         !!!parse-error (type => 'invalid character reference',  
                         text => (sprintf 'U-%08X', $code),  
                         line => $l, column => $c);  
         $code = 0xFFFD;  
       }  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (988);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN, data => chr $code,  
                   line => $l, column => $c,  
                  });  
         redo A;  
       } else {  
         !!!cp (987);  
         $self->{ca}->{value} .= chr $code;  
         $self->{ca}->{has_reference} = 1;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } elsif ($self->{state} == ENTITY_NAME_STATE) {  
       if (length $self->{s_kwd} < 30 and  
           ## NOTE: Some number greater than the maximum length of entity name  
           ((0x0041 <= $self->{nc} and # a  
             $self->{nc} <= 0x005A) or # x  
            (0x0061 <= $self->{nc} and # a  
             $self->{nc} <= 0x007A) or # z  
            (0x0030 <= $self->{nc} and # 0  
             $self->{nc} <= 0x0039) or # 9  
            $self->{nc} == 0x003B)) { # ;  
         our $EntityChar;  
         $self->{s_kwd} .= chr $self->{nc};  
         if (defined $EntityChar->{$self->{s_kwd}}) {  
           if ($self->{nc} == 0x003B) { # ;  
             !!!cp (1020);  
             $self->{entity__value} = $EntityChar->{$self->{s_kwd}};  
             $self->{entity__match} = 1;  
             !!!next-input-character;  
             #  
           } else {  
             !!!cp (1021);  
             $self->{entity__value} = $EntityChar->{$self->{s_kwd}};  
             $self->{entity__match} = -1;  
             ## Stay in the state.  
             !!!next-input-character;  
             redo A;  
           }  
         } else {  
           !!!cp (1022);  
           $self->{entity__value} .= chr $self->{nc};  
           $self->{entity__match} *= 2;  
           ## Stay in the state.  
           !!!next-input-character;  
           redo A;  
         }  
       }  
   
       my $data;  
       my $has_ref;  
       if ($self->{entity__match} > 0) {  
         !!!cp (1023);  
         $data = $self->{entity__value};  
         $has_ref = 1;  
         #  
       } elsif ($self->{entity__match} < 0) {  
         !!!parse-error (type => 'no refc');  
         if ($self->{prev_state} != DATA_STATE and # in attribute  
             $self->{entity__match} < -1) {  
           !!!cp (1024);  
           $data = '&' . $self->{s_kwd};  
           #  
         } else {  
           !!!cp (1025);  
           $data = $self->{entity__value};  
           $has_ref = 1;  
           #  
         }  
       } else {  
         !!!cp (1026);  
         !!!parse-error (type => 'bare ero',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev} - length $self->{s_kwd});  
         $data = '&' . $self->{s_kwd};  
         #  
       }  
     
       ## NOTE: In these cases, when a character reference is found,  
       ## it is consumed and a character token is returned, or, otherwise,  
       ## nothing is consumed and returned, according to the spec algorithm.  
       ## In this implementation, anything that has been examined by the  
       ## tokenizer is appended to the parent element or the attribute value  
       ## as string, either literal string when no character reference or  
       ## entity-replaced string otherwise, in this stage, since any characters  
       ## that would not be consumed are appended in the data state or in an  
       ## appropriate attribute value state anyway.  
   
       if ($self->{prev_state} == DATA_STATE) {  
         !!!cp (986);  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         !!!emit ({type => CHARACTER_TOKEN,  
                   data => $data,  
                   line => $self->{line_prev},  
                   column => $self->{column_prev} + 1 - length $self->{s_kwd},  
                  });  
         redo A;  
       } else {  
         !!!cp (985);  
         $self->{ca}->{value} .= $data;  
         $self->{ca}->{has_reference} = 1 if $has_ref;  
         $self->{state} = $self->{prev_state};  
         ## Reconsume.  
         redo A;  
       }  
     } else {  
       die "$0: $self->{state}: Unknown state";  
     }  
   } # A    
   
   die "$0: _get_next_token: unexpected case";  
 } # _get_next_token  
   
848  sub _initialize_tree_constructor ($) {  sub _initialize_tree_constructor ($) {
849    my $self = shift;    my $self = shift;
850    ## NOTE: $self->{document} MUST be specified before this method is called    ## NOTE: $self->{document} MUST be specified before this method is called
# Line 3469  sub _construct_tree ($) { Line 873  sub _construct_tree ($) {
873    ## When an interactive UA render the $self->{document} available    ## When an interactive UA render the $self->{document} available
874    ## to the user, or when it begin accepting user input, are    ## to the user, or when it begin accepting user input, are
875    ## 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  
876        
877    !!!next-token;    !!!next-token;
878    
879    undef $self->{form_element};    undef $self->{form_element};
880    undef $self->{head_element};    undef $self->{head_element};
881      undef $self->{head_element_inserted};
882    $self->{open_elements} = [];    $self->{open_elements} = [];
883    undef $self->{inner_html_node};    undef $self->{inner_html_node};
884      undef $self->{ignore_newline};
885    
886    ## NOTE: The "initial" insertion mode.    ## NOTE: The "initial" insertion mode.
887    $self->_tree_construction_initial; # MUST    $self->_tree_construction_initial; # MUST
# Line 3785  sub _tree_construction_root_element ($) Line 1187  sub _tree_construction_root_element ($)
1187      ## NOTE: Reprocess the token.      ## NOTE: Reprocess the token.
1188      !!!ack-later;      !!!ack-later;
1189      return; ## Go to the "before head" insertion mode.      return; ## Go to the "before head" insertion mode.
   
     ## ISSUE: There is an issue in the spec  
1190    } # B    } # B
1191    
1192    die "$0: _tree_construction_root_element: This should never be reached";    die "$0: _tree_construction_root_element: This should never be reached";
# Line 3822  sub _reset_insertion_mode ($) { Line 1222  sub _reset_insertion_mode ($) {
1222          ## SVG elements.  Currently the HTML syntax supports only MathML and          ## SVG elements.  Currently the HTML syntax supports only MathML and
1223          ## SVG elements as foreigners.          ## SVG elements as foreigners.
1224          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;
1225        } elsif ($node->[1] & TABLE_CELL_EL) {        } elsif ($node->[1] == TABLE_CELL_EL) {
1226          if ($last) {          if ($last) {
1227            !!!cp ('t28.2');            !!!cp ('t28.2');
1228            #            #
# Line 3851  sub _reset_insertion_mode ($) { Line 1251  sub _reset_insertion_mode ($) {
1251        $self->{insertion_mode} = $new_mode and return if defined $new_mode;        $self->{insertion_mode} = $new_mode and return if defined $new_mode;
1252                
1253        ## Step 15        ## Step 15
1254        if ($node->[1] & HTML_EL) {        if ($node->[1] == HTML_EL) {
1255          unless (defined $self->{head_element}) {          unless (defined $self->{head_element}) {
1256            !!!cp ('t29');            !!!cp ('t29');
1257            $self->{insertion_mode} = BEFORE_HEAD_IM;            $self->{insertion_mode} = BEFORE_HEAD_IM;
# Line 3983  sub _tree_construction_main ($) { Line 1383  sub _tree_construction_main ($) {
1383    
1384      ## Step 1      ## Step 1
1385      my $start_tag_name = $token->{tag_name};      my $start_tag_name = $token->{tag_name};
1386      my $el;      !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
     !!!create-element ($el, $HTML_NS, $start_tag_name, $token->{attributes}, $token);  
1387    
1388      ## Step 2      ## Step 2
     $insert->($el);  
   
     ## Step 3  
1389      $self->{content_model} = $content_model_flag; # CDATA or RCDATA      $self->{content_model} = $content_model_flag; # CDATA or RCDATA
1390      delete $self->{escape}; # MUST      delete $self->{escape}; # MUST
1391    
1392      ## Step 4      ## Step 3, 4
1393      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;  
     }  
1394    
1395      ## Step 5      !!!nack ('t40.1');
     if (length $text) {  
       !!!cp ('t41');  
       my $text = $self->{document}->create_text_node ($text);  
       $el->append_child ($text);  
     }  
   
     ## Step 6  
     $self->{content_model} = PCDATA_CONTENT_MODEL;  
   
     ## Step 7  
     if ($token->{type} == END_TAG_TOKEN and  
         $token->{tag_name} eq $start_tag_name) {  
       !!!cp ('t42');  
       ## Ignore the token  
     } else {  
       ## NOTE: An end-of-file token.  
       if ($content_model_flag == CDATA_CONTENT_MODEL) {  
         !!!cp ('t43');  
         !!!parse-error (type => 'in CDATA:#eof', token => $token);  
       } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {  
         !!!cp ('t44');  
         !!!parse-error (type => 'in RCDATA:#eof', token => $token);  
       } else {  
         die "$0: $content_model_flag in parse_rcdata";  
       }  
     }  
1396      !!!next-token;      !!!next-token;
1397    }; # $parse_rcdata    }; # $parse_rcdata
1398    
1399    my $script_start_tag = sub () {    my $script_start_tag = sub () {
1400        ## Step 1
1401      my $script_el;      my $script_el;
1402      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);      !!!create-element ($script_el, $HTML_NS, 'script', $token->{attributes}, $token);
1403    
1404        ## Step 2
1405      ## TODO: mark as "parser-inserted"      ## TODO: mark as "parser-inserted"
1406    
1407        ## Step 3
1408        ## TODO: Mark as "already executed", if ...
1409    
1410        ## Step 4
1411        $insert->($script_el);
1412    
1413        ## ISSUE: $script_el is not put into the stack
1414        push @{$self->{open_elements}}, [$script_el, $el_category->{script}];
1415    
1416        ## Step 5
1417      $self->{content_model} = CDATA_CONTENT_MODEL;      $self->{content_model} = CDATA_CONTENT_MODEL;
1418      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;  
1419    
1420      if ($token->{type} == END_TAG_TOKEN and      ## Step 6-7
1421          $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  
1422    
1423        $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...  
     }  
       
1424      !!!next-token;      !!!next-token;
1425    }; # $script_start_tag    }; # $script_start_tag
1426    
1427    ## NOTE: $open_tables->[-1]->[0] is the "current table" element node.    ## NOTE: $open_tables->[-1]->[0] is the "current table" element node.
1428    ## NOTE: $open_tables->[-1]->[1] is the "tainted" flag.    ## NOTE: $open_tables->[-1]->[1] is the "tainted" flag.
1429      ## NOTE: $open_tables->[-1]->[2] is set false when non-Text node inserted.
1430    my $open_tables = [[$self->{open_elements}->[0]->[0]]];    my $open_tables = [[$self->{open_elements}->[0]->[0]]];
1431    
1432    my $formatting_end_tag = sub {    my $formatting_end_tag = sub {
# Line 4171  sub _tree_construction_main ($) { Line 1511  sub _tree_construction_main ($) {
1511            !!!cp ('t59');            !!!cp ('t59');
1512            $furthest_block = $node;            $furthest_block = $node;
1513            $furthest_block_i_in_open = $_;            $furthest_block_i_in_open = $_;
1514              ## NOTE: The topmost (eldest) node.
1515          } elsif ($node->[0] eq $formatting_element->[0]) {          } elsif ($node->[0] eq $formatting_element->[0]) {
1516            !!!cp ('t60');            !!!cp ('t60');
1517            last OE;            last OE;
# Line 4257  sub _tree_construction_main ($) { Line 1598  sub _tree_construction_main ($) {
1598          my $foster_parent_element;          my $foster_parent_element;
1599          my $next_sibling;          my $next_sibling;
1600          OE: for (reverse 0..$#{$self->{open_elements}}) {          OE: for (reverse 0..$#{$self->{open_elements}}) {
1601            if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {            if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1602                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
1603                               if (defined $parent and $parent->node_type == 1) {                               if (defined $parent and $parent->node_type == 1) {
1604                                 !!!cp ('t65.1');                                 !!!cp ('t65.1');
# Line 4317  sub _tree_construction_main ($) { Line 1658  sub _tree_construction_main ($) {
1658            $i = $_;            $i = $_;
1659          }          }
1660        } # OE        } # OE
1661        splice @{$self->{open_elements}}, $i + 1, 1, $clone;        splice @{$self->{open_elements}}, $i + 1, 0, $clone;
1662                
1663        ## Step 14        ## Step 14
1664        redo FET;        redo FET;
# Line 4335  sub _tree_construction_main ($) { Line 1676  sub _tree_construction_main ($) {
1676        my $foster_parent_element;        my $foster_parent_element;
1677        my $next_sibling;        my $next_sibling;
1678        OE: for (reverse 0..$#{$self->{open_elements}}) {        OE: for (reverse 0..$#{$self->{open_elements}}) {
1679          if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {          if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
1680                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
1681                               if (defined $parent and $parent->node_type == 1) {                               if (defined $parent and $parent->node_type == 1) {
1682                                 !!!cp ('t70');                                 !!!cp ('t70');
# Line 4360  sub _tree_construction_main ($) { Line 1701  sub _tree_construction_main ($) {
1701      }      }
1702    }; # $insert_to_foster    }; # $insert_to_foster
1703    
1704      ## NOTE: Insert a character (MUST): When a character is inserted, if
1705      ## the last node that was inserted by the parser is a Text node and
1706      ## the character has to be inserted after that node, then the
1707      ## character is appended to the Text node.  However, if any other
1708      ## node is inserted by the parser, then a new Text node is created
1709      ## and the character is appended as that Text node.  If I'm not
1710      ## wrong, for a parser with scripting disabled, there are only two
1711      ## cases where this occurs.  One is the case where an element node
1712      ## is inserted to the |head| element.  This is covered by using the
1713      ## |$self->{head_element_inserted}| flag.  Another is the case where
1714      ## an element or comment is inserted into the |table| subtree while
1715      ## foster parenting happens.  This is covered by using the [2] flag
1716      ## of the |$open_tables| structure.  All other cases are handled
1717      ## simply by calling |manakai_append_text| method.
1718    
1719      ## TODO: |<body><script>document.write("a<br>");
1720      ## document.body.removeChild (document.body.lastChild);
1721      ## document.write ("b")</script>|
1722    
1723    B: while (1) {    B: while (1) {
1724      if ($token->{type} == DOCTYPE_TOKEN) {      if ($token->{type} == DOCTYPE_TOKEN) {
1725        !!!cp ('t73');        !!!cp ('t73');
# Line 4407  sub _tree_construction_main ($) { Line 1767  sub _tree_construction_main ($) {
1767        } else {        } else {
1768          !!!cp ('t87');          !!!cp ('t87');
1769          $self->{open_elements}->[-1]->[0]->append_child ($comment);          $self->{open_elements}->[-1]->[0]->append_child ($comment);
1770            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
1771        }        }
1772        !!!next-token;        !!!next-token;
1773        next B;        next B;
1774        } elsif ($self->{insertion_mode} & IN_CDATA_RCDATA_IM) {
1775          if ($token->{type} == CHARACTER_TOKEN) {
1776            $token->{data} =~ s/^\x0A// if $self->{ignore_newline};
1777            delete $self->{ignore_newline};
1778    
1779            if (length $token->{data}) {
1780              !!!cp ('t43');
1781              $self->{open_elements}->[-1]->[0]->manakai_append_text
1782                  ($token->{data});
1783            } else {
1784              !!!cp ('t43.1');
1785            }
1786            !!!next-token;
1787            next B;
1788          } elsif ($token->{type} == END_TAG_TOKEN) {
1789            delete $self->{ignore_newline};
1790    
1791            if ($token->{tag_name} eq 'script') {
1792              !!!cp ('t50');
1793              
1794              ## Para 1-2
1795              my $script = pop @{$self->{open_elements}};
1796              
1797              ## Para 3
1798              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1799    
1800              ## Para 4
1801              ## TODO: $old_insertion_point = $current_insertion_point;
1802              ## TODO: $current_insertion_point = just before $self->{nc};
1803    
1804              ## Para 5
1805              ## TODO: Run the $script->[0].
1806    
1807              ## Para 6
1808              ## TODO: $current_insertion_point = $old_insertion_point;
1809    
1810              ## Para 7
1811              ## TODO: if ($pending_external_script) {
1812                ## TODO: ...
1813              ## TODO: }
1814    
1815              !!!next-token;
1816              next B;
1817            } else {
1818              !!!cp ('t42');
1819    
1820              pop @{$self->{open_elements}};
1821    
1822              $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1823              !!!next-token;
1824              next B;
1825            }
1826          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
1827            delete $self->{ignore_newline};
1828    
1829            !!!cp ('t44');
1830            !!!parse-error (type => 'not closed',
1831                            text => $self->{open_elements}->[-1]->[0]
1832                                ->manakai_local_name,
1833                            token => $token);
1834    
1835            #if ($self->{open_elements}->[-1]->[1] == SCRIPT_EL) {
1836            #  ## TODO: Mark as "already executed"
1837            #}
1838    
1839            pop @{$self->{open_elements}};
1840    
1841            $self->{insertion_mode} &= ~ IN_CDATA_RCDATA_IM;
1842            ## Reprocess.
1843            next B;
1844          } else {
1845            die "$0: $token->{type}: In CDATA/RCDATA: Unknown token type";        
1846          }
1847      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {      } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM) {
1848        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
1849          !!!cp ('t87.1');          !!!cp ('t87.1');
# Line 4421  sub _tree_construction_main ($) { Line 1855  sub _tree_construction_main ($) {
1855               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or               $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or
1856              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or
1857              ($token->{tag_name} eq 'svg' and              ($token->{tag_name} eq 'svg' and
1858               $self->{open_elements}->[-1]->[1] & MML_AXML_EL)) {               $self->{open_elements}->[-1]->[1] == MML_AXML_EL)) {
1859            ## NOTE: "using the rules for secondary insertion mode"then"continue"            ## NOTE: "using the rules for secondary insertion mode"then"continue"
1860            !!!cp ('t87.2');            !!!cp ('t87.2');
1861            #            #
# Line 4522  sub _tree_construction_main ($) { Line 1956  sub _tree_construction_main ($) {
1956          pop @{$self->{open_elements}}          pop @{$self->{open_elements}}
1957              while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;              while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;
1958    
1959            ## NOTE: |<span><svg>| ... two parse errors, |<svg>| ... a parse error.
1960    
1961          $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;          $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;
1962          ## Reprocess.          ## Reprocess.
1963          next B;          next B;
# Line 4534  sub _tree_construction_main ($) { Line 1970  sub _tree_construction_main ($) {
1970        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
1971          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {          if ($token->{data} =~ s/^([\x09\x0A\x0C\x20]+)//) {
1972            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {            unless ($self->{insertion_mode} == BEFORE_HEAD_IM) {
1973              !!!cp ('t88.2');              if ($self->{head_element_inserted}) {
1974              $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                !!!cp ('t88.3');
1975              #                $self->{open_elements}->[-1]->[0]->append_child
1976                    ($self->{document}->create_text_node ($1));
1977                  delete $self->{head_element_inserted};
1978                  ## NOTE: |</head> <link> |
1979                  #
1980                } else {
1981                  !!!cp ('t88.2');
1982                  $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
1983                  ## NOTE: |</head> &#x20;|
1984                  #
1985                }
1986            } else {            } else {
1987              !!!cp ('t88.1');              !!!cp ('t88.1');
1988              ## Ignore the token.              ## Ignore the token.
# Line 4632  sub _tree_construction_main ($) { Line 2078  sub _tree_construction_main ($) {
2078            !!!cp ('t97');            !!!cp ('t97');
2079          }          }
2080    
2081              if ($token->{tag_name} eq 'base') {          if ($token->{tag_name} eq 'base') {
2082                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2083                  !!!cp ('t98');              !!!cp ('t98');
2084                  ## As if </noscript>              ## As if </noscript>
2085                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2086                  !!!parse-error (type => 'in noscript', text => 'base',              !!!parse-error (type => 'in noscript', text => 'base',
2087                                  token => $token);                              token => $token);
2088                            
2089                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2090                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2091                } else {            } else {
2092                  !!!cp ('t99');              !!!cp ('t99');
2093                }            }
2094    
2095                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2096                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2097                  !!!cp ('t100');              !!!cp ('t100');
2098                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2099                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2100                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2101                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2102                } else {              $self->{head_element_inserted} = 1;
2103                  !!!cp ('t101');            } else {
2104                }              !!!cp ('t101');
2105                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2106                pop @{$self->{open_elements}};            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2107                pop @{$self->{open_elements}} # <head>            pop @{$self->{open_elements}};
2108                    if $self->{insertion_mode} == AFTER_HEAD_IM;            pop @{$self->{open_elements}} # <head>
2109                !!!nack ('t101.1');                if $self->{insertion_mode} == AFTER_HEAD_IM;
2110                !!!next-token;            !!!nack ('t101.1');
2111                next B;            !!!next-token;
2112              next B;
2113          } elsif ($token->{tag_name} eq 'link') {          } elsif ($token->{tag_name} eq 'link') {
2114            ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2115            if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
# Line 4671  sub _tree_construction_main ($) { Line 2118  sub _tree_construction_main ($) {
2118                              text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2119              push @{$self->{open_elements}},              push @{$self->{open_elements}},
2120                  [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2121                $self->{head_element_inserted} = 1;
2122            } else {            } else {
2123              !!!cp ('t103');              !!!cp ('t103');
2124            }            }
# Line 4703  sub _tree_construction_main ($) { Line 2151  sub _tree_construction_main ($) {
2151              !!!cp ('t103.3');              !!!cp ('t103.3');
2152              #              #
2153            }            }
2154              } elsif ($token->{tag_name} eq 'meta') {          } elsif ($token->{tag_name} eq 'meta') {
2155                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2156                if ($self->{insertion_mode} == AFTER_HEAD_IM) {            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2157                  !!!cp ('t104');              !!!cp ('t104');
2158                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2159                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2160                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2161                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2162                } else {              $self->{head_element_inserted} = 1;
2163                  !!!cp ('t105');            } else {
2164                }              !!!cp ('t105');
2165                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            }
2166                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
2167              my $meta_el = pop @{$self->{open_elements}};
2168    
2169                unless ($self->{confident}) {                unless ($self->{confident}) {
2170                  if ($token->{attributes}->{charset}) {                  if ($token->{attributes}->{charset}) {
# Line 4773  sub _tree_construction_main ($) { Line 2222  sub _tree_construction_main ($) {
2222                !!!ack ('t110.1');                !!!ack ('t110.1');
2223                !!!next-token;                !!!next-token;
2224                next B;                next B;
2225              } elsif ($token->{tag_name} eq 'title') {          } elsif ($token->{tag_name} eq 'title') {
2226                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2227                  !!!cp ('t111');              !!!cp ('t111');
2228                  ## As if </noscript>              ## As if </noscript>
2229                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2230                  !!!parse-error (type => 'in noscript', text => 'title',              !!!parse-error (type => 'in noscript', text => 'title',
2231                                  token => $token);                              token => $token);
2232                            
2233                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2234                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2235                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2236                  !!!cp ('t112');              !!!cp ('t112');
2237                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2238                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2239                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2240                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2241                } else {              $self->{head_element_inserted} = 1;
2242                  !!!cp ('t113');            } else {
2243                }              !!!cp ('t113');
2244              }
2245    
2246                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2247                my $parent = defined $self->{head_element} ? $self->{head_element}            $parse_rcdata->(RCDATA_CONTENT_MODEL);
2248                    : $self->{open_elements}->[-1]->[0];            ## ISSUE: A spec bug [Bug 6038]
2249                $parse_rcdata->(RCDATA_CONTENT_MODEL);            splice @{$self->{open_elements}}, -2, 1, () # <head>
2250                pop @{$self->{open_elements}} # <head>                if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM;
2251                    if $self->{insertion_mode} == AFTER_HEAD_IM;            next B;
2252                next B;          } elsif ($token->{tag_name} eq 'style' or
2253              } elsif ($token->{tag_name} eq 'style' or                   $token->{tag_name} eq 'noframes') {
2254                       $token->{tag_name} eq 'noframes') {            ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
2255                ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and            ## insertion mode IN_HEAD_IM)
2256                ## insertion mode IN_HEAD_IM)            ## NOTE: There is a "as if in head" code clone.
2257                ## NOTE: There is a "as if in head" code clone.            if ($self->{insertion_mode} == AFTER_HEAD_IM) {
2258                if ($self->{insertion_mode} == AFTER_HEAD_IM) {              !!!cp ('t114');
2259                  !!!cp ('t114');              !!!parse-error (type => 'after head',
2260                  !!!parse-error (type => 'after head',                              text => $token->{tag_name}, token => $token);
2261                                  text => $token->{tag_name}, token => $token);              push @{$self->{open_elements}},
2262                  push @{$self->{open_elements}},                  [$self->{head_element}, $el_category->{head}];
2263                      [$self->{head_element}, $el_category->{head}];              $self->{head_element_inserted} = 1;
2264                } else {            } else {
2265                  !!!cp ('t115');              !!!cp ('t115');
2266                }            }
2267                $parse_rcdata->(CDATA_CONTENT_MODEL);            $parse_rcdata->(CDATA_CONTENT_MODEL);
2268                pop @{$self->{open_elements}} # <head>            ## ISSUE: A spec bug [Bug 6038]
2269                    if $self->{insertion_mode} == AFTER_HEAD_IM;            splice @{$self->{open_elements}}, -2, 1, () # <head>
2270                next B;                if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM;
2271              } elsif ($token->{tag_name} eq 'noscript') {            next B;
2272            } elsif ($token->{tag_name} eq 'noscript') {
2273                if ($self->{insertion_mode} == IN_HEAD_IM) {                if ($self->{insertion_mode} == IN_HEAD_IM) {
2274                  !!!cp ('t116');                  !!!cp ('t116');
2275                  ## NOTE: and scripting is disalbed                  ## NOTE: and scripting is disalbed
# Line 4839  sub _tree_construction_main ($) { Line 2290  sub _tree_construction_main ($) {
2290                  !!!cp ('t118');                  !!!cp ('t118');
2291                  #                  #
2292                }                }
2293              } elsif ($token->{tag_name} eq 'script') {          } elsif ($token->{tag_name} eq 'script') {
2294                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {            if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2295                  !!!cp ('t119');              !!!cp ('t119');
2296                  ## As if </noscript>              ## As if </noscript>
2297                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
2298                  !!!parse-error (type => 'in noscript', text => 'script',              !!!parse-error (type => 'in noscript', text => 'script',
2299                                  token => $token);                              token => $token);
2300                            
2301                  $self->{insertion_mode} = IN_HEAD_IM;              $self->{insertion_mode} = IN_HEAD_IM;
2302                  ## Reprocess in the "in head" insertion mode...              ## Reprocess in the "in head" insertion mode...
2303                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
2304                  !!!cp ('t120');              !!!cp ('t120');
2305                  !!!parse-error (type => 'after head',              !!!parse-error (type => 'after head',
2306                                  text => $token->{tag_name}, token => $token);                              text => $token->{tag_name}, token => $token);
2307                  push @{$self->{open_elements}},              push @{$self->{open_elements}},
2308                      [$self->{head_element}, $el_category->{head}];                  [$self->{head_element}, $el_category->{head}];
2309                } else {              $self->{head_element_inserted} = 1;
2310                  !!!cp ('t121');            } else {
2311                }              !!!cp ('t121');
2312              }
2313    
2314                ## NOTE: There is a "as if in head" code clone.            ## NOTE: There is a "as if in head" code clone.
2315                $script_start_tag->();            $script_start_tag->();
2316                pop @{$self->{open_elements}} # <head>            ## ISSUE: A spec bug  [Bug 6038]
2317                    if $self->{insertion_mode} == AFTER_HEAD_IM;            splice @{$self->{open_elements}}, -2, 1 # <head>
2318                next B;                if ($self->{insertion_mode} & AFTER_HEAD_IM) == AFTER_HEAD_IM;
2319              } elsif ($token->{tag_name} eq 'body' or            next B;
2320                       $token->{tag_name} eq 'frameset') {          } elsif ($token->{tag_name} eq 'body' or
2321                     $token->{tag_name} eq 'frameset') {
2322                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2323                  !!!cp ('t122');                  !!!cp ('t122');
2324                  ## As if </noscript>                  ## As if </noscript>
# Line 5000  sub _tree_construction_main ($) { Line 2453  sub _tree_construction_main ($) {
2453              } elsif ({              } elsif ({
2454                        body => 1, html => 1,                        body => 1, html => 1,
2455                       }->{$token->{tag_name}}) {                       }->{$token->{tag_name}}) {
2456                if ($self->{insertion_mode} == BEFORE_HEAD_IM or                ## TODO: This branch is entirely redundant.
2457                  if ($self->{insertion_mode} == BEFORE_HEAD_IM or
2458                    $self->{insertion_mode} == IN_HEAD_IM or                    $self->{insertion_mode} == IN_HEAD_IM or
2459                    $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                    $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
2460                  !!!cp ('t140');                  !!!cp ('t140');
# Line 5172  sub _tree_construction_main ($) { Line 2626  sub _tree_construction_main ($) {
2626        } else {        } else {
2627          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
2628        }        }
   
           ## ISSUE: An issue in the spec.  
2629      } elsif ($self->{insertion_mode} & BODY_IMS) {      } elsif ($self->{insertion_mode} & BODY_IMS) {
2630            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
2631              !!!cp ('t150');              !!!cp ('t150');
# Line 5193  sub _tree_construction_main ($) { Line 2645  sub _tree_construction_main ($) {
2645                  ## have an element in table scope                  ## have an element in table scope
2646                  for (reverse 0..$#{$self->{open_elements}}) {                  for (reverse 0..$#{$self->{open_elements}}) {
2647                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
2648                    if ($node->[1] & TABLE_CELL_EL) {                    if ($node->[1] == TABLE_CELL_EL) {
2649                      !!!cp ('t151');                      !!!cp ('t151');
2650    
2651                      ## Close the cell                      ## Close the cell
# Line 5217  sub _tree_construction_main ($) { Line 2669  sub _tree_construction_main ($) {
2669                  !!!nack ('t153.1');                  !!!nack ('t153.1');
2670                  !!!next-token;                  !!!next-token;
2671                  next B;                  next B;
2672                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif ($self->{insertion_mode} & IN_CAPTION_IM) {
2673                  !!!parse-error (type => 'not closed', text => 'caption',                  !!!parse-error (type => 'not closed', text => 'caption',
2674                                  token => $token);                                  token => $token);
2675                                    
# Line 5227  sub _tree_construction_main ($) { Line 2679  sub _tree_construction_main ($) {
2679                  INSCOPE: {                  INSCOPE: {
2680                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2681                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2682                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2683                        !!!cp ('t155');                        !!!cp ('t155');
2684                        $i = $_;                        $i = $_;
2685                        last INSCOPE;                        last INSCOPE;
# Line 5253  sub _tree_construction_main ($) { Line 2705  sub _tree_construction_main ($) {
2705                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2706                  }                  }
2707    
2708                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2709                    !!!cp ('t159');                    !!!cp ('t159');
2710                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2711                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5350  sub _tree_construction_main ($) { Line 2802  sub _tree_construction_main ($) {
2802                  INSCOPE: {                  INSCOPE: {
2803                    for (reverse 0..$#{$self->{open_elements}}) {                    for (reverse 0..$#{$self->{open_elements}}) {
2804                      my $node = $self->{open_elements}->[$_];                      my $node = $self->{open_elements}->[$_];
2805                      if ($node->[1] & CAPTION_EL) {                      if ($node->[1] == CAPTION_EL) {
2806                        !!!cp ('t171');                        !!!cp ('t171');
2807                        $i = $_;                        $i = $_;
2808                        last INSCOPE;                        last INSCOPE;
# Line 5375  sub _tree_construction_main ($) { Line 2827  sub _tree_construction_main ($) {
2827                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
2828                  }                  }
2829                                    
2830                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                  unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2831                    !!!cp ('t175');                    !!!cp ('t175');
2832                    !!!parse-error (type => 'not closed',                    !!!parse-error (type => 'not closed',
2833                                    text => $self->{open_elements}->[-1]->[0]                                    text => $self->{open_elements}->[-1]->[0]
# Line 5425  sub _tree_construction_main ($) { Line 2877  sub _tree_construction_main ($) {
2877                                line => $token->{line},                                line => $token->{line},
2878                                column => $token->{column}};                                column => $token->{column}};
2879                      next B;                      next B;
2880                    } elsif ($node->[1] & TABLE_CELL_EL) {                    } elsif ($node->[1] == TABLE_CELL_EL) {
2881                      !!!cp ('t180');                      !!!cp ('t180');
2882                      $tn = $node->[0]->manakai_local_name;                      $tn = $node->[0]->manakai_local_name;
2883                      ## NOTE: There is exactly one |td| or |th| element                      ## NOTE: There is exactly one |td| or |th| element
# Line 5454  sub _tree_construction_main ($) { Line 2906  sub _tree_construction_main ($) {
2906                my $i;                my $i;
2907                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
2908                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
2909                  if ($node->[1] & CAPTION_EL) {                  if ($node->[1] == CAPTION_EL) {
2910                    !!!cp ('t184');                    !!!cp ('t184');
2911                    $i = $_;                    $i = $_;
2912                    last INSCOPE;                    last INSCOPE;
# Line 5465  sub _tree_construction_main ($) { Line 2917  sub _tree_construction_main ($) {
2917                } # INSCOPE                } # INSCOPE
2918                unless (defined $i) {                unless (defined $i) {
2919                  !!!cp ('t186');                  !!!cp ('t186');
2920            ## TODO: Wrong error type?
2921                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
2922                                  text => 'caption', token => $token);                                  text => 'caption', token => $token);
2923                  ## Ignore the token                  ## Ignore the token
# Line 5478  sub _tree_construction_main ($) { Line 2931  sub _tree_construction_main ($) {
2931                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
2932                }                }
2933    
2934                unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {                unless ($self->{open_elements}->[-1]->[1] == CAPTION_EL) {
2935                  !!!cp ('t188');                  !!!cp ('t188');
2936                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
2937                                  text => $self->{open_elements}->[-1]->[0]                                  text => $self->{open_elements}->[-1]->[0]
# Line 5559  sub _tree_construction_main ($) { Line 3012  sub _tree_construction_main ($) {
3012    
3013          !!!parse-error (type => 'in table:#text', token => $token);          !!!parse-error (type => 'in table:#text', token => $token);
3014    
3015              ## As if in body, but insert into foster parent element          ## NOTE: As if in body, but insert into the foster parent element.
3016              ## ISSUE: Spec says that "whenever a node would be inserted          $reconstruct_active_formatting_elements->($insert_to_foster);
             ## into the current node" while characters might not be  
             ## result in a new Text node.  
             $reconstruct_active_formatting_elements->($insert_to_foster);  
3017                            
3018              if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {          if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
3019                # MUST            # MUST
3020                my $foster_parent_element;            my $foster_parent_element;
3021                my $next_sibling;            my $next_sibling;
3022                my $prev_sibling;            my $prev_sibling;
3023                OE: for (reverse 0..$#{$self->{open_elements}}) {            OE: for (reverse 0..$#{$self->{open_elements}}) {
3024                  if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {              if ($self->{open_elements}->[$_]->[1] == TABLE_EL) {
3025                    my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
3026                    if (defined $parent and $parent->node_type == 1) {                if (defined $parent and $parent->node_type == 1) {
3027                      !!!cp ('t196');                  $foster_parent_element = $parent;
3028                      $foster_parent_element = $parent;                  !!!cp ('t196');
3029                      $next_sibling = $self->{open_elements}->[$_]->[0];                  $next_sibling = $self->{open_elements}->[$_]->[0];
3030                      $prev_sibling = $next_sibling->previous_sibling;                  $prev_sibling = $next_sibling->previous_sibling;
3031                    } 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});  
3032                } else {                } else {
3033                  !!!cp ('t199');                  !!!cp ('t197');
3034                  $foster_parent_element->insert_before                  $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
3035                    ($self->{document}->create_text_node ($token->{data}),                  $prev_sibling = $foster_parent_element->last_child;
3036                     $next_sibling);                  #
3037                }                }
3038                  last OE;
3039                }
3040              } # OE
3041              $foster_parent_element = $self->{open_elements}->[0]->[0] and
3042              $prev_sibling = $foster_parent_element->last_child
3043                  unless defined $foster_parent_element;
3044              undef $prev_sibling unless $open_tables->[-1]->[2]; # ~node inserted
3045              if (defined $prev_sibling and
3046                  $prev_sibling->node_type == 3) {
3047                !!!cp ('t198');
3048                $prev_sibling->manakai_append_text ($token->{data});
3049              } else {
3050                !!!cp ('t199');
3051                $foster_parent_element->insert_before
3052                    ($self->{document}->create_text_node ($token->{data}),
3053                     $next_sibling);
3054              }
3055            $open_tables->[-1]->[1] = 1; # tainted            $open_tables->[-1]->[1] = 1; # tainted
3056              $open_tables->[-1]->[2] = 1; # ~node inserted
3057          } else {          } else {
3058              ## NOTE: Fragment case or in a foster parent'ed element
3059              ## (e.g. |<table><span>a|).  In fragment case, whether the
3060              ## character is appended to existing node or a new node is
3061              ## created is irrelevant, since the foster parent'ed nodes
3062              ## are discarded and fragment parsing does not invoke any
3063              ## script.
3064            !!!cp ('t200');            !!!cp ('t200');
3065            $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});            $self->{open_elements}->[-1]->[0]->manakai_append_text
3066                  ($token->{data});
3067          }          }
3068                            
3069          !!!next-token;          !!!next-token;
# Line 5639  sub _tree_construction_main ($) { Line 3100  sub _tree_construction_main ($) {
3100                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3101              }              }
3102                                    
3103                  $self->{insertion_mode} = IN_ROW_IM;              $self->{insertion_mode} = IN_ROW_IM;
3104                  if ($token->{tag_name} eq 'tr') {              if ($token->{tag_name} eq 'tr') {
3105                    !!!cp ('t204');                !!!cp ('t204');
3106                    !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3107                    !!!nack ('t204');                $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3108                    !!!next-token;                !!!nack ('t204');
3109                    next B;                !!!next-token;
3110                  } else {                next B;
3111                    !!!cp ('t205');              } else {
3112                    !!!insert-element ('tr',, $token);                !!!cp ('t205');
3113                    ## reprocess in the "in row" insertion mode                !!!insert-element ('tr',, $token);
3114                  }                ## reprocess in the "in row" insertion mode
3115                } else {              }
3116                  !!!cp ('t206');            } else {
3117                }              !!!cp ('t206');
3118              }
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 5662  sub _tree_construction_main ($) { Line 3124  sub _tree_construction_main ($) {
3124                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3125                }                }
3126                                
3127                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3128                $self->{insertion_mode} = IN_CELL_IM;            $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3129              $self->{insertion_mode} = IN_CELL_IM;
3130    
3131                push @$active_formatting_elements, ['#marker', ''];            push @$active_formatting_elements, ['#marker', ''];
3132                                
3133                !!!nack ('t207.1');            !!!nack ('t207.1');
3134              !!!next-token;
3135              next B;
3136            } elsif ({
3137                      caption => 1, col => 1, colgroup => 1,
3138                      tbody => 1, tfoot => 1, thead => 1,
3139                      tr => 1, # $self->{insertion_mode} == IN_ROW_IM
3140                     }->{$token->{tag_name}}) {
3141              if ($self->{insertion_mode} == IN_ROW_IM) {
3142                ## As if </tr>
3143                ## have an element in table scope
3144                my $i;
3145                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3146                  my $node = $self->{open_elements}->[$_];
3147                  if ($node->[1] == TABLE_ROW_EL) {
3148                    !!!cp ('t208');
3149                    $i = $_;
3150                    last INSCOPE;
3151                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
3152                    !!!cp ('t209');
3153                    last INSCOPE;
3154                  }
3155                } # INSCOPE
3156                unless (defined $i) {
3157                  !!!cp ('t210');
3158                  ## TODO: This type is wrong.
3159                  !!!parse-error (type => 'unmacthed end tag',
3160                                  text => $token->{tag_name}, token => $token);
3161                  ## Ignore the token
3162                  !!!nack ('t210.1');
3163                !!!next-token;                !!!next-token;
3164                next B;                next B;
3165              } 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;  
                 }  
3166                                    
3167                  ## Clear back to table row context                  ## Clear back to table row context
3168                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
# Line 5727  sub _tree_construction_main ($) { Line 3190  sub _tree_construction_main ($) {
3190                  my $i;                  my $i;
3191                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3192                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3193                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3194                      !!!cp ('t214');                      !!!cp ('t214');
3195                      $i = $_;                      $i = $_;
3196                      last INSCOPE;                      last INSCOPE;
# Line 5769  sub _tree_construction_main ($) { Line 3232  sub _tree_construction_main ($) {
3232                  !!!cp ('t218');                  !!!cp ('t218');
3233                }                }
3234    
3235                if ($token->{tag_name} eq 'col') {            if ($token->{tag_name} eq 'col') {
3236                  ## Clear back to table context              ## Clear back to table context
3237                  while (not ($self->{open_elements}->[-1]->[1]              while (not ($self->{open_elements}->[-1]->[1]
3238                                  & TABLE_SCOPING_EL)) {                              & TABLE_SCOPING_EL)) {
3239                    !!!cp ('t219');                !!!cp ('t219');
3240                    ## ISSUE: Can this state be reached?                ## ISSUE: Can this state be reached?
3241                    pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3242                  }              }
3243                                
3244                  !!!insert-element ('colgroup',, $token);              !!!insert-element ('colgroup',, $token);
3245                  $self->{insertion_mode} = IN_COLUMN_GROUP_IM;              $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
3246                  ## reprocess              ## reprocess
3247                  !!!ack-later;              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3248                  next B;              !!!ack-later;
3249                } elsif ({              next B;
3250                          caption => 1,            } elsif ({
3251                          colgroup => 1,                      caption => 1,
3252                          tbody => 1, tfoot => 1, thead => 1,                      colgroup => 1,
3253                         }->{$token->{tag_name}}) {                      tbody => 1, tfoot => 1, thead => 1,
3254                  ## Clear back to table context                     }->{$token->{tag_name}}) {
3255                ## Clear back to table context
3256                  while (not ($self->{open_elements}->[-1]->[1]                  while (not ($self->{open_elements}->[-1]->[1]
3257                                  & TABLE_SCOPING_EL)) {                                  & TABLE_SCOPING_EL)) {
3258                    !!!cp ('t220');                    !!!cp ('t220');
# Line 5796  sub _tree_construction_main ($) { Line 3260  sub _tree_construction_main ($) {
3260                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
3261                  }                  }
3262                                    
3263                  push @$active_formatting_elements, ['#marker', '']              push @$active_formatting_elements, ['#marker', '']
3264                      if $token->{tag_name} eq 'caption';                  if $token->{tag_name} eq 'caption';
3265                                    
3266                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);              !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3267                  $self->{insertion_mode} = {              $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3268                                             caption => IN_CAPTION_IM,              $self->{insertion_mode} = {
3269                                             colgroup => IN_COLUMN_GROUP_IM,                                         caption => IN_CAPTION_IM,
3270                                             tbody => IN_TABLE_BODY_IM,                                         colgroup => IN_COLUMN_GROUP_IM,
3271                                             tfoot => IN_TABLE_BODY_IM,                                         tbody => IN_TABLE_BODY_IM,
3272                                             thead => IN_TABLE_BODY_IM,                                         tfoot => IN_TABLE_BODY_IM,
3273                                            }->{$token->{tag_name}};                                         thead => IN_TABLE_BODY_IM,
3274                  !!!next-token;                                        }->{$token->{tag_name}};
3275                  !!!nack ('t220.1');              !!!next-token;
3276                  next B;              !!!nack ('t220.1');
3277                } else {              next B;
3278                  die "$0: in table: <>: $token->{tag_name}";            } else {
3279                }              die "$0: in table: <>: $token->{tag_name}";
3280              }
3281              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
3282                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
3283                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
# Line 5824  sub _tree_construction_main ($) { Line 3289  sub _tree_construction_main ($) {
3289                my $i;                my $i;
3290                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3291                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3292                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3293                    !!!cp ('t221');                    !!!cp ('t221');
3294                    $i = $_;                    $i = $_;
3295                    last INSCOPE;                    last INSCOPE;
# Line 5851  sub _tree_construction_main ($) { Line 3316  sub _tree_construction_main ($) {
3316                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3317                }                }
3318    
3319                unless ($self->{open_elements}->[-1]->[1] & TABLE_EL) {                unless ($self->{open_elements}->[-1]->[1] == TABLE_EL) {
3320                  !!!cp ('t225');                  !!!cp ('t225');
3321                  ## NOTE: |<table><tr><table>|                  ## NOTE: |<table><tr><table>|
3322                  !!!parse-error (type => 'not closed',                  !!!parse-error (type => 'not closed',
# Line 5875  sub _tree_construction_main ($) { Line 3340  sub _tree_construction_main ($) {
3340              !!!cp ('t227.8');              !!!cp ('t227.8');
3341              ## NOTE: This is a "as if in head" code clone.              ## NOTE: This is a "as if in head" code clone.
3342              $parse_rcdata->(CDATA_CONTENT_MODEL);              $parse_rcdata->(CDATA_CONTENT_MODEL);
3343                $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3344              next B;              next B;
3345            } else {            } else {
3346              !!!cp ('t227.7');              !!!cp ('t227.7');
# Line 5885  sub _tree_construction_main ($) { Line 3351  sub _tree_construction_main ($) {
3351              !!!cp ('t227.6');              !!!cp ('t227.6');
3352              ## NOTE: This is a "as if in head" code clone.              ## NOTE: This is a "as if in head" code clone.
3353              $script_start_tag->();              $script_start_tag->();
3354                $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3355              next B;              next B;
3356            } else {            } else {
3357              !!!cp ('t227.5');              !!!cp ('t227.5');
# Line 5900  sub _tree_construction_main ($) { Line 3367  sub _tree_construction_main ($) {
3367                                  text => $token->{tag_name}, token => $token);                                  text => $token->{tag_name}, token => $token);
3368    
3369                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3370                    $open_tables->[-1]->[2] = 0 if @$open_tables; # ~node inserted
3371    
3372                  ## TODO: form element pointer                  ## TODO: form element pointer
3373    
# Line 5937  sub _tree_construction_main ($) { Line 3405  sub _tree_construction_main ($) {
3405                my $i;                my $i;
3406                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3407                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3408                  if ($node->[1] & TABLE_ROW_EL) {                  if ($node->[1] == TABLE_ROW_EL) {
3409                    !!!cp ('t228');                    !!!cp ('t228');
3410                    $i = $_;                    $i = $_;
3411                    last INSCOPE;                    last INSCOPE;
# Line 5978  sub _tree_construction_main ($) { Line 3446  sub _tree_construction_main ($) {
3446                  my $i;                  my $i;
3447                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3448                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3449                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3450                      !!!cp ('t233');                      !!!cp ('t233');
3451                      $i = $_;                      $i = $_;
3452                      last INSCOPE;                      last INSCOPE;
# Line 6016  sub _tree_construction_main ($) { Line 3484  sub _tree_construction_main ($) {
3484                  my $i;                  my $i;
3485                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3486                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3487                    if ($node->[1] & TABLE_ROW_GROUP_EL) {                    if ($node->[1] == TABLE_ROW_GROUP_EL) {
3488                      !!!cp ('t237');                      !!!cp ('t237');
3489                      $i = $_;                      $i = $_;
3490                      last INSCOPE;                      last INSCOPE;
# Line 6063  sub _tree_construction_main ($) { Line 3531  sub _tree_construction_main ($) {
3531                my $i;                my $i;
3532                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3533                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
3534                  if ($node->[1] & TABLE_EL) {                  if ($node->[1] == TABLE_EL) {
3535                    !!!cp ('t241');                    !!!cp ('t241');
3536                    $i = $_;                    $i = $_;
3537                    last INSCOPE;                    last INSCOPE;
# Line 6122  sub _tree_construction_main ($) { Line 3590  sub _tree_construction_main ($) {
3590                  my $i;                  my $i;
3591                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3592                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
3593                    if ($node->[1] & TABLE_ROW_EL) {                    if ($node->[1] == TABLE_ROW_EL) {
3594                      !!!cp ('t250');                      !!!cp ('t250');
3595                      $i = $_;                      $i = $_;
3596                      last INSCOPE;                      last INSCOPE;
# Line 6212  sub _tree_construction_main ($) { Line 3680  sub _tree_construction_main ($) {
3680            #            #
3681          }          }
3682        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3683          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
3684                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
3685            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
3686            !!!cp ('t259.1');            !!!cp ('t259.1');
# Line 6254  sub _tree_construction_main ($) { Line 3722  sub _tree_construction_main ($) {
3722              }              }
3723            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
3724              if ($token->{tag_name} eq 'colgroup') {              if ($token->{tag_name} eq 'colgroup') {
3725                if ($self->{open_elements}->[-1]->[1] & HTML_EL) {                if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3726                  !!!cp ('t264');                  !!!cp ('t264');
3727                  !!!parse-error (type => 'unmatched end tag',                  !!!parse-error (type => 'unmatched end tag',
3728                                  text => 'colgroup', token => $token);                                  text => 'colgroup', token => $token);
# Line 6280  sub _tree_construction_main ($) { Line 3748  sub _tree_construction_main ($) {
3748                #                #
3749              }              }
3750        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
3751          if ($self->{open_elements}->[-1]->[1] & HTML_EL and          if ($self->{open_elements}->[-1]->[1] == HTML_EL and
3752              @{$self->{open_elements}} == 1) { # redundant, maybe              @{$self->{open_elements}} == 1) { # redundant, maybe
3753            !!!cp ('t270.2');            !!!cp ('t270.2');
3754            ## Stop parsing.            ## Stop parsing.
# Line 6298  sub _tree_construction_main ($) { Line 3766  sub _tree_construction_main ($) {
3766        }        }
3767    
3768            ## As if </colgroup>            ## As if </colgroup>
3769            if ($self->{open_elements}->[-1]->[1] & HTML_EL) {            if ($self->{open_elements}->[-1]->[1] == HTML_EL) {
3770              !!!cp ('t269');              !!!cp ('t269');
3771  ## TODO: Wrong error type?  ## TODO: Wrong error type?
3772              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6323  sub _tree_construction_main ($) { Line 3791  sub _tree_construction_main ($) {
3791          next B;          next B;
3792        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
3793          if ($token->{tag_name} eq 'option') {          if ($token->{tag_name} eq 'option') {
3794            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3795              !!!cp ('t272');              !!!cp ('t272');
3796              ## As if </option>              ## As if </option>
3797              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6336  sub _tree_construction_main ($) { Line 3804  sub _tree_construction_main ($) {
3804            !!!next-token;            !!!next-token;
3805            next B;            next B;
3806          } elsif ($token->{tag_name} eq 'optgroup') {          } elsif ($token->{tag_name} eq 'optgroup') {
3807            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3808              !!!cp ('t274');              !!!cp ('t274');
3809              ## As if </option>              ## As if </option>
3810              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6344  sub _tree_construction_main ($) { Line 3812  sub _tree_construction_main ($) {
3812              !!!cp ('t275');              !!!cp ('t275');
3813            }            }
3814    
3815            if ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3816              !!!cp ('t276');              !!!cp ('t276');
3817              ## As if </optgroup>              ## As if </optgroup>
3818              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6374  sub _tree_construction_main ($) { Line 3842  sub _tree_construction_main ($) {
3842            my $i;            my $i;
3843            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3844              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3845              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3846                !!!cp ('t278');                !!!cp ('t278');
3847                $i = $_;                $i = $_;
3848                last INSCOPE;                last INSCOPE;
# Line 6419  sub _tree_construction_main ($) { Line 3887  sub _tree_construction_main ($) {
3887          }          }
3888        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
3889          if ($token->{tag_name} eq 'optgroup') {          if ($token->{tag_name} eq 'optgroup') {
3890            if ($self->{open_elements}->[-1]->[1] & OPTION_EL and            if ($self->{open_elements}->[-1]->[1] == OPTION_EL and
3891                $self->{open_elements}->[-2]->[1] & OPTGROUP_EL) {                $self->{open_elements}->[-2]->[1] == OPTGROUP_EL) {
3892              !!!cp ('t283');              !!!cp ('t283');
3893              ## As if </option>              ## As if </option>
3894              splice @{$self->{open_elements}}, -2;              splice @{$self->{open_elements}}, -2;
3895            } elsif ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {            } elsif ($self->{open_elements}->[-1]->[1] == OPTGROUP_EL) {
3896              !!!cp ('t284');              !!!cp ('t284');
3897              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3898            } else {            } else {
# Line 6437  sub _tree_construction_main ($) { Line 3905  sub _tree_construction_main ($) {
3905            !!!next-token;            !!!next-token;
3906            next B;            next B;
3907          } elsif ($token->{tag_name} eq 'option') {          } elsif ($token->{tag_name} eq 'option') {
3908            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {            if ($self->{open_elements}->[-1]->[1] == OPTION_EL) {
3909              !!!cp ('t286');              !!!cp ('t286');
3910              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
3911            } else {            } else {
# Line 6454  sub _tree_construction_main ($) { Line 3922  sub _tree_construction_main ($) {
3922            my $i;            my $i;
3923            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3924              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3925              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3926                !!!cp ('t288');                !!!cp ('t288');
3927                $i = $_;                $i = $_;
3928                last INSCOPE;                last INSCOPE;
# Line 6516  sub _tree_construction_main ($) { Line 3984  sub _tree_construction_main ($) {
3984            undef $i;            undef $i;
3985            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
3986              my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
3987              if ($node->[1] & SELECT_EL) {              if ($node->[1] == SELECT_EL) {
3988                !!!cp ('t295');                !!!cp ('t295');
3989                $i = $_;                $i = $_;
3990                last INSCOPE;                last INSCOPE;
# Line 6555  sub _tree_construction_main ($) { Line 4023  sub _tree_construction_main ($) {
4023            next B;            next B;
4024          }          }
4025        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4026          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
4027                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
4028            !!!cp ('t299.1');            !!!cp ('t299.1');
4029            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6742  sub _tree_construction_main ($) { Line 4210  sub _tree_construction_main ($) {
4210        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
4211          if ($token->{tag_name} eq 'frameset' and          if ($token->{tag_name} eq 'frameset' and
4212              $self->{insertion_mode} == IN_FRAMESET_IM) {              $self->{insertion_mode} == IN_FRAMESET_IM) {
4213            if ($self->{open_elements}->[-1]->[1] & HTML_EL and            if ($self->{open_elements}->[-1]->[1] == HTML_EL and
4214                @{$self->{open_elements}} == 1) {                @{$self->{open_elements}} == 1) {
4215              !!!cp ('t325');              !!!cp ('t325');
4216              !!!parse-error (type => 'unmatched end tag',              !!!parse-error (type => 'unmatched end tag',
# Line 6756  sub _tree_construction_main ($) { Line 4224  sub _tree_construction_main ($) {
4224            }            }
4225    
4226            if (not defined $self->{inner_html_node} and            if (not defined $self->{inner_html_node} and
4227                not ($self->{open_elements}->[-1]->[1] & FRAMESET_EL)) {                not ($self->{open_elements}->[-1]->[1] == FRAMESET_EL)) {
4228              !!!cp ('t327');              !!!cp ('t327');
4229              $self->{insertion_mode} = AFTER_FRAMESET_IM;              $self->{insertion_mode} = AFTER_FRAMESET_IM;
4230            } else {            } else {
# Line 6788  sub _tree_construction_main ($) { Line 4256  sub _tree_construction_main ($) {
4256            next B;            next B;
4257          }          }
4258        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4259          unless ($self->{open_elements}->[-1]->[1] & HTML_EL and          unless ($self->{open_elements}->[-1]->[1] == HTML_EL and
4260                  @{$self->{open_elements}} == 1) { # redundant, maybe                  @{$self->{open_elements}} == 1) { # redundant, maybe
4261            !!!cp ('t331.1');            !!!cp ('t331.1');
4262            !!!parse-error (type => 'in body:#eof', token => $token);            !!!parse-error (type => 'in body:#eof', token => $token);
# Line 6801  sub _tree_construction_main ($) { Line 4269  sub _tree_construction_main ($) {
4269        } else {        } else {
4270          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
4271        }        }
   
       ## ISSUE: An issue in spec here  
4272      } else {      } else {
4273        die "$0: $self->{insertion_mode}: Unknown insertion mode";        die "$0: $self->{insertion_mode}: Unknown insertion mode";
4274      }      }
# Line 6893  sub _tree_construction_main ($) { Line 4359  sub _tree_construction_main ($) {
4359          !!!parse-error (type => 'in body', text => 'body', token => $token);          !!!parse-error (type => 'in body', text => 'body', token => $token);
4360                                
4361          if (@{$self->{open_elements}} == 1 or          if (@{$self->{open_elements}} == 1 or
4362              not ($self->{open_elements}->[1]->[1] & BODY_EL)) {              not ($self->{open_elements}->[1]->[1] == BODY_EL)) {
4363            !!!cp ('t342');            !!!cp ('t342');
4364            ## Ignore the token            ## Ignore the token
4365          } else {          } else {
# Line 6939  sub _tree_construction_main ($) { Line 4405  sub _tree_construction_main ($) {
4405    
4406          ## has a p element in scope          ## has a p element in scope
4407          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4408            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4409              !!!cp ('t344');              !!!cp ('t344');
4410              !!!back-token; # <form>              !!!back-token; # <form>
4411              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 6991  sub _tree_construction_main ($) { Line 4457  sub _tree_construction_main ($) {
4457            !!!next-token;            !!!next-token;
4458          }          }
4459          next B;          next B;
4460        } elsif ({        } elsif ($token->{tag_name} eq 'li') {
4461                  ## NOTE: As normal, but imply </li> when there's another <li>          ## NOTE: As normal, but imply </li> when there's another <li> ...
                 li => 1,  
                 ## NOTE: As normal, but imply </dt> or </dd> when ...  
                 dt => 1, dd => 1,  
                }->{$token->{tag_name}}) {  
         ## has a p element in scope  
         INSCOPE: for (reverse @{$self->{open_elements}}) {  
           if ($_->[1] & P_EL) {  
             !!!cp ('t353');  
             !!!back-token; # <x>  
             $token = {type => END_TAG_TOKEN, tag_name => 'p',  
                       line => $token->{line}, column => $token->{column}};  
             next B;  
           } elsif ($_->[1] & SCOPING_EL) {  
             !!!cp ('t354');  
             last INSCOPE;  
           }  
         } # INSCOPE  
4462    
4463          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)          ## NOTE: Special, Scope (<li><foo><li> == <li><foo><li/></foo></li>)
4464            ## Interpreted as <li><foo/></li><li/> (non-conforming)            ## Interpreted as <li><foo/></li><li/> (non-conforming)
# Line 7023  sub _tree_construction_main ($) { Line 4472  sub _tree_construction_main ($) {
4472          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)          ## address, div, p (<li><foo><li> == <li><foo/></li><li/>)
4473            ## Interpreted as <li><foo><li/></foo></li> (non-conforming)            ## Interpreted as <li><foo><li/></foo></li> (non-conforming)
4474            ## div (Fx, S)            ## div (Fx, S)
4475              
4476          ## Step 1          my $non_optional;
4477          my $i = -1;          my $i = -1;
4478          my $node = $self->{open_elements}->[$i];  
4479          my $li_or_dtdd = {li => {li => 1},          ## 1.
4480                            dt => {dt => 1, dd => 1},          for my $node (reverse @{$self->{open_elements}}) {
4481                            dd => {dt => 1, dd => 1}}->{$token->{tag_name}};            if ($node->[1] == LI_EL) {
4482          LI: {              ## 2. (a) As if </li>
4483            ## Step 2              {
4484            if ($li_or_dtdd->{$node->[0]->manakai_local_name}) {                ## If no </li> - not applied
4485              if ($i != -1) {                #
4486                !!!cp ('t355');  
4487                !!!parse-error (type => 'not closed',                ## Otherwise
4488                                text => $self->{open_elements}->[-1]->[0]  
4489                                    ->manakai_local_name,                ## 1. generate implied end tags, except for </li>
4490                                token => $token);                #
4491              } else {  
4492                !!!cp ('t356');                ## 2. If current node != "li", parse error
4493                  if ($non_optional) {
4494                    !!!parse-error (type => 'not closed',
4495                                    text => $non_optional->[0]->manakai_local_name,
4496                                    token => $token);
4497                    !!!cp ('t355');
4498                  } else {
4499                    !!!cp ('t356');
4500                  }
4501    
4502                  ## 3. Pop
4503                  splice @{$self->{open_elements}}, $i;
4504              }              }
4505              splice @{$self->{open_elements}}, $i;  
4506              last LI;              last; ## 2. (b) goto 5.
4507            } else {            } elsif (
4508                       ## NOTE: not "formatting" and not "phrasing"
4509                       ($node->[1] & SPECIAL_EL or
4510                        $node->[1] & SCOPING_EL) and
4511                       ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4512                       (not $node->[1] & ADDRESS_DIV_P_EL)
4513                      ) {
4514                ## 3.
4515              !!!cp ('t357');              !!!cp ('t357');
4516            }              last; ## goto 5.
4517                        } elsif ($node->[1] & END_TAG_OPTIONAL_EL) {
           ## Step 3  
           if (not ($node->[1] & FORMATTING_EL) and  
               #not $phrasing_category->{$node->[1]} and  
               ($node->[1] & SPECIAL_EL or  
                $node->[1] & SCOPING_EL) and  
               not ($node->[1] & ADDRESS_EL) and  
               not ($node->[1] & DIV_EL)) {  
4518              !!!cp ('t358');              !!!cp ('t358');
4519              last LI;              #
4520              } else {
4521                !!!cp ('t359');
4522                $non_optional ||= $node;
4523                #
4524            }            }
4525                        ## 4.
4526            !!!cp ('t359');            ## goto 2.
           ## Step 4  
4527            $i--;            $i--;
4528            $node = $self->{open_elements}->[$i];          }
4529            redo LI;  
4530          } # LI          ## 5. (a) has a |p| element in scope
4531                      INSCOPE: for (reverse @{$self->{open_elements}}) {
4532              if ($_->[1] == P_EL) {
4533                !!!cp ('t353');
4534    
4535                ## NOTE: |<p><li>|, for example.
4536    
4537                !!!back-token; # <x>
4538                $token = {type => END_TAG_TOKEN, tag_name => 'p',
4539                          line => $token->{line}, column => $token->{column}};
4540                next B;
4541              } elsif ($_->[1] & SCOPING_EL) {
4542                !!!cp ('t354');
4543                last INSCOPE;
4544              }
4545            } # INSCOPE
4546    
4547            ## 5. (b) insert
4548          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4549          !!!nack ('t359.1');          !!!nack ('t359.1');
4550          !!!next-token;          !!!next-token;
4551          next B;          next B;
4552          } elsif ($token->{tag_name} eq 'dt' or
4553                   $token->{tag_name} eq 'dd') {
4554            ## NOTE: As normal, but imply </dt> or </dd> when ...
4555    
4556            my $non_optional;
4557            my $i = -1;
4558    
4559            ## 1.
4560            for my $node (reverse @{$self->{open_elements}}) {
4561              if ($node->[1] == DTDD_EL) {
4562                ## 2. (a) As if </li>
4563                {
4564                  ## If no </li> - not applied
4565                  #
4566    
4567                  ## Otherwise
4568    
4569                  ## 1. generate implied end tags, except for </dt> or </dd>
4570                  #
4571    
4572                  ## 2. If current node != "dt"|"dd", parse error
4573                  if ($non_optional) {
4574                    !!!parse-error (type => 'not closed',
4575                                    text => $non_optional->[0]->manakai_local_name,
4576                                    token => $token);
4577                    !!!cp ('t355.1');
4578                  } else {
4579                    !!!cp ('t356.1');
4580                  }
4581    
4582                  ## 3. Pop
4583                  splice @{$self->{open_elements}}, $i;
4584                }
4585    
4586                last; ## 2. (b) goto 5.
4587              } elsif (
4588                       ## NOTE: not "formatting" and not "phrasing"
4589                       ($node->[1] & SPECIAL_EL or
4590                        $node->[1] & SCOPING_EL) and
4591                       ## NOTE: "li", "dt", and "dd" are in |SPECIAL_EL|.
4592    
4593                       (not $node->[1] & ADDRESS_DIV_P_EL)
4594                      ) {
4595                ## 3.
4596                !!!cp ('t357.1');
4597                last; ## goto 5.
4598              } elsif ($node->[1] & END_TAG_OPTIONAL_EL) {
4599                !!!cp ('t358.1');
4600                #
4601              } else {
4602                !!!cp ('t359.1');
4603                $non_optional ||= $node;
4604                #
4605              }
4606              ## 4.
4607              ## goto 2.
4608              $i--;
4609            }
4610    
4611            ## 5. (a) has a |p| element in scope
4612            INSCOPE: for (reverse @{$self->{open_elements}}) {
4613              if ($_->[1] == P_EL) {
4614                !!!cp ('t353.1');
4615                !!!back-token; # <x>
4616                $token = {type => END_TAG_TOKEN, tag_name => 'p',
4617                          line => $token->{line}, column => $token->{column}};
4618                next B;
4619              } elsif ($_->[1] & SCOPING_EL) {
4620                !!!cp ('t354.1');
4621                last INSCOPE;
4622              }
4623            } # INSCOPE
4624    
4625            ## 5. (b) insert
4626            !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4627            !!!nack ('t359.2');
4628            !!!next-token;
4629            next B;
4630        } elsif ($token->{tag_name} eq 'plaintext') {        } elsif ($token->{tag_name} eq 'plaintext') {
4631          ## NOTE: As normal, but effectively ends parsing          ## NOTE: As normal, but effectively ends parsing
4632    
4633          ## has a p element in scope          ## has a p element in scope
4634          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
4635            if ($_->[1] & P_EL) {            if ($_->[1] == P_EL) {
4636              !!!cp ('t367');              !!!cp ('t367');
4637              !!!back-token; # <plaintext>              !!!back-token; # <plaintext>
4638              $token = {type => END_TAG_TOKEN, tag_name => 'p',              $token = {type => END_TAG_TOKEN, tag_name => 'p',
# Line 7097  sub _tree_construction_main ($) { Line 4654  sub _tree_construction_main ($) {
4654        } elsif ($token->{tag_name} eq 'a') {        } elsif ($token->{tag_name} eq 'a') {
4655          AFE: for my $i (reverse 0..$#$active_formatting_elements) {          AFE: for my $i (reverse 0..$#$active_formatting_elements) {
4656            my $node = $active_formatting_elements->[$i];            my $node = $active_formatting_elements->[$i];
4657            if ($node->[1] & A_EL) {            if ($node->[1] == A_EL) {
4658              !!!cp ('t371');              !!!cp ('t371');
4659              !!!parse-error (type => 'in a:a', token => $token);              !!!parse-error (type => 'in a:a', token => $token);
4660                            
# Line 7141  sub _tree_construction_main ($) { Line 4698  sub _tree_construction_main ($) {
4698          ## has a |nobr| element in scope          ## has a |nobr| element in scope
4699          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4700            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4701            if ($node->[1] & NOBR_EL) {            if ($node->[1] == NOBR_EL) {
4702              !!!cp ('t376');              !!!cp ('t376');
4703              !!!parse-error (type => 'in nobr:nobr', token => $token);              !!!parse-error (type => 'in nobr:nobr', token => $token);
4704              !!!back-token; # <nobr>              !!!back-token; # <nobr>
# Line 7164  sub _tree_construction_main ($) { Line 4721  sub _tree_construction_main ($) {
4721          ## has a button element in scope          ## has a button element in scope
4722          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4723            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4724            if ($node->[1] & BUTTON_EL) {            if ($node->[1] == BUTTON_EL) {
4725              !!!cp ('t378');              !!!cp ('t378');
4726              !!!parse-error (type => 'in button:button', token => $token);              !!!parse-error (type => 'in button:button', token => $token);
4727              !!!back-token; # <button>              !!!back-token; # <button>
# Line 7264  sub _tree_construction_main ($) { Line 4821  sub _tree_construction_main ($) {
4821            next B;            next B;
4822          }          }
4823        } elsif ($token->{tag_name} eq 'textarea') {        } elsif ($token->{tag_name} eq 'textarea') {
4824          my $tag_name = $token->{tag_name};          ## Step 1
4825          my $el;          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
         !!!create-element ($el, $HTML_NS, $token->{tag_name}, $token->{attributes}, $token);  
4826                    
4827            ## Step 2
4828          ## TODO: $self->{form_element} if defined          ## TODO: $self->{form_element} if defined
4829    
4830            ## Step 3
4831            $self->{ignore_newline} = 1;
4832    
4833            ## Step 4
4834            ## ISSUE: This step is wrong. (r2302 enbugged)
4835    
4836            ## Step 5
4837          $self->{content_model} = RCDATA_CONTENT_MODEL;          $self->{content_model} = RCDATA_CONTENT_MODEL;
4838          delete $self->{escape}; # MUST          delete $self->{escape}; # MUST
4839            
4840          $insert->($el);          ## Step 6-7
4841                    $self->{insertion_mode} |= IN_CDATA_RCDATA_IM;
4842          my $text = '';  
4843          !!!nack ('t392.1');          !!!nack ('t392.1');
4844          !!!next-token;          !!!next-token;
4845          if ($token->{type} == CHARACTER_TOKEN) {          next B;
4846            $token->{data} =~ s/^\x0A//;        } elsif ($token->{tag_name} eq 'optgroup' or
4847            unless (length $token->{data}) {                 $token->{tag_name} eq 'option') {
4848              !!!cp ('t392');          ## has an |option| element in scope
4849              !!!next-token;          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4850            } else {            my $node = $self->{open_elements}->[$_];
4851              !!!cp ('t393');            if ($node->[1] == OPTION_EL) {
4852                !!!cp ('t397.1');
4853                ## NOTE: As if </option>
4854                !!!back-token; # <option> or <optgroup>
4855                $token = {type => END_TAG_TOKEN, tag_name => 'option',
4856                          line => $token->{line}, column => $token->{column}};
4857                next B;
4858              } elsif ($node->[1] & SCOPING_EL) {
4859                !!!cp ('t397.2');
4860                last INSCOPE;
4861            }            }
4862          } else {          } # INSCOPE
4863            !!!cp ('t394');  
4864          }          $reconstruct_active_formatting_elements->($insert_to_current);
4865          while ($token->{type} == CHARACTER_TOKEN) {  
4866            !!!cp ('t395');          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4867            $text .= $token->{data};  
4868            !!!next-token;          !!!nack ('t397.3');
         }  
         if (length $text) {  
           !!!cp ('t396');  
           $el->manakai_append_text ($text);  
         }  
           
         $self->{content_model} = PCDATA_CONTENT_MODEL;  
           
         if ($token->{type} == END_TAG_TOKEN and  
             $token->{tag_name} eq $tag_name) {  
           !!!cp ('t397');  
           ## Ignore the token  
         } else {  
           !!!cp ('t398');  
           !!!parse-error (type => 'in RCDATA:#eof', token => $token);  
         }  
4869          !!!next-token;          !!!next-token;
4870          next B;          redo B;
4871        } elsif ($token->{tag_name} eq 'rt' or        } elsif ($token->{tag_name} eq 'rt' or
4872                 $token->{tag_name} eq 'rp') {                 $token->{tag_name} eq 'rp') {
4873          ## has a |ruby| element in scope          ## has a |ruby| element in scope
4874          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4875            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4876            if ($node->[1] & RUBY_EL) {            if ($node->[1] == RUBY_EL) {
4877              !!!cp ('t398.1');              !!!cp ('t398.1');
4878              ## generate implied end tags              ## generate implied end tags
4879              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
4880                !!!cp ('t398.2');                !!!cp ('t398.2');
4881                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
4882              }              }
4883              unless ($self->{open_elements}->[-1]->[1] & RUBY_EL) {              unless ($self->{open_elements}->[-1]->[1] == RUBY_EL) {
4884                !!!cp ('t398.3');                !!!cp ('t398.3');
4885                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
4886                                text => $self->{open_elements}->[-1]->[0]                                text => $self->{open_elements}->[-1]->[0]
4887                                    ->manakai_local_name,                                    ->manakai_local_name,
4888                                token => $token);                                token => $token);
4889                pop @{$self->{open_elements}}                pop @{$self->{open_elements}}
4890                    while not $self->{open_elements}->[-1]->[1] & RUBY_EL;                    while not $self->{open_elements}->[-1]->[1] == RUBY_EL;
4891              }              }
4892              last INSCOPE;              last INSCOPE;
4893            } elsif ($node->[1] & SCOPING_EL) {            } elsif ($node->[1] & SCOPING_EL) {
# Line 7357  sub _tree_construction_main ($) { Line 4915  sub _tree_construction_main ($) {
4915                    
4916          if ($self->{self_closing}) {          if ($self->{self_closing}) {
4917            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
4918            !!!ack ('t398.1');            !!!ack ('t398.6');
4919          } else {          } else {
4920            !!!cp ('t398.2');            !!!cp ('t398.7');
4921            $self->{insertion_mode} |= IN_FOREIGN_CONTENT_IM;            $self->{insertion_mode} |= IN_FOREIGN_CONTENT_IM;
4922            ## NOTE: |<body><math><mi><svg>| -> "in foreign content" insertion            ## NOTE: |<body><math><mi><svg>| -> "in foreign content" insertion
4923            ## mode, "in body" (not "in foreign content") secondary insertion            ## mode, "in body" (not "in foreign content") secondary insertion
# Line 7370  sub _tree_construction_main ($) { Line 4928  sub _tree_construction_main ($) {
4928          next B;          next B;
4929        } elsif ({        } elsif ({
4930                  caption => 1, col => 1, colgroup => 1, frame => 1,                  caption => 1, col => 1, colgroup => 1, frame => 1,
4931                  frameset => 1, head => 1, option => 1, optgroup => 1,                  frameset => 1, head => 1,
4932                  tbody => 1, td => 1, tfoot => 1, th => 1,                  tbody => 1, td => 1, tfoot => 1, th => 1,
4933                  thead => 1, tr => 1,                  thead => 1, tr => 1,
4934                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
# Line 7381  sub _tree_construction_main ($) { Line 4939  sub _tree_construction_main ($) {
4939          !!!nack ('t401.1'); ## NOTE: |<col/>| or |<frame/>| here is an error.          !!!nack ('t401.1'); ## NOTE: |<col/>| or |<frame/>| here is an error.
4940          !!!next-token;          !!!next-token;
4941          next B;          next B;
4942                  } elsif ($token->{tag_name} eq 'param' or
4943          ## ISSUE: An issue on HTML5 new elements in the spec.                 $token->{tag_name} eq 'source') {
4944            !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
4945            pop @{$self->{open_elements}};
4946    
4947            !!!ack ('t398.5');
4948            !!!next-token;
4949            redo B;
4950        } else {        } else {
4951          if ($token->{tag_name} eq 'image') {          if ($token->{tag_name} eq 'image') {
4952            !!!cp ('t384');            !!!cp ('t384');
# Line 7418  sub _tree_construction_main ($) { Line 4982  sub _tree_construction_main ($) {
4982            !!!ack ('t388.2');            !!!ack ('t388.2');
4983          } elsif ({          } elsif ({
4984                    area => 1, basefont => 1, bgsound => 1, br => 1,                    area => 1, basefont => 1, bgsound => 1, br => 1,
4985                    embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,                    embed => 1, img => 1, spacer => 1, wbr => 1,
                   #image => 1,  
4986                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}}) {
4987            !!!cp ('t388.1');            !!!cp ('t388.1');
4988            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
# Line 7450  sub _tree_construction_main ($) { Line 5013  sub _tree_construction_main ($) {
5013          my $i;          my $i;
5014          INSCOPE: {          INSCOPE: {
5015            for (reverse @{$self->{open_elements}}) {            for (reverse @{$self->{open_elements}}) {
5016              if ($_->[1] & BODY_EL) {              if ($_->[1] == BODY_EL) {
5017                !!!cp ('t405');                !!!cp ('t405');
5018                $i = $_;                $i = $_;
5019                last INSCOPE;                last INSCOPE;
# Line 7460  sub _tree_construction_main ($) { Line 5023  sub _tree_construction_main ($) {
5023              }              }
5024            }            }
5025    
5026            !!!parse-error (type => 'start tag not allowed',            ## NOTE: |<marquee></body>|, |<svg><foreignobject></body>|
5027    
5028              !!!parse-error (type => 'unmatched end tag',
5029                            text => $token->{tag_name}, token => $token);                            text => $token->{tag_name}, token => $token);
5030            ## NOTE: Ignore the token.            ## NOTE: Ignore the token.
5031            !!!next-token;            !!!next-token;
# Line 7486  sub _tree_construction_main ($) { Line 5051  sub _tree_construction_main ($) {
5051          ## TODO: Update this code.  It seems that the code below is not          ## TODO: Update this code.  It seems that the code below is not
5052          ## up-to-date, though it has same effect as speced.          ## up-to-date, though it has same effect as speced.
5053          if (@{$self->{open_elements}} > 1 and          if (@{$self->{open_elements}} > 1 and
5054              $self->{open_elements}->[1]->[1] & BODY_EL) {              $self->{open_elements}->[1]->[1] == BODY_EL) {
5055            ## ISSUE: There is an issue in the spec.            unless ($self->{open_elements}->[-1]->[1] == BODY_EL) {
           unless ($self->{open_elements}->[-1]->[1] & BODY_EL) {  
5056              !!!cp ('t406');              !!!cp ('t406');
5057              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5058                              text => $self->{open_elements}->[1]->[0]                              text => $self->{open_elements}->[1]->[0]
# Line 7523  sub _tree_construction_main ($) { Line 5087  sub _tree_construction_main ($) {
5087    
5088                  applet => 1, button => 1, marquee => 1, object => 1,                  applet => 1, button => 1, marquee => 1, object => 1,
5089                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
5090            ## NOTE: Code for <li> start tags includes "as if </li>" code.
5091            ## Code for <dt> or <dd> start tags includes "as if </dt> or
5092            ## </dd>" code.
5093    
5094          ## has an element in scope          ## has an element in scope
5095          my $i;          my $i;
5096          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
# Line 7591  sub _tree_construction_main ($) { Line 5159  sub _tree_construction_main ($) {
5159          my $i;          my $i;
5160          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5161            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5162            if ($node->[1] & FORM_EL) {            if ($node->[1] == FORM_EL) {
5163              !!!cp ('t418');              !!!cp ('t418');
5164              $i = $_;              $i = $_;
5165              last INSCOPE;              last INSCOPE;
# Line 7639  sub _tree_construction_main ($) { Line 5207  sub _tree_construction_main ($) {
5207          my $i;          my $i;
5208          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5209            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5210            if ($node->[1] & HEADING_EL) {            if ($node->[1] == HEADING_EL) {
5211              !!!cp ('t423');              !!!cp ('t423');
5212              $i = $_;              $i = $_;
5213              last INSCOPE;              last INSCOPE;
# Line 7681  sub _tree_construction_main ($) { Line 5249  sub _tree_construction_main ($) {
5249          ## NOTE: As normal, except </p> implies <p> and ...          ## NOTE: As normal, except </p> implies <p> and ...
5250    
5251          ## has an element in scope          ## has an element in scope
5252            my $non_optional;
5253          my $i;          my $i;
5254          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5255            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5256            if ($node->[1] & P_EL) {            if ($node->[1] == P_EL) {
5257              !!!cp ('t410.1');              !!!cp ('t410.1');
5258              $i = $_;              $i = $_;
5259              last INSCOPE;              last INSCOPE;
5260            } elsif ($node->[1] & SCOPING_EL) {            } elsif ($node->[1] & SCOPING_EL) {
5261              !!!cp ('t411.1');              !!!cp ('t411.1');
5262              last INSCOPE;              last INSCOPE;
5263              } elsif ($node->[1] & END_TAG_OPTIONAL_EL) {
5264                ## NOTE: |END_TAG_OPTIONAL_EL| includes "p"
5265                !!!cp ('t411.2');
5266                #
5267              } else {
5268                !!!cp ('t411.3');
5269                $non_optional ||= $node;
5270                #
5271            }            }
5272          } # INSCOPE          } # INSCOPE
5273    
5274          if (defined $i) {          if (defined $i) {
5275            if ($self->{open_elements}->[-1]->[0]->manakai_local_name            ## 1. Generate implied end tags
5276                    ne $token->{tag_name}) {            #
5277    
5278              ## 2. If current node != "p", parse error
5279              if ($non_optional) {
5280              !!!cp ('t412.1');              !!!cp ('t412.1');
5281              !!!parse-error (type => 'not closed',              !!!parse-error (type => 'not closed',
5282                              text => $self->{open_elements}->[-1]->[0]                              text => $non_optional->[0]->manakai_local_name,
                                 ->manakai_local_name,  
5283                              token => $token);                              token => $token);
5284            } else {            } else {
5285              !!!cp ('t414.1');              !!!cp ('t414.1');
5286            }            }
5287    
5288              ## 3. Pop
5289            splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
5290          } else {          } else {
5291            !!!cp ('t413.1');            !!!cp ('t413.1');
# Line 7746  sub _tree_construction_main ($) { Line 5326  sub _tree_construction_main ($) {
5326          ## Ignore the token.          ## Ignore the token.
5327          !!!next-token;          !!!next-token;
5328          next B;          next B;
       } elsif ({  
                 caption => 1, col => 1, colgroup => 1, frame => 1,  
                 frameset => 1, head => 1, option => 1, optgroup => 1,  
                 tbody => 1, td => 1, tfoot => 1, th => 1,  
                 thead => 1, tr => 1,  
                 area => 1, basefont => 1, bgsound => 1,  
                 embed => 1, hr => 1, iframe => 1, image => 1,  
                 img => 1, input => 1, isindex => 1, noembed => 1,  
                 noframes => 1, param => 1, select => 1, spacer => 1,  
                 table => 1, textarea => 1, wbr => 1,  
                 noscript => 0, ## TODO: if scripting is enabled  
                }->{$token->{tag_name}}) {  
         !!!cp ('t429');  
         !!!parse-error (type => 'unmatched end tag',  
                         text => $token->{tag_name}, token => $token);  
         ## Ignore the token  
         !!!next-token;  
         next B;  
5329        } else {        } else {
5330          if ($token->{tag_name} eq 'sarcasm') {          if ($token->{tag_name} eq 'sarcasm') {
5331            sleep 0.001; # take a deep breath            sleep 0.001; # take a deep breath
# Line 7775  sub _tree_construction_main ($) { Line 5337  sub _tree_construction_main ($) {
5337    
5338          ## Step 2          ## Step 2
5339          S2: {          S2: {
5340            if ($node->[0]->manakai_local_name eq $token->{tag_name}) {            my $node_tag_name = $node->[0]->manakai_local_name;
5341              $node_tag_name =~ tr/A-Z/a-z/; # for SVG camelCase tag names
5342              if ($node_tag_name eq $token->{tag_name}) {
5343              ## Step 1              ## Step 1
5344              ## generate implied end tags              ## generate implied end tags
5345              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
# Line 7788  sub _tree_construction_main ($) { Line 5352  sub _tree_construction_main ($) {
5352              }              }
5353                    
5354              ## Step 2              ## Step 2
5355              if ($self->{open_elements}->[-1]->[0]->manakai_local_name              my $current_tag_name
5356                      ne $token->{tag_name}) {                  = $self->{open_elements}->[-1]->[0]->manakai_local_name;
5357                $current_tag_name =~ tr/A-Z/a-z/;
5358                if ($current_tag_name ne $token->{tag_name}) {
5359                !!!cp ('t431');                !!!cp ('t431');
5360                ## NOTE: <x><y></x>                ## NOTE: <x><y></x>
5361                !!!parse-error (type => 'not closed',                !!!parse-error (type => 'not closed',
# Line 8059  sub set_inner_html ($$$$;$) { Line 5625  sub set_inner_html ($$$$;$) {
5625      push @{$p->{open_elements}}, [$root, $el_category->{html}];      push @{$p->{open_elements}}, [$root, $el_category->{html}];
5626    
5627      undef $p->{head_element};      undef $p->{head_element};
5628        undef $p->{head_element_inserted};
5629    
5630      ## Step 6 # MUST      ## Step 6 # MUST
5631      $p->_reset_insertion_mode;      $p->_reset_insertion_mode;

Legend:
Removed from v.1.195  
changed lines
  Added in v.1.209

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24