/[suikacvs]/markup/html/whatpm/What/HTML.pm
Suika

Diff of /markup/html/whatpm/What/HTML.pm

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

revision 1.7 by wakaba, Mon Apr 30 14:12:02 2007 UTC revision 1.9 by wakaba, Tue May 1 07:46:42 2007 UTC
# Line 2  package What::HTML; Line 2  package What::HTML;
2  use strict;  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    
5  ## This is a very, very early version of an HTML parser.  ## This is an early version of an HTML parser.
6    
7  my $permitted_slash_tag_name = {  my $permitted_slash_tag_name = {
8    base => 1,    base => 1,
# Line 302  my $formatting_category = { Line 302  my $formatting_category = {
302  };  };
303  # $phrasing_category: all other elements  # $phrasing_category: all other elements
304    
305    sub parse_string ($$$;$) {
306      my $self = shift->new;
307      my $s = \$_[0];
308      $self->{document} = $_[1];
309    
310      my $i;
311      my $i = 0;
312      $self->{set_next_input_character} = sub {
313        my $self = shift;
314        $self->{next_input_character} = -1 and return if $i >= length $$s;
315        $self->{next_input_character} = ord substr $$s, $i++, 1;
316        
317        if ($self->{next_input_character} == 0x000D) { # CR
318          if ($i >= length $$s) {
319            #
320          } else {
321            my $next_char = ord substr $$s, $i++, 1;
322            if ($next_char == 0x000A) { # LF
323              #
324            } else {
325              push @{$self->{char}}, $next_char;
326            }
327          }
328          $self->{next_input_character} = 0x000A; # LF # MUST
329        } elsif ($self->{next_input_character} > 0x10FFFF) {
330          $self->{next_input_character} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
331        } elsif ($self->{next_input_character} == 0x0000) { # NULL
332          $self->{next_input_character} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
333        }
334      };
335    
336      $self->{parse_error} = $_[2] || sub {
337        warn "Parse error at character $i\n"; ## TODO: Report (line, column) pair
338      };
339    
340      $self->_initialize_tokenizer;
341      $self->_initialize_tree_constructor;
342      $self->_construct_tree;
343      $self->_terminate_tree_constructor;
344    
345      return $self->{document};
346    } # parse_string
347    
348  sub new ($) {  sub new ($) {
349    my $class = shift;    my $class = shift;
350    my $self = bless {}, $class;    my $self = bless {}, $class;
# Line 446  sub _get_next_token ($) { Line 489  sub _get_next_token ($) {
489            ## reconsume            ## reconsume
490            $self->{state} = 'data';            $self->{state} = 'data';
491    
492            return  (type => 'character', data => {'/'});            return  ({type => 'character', data => '<'});
493    
494            redo A;            redo A;
495          }          }
# Line 2081  sub _tokenize_attempt_to_consume_an_enti Line 2124  sub _tokenize_attempt_to_consume_an_enti
2124    
2125  sub _initialize_tree_constructor ($) {  sub _initialize_tree_constructor ($) {
2126    my $self = shift;    my $self = shift;
2127    require What::NanoDOM;    ## NOTE: $self->{document} MUST be specified before this method is called
   $self->{document} = What::NanoDOM::Document->new;  
2128    $self->{document}->strict_error_checking (0);    $self->{document}->strict_error_checking (0);
2129    ## TODO: Turn mutation events off # MUST    ## TODO: Turn mutation events off # MUST
2130    ## TODO: Turn loose Document option (manakai extension) on    ## TODO: Turn loose Document option (manakai extension) on
2131      ## TODO: Mark the Document as an HTML document # MUST
2132  } # _initialize_tree_constructor  } # _initialize_tree_constructor
2133    
2134  sub _terminate_tree_constructor ($) {  sub _terminate_tree_constructor ($) {
# Line 2119  sub _construct_tree ($) { Line 2162  sub _construct_tree ($) {
2162    my $insertion_mode = 'before head';    my $insertion_mode = 'before head';
2163    
2164    my $reconstruct_active_formatting_elements = sub { # MUST    my $reconstruct_active_formatting_elements = sub { # MUST
2165        my $insert = shift;
2166    
2167      ## Step 1      ## Step 1
2168      return unless @$active_formatting_elements;      return unless @$active_formatting_elements;
2169    
# Line 2134  sub _construct_tree ($) { Line 2179  sub _construct_tree ($) {
2179        }        }
2180      }      }
2181            
     ## Step 4  
2182      S4: {      S4: {
2183          ## Step 4
2184        last S4 if $active_formatting_elements->[0]->[0] eq $entry->[0];        last S4 if $active_formatting_elements->[0]->[0] eq $entry->[0];
2185    
2186        ## Step 5        ## Step 5
# Line 2149  sub _construct_tree ($) { Line 2194  sub _construct_tree ($) {
2194          my $in_open_elements;          my $in_open_elements;
2195          OE: for (@$open_elements) {          OE: for (@$open_elements) {
2196            if ($entry->[0] eq $_->[0]) {            if ($entry->[0] eq $_->[0]) {
2197            $in_open_elements = 1;              $in_open_elements = 1;
2198            last OE;              last OE;
2199          }            }
2200          }          }
2201          if ($in_open_elements) {          if ($in_open_elements) {
2202            #            #
# Line 2167  sub _construct_tree ($) { Line 2212  sub _construct_tree ($) {
2212    
2213      S7: {      S7: {
2214        ## Step 8        ## Step 8
2215        my $clone = $entry->[0]->clone_node (0);        my $clone = [$entry->[0]->clone_node (0), $entry->[1]];
2216            
2217        ## Step 9        ## Step 9
2218        $open_elements->[-1]->[0]->append_child ($clone);        $insert->($clone->[0]);
2219        push @$open_elements, [$clone, $entry->[1]];        push @$open_elements, $clone;
2220                
2221        ## Step 10        ## Step 10
2222        $active_formatting_elements->[$i] = $open_elements->[-1];        $active_formatting_elements->[$i] = $open_elements->[-1];
2223          
2224        unless ($i == $#$active_formatting_elements) {        ## Step 11
2225          unless ($clone->[0] eq $active_formatting_elements->[-1]->[0]) {
2226          ## Step 7'          ## Step 7'
2227          $i++;          $i++;
2228          $entry = $active_formatting_elements->[$i];          $entry = $active_formatting_elements->[$i];
# Line 2281  sub _construct_tree ($) { Line 2327  sub _construct_tree ($) {
2327    }; # $style_start_tag    }; # $style_start_tag
2328    
2329    my $script_start_tag = sub {    my $script_start_tag = sub {
2330      my $script_el;      my $script_el;
2331        
2332        $script_el = $self->{document}->create_element_ns        $script_el = $self->{document}->create_element_ns
2333          (q<http://www.w3.org/1999/xhtml>, [undef,  'script']);          (q<http://www.w3.org/1999/xhtml>, [undef,  'script']);
2334            
2335            for my $attr_name (keys %{ $token->{attributes}}) {
2336              $script_el->set_attribute_ns (undef, [undef, $attr_name],
2337                                     $token->{attributes} ->{$attr_name}->{value});
2338            }
2339          
2340      ## TODO: mark as "parser-inserted"      ## TODO: mark as "parser-inserted"
2341    
2342      $self->{content_model_flag} = 'CDATA';      $self->{content_model_flag} = 'CDATA';
# Line 2300  sub _construct_tree ($) { Line 2352  sub _construct_tree ($) {
2352      }      }
2353                                
2354      $self->{content_model_flag} = 'PCDATA';      $self->{content_model_flag} = 'PCDATA';
2355                  
2356      if ($token->{type} eq 'end tag' and      if ($token->{type} eq 'end tag' and
2357          $token->{tag_name} eq 'script') {          $token->{tag_name} eq 'script') {
2358        ## Ignore the token        ## Ignore the token
# Line 2509  sub _construct_tree ($) { Line 2561  sub _construct_tree ($) {
2561      } # FET      } # FET
2562    }; # $formatting_end_tag    }; # $formatting_end_tag
2563    
2564      my $insert_to_current = sub {
2565        $open_elements->[-1]->[0]->append_child (shift);
2566      }; # $insert_to_current
2567    
2568      my $insert_to_foster = sub {
2569                           my $child = shift;
2570                           if ({
2571                                table => 1, tbody => 1, tfoot => 1,
2572                                thead => 1, tr => 1,
2573                               }->{$open_elements->[-1]->[1]}) {
2574                             # MUST
2575                             my $foster_parent_element;
2576                             my $next_sibling;
2577                             OE: for (reverse 0..$#$open_elements) {
2578                               if ($open_elements->[$_]->[1] eq 'table') {
2579                                 my $parent = $open_elements->[$_]->[0]->parent_node;
2580                                 if (defined $parent and $parent->node_type == 1) {
2581                                   $foster_parent_element = $parent;
2582                                   $next_sibling = $open_elements->[$_]->[0];
2583                                 } else {
2584                                   $foster_parent_element
2585                                     = $open_elements->[$_ - 1]->[0];
2586                                 }
2587                                 last OE;
2588                               }
2589                             } # OE
2590                             $foster_parent_element = $open_elements->[0]->[0]
2591                               unless defined $foster_parent_element;
2592                             $foster_parent_element->insert_before
2593                               ($child, $next_sibling);
2594                           } else {
2595                             $open_elements->[-1]->[0]->append_child ($child);
2596                           }
2597      }; # $insert_to_foster
2598    
2599    my $in_body = sub {    my $in_body = sub {
2600      my $insert = shift;      my $insert = shift;
2601      if ($token->{type} eq 'start tag') {      if ($token->{type} eq 'start tag') {
# Line 2519  sub _construct_tree ($) { Line 2606  sub _construct_tree ($) {
2606          $style_start_tag->();          $style_start_tag->();
2607          return;          return;
2608        } elsif ({        } elsif ({
2609                  base => 1, link => 1, meta => 1, title => 1,                  base => 1, link => 1, meta => 1,
2610                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
2611          $self->{parse_error}->();          $self->{parse_error}-> ($token->{tag_name}.' in body');
2612          ## NOTE: This is an "as if in head" code clone          ## NOTE: This is an "as if in head" code clone
2613          my $el;          my $el;
2614                    
# Line 2539  sub _construct_tree ($) { Line 2626  sub _construct_tree ($) {
2626            $insert->($el);            $insert->($el);
2627          }          }
2628                    
2629          ## ISSUE: Issue on magical <base> in the spec          $token = $self->_get_next_token;
2630            return;
2631          } elsif ($token->{tag_name} eq 'title') {
2632            $self->{parse_error}-> ('title in body');
2633            ## NOTE: There is an "as if in head" code clone
2634            my $title_el;
2635            
2636          $title_el = $self->{document}->create_element_ns
2637            (q<http://www.w3.org/1999/xhtml>, [undef,  'title']);
2638        
2639            for my $attr_name (keys %{ $token->{attributes}}) {
2640              $title_el->set_attribute_ns (undef, [undef, $attr_name],
2641                                     $token->{attributes} ->{$attr_name}->{value});
2642            }
2643          
2644            (defined $head_element ? $head_element : $open_elements->[-1]->[0])
2645              ->append_child ($title_el);
2646            $self->{content_model_flag} = 'RCDATA';
2647            
2648            my $text = '';
2649            $token = $self->_get_next_token;
2650            while ($token->{type} eq 'character') {
2651              $text .= $token->{data};
2652              $token = $self->_get_next_token;
2653            }
2654            if (length $text) {
2655              $title_el->manakai_append_text ($text);
2656            }
2657            
2658            $self->{content_model_flag} = 'PCDATA';
2659                    
2660            if ($token->{type} eq 'end tag' and
2661                $token->{tag_name} eq 'title') {
2662              ## Ignore the token
2663            } else {
2664              $self->{parse_error}->();
2665              ## ISSUE: And ignore?
2666            }
2667          $token = $self->_get_next_token;          $token = $self->_get_next_token;
2668          return;          return;
2669        } elsif ($token->{tag_name} eq 'body') {        } elsif ($token->{tag_name} eq 'body') {
# Line 2683  sub _construct_tree ($) { Line 2806  sub _construct_tree ($) {
2806            }            }
2807                        
2808            ## Step 4            ## Step 4
2809            $i++;            $i--;
2810            $node = $open_elements->[$i];            $node = $open_elements->[$i];
2811            redo LI;            redo LI;
2812          } # LI          } # LI
# Line 2741  sub _construct_tree ($) { Line 2864  sub _construct_tree ($) {
2864            }            }
2865                        
2866            ## Step 4            ## Step 4
2867            $i++;            $i--;
2868            $node = $open_elements->[$i];            $node = $open_elements->[$i];
2869            redo LI;            redo LI;
2870          } # LI          } # LI
# Line 2863  sub _construct_tree ($) { Line 2986  sub _construct_tree ($) {
2986          AFE: for my $i (reverse 0..$#$active_formatting_elements) {          AFE: for my $i (reverse 0..$#$active_formatting_elements) {
2987            my $node = $active_formatting_elements->[$i];            my $node = $active_formatting_elements->[$i];
2988            if ($node->[1] eq 'a') {            if ($node->[1] eq 'a') {
2989              $self->{parse_error}->();              $self->{parse_error}-> ('a in a');
2990                            
2991              unshift @{$self->{token}}, $token;              unshift @{$self->{token}}, $token;
2992              $token = {type => 'end tag', tag_name => 'a'};              $token = {type => 'end tag', tag_name => 'a'};
2993              $formatting_end_tag->($token->{tag_name});              $formatting_end_tag->($token->{tag_name});
2994                            
2995              splice @$active_formatting_elements, $i;              AFE2: for (reverse 0..$#$active_formatting_elements) {
2996                  if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
2997                    splice @$active_formatting_elements, $_, 1;
2998                    last AFE2;
2999                  }
3000                } # AFE2
3001              OE: for (reverse 0..$#$open_elements) {              OE: for (reverse 0..$#$open_elements) {
3002                if ($open_elements->[$_]->[0] eq $node->[0]) {                if ($open_elements->[$_]->[0] eq $node->[0]) {
3003                  splice @$open_elements, $_;                  splice @$open_elements, $_, 1;
3004                  last OE;                  last OE;
3005                }                }
3006              } # OE              } # OE
# Line 2882  sub _construct_tree ($) { Line 3010  sub _construct_tree ($) {
3010            }            }
3011          } # AFE          } # AFE
3012                        
3013          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3014    
3015                    
3016      {      {
# Line 2909  sub _construct_tree ($) { Line 3037  sub _construct_tree ($) {
3037                  nobr => 1, s => 1, small => 1, strile => 1,                  nobr => 1, s => 1, small => 1, strile => 1,
3038                  strong => 1, tt => 1, u => 1,                  strong => 1, tt => 1, u => 1,
3039                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
3040          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3041                    
3042                    
3043      {      {
# Line 2948  sub _construct_tree ($) { Line 3076  sub _construct_tree ($) {
3076            }            }
3077          } # INSCOPE          } # INSCOPE
3078                        
3079          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3080                        
3081                    
3082      {      {
# Line 2972  sub _construct_tree ($) { Line 3100  sub _construct_tree ($) {
3100          return;          return;
3101        } elsif ($token->{tag_name} eq 'marquee' or        } elsif ($token->{tag_name} eq 'marquee' or
3102                 $token->{tag_name} eq 'object') {                 $token->{tag_name} eq 'object') {
3103          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3104                    
3105                    
3106      {      {
# Line 2995  sub _construct_tree ($) { Line 3123  sub _construct_tree ($) {
3123          $token = $self->_get_next_token;          $token = $self->_get_next_token;
3124          return;          return;
3125        } elsif ($token->{tag_name} eq 'xmp') {        } elsif ($token->{tag_name} eq 'xmp') {
3126          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3127                    
3128                    
3129      {      {
# Line 3064  sub _construct_tree ($) { Line 3192  sub _construct_tree ($) {
3192            $token->{tag_name} = 'img';            $token->{tag_name} = 'img';
3193          }          }
3194                    
3195          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3196                    
3197                    
3198      {      {
# Line 3122  sub _construct_tree ($) { Line 3250  sub _construct_tree ($) {
3250          $token = $self->_get_next_token;          $token = $self->_get_next_token;
3251          return;          return;
3252        } elsif ($token->{tag_name} eq 'input') {        } elsif ($token->{tag_name} eq 'input') {
3253          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3254                    
3255                    
3256      {      {
# Line 3161  sub _construct_tree ($) { Line 3289  sub _construct_tree ($) {
3289                          {type => 'start tag', tag_name => 'p'},                          {type => 'start tag', tag_name => 'p'},
3290                          {type => 'start tag', tag_name => 'label'},                          {type => 'start tag', tag_name => 'label'},
3291                          {type => 'character',                          {type => 'character',
3292                           data => 'This is a searchable index.  Insert your search keywords here: '}, # SHOULD                           data => 'This is a searchable index. Insert your search keywords here: '}, # SHOULD
3293                          ## TODO: make this configurable                          ## TODO: make this configurable
3294                          {type => 'start tag', tag_name => 'input', attributes => $at},                          {type => 'start tag', tag_name => 'input', attributes => $at},
3295                          #{type => 'character', data => ''}, # SHOULD                          #{type => 'character', data => ''}, # SHOULD
# Line 3222  sub _construct_tree ($) { Line 3350  sub _construct_tree ($) {
3350          }          }
3351          $token = $self->_get_next_token;          $token = $self->_get_next_token;
3352          return;          return;
3353        } elsif ($token->{type} eq 'select') {        } elsif ($token->{tag_name} eq 'select') {
3354          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3355                    
3356                    
3357      {      {
# Line 3258  sub _construct_tree ($) { Line 3386  sub _construct_tree ($) {
3386                    
3387          ## ISSUE: An issue on HTML5 new elements in the spec.          ## ISSUE: An issue on HTML5 new elements in the spec.
3388        } else {        } else {
3389          $reconstruct_active_formatting_elements->();          $reconstruct_active_formatting_elements->($insert_to_current);
3390                    
3391                    
3392      {      {
# Line 3574  sub _construct_tree ($) { Line 3702  sub _construct_tree ($) {
3702          my $top_el = $open_elements->[0]->[0];          my $top_el = $open_elements->[0]->[0];
3703          for my $attr_name (keys %{$token->{attributes}}) {          for my $attr_name (keys %{$token->{attributes}}) {
3704            unless ($top_el->has_attribute_ns (undef, $attr_name)) {            unless ($top_el->has_attribute_ns (undef, $attr_name)) {
3705              $top_el->set_attribute_ns (undef, [undef, $attr_name],              $top_el->set_attribute_ns
3706                                         $token->{attributes}->{value});                (undef, [undef, $attr_name],
3707                   $token->{attributes}->{$attr_name}->{value});
3708            }            }
3709          }          }
3710          $token = $self->_get_next_token;          $token = $self->_get_next_token;
# Line 3690  sub _construct_tree ($) { Line 3819  sub _construct_tree ($) {
3819              redo B;              redo B;
3820            } elsif ($token->{type} eq 'start tag') {            } elsif ($token->{type} eq 'start tag') {
3821              if ($token->{tag_name} eq 'title') {              if ($token->{tag_name} eq 'title') {
3822                my $title_el;                ## NOTE: There is an "as if in head" code clone
3823                  my $title_el;
3824                  
3825        $title_el = $self->{document}->create_element_ns        $title_el = $self->{document}->create_element_ns
3826          (q<http://www.w3.org/1999/xhtml>, [undef,  'title']);          (q<http://www.w3.org/1999/xhtml>, [undef,  'title']);
3827            
3828            for my $attr_name (keys %{ $token->{attributes}}) {
3829              $title_el->set_attribute_ns (undef, [undef, $attr_name],
3830                                     $token->{attributes} ->{$attr_name}->{value});
3831            }
3832          
3833                (defined $head_element ? $head_element : $open_elements->[-1]->[0])                (defined $head_element ? $head_element : $open_elements->[-1]->[0])
3834                  ->append_child ($title_el);                  ->append_child ($title_el);
3835                $self->{content_model_flag} = 'RCDATA';                $self->{content_model_flag} = 'RCDATA';
3836                  
3837                my $text = '';                my $text = '';
3838                $token = $self->_get_next_token;                $token = $self->_get_next_token;
3839                while ($token->{type} eq 'character') {                while ($token->{type} eq 'character') {
# Line 3739  sub _construct_tree ($) { Line 3875  sub _construct_tree ($) {
3875                
3876                (defined $head_element ? $head_element : $open_elements->[-1]->[0])                (defined $head_element ? $head_element : $open_elements->[-1]->[0])
3877                  ->append_child ($el);                  ->append_child ($el);
                 
               ## ISSUE: Issue on magical <base> in the spec  
3878    
3879                $token = $self->_get_next_token;                $token = $self->_get_next_token;
3880                redo B;                redo B;
# Line 3873  sub _construct_tree ($) { Line 4007  sub _construct_tree ($) {
4007          } elsif ($insertion_mode eq 'in body') {          } elsif ($insertion_mode eq 'in body') {
4008            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
4009              ## NOTE: There is a code clone of "character in body".              ## NOTE: There is a code clone of "character in body".
4010              $reconstruct_active_formatting_elements->();              $reconstruct_active_formatting_elements->($insert_to_current);
4011                            
4012              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
4013    
# Line 3886  sub _construct_tree ($) { Line 4020  sub _construct_tree ($) {
4020              $token = $self->_get_next_token;              $token = $self->_get_next_token;
4021              redo B;              redo B;
4022            } else {            } else {
4023              $in_body->(sub {              $in_body->($insert_to_current);
                          $open_elements->[-1]->[0]->append_child (shift);  
                        });  
4024              redo B;              redo B;
4025            }            }
4026          } elsif ($insertion_mode eq 'in table') {          } elsif ($insertion_mode eq 'in table') {
4027            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
4028              $reconstruct_active_formatting_elements->();              ## NOTE: There are "character in table" code clones.
4029                if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
4030              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});                $open_elements->[-1]->[0]->manakai_append_text ($1);
4031                  
4032                  unless (length $token->{data}) {
4033                    $token = $self->_get_next_token;
4034                    redo B;
4035                  }
4036                }
4037    
4038                ## As if in body, but insert into foster parent element
4039                ## ISSUE: Spec says that "whenever a node would be inserted
4040                ## into the current node" while characters might not be
4041                ## result in a new Text node.
4042                $reconstruct_active_formatting_elements->($insert_to_foster);
4043                
4044                if ({
4045                     table => 1, tbody => 1, tfoot => 1,
4046                     thead => 1, tr => 1,
4047                    }->{$open_elements->[-1]->[1]}) {
4048                  # MUST
4049                  my $foster_parent_element;
4050                  my $next_sibling;
4051                  my $prev_sibling;
4052                  OE: for (reverse 0..$#$open_elements) {
4053                    if ($open_elements->[$_]->[1] eq 'table') {
4054                      my $parent = $open_elements->[$_]->[0]->parent_node;
4055                      if (defined $parent and $parent->node_type == 1) {
4056                        $foster_parent_element = $parent;
4057                        $next_sibling = $open_elements->[$_]->[0];
4058                        $prev_sibling = $next_sibling->previous_sibling;
4059                      } else {
4060                        $foster_parent_element = $open_elements->[$_ - 1]->[0];
4061                        $prev_sibling = $foster_parent_element->last_child;
4062                      }
4063                      last OE;
4064                    }
4065                  } # OE
4066                  $foster_parent_element = $open_elements->[0]->[0] and
4067                  $prev_sibling = $foster_parent_element->last_child
4068                    unless defined $foster_parent_element;
4069                  if (defined $prev_sibling and
4070                      $prev_sibling->node_type == 3) {
4071                    $prev_sibling->manakai_append_text ($token->{data});
4072                  } else {
4073                    $foster_parent_element->insert_before
4074                      ($self->{document}->create_text_node ($token->{data}),
4075                       $next_sibling);
4076                  }
4077                } else {
4078                  $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
4079                }
4080                
4081              $token = $self->_get_next_token;              $token = $self->_get_next_token;
4082              redo B;              redo B;
4083            } elsif ($token->{type} eq 'comment') {            } elsif ($token->{type} eq 'comment') {
# Line 4081  sub _construct_tree ($) { Line 4262  sub _construct_tree ($) {
4262              #              #
4263            }            }
4264    
           ## NOTE: There are code clones of "misc in table".  
4265            $self->{parse_error}->();            $self->{parse_error}->();
4266            $in_body->(sub {            $in_body->($insert_to_foster);
                        my $child = shift;  
                        if ({  
                             table => 1, tbody => 1, tfoot => 1,  
                             thead => 1, tr => 1,  
                            }->{$open_elements->[-1]->[1]}) {  
                          # MUST  
                          my $foster_parent_element;  
                          my $next_sibling;  
                          OE: for (reverse 0..$#$open_elements) {  
                            if ($open_elements->[$_]->[1] eq 'table') {  
                              my $parent = $open_elements->[$_]->[0]->parent_node;  
                              if (defined $parent and $parent->node_type == 1) {  
                                $foster_parent_element = $parent;  
                                $next_sibling = $open_elements->[$_]->[0];  
                              } else {  
                                $foster_parent_element  
                                  = $open_elements->[$_ - 1]->[0];  
                              }  
                              last OE;  
                            }  
                          } # OE  
                          $foster_parent_element = $open_elements->[0]->[0]  
                            unless defined $foster_parent_element;  
                          $foster_parent_element->insert_before  
                            ($child, $next_sibling);  
                        } else {  
                          $open_elements->[-1]->[0]->append_child ($child);  
                        }  
                      });  
4267            redo B;            redo B;
4268          } elsif ($insertion_mode eq 'in caption') {          } elsif ($insertion_mode eq 'in caption') {
4269            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
4270              ## NOTE: This is a code clone of "character in body".              ## NOTE: This is a code clone of "character in body".
4271              $reconstruct_active_formatting_elements->();              $reconstruct_active_formatting_elements->($insert_to_current);
4272                            
4273              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
4274    
# Line 4294  sub _construct_tree ($) { Line 4445  sub _construct_tree ($) {
4445              #              #
4446            }            }
4447                                
4448            $in_body->(sub {            $in_body->($insert_to_current);
                        $open_elements->[-1]->[0]->append_child (shift);  
                      });  
4449            redo B;            redo B;
4450          } elsif ($insertion_mode eq 'in column group') {          } elsif ($insertion_mode eq 'in column group') {
4451            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
# Line 4377  sub _construct_tree ($) { Line 4526  sub _construct_tree ($) {
4526            }            }
4527          } elsif ($insertion_mode eq 'in table body') {          } elsif ($insertion_mode eq 'in table body') {
4528            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
4529              ## Copied from 'in table'              ## NOTE: This is a "character in table" code clone.
4530              $reconstruct_active_formatting_elements->();              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
4531                  $open_elements->[-1]->[0]->manakai_append_text ($1);
4532                  
4533                  unless (length $token->{data}) {
4534                    $token = $self->_get_next_token;
4535                    redo B;
4536                  }
4537                }
4538    
4539              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});              ## As if in body, but insert into foster parent element
4540                ## ISSUE: Spec says that "whenever a node would be inserted
4541                ## into the current node" while characters might not be
4542                ## result in a new Text node.
4543                $reconstruct_active_formatting_elements->($insert_to_foster);
4544    
4545                if ({
4546                     table => 1, tbody => 1, tfoot => 1,
4547                     thead => 1, tr => 1,
4548                    }->{$open_elements->[-1]->[1]}) {
4549                  # MUST
4550                  my $foster_parent_element;
4551                  my $next_sibling;
4552                  my $prev_sibling;
4553                  OE: for (reverse 0..$#$open_elements) {
4554                    if ($open_elements->[$_]->[1] eq 'table') {
4555                      my $parent = $open_elements->[$_]->[0]->parent_node;
4556                      if (defined $parent and $parent->node_type == 1) {
4557                        $foster_parent_element = $parent;
4558                        $next_sibling = $open_elements->[$_]->[0];
4559                        $prev_sibling = $next_sibling->previous_sibling;
4560                      } else {
4561                        $foster_parent_element = $open_elements->[$_ - 1]->[0];
4562                        $prev_sibling = $foster_parent_element->last_child;
4563                      }
4564                      last OE;
4565                    }
4566                  } # OE
4567                  $foster_parent_element = $open_elements->[0]->[0] and
4568                  $prev_sibling = $foster_parent_element->last_child
4569                    unless defined $foster_parent_element;
4570                  if (defined $prev_sibling and
4571                      $prev_sibling->node_type == 3) {
4572                    $prev_sibling->manakai_append_text ($token->{data});
4573                  } else {
4574                    $foster_parent_element->insert_before
4575                      ($self->{document}->create_text_node ($token->{data}),
4576                       $next_sibling);
4577                  }
4578                } else {
4579                  $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
4580                }
4581                
4582              $token = $self->_get_next_token;              $token = $self->_get_next_token;
4583              redo B;              redo B;
4584            } elsif ($token->{type} eq 'comment') {            } elsif ($token->{type} eq 'comment') {
# Line 4627  sub _construct_tree ($) { Line 4824  sub _construct_tree ($) {
4824            }            }
4825                        
4826            ## As if in table            ## As if in table
           ## NOTE: This is a code clone of "misc in table".  
4827            $self->{parse_error}->();            $self->{parse_error}->();
4828            $in_body->(sub {            $in_body->($insert_to_foster);
                        my $child = shift;  
                        if ({  
                             table => 1, tbody => 1, tfoot => 1,  
                             thead => 1, tr => 1,  
                            }->{$open_elements->[-1]->[1]}) {  
                          # MUST  
                          my $foster_parent_element;  
                          my $next_sibling;  
                          OE: for (reverse 0..$#$open_elements) {  
                            if ($open_elements->[$_]->[1] eq 'table') {  
                              my $parent = $open_elements->[$_]->[0]->parent_node;  
                              if (defined $parent and $parent->node_type == 1) {  
                                $foster_parent_element = $parent;  
                                $next_sibling = $open_elements->[$_]->[0];  
                              } else {  
                                $foster_parent_element  
                                  = $open_elements->[$_ - 1]->[0];  
                              }  
                              last OE;  
                            }  
                          } # OE  
                          $foster_parent_element = $open_elements->[0]->[0]  
                            unless defined $foster_parent_element;  
                          $foster_parent_element->insert_before  
                            ($child, $next_sibling);  
                        } else {  
                          $open_elements->[-1]->[0]->append_child ($child);  
                        }  
                      });  
4829            redo B;            redo B;
4830          } elsif ($insertion_mode eq 'in row') {          } elsif ($insertion_mode eq 'in row') {
4831            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
4832              ## Copied from 'in table'              ## NOTE: This is a "character in table" code clone.
4833              $reconstruct_active_formatting_elements->();              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
4834                  $open_elements->[-1]->[0]->manakai_append_text ($1);
4835              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});                
4836                  unless (length $token->{data}) {
4837                    $token = $self->_get_next_token;
4838                    redo B;
4839                  }
4840                }
4841    
4842                ## As if in body, but insert into foster parent element
4843                ## ISSUE: Spec says that "whenever a node would be inserted
4844                ## into the current node" while characters might not be
4845                ## result in a new Text node.
4846                $reconstruct_active_formatting_elements->($insert_to_foster);
4847                
4848                if ({
4849                     table => 1, tbody => 1, tfoot => 1,
4850                     thead => 1, tr => 1,
4851                    }->{$open_elements->[-1]->[1]}) {
4852                  # MUST
4853                  my $foster_parent_element;
4854                  my $next_sibling;
4855                  my $prev_sibling;
4856                  OE: for (reverse 0..$#$open_elements) {
4857                    if ($open_elements->[$_]->[1] eq 'table') {
4858                      my $parent = $open_elements->[$_]->[0]->parent_node;
4859                      if (defined $parent and $parent->node_type == 1) {
4860                        $foster_parent_element = $parent;
4861                        $next_sibling = $open_elements->[$_]->[0];
4862                        $prev_sibling = $next_sibling->previous_sibling;
4863                      } else {
4864                        $foster_parent_element = $open_elements->[$_ - 1]->[0];
4865                        $prev_sibling = $foster_parent_element->last_child;
4866                      }
4867                      last OE;
4868                    }
4869                  } # OE
4870                  $foster_parent_element = $open_elements->[0]->[0] and
4871                  $prev_sibling = $foster_parent_element->last_child
4872                    unless defined $foster_parent_element;
4873                  if (defined $prev_sibling and
4874                      $prev_sibling->node_type == 3) {
4875                    $prev_sibling->manakai_append_text ($token->{data});
4876                  } else {
4877                    $foster_parent_element->insert_before
4878                      ($self->{document}->create_text_node ($token->{data}),
4879                       $next_sibling);
4880                  }
4881                } else {
4882                  $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
4883                }
4884                
4885              $token = $self->_get_next_token;              $token = $self->_get_next_token;
4886              redo B;              redo B;
4887            } elsif ($token->{type} eq 'comment') {            } elsif ($token->{type} eq 'comment') {
# Line 4936  sub _construct_tree ($) { Line 5151  sub _construct_tree ($) {
5151            }            }
5152    
5153            ## As if in table            ## As if in table
           ## NOTE: This is a code clone of "misc in table".  
5154            $self->{parse_error}->();            $self->{parse_error}->();
5155            $in_body->(sub {            $in_body->($insert_to_foster);
                        my $child = shift;  
                        if ({  
                             table => 1, tbody => 1, tfoot => 1,  
                             thead => 1, tr => 1,  
                            }->{$open_elements->[-1]->[1]}) {  
                          # MUST  
                          my $foster_parent_element;  
                          my $next_sibling;  
                          OE: for (reverse 0..$#$open_elements) {  
                            if ($open_elements->[$_]->[1] eq 'table') {  
                              my $parent = $open_elements->[$_]->[0]->parent_node;  
                              if (defined $parent and $parent->node_type == 1) {  
                                $foster_parent_element = $parent;  
                                $next_sibling = $open_elements->[$_]->[0];  
                              } else {  
                                $foster_parent_element  
                                  = $open_elements->[$_ - 1]->[0];  
                              }  
                              last OE;  
                            }  
                          } # OE  
                          $foster_parent_element = $open_elements->[0]->[0]  
                            unless defined $foster_parent_element;  
                          $foster_parent_element->insert_before  
                            ($child, $next_sibling);  
                        } else {  
                          $open_elements->[-1]->[0]->append_child ($child);  
                        }  
                      });  
5156            redo B;            redo B;
5157          } elsif ($insertion_mode eq 'in cell') {          } elsif ($insertion_mode eq 'in cell') {
5158            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
5159              ## NOTE: This is a code clone of "character in body".              ## NOTE: This is a code clone of "character in body".
5160              $reconstruct_active_formatting_elements->();              $reconstruct_active_formatting_elements->($insert_to_current);
5161                            
5162              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});              $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
5163    
# Line 5112  sub _construct_tree ($) { Line 5297  sub _construct_tree ($) {
5297              #              #
5298            }            }
5299                        
5300            $in_body->(sub {            $in_body->($insert_to_current);
                        $open_elements->[-1]->[0]->append_child (shift);  
                      });  
5301            redo B;            redo B;
5302          } elsif ($insertion_mode eq 'in select') {          } elsif ($insertion_mode eq 'in select') {
5303            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
# Line 5323  sub _construct_tree ($) { Line 5506  sub _construct_tree ($) {
5506    
5507            $self->{parse_error}->();            $self->{parse_error}->();
5508            ## Ignore the token            ## Ignore the token
5509              $token = $self->_get_next_token;
5510            redo B;            redo B;
5511          } elsif ($insertion_mode eq 'after body') {          } elsif ($insertion_mode eq 'after body') {
5512            if ($token->{type} eq 'character') {            if ($token->{type} eq 'character') {
5513              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
5514                ## As if in body                ## As if in body
5515                $reconstruct_active_formatting_elements->();                $reconstruct_active_formatting_elements->($insert_to_current);
5516                                
5517                $open_elements->[-1]->[0]->manakai_append_text ($token->{data});                $open_elements->[-1]->[0]->manakai_append_text ($token->{data});
5518    
# Line 5358  sub _construct_tree ($) { Line 5542  sub _construct_tree ($) {
5542              #              #
5543            }            }
5544    
5545            $self->{parse_error}->();            $self->{parse_error}-> ('data after body');
5546            $insertion_mode = 'in body';            $insertion_mode = 'in body';
5547            ## reprocess            ## reprocess
5548            redo B;            redo B;
# Line 5420  sub _construct_tree ($) { Line 5604  sub _construct_tree ($) {
5604                $token = $self->_get_next_token;                $token = $self->_get_next_token;
5605                redo B;                redo B;
5606              } elsif ($token->{tag_name} eq 'noframes') {              } elsif ($token->{tag_name} eq 'noframes') {
5607                $in_body->(sub {                $in_body->($insert_to_current);
                            $open_elements->[-1]->[0]->append_child (shift);  
                          });  
5608                redo B;                redo B;
5609              } else {              } else {
5610                #                #
# Line 5474  sub _construct_tree ($) { Line 5656  sub _construct_tree ($) {
5656              redo B;              redo B;
5657            } elsif ($token->{type} eq 'start tag') {            } elsif ($token->{type} eq 'start tag') {
5658              if ($token->{tag_name} eq 'noframes') {              if ($token->{tag_name} eq 'noframes') {
5659                $in_body->(sub {                $in_body->($insert_to_current);
                            $open_elements->[-1]->[0]->append_child (shift);  
                          });  
5660                redo B;                redo B;
5661              } else {              } else {
5662                #                #
# Line 5518  sub _construct_tree ($) { Line 5698  sub _construct_tree ($) {
5698          redo B;          redo B;
5699        } elsif ($token->{type} eq 'character') {        } elsif ($token->{type} eq 'character') {
5700          if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {          if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
5701              my $data = $1;
5702            ## As if in the main phase.            ## As if in the main phase.
5703            ## NOTE: The insertion mode in the main phase            ## NOTE: The insertion mode in the main phase
5704            ## just before the phase has been changed to the trailing            ## just before the phase has been changed to the trailing
5705            ## end phase is either "after body" or "after frameset".            ## end phase is either "after body" or "after frameset".
5706            $reconstruct_active_formatting_elements->()            $reconstruct_active_formatting_elements->($insert_to_current)
5707              if $phase eq 'main';              if $phase eq 'main';
5708                        
5709            $open_elements->[-1]->[0]->manakai_append_text ($token->{data});            $open_elements->[-1]->[0]->manakai_append_text ($data);
5710                        
5711            unless (length $token->{data}) {            unless (length $token->{data}) {
5712              $token = $self->_get_next_token;              $token = $self->_get_next_token;
# Line 5557  sub _construct_tree ($) { Line 5738  sub _construct_tree ($) {
5738    ## TODO: script stuffs    ## TODO: script stuffs
5739  } # _construct_tree  } # _construct_tree
5740    
5741  sub inner_html ($$$) {  sub get_inner_html ($$$) {
5742    my ($class, $node, $on_error) = @_;    my ($class, $node, $on_error) = @_;
5743    
5744    ## Step 1    ## Step 1
# Line 5645  sub inner_html ($$$) { Line 5826  sub inner_html ($$$) {
5826      } elsif ($nt == 5) { # entrefs      } elsif ($nt == 5) { # entrefs
5827        push @node, @{$child->child_nodes};        push @node, @{$child->child_nodes};
5828      } else {      } else {
5829        $on_error->($child);        $on_error->($child) if defined $on_error;
5830      }      }
5831        ## ISSUE: This code does not support PIs.
5832    } # C    } # C
5833        
5834    ## Step 3    ## Step 3
5835    return \$s;    return \$s;
5836  } # inner_html  } # get_inner_html
5837    
5838  1;  1;
5839  # $Date$  # $Date$

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.9

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24