/[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.127 by wakaba, Sat Apr 12 15:25:52 2008 UTC revision 1.151 by wakaba, Sun Jun 8 05:08:42 2008 UTC
# Line 8  use Error qw(:try); Line 8  use Error qw(:try);
8  ## doc.write ('');  ## doc.write ('');
9  ## alert (doc.compatMode);  ## alert (doc.compatMode);
10    
11  ## TODO: Control charcters and noncharacters are not allowed (HTML5 revision 1263)  require IO::Handle;
 ## TODO: 1252 parse error (revision 1264)  
 ## TODO: 8859-11 = 874 (revision 1271)  
12    
13  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
14  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;  my $MML_NS = q<http://www.w3.org/1998/Math/MathML>;
# Line 47  sub MISC_SPECIAL_EL () { 0b1000000000000 Line 45  sub MISC_SPECIAL_EL () { 0b1000000000000
45  sub FOREIGN_EL () { 0b10000000000000000000000000 }  sub FOREIGN_EL () { 0b10000000000000000000000000 }
46  sub FOREIGN_FLOW_CONTENT_EL () { 0b100000000000000000000000000 }  sub FOREIGN_FLOW_CONTENT_EL () { 0b100000000000000000000000000 }
47  sub MML_AXML_EL () { 0b1000000000000000000000000000 }  sub MML_AXML_EL () { 0b1000000000000000000000000000 }
48    sub RUBY_EL () { 0b10000000000000000000000000000 }
49    sub RUBY_COMPONENT_EL () { 0b100000000000000000000000000000 }
50    
51  sub TABLE_ROWS_EL () {  sub TABLE_ROWS_EL () {
52    TABLE_EL |    TABLE_EL |
# Line 54  sub TABLE_ROWS_EL () { Line 54  sub TABLE_ROWS_EL () {
54    TABLE_ROW_GROUP_EL    TABLE_ROW_GROUP_EL
55  }  }
56    
57    ## NOTE: Used in "generate implied end tags" algorithm.
58    ## NOTE: There is a code where a modified version of END_TAG_OPTIONAL_EL
59    ## is used in "generate implied end tags" implementation (search for the
60    ## function mae).
61  sub END_TAG_OPTIONAL_EL () {  sub END_TAG_OPTIONAL_EL () {
62    DD_EL |    DD_EL |
63    DT_EL |    DT_EL |
64    LI_EL |    LI_EL |
65    P_EL    P_EL |
66      RUBY_COMPONENT_EL
67  }  }
68    
69    ## NOTE: Used in </body> and EOF algorithms.
70  sub ALL_END_TAG_OPTIONAL_EL () {  sub ALL_END_TAG_OPTIONAL_EL () {
71    END_TAG_OPTIONAL_EL |    DD_EL |
72      DT_EL |
73      LI_EL |
74      P_EL |
75    
76    BODY_EL |    BODY_EL |
77    HTML_EL |    HTML_EL |
78    TABLE_CELL_EL |    TABLE_CELL_EL |
# Line 98  sub SPECIAL_EL () { Line 108  sub SPECIAL_EL () {
108    ADDRESS_EL |    ADDRESS_EL |
109    BODY_EL |    BODY_EL |
110    DIV_EL |    DIV_EL |
111    END_TAG_OPTIONAL_EL |  
112      DD_EL |
113      DT_EL |
114      LI_EL |
115      P_EL |
116    
117    FORM_EL |    FORM_EL |
118    FRAMESET_EL |    FRAMESET_EL |
119    HEADING_EL |    HEADING_EL |
# Line 172  my $el_category = { Line 187  my $el_category = {
187    param => MISC_SPECIAL_EL,    param => MISC_SPECIAL_EL,
188    plaintext => MISC_SPECIAL_EL,    plaintext => MISC_SPECIAL_EL,
189    pre => MISC_SPECIAL_EL,    pre => MISC_SPECIAL_EL,
190      rp => RUBY_COMPONENT_EL,
191      rt => RUBY_COMPONENT_EL,
192      ruby => RUBY_EL,
193    s => FORMATTING_EL,    s => FORMATTING_EL,
194    script => MISC_SPECIAL_EL,    script => MISC_SPECIAL_EL,
195    select => SELECT_EL,    select => SELECT_EL,
# Line 205  my $el_category_f = { Line 223  my $el_category_f = {
223      mtext => FOREIGN_FLOW_CONTENT_EL,      mtext => FOREIGN_FLOW_CONTENT_EL,
224    },    },
225    $SVG_NS => {    $SVG_NS => {
226      foreignobject => FOREIGN_FLOW_CONTENT_EL, ## TODO: case      foreignObject => FOREIGN_FLOW_CONTENT_EL,
227      desc => FOREIGN_FLOW_CONTENT_EL,      desc => FOREIGN_FLOW_CONTENT_EL,
228      title => FOREIGN_FLOW_CONTENT_EL,      title => FOREIGN_FLOW_CONTENT_EL,
229    },    },
230    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.    ## NOTE: In addition, FOREIGN_EL is set to non-HTML elements.
231  };  };
232    
233    my $svg_attr_name = {
234      attributename => 'attributeName',
235      attributetype => 'attributeType',
236      basefrequency => 'baseFrequency',
237      baseprofile => 'baseProfile',
238      calcmode => 'calcMode',
239      clippathunits => 'clipPathUnits',
240      contentscripttype => 'contentScriptType',
241      contentstyletype => 'contentStyleType',
242      diffuseconstant => 'diffuseConstant',
243      edgemode => 'edgeMode',
244      externalresourcesrequired => 'externalResourcesRequired',
245      filterres => 'filterRes',
246      filterunits => 'filterUnits',
247      glyphref => 'glyphRef',
248      gradienttransform => 'gradientTransform',
249      gradientunits => 'gradientUnits',
250      kernelmatrix => 'kernelMatrix',
251      kernelunitlength => 'kernelUnitLength',
252      keypoints => 'keyPoints',
253      keysplines => 'keySplines',
254      keytimes => 'keyTimes',
255      lengthadjust => 'lengthAdjust',
256      limitingconeangle => 'limitingConeAngle',
257      markerheight => 'markerHeight',
258      markerunits => 'markerUnits',
259      markerwidth => 'markerWidth',
260      maskcontentunits => 'maskContentUnits',
261      maskunits => 'maskUnits',
262      numoctaves => 'numOctaves',
263      pathlength => 'pathLength',
264      patterncontentunits => 'patternContentUnits',
265      patterntransform => 'patternTransform',
266      patternunits => 'patternUnits',
267      pointsatx => 'pointsAtX',
268      pointsaty => 'pointsAtY',
269      pointsatz => 'pointsAtZ',
270      preservealpha => 'preserveAlpha',
271      preserveaspectratio => 'preserveAspectRatio',
272      primitiveunits => 'primitiveUnits',
273      refx => 'refX',
274      refy => 'refY',
275      repeatcount => 'repeatCount',
276      repeatdur => 'repeatDur',
277      requiredextensions => 'requiredExtensions',
278      requiredfeatures => 'requiredFeatures',
279      specularconstant => 'specularConstant',
280      specularexponent => 'specularExponent',
281      spreadmethod => 'spreadMethod',
282      startoffset => 'startOffset',
283      stddeviation => 'stdDeviation',
284      stitchtiles => 'stitchTiles',
285      surfacescale => 'surfaceScale',
286      systemlanguage => 'systemLanguage',
287      tablevalues => 'tableValues',
288      targetx => 'targetX',
289      targety => 'targetY',
290      textlength => 'textLength',
291      viewbox => 'viewBox',
292      viewtarget => 'viewTarget',
293      xchannelselector => 'xChannelSelector',
294      ychannelselector => 'yChannelSelector',
295      zoomandpan => 'zoomAndPan',
296    };
297    
298    my $foreign_attr_xname = {
299      'xlink:actuate' => [$XLINK_NS, ['xlink', 'actuate']],
300      'xlink:arcrole' => [$XLINK_NS, ['xlink', 'arcrole']],
301      'xlink:href' => [$XLINK_NS, ['xlink', 'href']],
302      'xlink:role' => [$XLINK_NS, ['xlink', 'role']],
303      'xlink:show' => [$XLINK_NS, ['xlink', 'show']],
304      'xlink:title' => [$XLINK_NS, ['xlink', 'title']],
305      'xlink:type' => [$XLINK_NS, ['xlink', 'type']],
306      'xml:base' => [$XML_NS, ['xml', 'base']],
307      'xml:lang' => [$XML_NS, ['xml', 'lang']],
308      'xml:space' => [$XML_NS, ['xml', 'space']],
309      'xmlns' => [$XMLNS_NS, [undef, 'xmlns']],
310      'xmlns:xlink' => [$XMLNS_NS, ['xmlns', 'xlink']],
311    };
312    
313    ## ISSUE: xmlns:xlink="non-xlink-ns" is not an error.
314    
315  my $c1_entity_char = {  my $c1_entity_char = {
316    0x80 => 0x20AC,    0x80 => 0x20AC,
317    0x81 => 0xFFFD,    0x81 => 0xFFFD,
# Line 248  my $c1_entity_char = { Line 348  my $c1_entity_char = {
348  }; # $c1_entity_char  }; # $c1_entity_char
349    
350  sub parse_byte_string ($$$$;$) {  sub parse_byte_string ($$$$;$) {
351      my $self = shift;
352      my $charset_name = shift;
353      open my $input, '<', ref $_[0] ? $_[0] : \($_[0]);
354      return $self->parse_byte_stream ($charset_name, $input, @_[1..$#_]);
355    } # parse_byte_string
356    
357    sub parse_byte_stream ($$$$;$) {
358    my $self = ref $_[0] ? shift : shift->new;    my $self = ref $_[0] ? shift : shift->new;
359    my $charset = shift;    my $charset_name = shift;
360    my $bytes_s = ref $_[0] ? $_[0] : \($_[0]);    my $byte_stream = $_[0];
   my $s;  
     
   if (defined $charset) {  
     require Encode; ## TODO: decode(utf8) don't delete BOM  
     $s = \ (Encode::decode ($charset, $$bytes_s));  
     $self->{input_encoding} = lc $charset; ## TODO: normalize name  
     $self->{confident} = 1;  
   } else {  
     ## TODO: Implement HTML5 detection algorithm  
     require Whatpm::Charset::UniversalCharDet;  
     $charset = Whatpm::Charset::UniversalCharDet->detect_byte_string  
         (substr ($$bytes_s, 0, 1024));  
     $charset ||= 'windows-1252';  
     $s = \ (Encode::decode ($charset, $$bytes_s));  
     $self->{input_encoding} = $charset;  
     $self->{confident} = 0;  
   }  
361    
362    $self->{change_encoding} = sub {    my $onerror = $_[2] || sub {
363      my $self = shift;      my (%opt) = @_;
364      my $charset = lc shift;      warn "Parse error ($opt{type})\n";
365      my $token = shift;    };
366      ## TODO: if $charset is supported    $self->{parse_error} = $onerror; # updated later by parse_char_string
367      ## TODO: normalize charset name  
368      ## HTML5 encoding sniffing algorithm
369      require Message::Charset::Info;
370      my $charset;
371      my $buffer;
372      my ($char_stream, $e_status);
373    
374      ## "Change the encoding" algorithm:    SNIFFING: {
375    
376      ## Step 1          ## Step 1
377      if ($charset eq 'utf-16') { ## ISSUE: UTF-16BE -> UTF-8? UTF-16LE -> UTF-8?      if (defined $charset_name) {
378        $charset = 'utf-8';        $charset = Message::Charset::Info->get_by_iana_name ($charset_name);
379    
380          ## ISSUE: Unsupported encoding is not ignored according to the spec.
381          ($char_stream, $e_status) = $charset->get_decode_handle
382              ($byte_stream, allow_error_reporting => 1,
383               allow_fallback => 1);
384          if ($char_stream) {
385            $self->{confident} = 1;
386            last SNIFFING;
387          } else {
388            ## TODO: unsupported error
389          }
390      }      }
391    
392      ## Step 2      ## Step 2
393      if (defined $self->{input_encoding} and      my $byte_buffer = '';
394          $self->{input_encoding} eq $charset) {      for (1..1024) {
395          my $char = $byte_stream->getc;
396          last unless defined $char;
397          $byte_buffer .= $char;
398        } ## TODO: timeout
399    
400        ## Step 3
401        if ($byte_buffer =~ /^\xFE\xFF/) {
402          $charset = Message::Charset::Info->get_by_iana_name ('utf-16be');
403          ($char_stream, $e_status) = $charset->get_decode_handle
404              ($byte_stream, allow_error_reporting => 1,
405               allow_fallback => 1, byte_buffer => \$byte_buffer);
406        $self->{confident} = 1;        $self->{confident} = 1;
407        return;        last SNIFFING;
408        } elsif ($byte_buffer =~ /^\xFF\xFE/) {
409          $charset = Message::Charset::Info->get_by_iana_name ('utf-16le');
410          ($char_stream, $e_status) = $charset->get_decode_handle
411              ($byte_stream, allow_error_reporting => 1,
412               allow_fallback => 1, byte_buffer => \$byte_buffer);
413          $self->{confident} = 1;
414          last SNIFFING;
415        } elsif ($byte_buffer =~ /^\xEF\xBB\xBF/) {
416          $charset = Message::Charset::Info->get_by_iana_name ('utf-8');
417          ($char_stream, $e_status) = $charset->get_decode_handle
418              ($byte_stream, allow_error_reporting => 1,
419               allow_fallback => 1, byte_buffer => \$byte_buffer);
420          $self->{confident} = 1;
421          last SNIFFING;
422      }      }
423    
424      !!!parse-error (type => 'charset label detected:'.$self->{input_encoding}.      ## Step 4
425          ':'.$charset, level => 'w', token => $token);      ## TODO: <meta charset>
426    
427      ## Step 3      ## Step 5
428      # if (can) {      ## TODO: from history
       ## change the encoding on the fly.  
       #$self->{confident} = 1;  
       #return;  
     # }  
429    
430      ## Step 4      ## Step 6
431      throw Whatpm::HTML::RestartParser (charset => $charset);      require Whatpm::Charset::UniversalCharDet;
432        $charset_name = Whatpm::Charset::UniversalCharDet->detect_byte_string
433            ($byte_buffer);
434        if (defined $charset_name) {
435          $charset = Message::Charset::Info->get_by_iana_name ($charset_name);
436    
437          ## ISSUE: Unsupported encoding is not ignored according to the spec.
438          require Whatpm::Charset::DecodeHandle;
439          $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new
440              ($byte_stream);
441          ($char_stream, $e_status) = $charset->get_decode_handle
442              ($buffer, allow_error_reporting => 1,
443               allow_fallback => 1, byte_buffer => \$byte_buffer);
444          if ($char_stream) {
445            $buffer->{buffer} = $byte_buffer;
446            !!!parse-error (type => 'sniffing:chardet', ## TODO: type name
447                            value => $charset_name,
448                            level => $self->{info_level},
449                            line => 1, column => 1);
450            $self->{confident} = 0;
451            last SNIFFING;
452          }
453        }
454    
455        ## Step 7: default
456        ## TODO: Make this configurable.
457        $charset = Message::Charset::Info->get_by_iana_name ('windows-1252');
458            ## NOTE: We choose |windows-1252| here, since |utf-8| should be
459            ## detectable in the step 6.
460        require Whatpm::Charset::DecodeHandle;
461        $buffer = Whatpm::Charset::DecodeHandle::ByteBuffer->new
462            ($byte_stream);
463        ($char_stream, $e_status)
464            = $charset->get_decode_handle ($buffer,
465                                           allow_error_reporting => 1,
466                                           allow_fallback => 1,
467                                           byte_buffer => \$byte_buffer);
468        $buffer->{buffer} = $byte_buffer;
469        !!!parse-error (type => 'sniffing:default', ## TODO: type name
470                        value => 'windows-1252',
471                        level => $self->{info_level},
472                        line => 1, column => 1);
473        $self->{confident} = 0;
474      } # SNIFFING
475    
476      $self->{input_encoding} = $charset->get_iana_name;
477      if ($e_status & Message::Charset::Info::FALLBACK_ENCODING_IMPL ()) {
478        !!!parse-error (type => 'chardecode:fallback', ## TODO: type name
479                        value => $self->{input_encoding},
480                        level => $self->{unsupported_level},
481                        line => 1, column => 1);
482      } elsif (not ($e_status &
483                    Message::Charset::Info::ERROR_REPORTING_ENCODING_IMPL())) {
484        !!!parse-error (type => 'chardecode:no error', ## TODO: type name
485                        value => $self->{input_encoding},
486                        level => $self->{unsupported_level},
487                        line => 1, column => 1);
488      }
489    
490      $self->{change_encoding} = sub {
491        my $self = shift;
492        $charset_name = shift;
493        my $token = shift;
494    
495        $charset = Message::Charset::Info->get_by_iana_name ($charset_name);
496        ($char_stream, $e_status) = $charset->get_decode_handle
497            ($byte_stream, allow_error_reporting => 1, allow_fallback => 1,
498             byte_buffer => \ $buffer->{buffer});
499        
500        if ($char_stream) { # if supported
501          ## "Change the encoding" algorithm:
502    
503          ## Step 1    
504          if ($charset->{category} &
505              Message::Charset::Info::CHARSET_CATEGORY_UTF16 ()) {
506            $charset = Message::Charset::Info->get_by_iana_name ('utf-8');
507            ($char_stream, $e_status) = $charset->get_decode_handle
508                ($byte_stream,
509                 byte_buffer => \ $buffer->{buffer});
510          }
511          $charset_name = $charset->get_iana_name;
512          
513          ## Step 2
514          if (defined $self->{input_encoding} and
515              $self->{input_encoding} eq $charset_name) {
516            !!!parse-error (type => 'charset label:matching', ## TODO: type
517                            value => $charset_name,
518                            level => $self->{info_level});
519            $self->{confident} = 1;
520            return;
521          }
522    
523          !!!parse-error (type => 'charset label detected:'.$self->{input_encoding}.
524              ':'.$charset_name, level => 'w', token => $token);
525          
526          ## Step 3
527          # if (can) {
528            ## change the encoding on the fly.
529            #$self->{confident} = 1;
530            #return;
531          # }
532          
533          ## Step 4
534          throw Whatpm::HTML::RestartParser ();
535        }
536    }; # $self->{change_encoding}    }; # $self->{change_encoding}
537    
538      my $char_onerror = sub {
539        my (undef, $type, %opt) = @_;
540        !!!parse-error (%opt, type => $type,
541                        line => $self->{line}, column => $self->{column} + 1);
542        if ($opt{octets}) {
543          ${$opt{octets}} = "\x{FFFD}"; # relacement character
544        }
545      };
546      $char_stream->onerror ($char_onerror);
547    
548    my @args = @_; shift @args; # $s    my @args = @_; shift @args; # $s
549    my $return;    my $return;
550    try {    try {
551      $return = $self->parse_char_string ($s, @args);        $return = $self->parse_char_stream ($char_stream, @args);  
552    } catch Whatpm::HTML::RestartParser with {    } catch Whatpm::HTML::RestartParser with {
553      my $charset = shift->{charset};      ## NOTE: Invoked after {change_encoding}.
554      $s = \ (Encode::decode ($charset, $$bytes_s));      
555      $self->{input_encoding} = $charset; ## TODO: normalize      $self->{input_encoding} = $charset->get_iana_name;
556        if ($e_status & Message::Charset::Info::FALLBACK_ENCODING_IMPL ()) {
557          !!!parse-error (type => 'chardecode:fallback', ## TODO: type name
558                          value => $self->{input_encoding},
559                          level => $self->{unsupported_level},
560                          line => 1, column => 1);
561        } elsif (not ($e_status &
562                      Message::Charset::Info::ERROR_REPORTING_ENCODING_IMPL())) {
563          !!!parse-error (type => 'chardecode:no error', ## TODO: type name
564                          value => $self->{input_encoding},
565                          level => $self->{unsupported_level},
566                          line => 1, column => 1);
567        }
568      $self->{confident} = 1;      $self->{confident} = 1;
569      $return = $self->parse_char_string ($s, @args);      $char_stream->onerror ($char_onerror);
570        $return = $self->parse_char_stream ($char_stream, @args);
571    };    };
572    return $return;    return $return;
573  } # parse_byte_string  } # parse_byte_stream
574    
575  ## NOTE: HTML5 spec says that the encoding layer MUST NOT strip BOM  ## NOTE: HTML5 spec says that the encoding layer MUST NOT strip BOM
576  ## and the HTML layer MUST ignore it.  However, we does strip BOM in  ## and the HTML layer MUST ignore it.  However, we does strip BOM in
# Line 327  sub parse_byte_string ($$$$;$) { Line 581  sub parse_byte_string ($$$$;$) {
581  ## such as |parse_byte_string| in this module, must ensure that it does  ## such as |parse_byte_string| in this module, must ensure that it does
582  ## strip the BOM and never strip any ZWNBSP.  ## strip the BOM and never strip any ZWNBSP.
583    
584  *parse_char_string = \&parse_string;  sub parse_char_string ($$$;$) {
585      my $self = shift;
586      require utf8;
587      my $s = ref $_[0] ? $_[0] : \($_[0]);
588      open my $input, '<' . (utf8::is_utf8 ($$s) ? ':utf8' : ''), $s;
589      return $self->parse_char_stream ($input, @_[1..$#_]);
590    } # parse_char_string
591    *parse_string = \&parse_char_string;
592    
593  sub parse_string ($$$;$) {  sub parse_char_stream ($$$;$) {
594    my $self = ref $_[0] ? shift : shift->new;    my $self = ref $_[0] ? shift : shift->new;
595    my $s = ref $_[0] ? $_[0] : \($_[0]);    my $input = $_[0];
596    $self->{document} = $_[1];    $self->{document} = $_[1];
597    @{$self->{document}->child_nodes} = ();    @{$self->{document}->child_nodes} = ();
598    
# Line 350  sub parse_string ($$$;$) { Line 611  sub parse_string ($$$;$) {
611      pop @{$self->{prev_char}};      pop @{$self->{prev_char}};
612      unshift @{$self->{prev_char}}, $self->{next_char};      unshift @{$self->{prev_char}}, $self->{next_char};
613    
614      $self->{next_char} = -1 and return if $i >= length $$s;      my $char;
615      $self->{next_char} = ord substr $$s, $i++, 1;      if (defined $self->{next_next_char}) {
616          $char = $self->{next_next_char};
617          delete $self->{next_next_char};
618        } else {
619          $char = $input->getc;
620        }
621        $self->{next_char} = -1 and return unless defined $char;
622        $self->{next_char} = ord $char;
623    
624      ($self->{line_prev}, $self->{column_prev})      ($self->{line_prev}, $self->{column_prev})
625          = ($self->{line}, $self->{column});          = ($self->{line}, $self->{column});
626      $self->{column}++;      $self->{column}++;
627            
628      if ($self->{next_char} == 0x000A) { # LF      if ($self->{next_char} == 0x000A) { # LF
629          !!!cp ('j1');
630        $self->{line}++;        $self->{line}++;
631        $self->{column} = 0;        $self->{column} = 0;
632      } elsif ($self->{next_char} == 0x000D) { # CR      } elsif ($self->{next_char} == 0x000D) { # CR
633        $i++ if substr ($$s, $i, 1) eq "\x0A";        !!!cp ('j2');
634          my $next = $input->getc;
635          if (defined $next and $next ne "\x0A") {
636            $self->{next_next_char} = $next;
637          }
638        $self->{next_char} = 0x000A; # LF # MUST        $self->{next_char} = 0x000A; # LF # MUST
639        $self->{line}++;        $self->{line}++;
640        $self->{column} = 0;        $self->{column} = 0;
641      } elsif ($self->{next_char} > 0x10FFFF) {      } elsif ($self->{next_char} > 0x10FFFF) {
642          !!!cp ('j3');
643        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
644      } elsif ($self->{next_char} == 0x0000) { # NULL      } elsif ($self->{next_char} == 0x0000) { # NULL
645          !!!cp ('j4');
646        !!!parse-error (type => 'NULL');        !!!parse-error (type => 'NULL');
647        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
648        } elsif ($self->{next_char} <= 0x0008 or
649                 (0x000E <= $self->{next_char} and $self->{next_char} <= 0x001F) or
650                 (0x007F <= $self->{next_char} and $self->{next_char} <= 0x009F) or
651                 (0xD800 <= $self->{next_char} and $self->{next_char} <= 0xDFFF) or
652                 (0xFDD0 <= $self->{next_char} and $self->{next_char} <= 0xFDDF) or
653                 {
654                  0xFFFE => 1, 0xFFFF => 1, 0x1FFFE => 1, 0x1FFFF => 1,
655                  0x2FFFE => 1, 0x2FFFF => 1, 0x3FFFE => 1, 0x3FFFF => 1,
656                  0x4FFFE => 1, 0x4FFFF => 1, 0x5FFFE => 1, 0x5FFFF => 1,
657                  0x6FFFE => 1, 0x6FFFF => 1, 0x7FFFE => 1, 0x7FFFF => 1,
658                  0x8FFFE => 1, 0x8FFFF => 1, 0x9FFFE => 1, 0x9FFFF => 1,
659                  0xAFFFE => 1, 0xAFFFF => 1, 0xBFFFE => 1, 0xBFFFF => 1,
660                  0xCFFFE => 1, 0xCFFFF => 1, 0xDFFFE => 1, 0xDFFFF => 1,
661                  0xEFFFE => 1, 0xEFFFF => 1, 0xFFFFE => 1, 0xFFFFF => 1,
662                  0x10FFFE => 1, 0x10FFFF => 1,
663                 }->{$self->{next_char}}) {
664          !!!cp ('j5');
665          !!!parse-error (type => 'control char', level => $self->{must_level});
666    ## TODO: error type documentation
667      }      }
668    };    };
669    $self->{prev_char} = [-1, -1, -1];    $self->{prev_char} = [-1, -1, -1];
# Line 393  sub parse_string ($$$;$) { Line 687  sub parse_string ($$$;$) {
687    delete $self->{parse_error}; # remove loop    delete $self->{parse_error}; # remove loop
688    
689    return $self->{document};    return $self->{document};
690  } # parse_string  } # parse_char_stream
691    
692  sub new ($) {  sub new ($) {
693    my $class = shift;    my $class = shift;
694    my $self = bless {}, $class;    my $self = bless {
695        must_level => 'm',
696        should_level => 's',
697        good_level => 'w',
698        warn_level => 'w',
699        info_level => 'i',
700        unsupported_level => 'u',
701      }, $class;
702    $self->{set_next_char} = sub {    $self->{set_next_char} = sub {
703      $self->{next_char} = -1;      $self->{next_char} = -1;
704    };    };
# Line 543  sub _initialize_tokenizer ($) { Line 844  sub _initialize_tokenizer ($) {
844  ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|  ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|
845  ##     while the token is pushed back to the stack.  ##     while the token is pushed back to the stack.
846    
 ## ISSUE: "When a DOCTYPE token is created, its  
 ## <i>self-closing flag</i> must be unset (its other state is that it  
 ## be set), and its attributes list must be empty.": Wrong subject?  
   
847  ## Emitted token MUST immediately be handled by the tree construction state.  ## Emitted token MUST immediately be handled by the tree construction state.
848    
849  ## Before each step, UA MAY check to see if either one of the scripts in  ## Before each step, UA MAY check to see if either one of the scripts in
# Line 762  sub _get_next_token ($) { Line 1059  sub _get_next_token ($) {
1059            redo A;            redo A;
1060          } else {          } else {
1061            !!!cp (23);            !!!cp (23);
1062            !!!parse-error (type => 'bare stago');            !!!parse-error (type => 'bare stago',
1063                              line => $self->{line_prev},
1064                              column => $self->{column_prev});
1065            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
1066            ## reconsume            ## reconsume
1067    
# Line 1539  sub _get_next_token ($) { Line 1838  sub _get_next_token ($) {
1838          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1839          !!!next-input-character;          !!!next-input-character;
1840          redo A;          redo A;
1841          } elsif ($self->{next_char} == -1) {
1842            !!!parse-error (type => 'unclosed tag');
1843            if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1844              !!!cp (122.3);
1845              $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1846            } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1847              if ($self->{current_token}->{attributes}) {
1848                !!!cp (122.1);
1849                !!!parse-error (type => 'end tag attribute');
1850              } else {
1851                ## NOTE: This state should never be reached.
1852                !!!cp (122.2);
1853              }
1854            } else {
1855              die "$0: $self->{current_token}->{type}: Unknown token type";
1856            }
1857            $self->{state} = DATA_STATE;
1858            ## Reconsume.
1859            !!!emit ($self->{current_token}); # start tag or end tag
1860            redo A;
1861        } else {        } else {
1862          !!!cp ('124.1');          !!!cp ('124.1');
1863          !!!parse-error (type => 'no space between attributes');          !!!parse-error (type => 'no space between attributes');
# Line 1571  sub _get_next_token ($) { Line 1890  sub _get_next_token ($) {
1890          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
1891    
1892          redo A;          redo A;
1893          } elsif ($self->{next_char} == -1) {
1894            !!!parse-error (type => 'unclosed tag');
1895            if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1896              !!!cp (124.7);
1897              $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1898            } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1899              if ($self->{current_token}->{attributes}) {
1900                !!!cp (124.5);
1901                !!!parse-error (type => 'end tag attribute');
1902              } else {
1903                ## NOTE: This state should never be reached.
1904                !!!cp (124.6);
1905              }
1906            } else {
1907              die "$0: $self->{current_token}->{type}: Unknown token type";
1908            }
1909            $self->{state} = DATA_STATE;
1910            ## Reconsume.
1911            !!!emit ($self->{current_token}); # start tag or end tag
1912            redo A;
1913        } else {        } else {
1914          !!!cp ('124.4');          !!!cp ('124.4');
1915          !!!parse-error (type => 'nestc');          !!!parse-error (type => 'nestc');
# Line 2412  sub _get_next_token ($) { Line 2751  sub _get_next_token ($) {
2751        } elsif ($self->{next_char} == -1) {        } elsif ($self->{next_char} == -1) {
2752          !!!cp (217);          !!!cp (217);
2753          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
   
2754          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2755          ## reconsume          ## reconsume
2756    
# Line 2657  sub _tokenize_attempt_to_consume_an_enti Line 2995  sub _tokenize_attempt_to_consume_an_enti
2995      require Whatpm::_NamedEntityList;      require Whatpm::_NamedEntityList;
2996      our $EntityChar;      our $EntityChar;
2997    
2998      while (length $entity_name < 10 and      while (length $entity_name < 30 and
2999             ## NOTE: Some number greater than the maximum length of entity name             ## NOTE: Some number greater than the maximum length of entity name
3000             ((0x0041 <= $self->{next_char} and # a             ((0x0041 <= $self->{next_char} and # a
3001               $self->{next_char} <= 0x005A) or # x               $self->{next_char} <= 0x005A) or # x
# Line 2815  sub _tree_construction_initial ($) { Line 3153  sub _tree_construction_initial ($) {
3153        } elsif (defined $token->{public_identifier}) {        } elsif (defined $token->{public_identifier}) {
3154          my $pubid = $token->{public_identifier};          my $pubid = $token->{public_identifier};
3155          $pubid =~ tr/a-z/A-z/;          $pubid =~ tr/a-z/A-z/;
3156          if ({          my $prefix = [
3157            "+//SILMARIL//DTD HTML PRO V0R11 19970101//EN" => 1,            "+//SILMARIL//DTD HTML PRO V0R11 19970101//",
3158            "-//ADVASOFT LTD//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,            "-//ADVASOFT LTD//DTD HTML 3.0 ASWEDIT + EXTENSIONS//",
3159            "-//AS//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,            "-//AS//DTD HTML 3.0 ASWEDIT + EXTENSIONS//",
3160            "-//IETF//DTD HTML 2.0 LEVEL 1//EN" => 1,            "-//IETF//DTD HTML 2.0 LEVEL 1//",
3161            "-//IETF//DTD HTML 2.0 LEVEL 2//EN" => 1,            "-//IETF//DTD HTML 2.0 LEVEL 2//",
3162            "-//IETF//DTD HTML 2.0 STRICT LEVEL 1//EN" => 1,            "-//IETF//DTD HTML 2.0 STRICT LEVEL 1//",
3163            "-//IETF//DTD HTML 2.0 STRICT LEVEL 2//EN" => 1,            "-//IETF//DTD HTML 2.0 STRICT LEVEL 2//",
3164            "-//IETF//DTD HTML 2.0 STRICT//EN" => 1,            "-//IETF//DTD HTML 2.0 STRICT//",
3165            "-//IETF//DTD HTML 2.0//EN" => 1,            "-//IETF//DTD HTML 2.0//",
3166            "-//IETF//DTD HTML 2.1E//EN" => 1,            "-//IETF//DTD HTML 2.1E//",
3167            "-//IETF//DTD HTML 3.0//EN" => 1,            "-//IETF//DTD HTML 3.0//",
3168            "-//IETF//DTD HTML 3.0//EN//" => 1,            "-//IETF//DTD HTML 3.2 FINAL//",
3169            "-//IETF//DTD HTML 3.2 FINAL//EN" => 1,            "-//IETF//DTD HTML 3.2//",
3170            "-//IETF//DTD HTML 3.2//EN" => 1,            "-//IETF//DTD HTML 3//",
3171            "-//IETF//DTD HTML 3//EN" => 1,            "-//IETF//DTD HTML LEVEL 0//",
3172            "-//IETF//DTD HTML LEVEL 0//EN" => 1,            "-//IETF//DTD HTML LEVEL 1//",
3173            "-//IETF//DTD HTML LEVEL 0//EN//2.0" => 1,            "-//IETF//DTD HTML LEVEL 2//",
3174            "-//IETF//DTD HTML LEVEL 1//EN" => 1,            "-//IETF//DTD HTML LEVEL 3//",
3175            "-//IETF//DTD HTML LEVEL 1//EN//2.0" => 1,            "-//IETF//DTD HTML STRICT LEVEL 0//",
3176            "-//IETF//DTD HTML LEVEL 2//EN" => 1,            "-//IETF//DTD HTML STRICT LEVEL 1//",
3177            "-//IETF//DTD HTML LEVEL 2//EN//2.0" => 1,            "-//IETF//DTD HTML STRICT LEVEL 2//",
3178            "-//IETF//DTD HTML LEVEL 3//EN" => 1,            "-//IETF//DTD HTML STRICT LEVEL 3//",
3179            "-//IETF//DTD HTML LEVEL 3//EN//3.0" => 1,            "-//IETF//DTD HTML STRICT//",
3180            "-//IETF//DTD HTML STRICT LEVEL 0//EN" => 1,            "-//IETF//DTD HTML//",
3181            "-//IETF//DTD HTML STRICT LEVEL 0//EN//2.0" => 1,            "-//METRIUS//DTD METRIUS PRESENTATIONAL//",
3182            "-//IETF//DTD HTML STRICT LEVEL 1//EN" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML STRICT//",
3183            "-//IETF//DTD HTML STRICT LEVEL 1//EN//2.0" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML//",
3184            "-//IETF//DTD HTML STRICT LEVEL 2//EN" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 TABLES//",
3185            "-//IETF//DTD HTML STRICT LEVEL 2//EN//2.0" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML STRICT//",
3186            "-//IETF//DTD HTML STRICT LEVEL 3//EN" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML//",
3187            "-//IETF//DTD HTML STRICT LEVEL 3//EN//3.0" => 1,            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 TABLES//",
3188            "-//IETF//DTD HTML STRICT//EN" => 1,            "-//NETSCAPE COMM. CORP.//DTD HTML//",
3189            "-//IETF//DTD HTML STRICT//EN//2.0" => 1,            "-//NETSCAPE COMM. CORP.//DTD STRICT HTML//",
3190            "-//IETF//DTD HTML STRICT//EN//3.0" => 1,            "-//O'REILLY AND ASSOCIATES//DTD HTML 2.0//",
3191            "-//IETF//DTD HTML//EN" => 1,            "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED 1.0//",
3192            "-//IETF//DTD HTML//EN//2.0" => 1,            "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED RELAXED 1.0//",
3193            "-//IETF//DTD HTML//EN//3.0" => 1,            "-//SOFTQUAD SOFTWARE//DTD HOTMETAL PRO 6.0::19990601::EXTENSIONS TO HTML 4.0//",
3194            "-//METRIUS//DTD METRIUS PRESENTATIONAL//EN" => 1,            "-//SOFTQUAD//DTD HOTMETAL PRO 4.0::19971010::EXTENSIONS TO HTML 4.0//",
3195            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML STRICT//EN" => 1,            "-//SPYGLASS//DTD HTML 2.0 EXTENDED//",
3196            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML//EN" => 1,            "-//SQ//DTD HTML 2.0 HOTMETAL + EXTENSIONS//",
3197            "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 TABLES//EN" => 1,            "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA HTML//",
3198            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML STRICT//EN" => 1,            "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA STRICT HTML//",
3199            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML//EN" => 1,            "-//W3C//DTD HTML 3 1995-03-24//",
3200            "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 TABLES//EN" => 1,            "-//W3C//DTD HTML 3.2 DRAFT//",
3201            "-//NETSCAPE COMM. CORP.//DTD HTML//EN" => 1,            "-//W3C//DTD HTML 3.2 FINAL//",
3202            "-//NETSCAPE COMM. CORP.//DTD STRICT HTML//EN" => 1,            "-//W3C//DTD HTML 3.2//",
3203            "-//O'REILLY AND ASSOCIATES//DTD HTML 2.0//EN" => 1,            "-//W3C//DTD HTML 3.2S DRAFT//",
3204            "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED 1.0//EN" => 1,            "-//W3C//DTD HTML 4.0 FRAMESET//",
3205            "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED RELAXED 1.0//EN" => 1,            "-//W3C//DTD HTML 4.0 TRANSITIONAL//",
3206            "-//SOFTQUAD SOFTWARE//DTD HOTMETAL PRO 6.0::19990601::EXTENSIONS TO HTML 4.0//EN" => 1,            "-//W3C//DTD HTML EXPERIMETNAL 19960712//",
3207            "-//SOFTQUAD//DTD HOTMETAL PRO 4.0::19971010::EXTENSIONS TO HTML 4.0//EN" => 1,            "-//W3C//DTD HTML EXPERIMENTAL 970421//",
3208            "-//SPYGLASS//DTD HTML 2.0 EXTENDED//EN" => 1,            "-//W3C//DTD W3 HTML//",
3209            "-//SQ//DTD HTML 2.0 HOTMETAL + EXTENSIONS//EN" => 1,            "-//W3O//DTD W3 HTML 3.0//",
3210            "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA HTML//EN" => 1,            "-//WEBTECHS//DTD MOZILLA HTML 2.0//",
3211            "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA STRICT HTML//EN" => 1,            "-//WEBTECHS//DTD MOZILLA HTML//",
3212            "-//W3C//DTD HTML 3 1995-03-24//EN" => 1,          ]; # $prefix
3213            "-//W3C//DTD HTML 3.2 DRAFT//EN" => 1,          my $match;
3214            "-//W3C//DTD HTML 3.2 FINAL//EN" => 1,          for (@$prefix) {
3215            "-//W3C//DTD HTML 3.2//EN" => 1,            if (substr ($prefix, 0, length $_) eq $_) {
3216            "-//W3C//DTD HTML 3.2S DRAFT//EN" => 1,              $match = 1;
3217            "-//W3C//DTD HTML 4.0 FRAMESET//EN" => 1,              last;
3218            "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN" => 1,            }
3219            "-//W3C//DTD HTML EXPERIMETNAL 19960712//EN" => 1,          }
3220            "-//W3C//DTD HTML EXPERIMENTAL 970421//EN" => 1,          if ($match or
3221            "-//W3C//DTD W3 HTML//EN" => 1,              $pubid eq "-//W3O//DTD W3 HTML STRICT 3.0//EN//" or
3222            "-//W3O//DTD W3 HTML 3.0//EN" => 1,              $pubid eq "-/W3C/DTD HTML 4.0 TRANSITIONAL/EN" or
3223            "-//W3O//DTD W3 HTML 3.0//EN//" => 1,              $pubid eq "HTML") {
           "-//W3O//DTD W3 HTML STRICT 3.0//EN//" => 1,  
           "-//WEBTECHS//DTD MOZILLA HTML 2.0//EN" => 1,  
           "-//WEBTECHS//DTD MOZILLA HTML//EN" => 1,  
           "-/W3C/DTD HTML 4.0 TRANSITIONAL/EN" => 1,  
           "HTML" => 1,  
         }->{$pubid}) {  
3224            !!!cp ('t5');            !!!cp ('t5');
3225            $self->{document}->manakai_compat_mode ('quirks');            $self->{document}->manakai_compat_mode ('quirks');
3226          } elsif ($pubid eq "-//W3C//DTD HTML 4.01 FRAMESET//EN" or          } elsif ($pubid =~ m[^-//W3C//DTD HTML 4.01 FRAMESET//] or
3227                   $pubid eq "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN") {                   $pubid =~ m[^-//W3C//DTD HTML 4.01 TRANSITIONAL//]) {
3228            if (defined $token->{system_identifier}) {            if (defined $token->{system_identifier}) {
3229              !!!cp ('t6');              !!!cp ('t6');
3230              $self->{document}->manakai_compat_mode ('quirks');              $self->{document}->manakai_compat_mode ('quirks');
# Line 2900  sub _tree_construction_initial ($) { Line 3232  sub _tree_construction_initial ($) {
3232              !!!cp ('t7');              !!!cp ('t7');
3233              $self->{document}->manakai_compat_mode ('limited quirks');              $self->{document}->manakai_compat_mode ('limited quirks');
3234            }            }
3235          } elsif ($pubid eq "-//W3C//DTD XHTML 1.0 FRAMESET//EN" or          } elsif ($pubid =~ m[^-//W3C//DTD XHTML 1.0 FRAMESET//] or
3236                   $pubid eq "-//W3C//DTD XHTML 1.0 TRANSITIONAL//EN") {                   $pubid =~ m[^-//W3C//DTD XHTML 1.0 TRANSITIONAL//]) {
3237            !!!cp ('t8');            !!!cp ('t8');
3238            $self->{document}->manakai_compat_mode ('limited quirks');            $self->{document}->manakai_compat_mode ('limited quirks');
3239          } else {          } else {
# Line 2914  sub _tree_construction_initial ($) { Line 3246  sub _tree_construction_initial ($) {
3246          my $sysid = $token->{system_identifier};          my $sysid = $token->{system_identifier};
3247          $sysid =~ tr/A-Z/a-z/;          $sysid =~ tr/A-Z/a-z/;
3248          if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {          if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
3249            ## TODO: Check the spec: PUBLIC "(limited quirks)" "(quirks)"            ## NOTE: Ensure that |PUBLIC "(limited quirks)" "(quirks)"| is
3250              ## marked as quirks.
3251            $self->{document}->manakai_compat_mode ('quirks');            $self->{document}->manakai_compat_mode ('quirks');
3252            !!!cp ('t11');            !!!cp ('t11');
3253          } else {          } else {
# Line 3086  sub _reset_insertion_mode ($) { Line 3419  sub _reset_insertion_mode ($) {
3419        if ($self->{open_elements}->[0]->[0] eq $node->[0]) {        if ($self->{open_elements}->[0]->[0] eq $node->[0]) {
3420          $last = 1;          $last = 1;
3421          if (defined $self->{inner_html_node}) {          if (defined $self->{inner_html_node}) {
3422            if ($self->{inner_html_node}->[1] & TABLE_CELL_EL) {            !!!cp ('t28');
3423              !!!cp ('t27');            $node = $self->{inner_html_node};
3424              #          } else {
3425            } else {            die "_reset_insertion_mode: t27";
             !!!cp ('t28');  
             $node = $self->{inner_html_node};  
           }  
3426          }          }
3427        }        }
3428              
3429      ## Step 4..14        ## Step 4..14
3430      my $new_mode;        my $new_mode;
3431      if ($node->[1] & FOREIGN_EL) {        if ($node->[1] & FOREIGN_EL) {
3432        ## NOTE: Strictly spaking, the line below only applies to MathML and          !!!cp ('t28.1');
3433        ## SVG elements.  Currently the HTML syntax supports only MathML and          ## NOTE: Strictly spaking, the line below only applies to MathML and
3434        ## SVG elements as foreigners.          ## SVG elements.  Currently the HTML syntax supports only MathML and
3435        $new_mode = $self->{insertion_mode} | IN_FOREIGN_CONTENT_IM;          ## SVG elements as foreigners.
3436        ## ISSUE: What is set as the secondary insertion mode?          $new_mode = IN_BODY_IM | IN_FOREIGN_CONTENT_IM;
3437      } else {        } elsif ($node->[1] & TABLE_CELL_EL) {
3438        $new_mode = {          if ($last) {
3439              !!!cp ('t28.2');
3440              #
3441            } else {
3442              !!!cp ('t28.3');
3443              $new_mode = IN_CELL_IM;
3444            }
3445          } else {
3446            !!!cp ('t28.4');
3447            $new_mode = {
3448                        select => IN_SELECT_IM,                        select => IN_SELECT_IM,
3449                        ## NOTE: |option| and |optgroup| do not set                        ## NOTE: |option| and |optgroup| do not set
3450                        ## insertion mode to "in select" by themselves.                        ## insertion mode to "in select" by themselves.
                       td => IN_CELL_IM,  
                       th => IN_CELL_IM,  
3451                        tr => IN_ROW_IM,                        tr => IN_ROW_IM,
3452                        tbody => IN_TABLE_BODY_IM,                        tbody => IN_TABLE_BODY_IM,
3453                        thead => IN_TABLE_BODY_IM,                        thead => IN_TABLE_BODY_IM,
# Line 3122  sub _reset_insertion_mode ($) { Line 3459  sub _reset_insertion_mode ($) {
3459                        body => IN_BODY_IM,                        body => IN_BODY_IM,
3460                        frameset => IN_FRAMESET_IM,                        frameset => IN_FRAMESET_IM,
3461                       }->{$node->[0]->manakai_local_name};                       }->{$node->[0]->manakai_local_name};
3462      }        }
3463      $self->{insertion_mode} = $new_mode and return if defined $new_mode;        $self->{insertion_mode} = $new_mode and return if defined $new_mode;
3464                
3465        ## Step 15        ## Step 15
3466        if ($node->[1] & HTML_EL) {        if ($node->[1] & HTML_EL) {
# Line 3690  sub _tree_construction_main ($) { Line 4027  sub _tree_construction_main ($) {
4027          !!!next-token;          !!!next-token;
4028          next B;          next B;
4029        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
4030          if ($self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL or          if ((not {mglyph => 1, malignmark => 1}->{$token->{tag_name}} and
4031                 $self->{open_elements}->[-1]->[1] & FOREIGN_FLOW_CONTENT_EL) or
4032              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or              not ($self->{open_elements}->[-1]->[1] & FOREIGN_EL) or
4033              ($token->{tag_name} eq 'svg' and              ($token->{tag_name} eq 'svg' and
4034               $self->{open_elements}->[-1]->[1] & MML_AXML_EL)) {               $self->{open_elements}->[-1]->[1] & MML_AXML_EL)) {
# Line 3698  sub _tree_construction_main ($) { Line 4036  sub _tree_construction_main ($) {
4036            !!!cp ('t87.2');            !!!cp ('t87.2');
4037            #            #
4038          } elsif ({          } elsif ({
4039    ## TODO:                    b => 1, big => 1, blockquote => 1, body => 1, br => 1,
4040                      center => 1, code => 1, dd => 1, div => 1, dl => 1, dt => 1,
4041                      em => 1, embed => 1, font => 1, h1 => 1, h2 => 1, h3 => 1,
4042                      h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, i => 1,
4043                      img => 1, li => 1, listing => 1, menu => 1, meta => 1,
4044                      nobr => 1, ol => 1, p => 1, pre => 1, ruby => 1, s => 1,
4045                      small => 1, span => 1, strong => 1, strike => 1, sub => 1,
4046                      sup => 1, table => 1, tt => 1, u => 1, ul => 1, var => 1,
4047                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}}) {
4048            !!!cp ('t87.2');            !!!cp ('t87.2');
4049            !!!parse-error (type => 'not closed',            !!!parse-error (type => 'not closed',
# Line 3709  sub _tree_construction_main ($) { Line 4054  sub _tree_construction_main ($) {
4054            pop @{$self->{open_elements}}            pop @{$self->{open_elements}}
4055                while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;                while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;
4056    
4057            $self->{insertion_mode} &= ~ $self->{insertion_mode};            $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;
4058            ## Reprocess.            ## Reprocess.
4059            next B;            next B;
4060          } else {          } else {
4061            ## TODO: case fixup            my $nsuri = $self->{open_elements}->[-1]->[0]->namespace_uri;
4062              my $tag_name = $token->{tag_name};
4063              if ($nsuri eq $SVG_NS) {
4064                $tag_name = {
4065                   altglyph => 'altGlyph',
4066                   altglyphdef => 'altGlyphDef',
4067                   altglyphitem => 'altGlyphItem',
4068                   animatecolor => 'animateColor',
4069                   animatemotion => 'animateMotion',
4070                   animatetransform => 'animateTransform',
4071                   clippath => 'clipPath',
4072                   feblend => 'feBlend',
4073                   fecolormatrix => 'feColorMatrix',
4074                   fecomponenttransfer => 'feComponentTransfer',
4075                   fecomposite => 'feComposite',
4076                   feconvolvematrix => 'feConvolveMatrix',
4077                   fediffuselighting => 'feDiffuseLighting',
4078                   fedisplacementmap => 'feDisplacementMap',
4079                   fedistantlight => 'feDistantLight',
4080                   feflood => 'feFlood',
4081                   fefunca => 'feFuncA',
4082                   fefuncb => 'feFuncB',
4083                   fefuncg => 'feFuncG',
4084                   fefuncr => 'feFuncR',
4085                   fegaussianblur => 'feGaussianBlur',
4086                   feimage => 'feImage',
4087                   femerge => 'feMerge',
4088                   femergenode => 'feMergeNode',
4089                   femorphology => 'feMorphology',
4090                   feoffset => 'feOffset',
4091                   fepointlight => 'fePointLight',
4092                   fespecularlighting => 'feSpecularLighting',
4093                   fespotlight => 'feSpotLight',
4094                   fetile => 'feTile',
4095                   feturbulence => 'feTurbulence',
4096                   foreignobject => 'foreignObject',
4097                   glyphref => 'glyphRef',
4098                   lineargradient => 'linearGradient',
4099                   radialgradient => 'radialGradient',
4100                   #solidcolor => 'solidColor', ## NOTE: Commented in spec (SVG1.2)
4101                   textpath => 'textPath',  
4102                }->{$tag_name} || $tag_name;
4103              }
4104    
4105              ## "adjust SVG attributes" (SVG only) - done in insert-element-f
4106    
4107            !!!insert-element-f ($self->{open_elements}->[-1]->[0]->namespace_uri, $token);            ## "adjust foreign attributes" - done in insert-element-f
4108    
4109              !!!insert-element-f ($nsuri, $tag_name, $token->{attributes}, $token);
4110    
4111            if ($self->{self_closing}) {            if ($self->{self_closing}) {
4112              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 3732  sub _tree_construction_main ($) { Line 4123  sub _tree_construction_main ($) {
4123          !!!cp ('t87.5');          !!!cp ('t87.5');
4124          #          #
4125        } elsif ($token->{type} == END_OF_FILE_TOKEN) {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
         ## NOTE: "using the rules for secondary insertion mode" then "continue"  
4126          !!!cp ('t87.6');          !!!cp ('t87.6');
4127          #          !!!parse-error (type => 'not closed',
4128          ## TODO: ...                          value => $self->{open_elements}->[-1]->[0]
4129                                ->manakai_local_name,
4130                            token => $token);
4131    
4132            pop @{$self->{open_elements}}
4133                while $self->{open_elements}->[-1]->[1] & FOREIGN_EL;
4134    
4135            $self->{insertion_mode} &= ~ IN_FOREIGN_CONTENT_IM;
4136            ## Reprocess.
4137            next B;
4138        } else {        } else {
4139          die "$0: $token->{type}: Unknown token type";                  die "$0: $token->{type}: Unknown token type";        
4140        }        }
# Line 3812  sub _tree_construction_main ($) { Line 4211  sub _tree_construction_main ($) {
4211              !!!next-token;              !!!next-token;
4212              next B;              next B;
4213            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {            } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
4214              !!!cp ('t94');              !!!cp ('t93.2');
4215              #              !!!parse-error (type => 'after head:head', token => $token); ## TODO: error type
4216                ## Ignore the token
4217                !!!nack ('t93.3');
4218                !!!next-token;
4219                next B;
4220            } else {            } else {
4221              !!!cp ('t95');              !!!cp ('t95');
4222              !!!parse-error (type => 'in head:head', token => $token); # or in head noscript              !!!parse-error (type => 'in head:head', token => $token); # or in head noscript
# Line 3896  sub _tree_construction_main ($) { Line 4299  sub _tree_construction_main ($) {
4299                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
4300    
4301                unless ($self->{confident}) {                unless ($self->{confident}) {
4302                  if ($token->{attributes}->{charset}) { ## TODO: And if supported                  if ($token->{attributes}->{charset}) {
4303                    !!!cp ('t106');                    !!!cp ('t106');
4304                      ## NOTE: Whether the encoding is supported or not is handled
4305                      ## in the {change_encoding} callback.
4306                    $self->{change_encoding}                    $self->{change_encoding}
4307                        ->($self, $token->{attributes}->{charset}->{value},                        ->($self, $token->{attributes}->{charset}->{value},
4308                           $token);                           $token);
# Line 3907  sub _tree_construction_main ($) { Line 4312  sub _tree_construction_main ($) {
4312                                             $token->{attributes}->{charset}                                             $token->{attributes}->{charset}
4313                                                 ->{has_reference});                                                 ->{has_reference});
4314                  } elsif ($token->{attributes}->{content}) {                  } elsif ($token->{attributes}->{content}) {
                   ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.  
4315                    if ($token->{attributes}->{content}->{value}                    if ($token->{attributes}->{content}->{value}
4316                        =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]                        =~ /[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
4317                            [\x09-\x0D\x20]*=                            [\x09-\x0D\x20]*=
4318                            [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|                            [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
4319                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20\x3B]*))/x) {
4320                      !!!cp ('t107');                      !!!cp ('t107');
4321                        ## NOTE: Whether the encoding is supported or not is handled
4322                        ## in the {change_encoding} callback.
4323                      $self->{change_encoding}                      $self->{change_encoding}
4324                          ->($self, defined $1 ? $1 : defined $2 ? $2 : $3,                          ->($self, defined $1 ? $1 : defined $2 ? $2 : $3,
4325                             $token);                             $token);
# Line 3972  sub _tree_construction_main ($) { Line 4378  sub _tree_construction_main ($) {
4378                pop @{$self->{open_elements}} # <head>                pop @{$self->{open_elements}} # <head>
4379                    if $self->{insertion_mode} == AFTER_HEAD_IM;                    if $self->{insertion_mode} == AFTER_HEAD_IM;
4380                next B;                next B;
4381              } elsif ($token->{tag_name} eq 'style') {              } elsif ($token->{tag_name} eq 'style' or
4382                         $token->{tag_name} eq 'noframes') {
4383                ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and                ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
4384                ## insertion mode IN_HEAD_IM)                ## insertion mode IN_HEAD_IM)
4385                ## NOTE: There is a "as if in head" code clone.                ## NOTE: There is a "as if in head" code clone.
# Line 4132  sub _tree_construction_main ($) { Line 4539  sub _tree_construction_main ($) {
4539                  $self->{insertion_mode} = AFTER_HEAD_IM;                  $self->{insertion_mode} = AFTER_HEAD_IM;
4540                  !!!next-token;                  !!!next-token;
4541                  next B;                  next B;
4542                  } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
4543                    !!!cp ('t134.1');
4544                    !!!parse-error (type => 'unmatched end tag:head', token => $token);
4545                    ## Ignore the token
4546                    !!!next-token;
4547                    next B;
4548                } else {                } else {
4549                  !!!cp ('t135');                  die "$0: $self->{insertion_mode}: Unknown insertion mode";
                 #  
4550                }                }
4551              } elsif ($token->{tag_name} eq 'noscript') {              } elsif ($token->{tag_name} eq 'noscript') {
4552                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
# Line 4143  sub _tree_construction_main ($) { Line 4555  sub _tree_construction_main ($) {
4555                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
4556                  !!!next-token;                  !!!next-token;
4557                  next B;                  next B;
4558                } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {                } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM or
4559                           $self->{insertion_mode} == AFTER_HEAD_IM) {
4560                  !!!cp ('t137');                  !!!cp ('t137');
4561                  !!!parse-error (type => 'unmatched end tag:noscript', token => $token);                  !!!parse-error (type => 'unmatched end tag:noscript', token => $token);
4562                  ## Ignore the token ## ISSUE: An issue in the spec.                  ## Ignore the token ## ISSUE: An issue in the spec.
# Line 4156  sub _tree_construction_main ($) { Line 4569  sub _tree_construction_main ($) {
4569              } elsif ({              } elsif ({
4570                        body => 1, html => 1,                        body => 1, html => 1,
4571                       }->{$token->{tag_name}}) {                       }->{$token->{tag_name}}) {
4572                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {                if ($self->{insertion_mode} == BEFORE_HEAD_IM or
4573                  !!!cp ('t139');                    $self->{insertion_mode} == IN_HEAD_IM or
4574                  ## As if <head>                    $self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
                 !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);  
                 $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});  
                 push @{$self->{open_elements}},  
                     [$self->{head_element}, $el_category->{head}];  
   
                 $self->{insertion_mode} = IN_HEAD_IM;  
                 ## Reprocess in the "in head" insertion mode...  
               } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {  
4575                  !!!cp ('t140');                  !!!cp ('t140');
4576                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4577                  ## Ignore the token                  ## Ignore the token
4578                  !!!next-token;                  !!!next-token;
4579                  next B;                  next B;
4580                  } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
4581                    !!!cp ('t140.1');
4582                    !!!parse-error (type => 'unmatched end tag:' . $token->{tag_name}, token => $token);
4583                    ## Ignore the token
4584                    !!!next-token;
4585                    next B;
4586                } else {                } else {
4587                  !!!cp ('t141');                  die "$0: $self->{insertion_mode}: Unknown insertion mode";
4588                }                }
4589                              } elsif ($token->{tag_name} eq 'p') {
4590                #                !!!cp ('t142');
4591              } elsif ({                !!!parse-error (type => 'unmatched end tag:p', token => $token);
4592                        p => 1, br => 1,                ## Ignore the token
4593                       }->{$token->{tag_name}}) {                !!!next-token;
4594                  next B;
4595                } elsif ($token->{tag_name} eq 'br') {
4596                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
4597                  !!!cp ('t142');                  !!!cp ('t142.2');
4598                  ## As if <head>                  ## (before head) as if <head>, (in head) as if </head>
4599                  !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);                  !!!create-element ($self->{head_element}, $HTML_NS, 'head',, $token);
4600                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
4601                  push @{$self->{open_elements}},                  $self->{insertion_mode} = AFTER_HEAD_IM;
4602                      [$self->{head_element}, $el_category->{head}];    
4603                    ## Reprocess in the "after head" insertion mode...
4604                  } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
4605                    !!!cp ('t143.2');
4606                    ## As if </head>
4607                    pop @{$self->{open_elements}};
4608                    $self->{insertion_mode} = AFTER_HEAD_IM;
4609      
4610                    ## Reprocess in the "after head" insertion mode...
4611                  } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
4612                    !!!cp ('t143.3');
4613                    ## ISSUE: Two parse errors for <head><noscript></br>
4614                    !!!parse-error (type => 'unmatched end tag:br', token => $token);
4615                    ## As if </noscript>
4616                    pop @{$self->{open_elements}};
4617                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
4618    
4619                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
4620                } else {                  ## As if </head>
4621                  !!!cp ('t143');                  pop @{$self->{open_elements}};
4622                }                  $self->{insertion_mode} = AFTER_HEAD_IM;
4623    
4624                #                  ## Reprocess in the "after head" insertion mode...
4625              } else {                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
4626                if ($self->{insertion_mode} == AFTER_HEAD_IM) {                  !!!cp ('t143.4');
                 !!!cp ('t144');  
4627                  #                  #
4628                } else {                } else {
4629                  !!!cp ('t145');                  die "$0: $self->{insertion_mode}: Unknown insertion mode";
                 !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);  
                 ## Ignore the token  
                 !!!next-token;  
                 next B;  
4630                }                }
4631    
4632                  ## ISSUE: does not agree with IE7 - it doesn't ignore </br>.
4633                  !!!parse-error (type => 'unmatched end tag:br', token => $token);
4634                  ## Ignore the token
4635                  !!!next-token;
4636                  next B;
4637                } else {
4638                  !!!cp ('t145');
4639                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4640                  ## Ignore the token
4641                  !!!next-token;
4642                  next B;
4643              }              }
4644    
4645              if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {              if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
# Line 4959  sub _tree_construction_main ($) { Line 5393  sub _tree_construction_main ($) {
5393                  next B;                  next B;
5394                }                }
5395                                
5396  ## TODO: Followings are removed from the latest spec.  ## TODO: Followings are removed from the latest spec.
5397                ## generate implied end tags                ## generate implied end tags
5398                while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {                while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
5399                  !!!cp ('t224');                  !!!cp ('t224');
# Line 5457  sub _tree_construction_main ($) { Line 5891  sub _tree_construction_main ($) {
5891            !!!nack ('t277.1');            !!!nack ('t277.1');
5892            !!!next-token;            !!!next-token;
5893            next B;            next B;
5894          } elsif ($token->{tag_name} eq 'select' or          } elsif ({
5895                   $token->{tag_name} eq 'input' or                     select => 1, input => 1, textarea => 1,
5896                     }->{$token->{tag_name}} or
5897                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and
5898                    {                    {
5899                     caption => 1, table => 1,                     caption => 1, table => 1,
# Line 5815  sub _tree_construction_main ($) { Line 6250  sub _tree_construction_main ($) {
6250            next B;            next B;
6251          } elsif ($token->{tag_name} eq 'noframes') {          } elsif ($token->{tag_name} eq 'noframes') {
6252            !!!cp ('t320');            !!!cp ('t320');
6253            ## NOTE: As if in body.            ## NOTE: As if in head.
6254            $parse_rcdata->(CDATA_CONTENT_MODEL);            $parse_rcdata->(CDATA_CONTENT_MODEL);
6255            next B;            next B;
6256          } else {          } else {
# Line 5930  sub _tree_construction_main ($) { Line 6365  sub _tree_construction_main ($) {
6365          my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.          my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6366    
6367          unless ($self->{confident}) {          unless ($self->{confident}) {
6368            if ($token->{attributes}->{charset}) { ## TODO: And if supported            if ($token->{attributes}->{charset}) {
6369              !!!cp ('t335');              !!!cp ('t335');
6370                ## NOTE: Whether the encoding is supported or not is handled
6371                ## in the {change_encoding} callback.
6372              $self->{change_encoding}              $self->{change_encoding}
6373                  ->($self, $token->{attributes}->{charset}->{value}, $token);                  ->($self, $token->{attributes}->{charset}->{value}, $token);
6374                            
# Line 5940  sub _tree_construction_main ($) { Line 6377  sub _tree_construction_main ($) {
6377                                       $token->{attributes}->{charset}                                       $token->{attributes}->{charset}
6378                                           ->{has_reference});                                           ->{has_reference});
6379            } elsif ($token->{attributes}->{content}) {            } elsif ($token->{attributes}->{content}) {
             ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.  
6380              if ($token->{attributes}->{content}->{value}              if ($token->{attributes}->{content}->{value}
6381                  =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]                  =~ /[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
6382                      [\x09-\x0D\x20]*=                      [\x09-\x0D\x20]*=
6383                      [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|                      [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
6384                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20\x3B]*))/x) {
6385                !!!cp ('t336');                !!!cp ('t336');
6386                  ## NOTE: Whether the encoding is supported or not is handled
6387                  ## in the {change_encoding} callback.
6388                $self->{change_encoding}                $self->{change_encoding}
6389                    ->($self, defined $1 ? $1 : defined $2 ? $2 : $3, $token);                    ->($self, defined $1 ? $1 : defined $2 ? $2 : $3, $token);
6390                $meta_el->[0]->get_attribute_node_ns (undef, 'content')                $meta_el->[0]->get_attribute_node_ns (undef, 'content')
# Line 6255  sub _tree_construction_main ($) { Line 6693  sub _tree_construction_main ($) {
6693                  xmp => 1,                  xmp => 1,
6694                  iframe => 1,                  iframe => 1,
6695                  noembed => 1,                  noembed => 1,
6696                  noframes => 1,                  noframes => 1, ## NOTE: This is an "as if in head" code clone.
6697                  noscript => 0, ## TODO: 1 if scripting is enabled                  noscript => 0, ## TODO: 1 if scripting is enabled
6698                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6699          if ($token->{tag_name} eq 'xmp') {          if ($token->{tag_name} eq 'xmp') {
# Line 6277  sub _tree_construction_main ($) { Line 6715  sub _tree_construction_main ($) {
6715            !!!next-token;            !!!next-token;
6716            next B;            next B;
6717          } else {          } else {
6718              !!!ack ('t391.1');
6719    
6720            my $at = $token->{attributes};            my $at = $token->{attributes};
6721            my $form_attrs;            my $form_attrs;
6722            $form_attrs->{action} = $at->{action} if $at->{action};            $form_attrs->{action} = $at->{action} if $at->{action};
# Line 6320  sub _tree_construction_main ($) { Line 6760  sub _tree_construction_main ($) {
6760                           line => $token->{line}, column => $token->{column}},                           line => $token->{line}, column => $token->{column}},
6761                          {type => END_TAG_TOKEN, tag_name => 'form',                          {type => END_TAG_TOKEN, tag_name => 'form',
6762                           line => $token->{line}, column => $token->{column}};                           line => $token->{line}, column => $token->{column}};
           !!!nack ('t391.1'); ## NOTE: Not acknowledged.  
6763            !!!back-token (@tokens);            !!!back-token (@tokens);
6764            !!!next-token;            !!!next-token;
6765            next B;            next B;
# Line 6372  sub _tree_construction_main ($) { Line 6811  sub _tree_construction_main ($) {
6811          }          }
6812          !!!next-token;          !!!next-token;
6813          next B;          next B;
6814          } elsif ($token->{tag_name} eq 'rt' or
6815                   $token->{tag_name} eq 'rp') {
6816            ## has a |ruby| element in scope
6817            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6818              my $node = $self->{open_elements}->[$_];
6819              if ($node->[1] & RUBY_EL) {
6820                !!!cp ('t398.1');
6821                ## generate implied end tags
6822                while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
6823                  !!!cp ('t398.2');
6824                  pop @{$self->{open_elements}};
6825                }
6826                unless ($self->{open_elements}->[-1]->[1] & RUBY_EL) {
6827                  !!!cp ('t398.3');
6828                  !!!parse-error (type => 'not closed',
6829                                  value => $self->{open_elements}->[-1]->[0]
6830                                      ->manakai_local_name,
6831                                  token => $token);
6832                  pop @{$self->{open_elements}}
6833                      while not $self->{open_elements}->[-1]->[1] & RUBY_EL;
6834                }
6835                last INSCOPE;
6836              } elsif ($node->[1] & SCOPING_EL) {
6837                !!!cp ('t398.4');
6838                last INSCOPE;
6839              }
6840            } # INSCOPE
6841    
6842            !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
6843    
6844            !!!nack ('t398.5');
6845            !!!next-token;
6846            redo B;
6847        } elsif ($token->{tag_name} eq 'math' or        } elsif ($token->{tag_name} eq 'math' or
6848                 $token->{tag_name} eq 'svg') {                 $token->{tag_name} eq 'svg') {
6849          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
6850    
6851            ## "adjust SVG attributes" ('svg' only) - done in insert-element-f
6852    
6853            ## "adjust foreign attributes" - done in insert-element-f
6854                    
6855          !!!insert-element-f ($token->{tag_name} eq 'math' ? $MML_NS : $SVG_NS, $token);          !!!insert-element-f ($token->{tag_name} eq 'math' ? $MML_NS : $SVG_NS, $token->{tag_name}, $token->{attributes}, $token);
6856                    
6857          if ($self->{self_closing}) {          if ($self->{self_closing}) {
6858            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
# Line 6556  sub _tree_construction_main ($) { Line 7032  sub _tree_construction_main ($) {
7032          } else {          } else {
7033            ## Step 1. generate implied end tags            ## Step 1. generate implied end tags
7034            while ({            while ({
7035                      ## END_TAG_OPTIONAL_EL
7036                    dd => ($token->{tag_name} ne 'dd'),                    dd => ($token->{tag_name} ne 'dd'),
7037                    dt => ($token->{tag_name} ne 'dt'),                    dt => ($token->{tag_name} ne 'dt'),
7038                    li => ($token->{tag_name} ne 'li'),                    li => ($token->{tag_name} ne 'li'),
7039                    p => 1,                    p => 1,
7040                      rt => 1,
7041                      rp => 1,
7042                   }->{$self->{open_elements}->[-1]->[0]->manakai_local_name}) {                   }->{$self->{open_elements}->[-1]->[0]->manakai_local_name}) {
7043              !!!cp ('t409');              !!!cp ('t409');
7044              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
# Line 6772  sub _tree_construction_main ($) { Line 7251  sub _tree_construction_main ($) {
7251              ## generate implied end tags              ## generate implied end tags
7252              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
7253                !!!cp ('t430');                !!!cp ('t430');
7254                ## ISSUE: Can this case be reached?                ## NOTE: |<ruby><rt></ruby>|.
7255                  ## ISSUE: <ruby><rt></rt> will also take this code path,
7256                  ## which seems wrong.
7257                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
7258                  $node_i++;
7259              }              }
7260                    
7261              ## Step 2              ## Step 2
# Line 6790  sub _tree_construction_main ($) { Line 7272  sub _tree_construction_main ($) {
7272              }              }
7273                            
7274              ## Step 3              ## Step 3
7275              splice @{$self->{open_elements}}, $node_i;              splice @{$self->{open_elements}}, $node_i if $node_i < 0;
7276    
7277              !!!next-token;              !!!next-token;
7278              last S2;              last S2;
# Line 6916  sub set_inner_html ($$$) { Line 7398  sub set_inner_html ($$$) {
7398          !!!cp ('i4');          !!!cp ('i4');
7399          !!!parse-error (type => 'NULL');          !!!parse-error (type => 'NULL');
7400          $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST          $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
7401          } elsif ($self->{next_char} <= 0x0008 or
7402                   (0x000E <= $self->{next_char} and
7403                    $self->{next_char} <= 0x001F) or
7404                   (0x007F <= $self->{next_char} and
7405                    $self->{next_char} <= 0x009F) or
7406                   (0xD800 <= $self->{next_char} and
7407                    $self->{next_char} <= 0xDFFF) or
7408                   (0xFDD0 <= $self->{next_char} and
7409                    $self->{next_char} <= 0xFDDF) or
7410                   {
7411                    0xFFFE => 1, 0xFFFF => 1, 0x1FFFE => 1, 0x1FFFF => 1,
7412                    0x2FFFE => 1, 0x2FFFF => 1, 0x3FFFE => 1, 0x3FFFF => 1,
7413                    0x4FFFE => 1, 0x4FFFF => 1, 0x5FFFE => 1, 0x5FFFF => 1,
7414                    0x6FFFE => 1, 0x6FFFF => 1, 0x7FFFE => 1, 0x7FFFF => 1,
7415                    0x8FFFE => 1, 0x8FFFF => 1, 0x9FFFE => 1, 0x9FFFF => 1,
7416                    0xAFFFE => 1, 0xAFFFF => 1, 0xBFFFE => 1, 0xBFFFF => 1,
7417                    0xCFFFE => 1, 0xCFFFF => 1, 0xDFFFE => 1, 0xDFFFF => 1,
7418                    0xEFFFE => 1, 0xEFFFF => 1, 0xFFFFE => 1, 0xFFFFF => 1,
7419                    0x10FFFE => 1, 0x10FFFF => 1,
7420                   }->{$self->{next_char}}) {
7421            !!!cp ('i4.1');
7422            !!!parse-error (type => 'control char', level => $self->{must_level});
7423    ## TODO: error type documentation
7424        }        }
7425      };      };
7426      $p->{prev_char} = [-1, -1, -1];      $p->{prev_char} = [-1, -1, -1];

Legend:
Removed from v.1.127  
changed lines
  Added in v.1.151

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24