/[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.58 by wakaba, Tue Sep 4 11:19:07 2007 UTC revision 1.63 by wakaba, Sun Nov 11 06:54:36 2007 UTC
# Line 1  Line 1 
1  package Whatpm::HTML;  package Whatpm::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    use Error qw(:try);
5    
6  ## ISSUE:  ## ISSUE:
7  ## var doc = implementation.createDocument (null, null, null);  ## var doc = implementation.createDocument (null, null, null);
# Line 84  my $formatting_category = { Line 85  my $formatting_category = {
85  };  };
86  # $phrasing_category: all other elements  # $phrasing_category: all other elements
87    
88    sub parse_byte_string ($$$$;$) {
89      my $self = ref $_[0] ? shift : shift->new;
90      my $charset = shift;
91      my $bytes_s = ref $_[0] ? $_[0] : \($_[0]);
92      my $s;
93      
94      if (defined $charset) {
95        require Encode;
96        $s = \ (Encode::decode ($charset, $$bytes_s));
97        $self->{input_encoding} = lc $charset; ## TODO: normalize name ## TODO: set $doc->input_encoding
98        $self->{confident} = 1;
99      } else {
100        $s = ref $_[0] ? $_[0] : \($_[0]);
101        $self->{confident} = 0;
102      }
103    
104      $self->{change_encoding} = sub {
105        my $self = shift;
106        my $charset = lc shift;
107        ## TODO: if $charset is supported
108        ## TODO: normalize charset name
109    
110        ## "Change the encoding" algorithm:
111    
112        ## Step 1    
113        if ($charset eq 'utf-16') { ## ISSUE: UTF-16BE -> UTF-8? UTF-16LE -> UTF-8?
114          $charset = 'utf-8';
115        }
116    
117        ## Step 2
118        if (defined $self->{input_encoding} and
119            $self->{input_encoding} eq $charset) {
120          $self->{confident} = 1;
121          return;
122        }
123    
124        !!!parse-error (type => 'charset label detected', level => 'w');
125    
126        ## Step 3
127        # if (can) {
128          ## change the encoding on the fly.
129          #$self->{confident} = 1;
130          #return;
131        # }
132    
133        ## Step 4
134        throw Whatpm::HTML::RestartParser (charset => $charset);
135      }; # $self->{change_encoding}
136    
137      my @args = @_; shift @args; # $s
138      my $return;
139      try {
140        $return = $self->parse_char_string ($s, @args);  
141      } catch Whatpm::HTML::RestartParser with {
142        my $charset = shift->{charset};
143        $s = \ (Encode::decode ($charset, $$bytes_s));    
144        $self->{input_encoding} = $charset; ## TODO: $doc->input_encoding;
145        $self->{confident} = 1;
146        $return = $self->parse_char_string ($s, @args);
147      };
148      return $return;
149    } # parse_byte_string
150    
151    *parse_char_string = \&parse_string;
152    
153  sub parse_string ($$$;$) {  sub parse_string ($$$;$) {
154    my $self = shift->new;    my $self = ref $_[0] ? shift : shift->new;
155    my $s = \$_[0];    my $s = ref $_[0] ? $_[0] : \($_[0]);
156    $self->{document} = $_[1];    $self->{document} = $_[1];
157      @{$self->{document}->child_nodes} = ();
158    
159    ## NOTE: |set_inner_html| copies most of this method's code    ## NOTE: |set_inner_html| copies most of this method's code
160    
161      $self->{confident} = 1 unless exists $self->{confident};
162    
163    my $i = 0;    my $i = 0;
164    my $line = 1;    my $line = 1;
165    my $column = 0;    my $column = 0;
# Line 147  sub new ($) { Line 216  sub new ($) {
216    $self->{parse_error} = sub {    $self->{parse_error} = sub {
217      #      #
218    };    };
219      $self->{change_encoding} = sub {
220        # if ($_[0] is a supported encoding) {
221        #   run "change the encoding" algorithm;
222        #   throw Whatpm::HTML::RestartParser (charset => $new_encoding);
223        # }
224      };
225      $self->{application_cache_selection} = sub {
226        #
227      };
228    return $self;    return $self;
229  } # new  } # new
230    
# Line 263  sub _initialize_tokenizer ($) { Line 341  sub _initialize_tokenizer ($) {
341  ## has completed loading.  If one has, then it MUST be executed  ## has completed loading.  If one has, then it MUST be executed
342  ## and removed from the list.  ## and removed from the list.
343    
344    ## NOTE: HTML5 "Writing HTML documents" section, applied to
345    ## documents and not to user agents and conformance checkers,
346    ## contains some requirements that are not detected by the
347    ## parsing algorithm:
348    ## - Some requirements on character encoding declarations. ## TODO
349    ## - "Elements MUST NOT contain content that their content model disallows."
350    ##   ... Some are parse error, some are not (will be reported by c.c.).
351    ## - Polytheistic slash SHOULD NOT be used. (Applied only to atheists.) ## TODO
352    ## - Text (in elements, attributes, and comments) SHOULD NOT contain
353    ##   control characters other than space characters. ## TODO: (what is control character? C0, C1 and DEL?  Unicode control character?)
354    
355    ## TODO: HTML5 poses authors two SHOULD-level requirements that cannot
356    ## be detected by the HTML5 parsing algorithm:
357    ## - Text,
358    
359  sub _get_next_token ($) {  sub _get_next_token ($) {
360    my $self = shift;    my $self = shift;
361    if (@{$self->{token}}) {    if (@{$self->{token}}) {
# Line 2080  sub _tree_construction_root_element ($) Line 2173  sub _tree_construction_root_element ($)
2173              redo B;              redo B;
2174            }            }
2175          }          }
2176    
2177            $self->{application_cache_selection}->(undef);
2178    
2179            #
2180          } elsif ($token->{type} == START_TAG_TOKEN) {
2181            if ($token->{tag_name} eq 'html' and
2182                $token->{attributes}->{manifest}) { ## ISSUE: Spec spells as "application"
2183              $self->{application_cache_selection}
2184                   ->($token->{attributes}->{manifest}->{value});
2185              ## ISSUE: No relative reference resolution?
2186            } else {
2187              $self->{application_cache_selection}->(undef);
2188            }
2189    
2190            ## ISSUE: There is an issue in the spec
2191          #          #
2192        } elsif ({        } elsif ({
                 START_TAG_TOKEN, 1,  
2193                  END_TAG_TOKEN, 1,                  END_TAG_TOKEN, 1,
2194                  END_OF_FILE_TOKEN, 1,                  END_OF_FILE_TOKEN, 1,
2195                 }->{$token->{type}}) {                 }->{$token->{type}}) {
2196            $self->{application_cache_selection}->(undef);
2197    
2198          ## ISSUE: There is an issue in the spec          ## ISSUE: There is an issue in the spec
2199          #          #
2200        } else {        } else {
2201          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
2202        }        }
2203    
2204        my $root_element; !!!create-element ($root_element, 'html');        my $root_element; !!!create-element ($root_element, 'html');
2205        $self->{document}->append_child ($root_element);        $self->{document}->append_child ($root_element);
2206        push @{$self->{open_elements}}, [$root_element, 'html'];        push @{$self->{open_elements}}, [$root_element, 'html'];
# Line 2750  sub _tree_construction_main ($) { Line 2860  sub _tree_construction_main ($) {
2860                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
2861    
2862                unless ($self->{confident}) {                unless ($self->{confident}) {
                 my $charset;  
2863                  if ($token->{attributes}->{charset}) { ## TODO: And if supported                  if ($token->{attributes}->{charset}) { ## TODO: And if supported
2864                    $charset = $token->{attributes}->{charset}->{value};                    $self->{change_encoding}
2865                  }                        ->($self, $token->{attributes}->{charset}->{value});
2866                  if ($token->{attributes}->{'http-equiv'}) {                  } elsif ($token->{attributes}->{content}) {
2867                    ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.                    ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
2868                    if ($token->{attributes}->{'http-equiv'}->{value}                    if ($token->{attributes}->{content}->{value}
2869                        =~ /\A[^;]*;[\x09-\x0D\x20]*charset[\x09-\x0D\x20]*=                        =~ /\A[^;]*;[\x09-\x0D\x20]*charset[\x09-\x0D\x20]*=
2870                            [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|                            [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
2871                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
2872                      $charset = defined $1 ? $1 : defined $2 ? $2 : $3;                      $self->{change_encoding}
2873                    } ## TODO: And if supported                          ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
2874                      }
2875                  }                  }
                 ## TODO: Change the encoding  
2876                }                }
2877    
               ## TODO: Extracting |charset| from |meta|.  
2878                pop @{$self->{open_elements}}                pop @{$self->{open_elements}}
2879                    if $self->{insertion_mode} == AFTER_HEAD_IM;                    if $self->{insertion_mode} == AFTER_HEAD_IM;
2880                !!!next-token;                !!!next-token;
# Line 4340  sub _tree_construction_main ($) { Line 4448  sub _tree_construction_main ($) {
4448          pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.          pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
4449    
4450          unless ($self->{confident}) {          unless ($self->{confident}) {
           my $charset;  
4451            if ($token->{attributes}->{charset}) { ## TODO: And if supported            if ($token->{attributes}->{charset}) { ## TODO: And if supported
4452              $charset = $token->{attributes}->{charset}->{value};              $self->{change_encoding}
4453            }                  ->($self, $token->{attributes}->{charset}->{value});
4454            if ($token->{attributes}->{'http-equiv'}) {            } elsif ($token->{attributes}->{content}) {
4455              ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.              ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
4456              if ($token->{attributes}->{'http-equiv'}->{value}              if ($token->{attributes}->{content}->{value}
4457                  =~ /\A[^;]*;[\x09-\x0D\x20]*charset[\x09-\x0D\x20]*=                  =~ /\A[^;]*;[\x09-\x0D\x20]*charset[\x09-\x0D\x20]*=
4458                      [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|                      [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
4459                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
4460                $charset = defined $1 ? $1 : defined $2 ? $2 : $3;                $self->{change_encoding}
4461              } ## TODO: And if supported                    ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
4462                }
4463            }            }
           ## TODO: Change the encoding  
4464          }          }
4465    
4466          !!!next-token;          !!!next-token;
# Line 5179  sub set_inner_html ($$$) { Line 5286  sub set_inner_html ($$$) {
5286    my $s = \$_[0];    my $s = \$_[0];
5287    my $onerror = $_[1];    my $onerror = $_[1];
5288    
5289      ## ISSUE: Should {confident} be true?
5290    
5291    my $nt = $node->node_type;    my $nt = $node->node_type;
5292    if ($nt == 9) {    if ($nt == 9) {
5293      # MUST      # MUST
# Line 5331  sub set_inner_html ($$$) { Line 5440  sub set_inner_html ($$$) {
5440    
5441  } # tree construction stage  } # tree construction stage
5442    
5443  sub get_inner_html ($$$) {  package Whatpm::HTML::RestartParser;
5444    my (undef, $node, $on_error) = @_;  push our @ISA, 'Error';
   
   ## Step 1  
   my $s = '';  
   
   my $in_cdata;  
   my $parent = $node;  
   while (defined $parent) {  
     if ($parent->node_type == 1 and  
         $parent->namespace_uri eq 'http://www.w3.org/1999/xhtml' and  
         {  
           style => 1, script => 1, xmp => 1, iframe => 1,  
           noembed => 1, noframes => 1, noscript => 1,  
         }->{$parent->local_name}) { ## TODO: case thingy  
       $in_cdata = 1;  
     }  
     $parent = $parent->parent_node;  
   }  
   
   ## Step 2  
   my @node = @{$node->child_nodes};  
   C: while (@node) {  
     my $child = shift @node;  
     unless (ref $child) {  
       if ($child eq 'cdata-out') {  
         $in_cdata = 0;  
       } else {  
         $s .= $child; # end tag  
       }  
       next C;  
     }  
       
     my $nt = $child->node_type;  
     if ($nt == 1) { # Element  
       my $tag_name = $child->tag_name; ## TODO: manakai_tag_name  
       $s .= '<' . $tag_name;  
       ## NOTE: Non-HTML case:  
       ## <http://permalink.gmane.org/gmane.org.w3c.whatwg.discuss/11191>  
   
       my @attrs = @{$child->attributes}; # sort order MUST be stable  
       for my $attr (@attrs) { # order is implementation dependent  
         my $attr_name = $attr->name; ## TODO: manakai_name  
         $s .= ' ' . $attr_name . '="';  
         my $attr_value = $attr->value;  
         ## escape  
         $attr_value =~ s/&/&amp;/g;  
         $attr_value =~ s/</&lt;/g;  
         $attr_value =~ s/>/&gt;/g;  
         $attr_value =~ s/"/&quot;/g;  
         $s .= $attr_value . '"';  
       }  
       $s .= '>';  
         
       next C if {  
         area => 1, base => 1, basefont => 1, bgsound => 1,  
         br => 1, col => 1, embed => 1, frame => 1, hr => 1,  
         img => 1, input => 1, link => 1, meta => 1, param => 1,  
         spacer => 1, wbr => 1,  
       }->{$tag_name};  
   
       $s .= "\x0A" if $tag_name eq 'pre' or $tag_name eq 'textarea';  
   
       if (not $in_cdata and {  
         style => 1, script => 1, xmp => 1, iframe => 1,  
         noembed => 1, noframes => 1, noscript => 1,  
         plaintext => 1,  
       }->{$tag_name}) {  
         unshift @node, 'cdata-out';  
         $in_cdata = 1;  
       }  
   
       unshift @node, @{$child->child_nodes}, '</' . $tag_name . '>';  
     } elsif ($nt == 3 or $nt == 4) {  
       if ($in_cdata) {  
         $s .= $child->data;  
       } else {  
         my $value = $child->data;  
         $value =~ s/&/&amp;/g;  
         $value =~ s/</&lt;/g;  
         $value =~ s/>/&gt;/g;  
         $value =~ s/"/&quot;/g;  
         $s .= $value;  
       }  
     } elsif ($nt == 8) {  
       $s .= '<!--' . $child->data . '-->';  
     } elsif ($nt == 10) {  
       $s .= '<!DOCTYPE ' . $child->name . '>';  
     } elsif ($nt == 5) { # entrefs  
       push @node, @{$child->child_nodes};  
     } else {  
       $on_error->($child) if defined $on_error;  
     }  
     ## ISSUE: This code does not support PIs.  
   } # C  
     
   ## Step 3  
   return \$s;  
 } # get_inner_html  
5445    
5446  1;  1;
5447  # $Date$  # $Date$

Legend:
Removed from v.1.58  
changed lines
  Added in v.1.63

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24