/[suikacvs]/markup/html/whatpm/Whatpm/ContentChecker/HTML.pm
Suika

Diff of /markup/html/whatpm/Whatpm/ContentChecker/HTML.pm

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

revision 1.28 by wakaba, Sun Feb 10 04:09:57 2008 UTC revision 1.29 by wakaba, Sun Feb 17 06:36:28 2008 UTC
# Line 4  require Whatpm::ContentChecker; Line 4  require Whatpm::ContentChecker;
4    
5  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;  my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
6    
7    ## December 2007 HTML5 Classification
8    
9    my $HTMLMetadataContent = {
10      $HTML_NS => {
11        title => 1, base => 1, link => 1, style => 1, script => 1, noscript => 1,
12        'event-source' => 1, command => 1, datatemplate => 1,
13        ## NOTE: A |meta| with no |name| element is not allowed as
14        ## a metadata content other than |head| element.
15        meta => 1,
16      },
17      ## NOTE: RDF is mentioned in the HTML5 spec.
18      ## TODO: Other RDF elements?
19      q<http://www.w3.org/1999/02/22-rdf-syntax-ns#> => {RDF => 1},
20    };
21    
22    my $HTMLProseContent = {
23      $HTML_NS => {
24        section => 1, nav => 1, article => 1, blockquote => 1, aside => 1,
25        h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1, header => 1,
26        footer => 1, address => 1, p => 1, hr => 1, dialog => 1, pre => 1,
27        ol => 1, ul => 1, dl => 1, figure => 1, map => 1, table => 1,
28        details => 1, ## ISSUE: "Prose element" in spec.
29        datagrid => 1, ## ISSUE: "Prose element" in spec.
30        datatemplate => 1,
31        div => 1, ## ISSUE: No category in spec.
32        ## NOTE: |style| is only allowed if |scoped| attribute is specified.
33        ## Additionally, it must be before any other element or
34        ## non-inter-element-whitespace text node.
35        style => 1,  
36    
37        br => 1, q => 1, cite => 1, em => 1, strong => 1, small => 1, m => 1,
38        dfn => 1, abbr => 1, time => 1, progress => 1, meter => 1, code => 1,
39        var => 1, samp => 1, kbd => 1, sub => 1, sup => 1, span => 1, i => 1,
40        b => 1, bdo => 1, script => 1, noscript => 1, 'event-source' => 1,
41        command => 1, font => 1,
42        a => 1,
43        datagrid => 1, ## ISSUE: "Interactive element" in the spec.
44        ## NOTE: |area| is allowed only as a descendant of |map|.
45        area => 1,
46        
47        ins => 1, del => 1,
48    
49        ## NOTE: If there is a |menu| ancestor, phrasing.  Otherwise, prose.
50        menu => 1,
51    
52        img => 1, iframe => 1, embed => 1, object => 1, video => 1, audio => 1,
53        canvas => 1,
54      },
55    
56      ## NOTE: Embedded
57      q<http://www.w3.org/1998/Math/MathML> => {math => 1},
58      q<http://www.w3.org/2000/svg> => {svg => 1},
59    };
60    
61    my $HTMLSectioningContent = {
62      $HTML_NS => {
63        section => 1, nav => 1, article => 1, blockquote => 1, aside => 1,
64        ## NOTE: |body| is only allowed in |html| element.
65        body => 1,
66      },
67    };
68    
69    my $HTMLHeadingContent = {
70      $HTML_NS => {
71        h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1, header => 1,
72      },
73    };
74    
75    my $HTMLPhrasingContent = {
76      ## NOTE: All phrasing content is also prose content.
77      $HTML_NS => {
78        br => 1, q => 1, cite => 1, em => 1, strong => 1, small => 1, m => 1,
79        dfn => 1, abbr => 1, time => 1, progress => 1, meter => 1, code => 1,
80        var => 1, samp => 1, kbd => 1, sub => 1, sup => 1, span => 1, i => 1,
81        b => 1, bdo => 1, script => 1, noscript => 1, 'event-source' => 1,
82        command => 1, font => 1,
83        a => 1,
84        datagrid => 1, ## ISSUE: "Interactive element" in the spec.
85        ## NOTE: |area| is allowed only as a descendant of |map|.
86        area => 1,
87    
88        ## NOTE: Transparent.    
89        ins => 1, del => 1,
90    
91        ## NOTE: If there is a |menu| ancestor, phrasing.  Otherwise, prose.
92        menu => 1,
93    
94        img => 1, iframe => 1, embed => 1, object => 1, video => 1, audio => 1,
95        canvas => 1,
96      },
97    
98      ## NOTE: Embedded
99      q<http://www.w3.org/1998/Math/MathML> => {math => 1},
100      q<http://www.w3.org/2000/svg> => {svg => 1},
101    
102      ## NOTE: And non-inter-element-whitespace text nodes.
103    };
104    
105    my $HTMLEmbeddedContent = {
106      ## NOTE: All embedded content is also phrasing content.
107      $HTML_NS => {
108        img => 1, iframe => 1, embed => 1, object => 1, video => 1, audio => 1,
109        canvas => 1,
110      },
111      ## NOTE: MathML is mentioned in the HTML5 spec.
112      q<http://www.w3.org/1998/Math/MathML> => {math => 1},
113      ## NOTE: SVG is mentioned in the HTML5 spec.
114      q<http://www.w3.org/2000/svg> => {svg => 1},
115      ## NOTE: Foreign elements with content (but no metadata) are
116      ## embedded content.
117    };  
118    
119    my $HTMLInteractiveContent = {
120      $HTML_NS => {
121        a => 1,
122      },
123    };
124    
125    ## Old HTML5 categories
126    
127  my $HTMLMetadataElements = {  my $HTMLMetadataElements = {
128    $HTML_NS => {    $HTML_NS => {
129      qw/link 1 meta 1 style 1 script 1 event-source 1 command 1 base 1 title 1      qw/link 1 meta 1 style 1 script 1 event-source 1 command 1 base 1 title 1
# Line 73  my $HTMLSignificantContentErrors = { Line 193  my $HTMLSignificantContentErrors = {
193    },    },
194  }; # $HTMLSignificantContentErrors  }; # $HTMLSignificantContentErrors
195    
196    ## TODO:
197    
198    =pod
199    
200    As a general rule, elements whose content model allows any
201    +  <span>prose content</span> should have either at least one
202    +  descendant text node that is not <span>inter-element
203    +  whitespace</span>, or at least one descendant element node that is
204    +  <span>embedded content</span>. For the purposes of this requirement,
205    +  <code>del</code> elements and their descendants must not be
206    +  counted as contributing to the ancestors of the <code>del</code>
207    +  element.
208    
209    =cut
210    
211  our $AnyChecker;  our $AnyChecker;
212  my $HTMLAnyChecker = sub {  my $HTMLAnyChecker = sub {
213    my ($self, $todo) = @_;    my ($self, $todo) = @_;
# Line 234  my $HTMLStylableBlockChecker = sub { Line 369  my $HTMLStylableBlockChecker = sub {
369    return ($new_todos);    return ($new_todos);
370  }; # $HTMLStylableBlockChecker  }; # $HTMLStylableBlockChecker
371    
372    my $HTMLProseContentChecker = sub {
373      my ($self, $todo) = @_;
374      my $el = $todo->{node};
375      my $new_todos = [];
376      my @nodes = (@{$el->child_nodes});
377    
378      my $old_values = {significant =>
379                            $todo->{flag}->{has_descendant}->{significant}};
380      $todo->{flag}->{has_descendant}->{significant} = 0;
381      
382      my $has_non_style;
383      while (@nodes) {
384        my $node = shift @nodes;
385        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
386    
387        my $nt = $node->node_type;
388        if ($nt == 1) {
389          my $node_ns = $node->namespace_uri;
390          $node_ns = '' unless defined $node_ns;
391          my $node_ln = $node->manakai_local_name;
392          my $not_allowed = $self->{minuses}->{$node_ns}->{$node_ln};
393          if ($node_ns eq $HTML_NS and $node_ln eq 'style') {
394            $not_allowed = 2 if $has_non_style or
395                not $node->has_attribute_ns (undef, 'scoped');
396          } elsif ($HTMLProseContent->{$node_ns}->{$node_ln}) {
397            $has_non_style = 1;
398            if ($HTMLEmbeddedContent->{$node_ns}->{$node_ln}) {
399              $todo->{flag}->{has_descendant}->{significant} = 1;
400            }
401          } elsif ($self->{pluses}->{$node_ns}->{$node_ln}) {
402            #
403          } else {
404            $has_non_style = 1;
405            $not_allowed = 1;
406          }
407          if ($not_allowed) {
408            if ($not_allowed == 2) {
409              $self->{onerror}->(node => $node,
410                                 type => 'element not allowed:prose style')
411            } else {
412              $self->{onerror}->(node => $node,
413                                 type => 'element not allowed:prose')
414            }
415          }
416          my ($sib, $ch) = $self->_check_get_children ($node, $todo);
417          unshift @nodes, @$sib;
418          push @$new_todos, @$ch;
419        } elsif ($nt == 3 or $nt == 4) {
420          if ($node->data =~ /[^\x09-\x0D\x20]/) {
421            $has_non_style = 1;
422            $todo->{flag}->{has_descendant}->{significant} = 1;
423          }
424        } elsif ($nt == 5) {
425          unshift @nodes, @{$node->child_nodes};
426        }
427      }
428    
429      push @$new_todos, {
430        type => 'descendant', node => $todo->{node}, flag => $todo->{flag},
431        old_values => $old_values,
432        errors => $HTMLSignificantContentErrors,
433      };
434    
435      return ($new_todos);
436    }; # $HTMLProseContentChecker
437    
438  ## Zero or more block-level elements  ## Zero or more block-level elements
439  my $HTMLBlockChecker = sub {  my $HTMLBlockChecker = sub {
440    my ($self, $todo) = @_;    my ($self, $todo) = @_;
# Line 445  my $HTMLInlineOrStrictlyInlineChecker = Line 646  my $HTMLInlineOrStrictlyInlineChecker =
646    return ($new_todos);    return ($new_todos);
647  }; # $HTMLInlineOrStrictlyInlineChecker  }; # $HTMLInlineOrStrictlyInlineChecker
648    
649    my $HTMLPhrasingContentChecker = sub {
650      my ($self, $todo) = @_;
651      my $el = $todo->{node};
652      my $new_todos = [];
653      my @nodes = (@{$el->child_nodes});
654    
655      my $old_values = {significant =>
656                            $todo->{flag}->{has_descendant}->{significant}};
657      $todo->{flag}->{has_descendant}->{significant} = 0;
658      
659      while (@nodes) {
660        my $node = shift @nodes;
661        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
662    
663        my $nt = $node->node_type;
664        if ($nt == 1) {
665          my $node_ns = $node->namespace_uri;
666          $node_ns = '' unless defined $node_ns;
667          my $node_ln = $node->manakai_local_name;
668          my $not_allowed = $self->{minuses}->{$node_ns}->{$node_ln};
669          $not_allowed = 1
670              unless $HTMLPhrasingContent->{$node_ns}->{$node_ln} or
671                  $self->{pluses}->{$node_ns}->{$node_ln};
672          $self->{onerror}->(node => $node, type => 'element not allowed:phrasing')
673            if $not_allowed;
674          my ($sib, $ch) = $self->_check_get_children ($node, $todo);
675          unshift @nodes, @$sib;
676          push @$new_todos, @$ch;
677        } elsif ($nt == 3 or $nt == 4) {
678          if ($node->data =~ /[^\x09-\x0D\x20]/) {
679            $todo->{flag}->{has_descendant}->{significant} = 1;
680          }
681        } elsif ($nt == 5) {
682          unshift @nodes, @{$node->child_nodes};
683        }
684      }
685    
686      push @$new_todos, {
687        type => 'descendant', node => $todo->{node}, flag => $todo->{flag},
688        old_values => $old_values,
689        errors => $HTMLSignificantContentErrors,
690      };
691    
692      return ($new_todos);
693    }; # $HTMLPhrasingContentChecker
694    
695  ## Block-level content or inline-level content (i.e. bimorphic content model)  ## Block-level content or inline-level content (i.e. bimorphic content model)
696  my $HTMLBlockOrInlineChecker = sub {  my $HTMLBlockOrInlineChecker = sub {
697    my ($self, $todo) = @_;    my ($self, $todo) = @_;
# Line 632  my $GetHTMLZeroOrMoreThenBlockOrInlineCh Line 879  my $GetHTMLZeroOrMoreThenBlockOrInlineCh
879    };    };
880  }; # $GetHTMLZeroOrMoreThenBlockOrInlineChecker  }; # $GetHTMLZeroOrMoreThenBlockOrInlineChecker
881    
882  my $HTMLTransparentChecker = $HTMLBlockOrInlineChecker;  my $HTMLTransparentChecker = $HTMLProseContentChecker;
883  ## ISSUE: Significant content rule should be applied to transparent element  ## ISSUE: Significant content rule should be applied to transparent element
884  ## with parent?  Currently, applied to |video| but not to others.  ## with parent?  Currently, applied to |video| but not to others.
885    
# Line 970  my $HTMLTargetAttrChecker = sub { Line 1217  my $HTMLTargetAttrChecker = sub {
1217                           type => 'reserved browsing context name');                           type => 'reserved browsing context name');
1218      }      }
1219    } else {    } else {
1220      #$ ISSUE: An empty string is conforming?      ## NOTE: An empty string is a valid browsing context name (same as _self).
1221    }    }
1222  }; # $HTMLTargetAttrChecker  }; # $HTMLTargetAttrChecker
1223    
# Line 1222  $Element->{$HTML_NS}->{head} = { Line 1469  $Element->{$HTML_NS}->{head} = {
1469      my @nodes = (@{$el->child_nodes});      my @nodes = (@{$el->child_nodes});
1470    
1471      my $has_title;      my $has_title;
     my $phase = 'initial'; # 'after charset', 'after base'  
1472      while (@nodes) {      while (@nodes) {
1473        my $node = shift @nodes;        my $node = shift @nodes;
1474        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
# Line 1236  $Element->{$HTML_NS}->{head} = { Line 1482  $Element->{$HTML_NS}->{head} = {
1482          if ($self->{pluses}->{$node_ns}->{$node_ln}) {          if ($self->{pluses}->{$node_ns}->{$node_ln}) {
1483            #            #
1484          } elsif ($node_ns eq $HTML_NS and $node_ln eq 'title') {          } elsif ($node_ns eq $HTML_NS and $node_ln eq 'title') {
           $phase = 'after base';  
1485            unless ($has_title) {            unless ($has_title) {
1486              $has_title = 1;              $has_title = 1;
1487            } else {            } else {
1488              $not_allowed = 1;              $not_allowed = 1;
1489            }            }
1490          } elsif ($node_ns eq $HTML_NS and $node_ln eq 'meta') {          } elsif ($HTMLMetadataContent->{$node_ns}->{$node_ln}) {
1491            if ($node->has_attribute_ns (undef, 'charset')) {            #
1492              if ($phase eq 'initial') {  
1493                $phase = 'after charset';            ## NOTE: |meta| is a metadata content.  However, strictly speaking,
1494              } else {            ## a |meta| element with none of |charset|, |name|,
1495                $not_allowed = 1;            ## or |http-equiv| attribute is not allowed.  It is non-conforming
1496                ## NOTE: See also |base|'s "contexts" field in the spec            ## anyway.
             }  
           } elsif ($node->has_attribute_ns (undef, 'name') or  
                    $node->has_attribute_ns (undef, 'http-equiv')) {  
             $phase = 'after base';  
           } else {  
             $phase = 'after base';  
             $not_allowed = 1;  
           }  
         } elsif ($node_ns eq $HTML_NS and $node_ln eq 'base') {  
           if ($phase eq 'initial' or $phase eq 'after charset') {  
             $phase = 'after base';  
           } else {  
             $not_allowed = 1;  
           }  
         } elsif ($node_ns eq $HTML_NS and $node_ln eq 'style') {  
           $phase = 'after base';  
           if ($node->has_attribute_ns (undef, 'scoped')) {  
             $not_allowed = 1;  
           }  
         } elsif ($HTMLMetadataElements->{$node_ns}->{$node_ln}) {  
           $phase = 'after base';  
1497          } else {          } else {
1498            $not_allowed = 1;            $not_allowed = 1;
1499          }          }
# Line 1304  $Element->{$HTML_NS}->{base} = { Line 1528  $Element->{$HTML_NS}->{base} = {
1528    attrs_checker => sub {    attrs_checker => sub {
1529      my ($self, $todo) = @_;      my ($self, $todo) = @_;
1530    
1531        if ($self->{has_base}) {
1532          $self->{onerror}->(node => $todo->{node},
1533                             type => 'element not allowed:base');
1534        } else {
1535          $self->{has_base} = 1;
1536        }
1537    
1538      my $has_href = $todo->{node}->has_attribute_ns (undef, 'href');      my $has_href = $todo->{node}->has_attribute_ns (undef, 'href');
1539      my $has_target = $todo->{node}->has_attribute_ns (undef, 'target');      my $has_target = $todo->{node}->has_attribute_ns (undef, 'target');
1540    
# Line 1314  $Element->{$HTML_NS}->{base} = { Line 1545  $Element->{$HTML_NS}->{base} = {
1545        ## <title xml:base="relative"/><base href/> (maybe it should be)        ## <title xml:base="relative"/><base href/> (maybe it should be)
1546        ## <unknown xmlns="relative"/><base href/> (assuming that        ## <unknown xmlns="relative"/><base href/> (assuming that
1547        ## |{relative}:unknown| is allowed before XHTML |base| (unlikely, though))        ## |{relative}:unknown| is allowed before XHTML |base| (unlikely, though))
       ## <?xml-stylesheet href="relative"?>...<base href=""/>  
       ## NOTE: These are non-conformant anyway because of |head|'s content model:  
1548        ## <style>@import 'relative';</style><base href>        ## <style>@import 'relative';</style><base href>
1549        ## <script>location.href = 'relative';</script><base href>        ## <script>location.href = 'relative';</script><base href>
1550        ## NOTE: <html manifest=".."><head><base href=""/> is conforming as        ## NOTE: <html manifest=".."><head><base href=""/> is conforming as
# Line 1481  $Element->{$HTML_NS}->{meta} = { Line 1710  $Element->{$HTML_NS}->{meta} = {
1710      }      }
1711    
1712      if (defined $charset_attr) {      if (defined $charset_attr) {
1713          my $parent = $todo->{node}->manakai_parent_element;
1714          if ($parent and $parent eq $parent->owner_document->manakai_head) {
1715            for my $el (@{$parent->child_nodes}) {
1716              next unless $el->node_type == 1; # ELEMENT_NODE
1717              unless ($el eq $todo->{node}) {
1718                ## NOTE: Not the first child element.
1719                $self->{onerror}->(node => $todo->{node},
1720                                   type => 'element not allowed:meta charset');
1721              }
1722              last;
1723              ## NOTE: Entity references are not supported.
1724            }
1725          } else {
1726            $self->{onerror}->(node => $todo->{node},
1727                               type => 'element not allowed:meta charset');
1728          }
1729    
1730        unless ($todo->{node}->owner_document->manakai_is_html) {        unless ($todo->{node}->owner_document->manakai_is_html) {
1731          $self->{onerror}->(node => $charset_attr,          $self->{onerror}->(node => $charset_attr,
1732                             type => 'in XML:charset');                             type => 'in XML:charset');
# Line 1594  $Element->{$HTML_NS}->{style} = { Line 1840  $Element->{$HTML_NS}->{style} = {
1840                    
1841          my $nt = $node->node_type;          my $nt = $node->node_type;
1842          if ($nt == 1) {          if ($nt == 1) {
1843            $self->{onerror}->(node => $node, type => 'element not allowed');            my $node_ns = $node->namespace_uri;
1844              $node_ns = '' unless defined $node_ns;
1845              my $node_ln = $node->manakai_local_name;
1846              if ($self->{pluses}->{$node_ns}->{$node_ln}) {
1847                #
1848              } else {
1849                $self->{onerror}->(node => $node, type => 'element not allowed');
1850              }
1851            my ($sib, $ch) = $self->_check_get_children ($node, $todo);            my ($sib, $ch) = $self->_check_get_children ($node, $todo);
1852            unshift @nodes, @$sib;            unshift @nodes, @$sib;
1853            push @$new_todos, @$ch;            push @$new_todos, @$ch;
# Line 1619  $Element->{$HTML_NS}->{style} = { Line 1872  $Element->{$HTML_NS}->{style} = {
1872    
1873  $Element->{$HTML_NS}->{body} = {  $Element->{$HTML_NS}->{body} = {
1874    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1875    checker => $HTMLBlockChecker,    checker => $HTMLProseContentChecker,
1876  };  };
1877    
1878  $Element->{$HTML_NS}->{section} = {  $Element->{$HTML_NS}->{section} = {
1879    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1880    checker => $HTMLStylableBlockChecker,    checker => $HTMLProseContentChecker,
1881  };  };
1882    
1883  $Element->{$HTML_NS}->{nav} = {  $Element->{$HTML_NS}->{nav} = {
1884    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1885    checker => $HTMLBlockOrInlineChecker,    checker => $HTMLProseContentChecker,
1886  };  };
1887    
1888  $Element->{$HTML_NS}->{article} = {  $Element->{$HTML_NS}->{article} = {
1889    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1890    checker => $HTMLStylableBlockChecker,    checker => $HTMLProseContentChecker,
1891  };  };
1892    
1893  $Element->{$HTML_NS}->{blockquote} = {  $Element->{$HTML_NS}->{blockquote} = {
1894    attrs_checker => $GetHTMLAttrsChecker->({    attrs_checker => $GetHTMLAttrsChecker->({
1895      cite => $HTMLURIAttrChecker,      cite => $HTMLURIAttrChecker,
1896    }),    }),
1897    checker => $HTMLBlockChecker,    checker => $HTMLProseContentChecker,
1898  };  };
1899    
1900  $Element->{$HTML_NS}->{aside} = {  $Element->{$HTML_NS}->{aside} = {
1901    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1902    checker => $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'style'),    checker => $HTMLProseContentChecker,
1903  };  };
1904    
1905  $Element->{$HTML_NS}->{h1} = {  $Element->{$HTML_NS}->{h1} = {
# Line 1654  $Element->{$HTML_NS}->{h1} = { Line 1907  $Element->{$HTML_NS}->{h1} = {
1907    checker => sub {    checker => sub {
1908      my ($self, $todo) = @_;      my ($self, $todo) = @_;
1909      $todo->{flag}->{has_descendant}->{hn} = 1;      $todo->{flag}->{has_descendant}->{hn} = 1;
1910      return $HTMLStrictlyInlineChecker->($self, $todo);      return $HTMLPhrasingContentChecker->($self, $todo);
1911    },    },
1912  };  };
1913    
# Line 1683  $Element->{$HTML_NS}->{h6} = { Line 1936  $Element->{$HTML_NS}->{h6} = {
1936    checker => $Element->{$HTML_NS}->{h1}->{checker},    checker => $Element->{$HTML_NS}->{h1}->{checker},
1937  };  };
1938    
1939    ## TODO: Explicit sectioning is "encouraged".
1940    
1941  $Element->{$HTML_NS}->{header} = {  $Element->{$HTML_NS}->{header} = {
1942    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1943    checker => sub {    checker => sub {
# Line 1693  $Element->{$HTML_NS}->{header} = { Line 1948  $Element->{$HTML_NS}->{header} = {
1948    
1949      my $end = $self->_add_minuses      my $end = $self->_add_minuses
1950          ({$HTML_NS => {qw/header 1 footer 1/}},          ({$HTML_NS => {qw/header 1 footer 1/}},
1951           $HTMLSectioningElements);           $HTMLSectioningContent);
1952      my ($new_todos, $ch) = $HTMLBlockChecker->($self, $todo);      my ($new_todos, $ch) = $HTMLProseContentChecker->($self, $todo);
1953      push @$new_todos, $end,      push @$new_todos, $end,
1954          {type => 'descendant', node => $todo->{node},          {type => 'descendant', node => $todo->{node},
1955           flag => $todo->{flag}, old_values => $old_flags,           flag => $todo->{flag}, old_values => $old_flags,
# Line 1713  $Element->{$HTML_NS}->{header} = { Line 1968  $Element->{$HTML_NS}->{header} = {
1968    
1969  $Element->{$HTML_NS}->{footer} = {  $Element->{$HTML_NS}->{footer} = {
1970    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1971    checker => sub { ## block -hn -header -footer -sectioning or inline    checker => sub {
1972      my ($self, $todo) = @_;      my ($self, $todo) = @_;
     my $el = $todo->{node};  
     my $new_todos = [];  
     my @nodes = (@{$el->child_nodes});  
1973    
1974      my $old_values = {significant =>      my $old_flags = {hn => $todo->{flag}->{has_descendant}->{hn}};
1975                            $todo->{flag}->{has_descendant}->{significant}};      $todo->{flag}->{has_descendant}->{hn} = 0;
     $todo->{flag}->{has_descendant}->{significant} = 0;  
     
     my $content = 'block-or-inline'; # or 'block' or 'inline'  
     my @block_not_inline;  
     while (@nodes) {  
       my $node = shift @nodes;  
       $self->_remove_minuses ($node) and next if ref $node eq 'HASH';  
   
       my $nt = $node->node_type;  
       if ($nt == 1) {  
         my $node_ns = $node->namespace_uri;  
         $node_ns = '' unless defined $node_ns;    
         my $node_ln = $node->manakai_local_name;  
         my $not_allowed;  
         if ($self->{minuses}->{$node_ns}->{$node_ln}) {  
           $not_allowed = 1;  
         } elsif ($node_ns eq $HTML_NS and  
                  {  
                    qw/h1 1 h2 1 h3 1 h4 1 h5 1 h6 1 header 1 footer 1/  
                  }->{$node_ln}) {  
           $not_allowed = 1;  
         } elsif ($HTMLSectioningElements->{$node_ns}->{$node_ln}) {  
           $not_allowed = 1;  
         }  
         if ($content eq 'block') {  
           $not_allowed = 1  
             unless $HTMLBlockLevelElements->{$node_ns}->{$node_ln} or  
                 $self->{pluses}->{$node_ns}->{$node_ln};  
         } elsif ($content eq 'inline') {  
           $not_allowed = 1  
             unless $HTMLStrictlyInlineLevelElements->{$node_ns}->{$node_ln} or  
                 $HTMLStructuredInlineLevelElements->{$node_ns}->{$node_ln} or  
                 $self->{pluses}->{$node_ns}->{$node_ln};  
         } else {  
           my $is_block = $HTMLBlockLevelElements->{$node_ns}->{$node_ln};  
           my $is_inline  
             = $HTMLStrictlyInlineLevelElements->{$node_ns}->{$node_ln} ||  
               $HTMLStructuredInlineLevelElements->{$node_ns}->{$node_ln};  
             
           push @block_not_inline, $node  
             if $is_block and not $is_inline and not $not_allowed;  
           if (not $is_block and not $self->{pluses}->{$node_ns}->{$node_ln}) {  
             $content = 'inline';  
             for (@block_not_inline) {  
               $self->{onerror}->(node => $_, type => 'element not allowed');  
             }  
             $not_allowed = 1 unless $is_inline;  
           }  
         }  
         $self->{onerror}->(node => $node, type => 'element not allowed')  
           if $not_allowed;  
         my ($sib, $ch) = $self->_check_get_children ($node, $todo);  
         unshift @nodes, @$sib;  
         push @$new_todos, @$ch;  
       } elsif ($nt == 3 or $nt == 4) {  
         if ($node->data =~ /[^\x09-\x0D\x20]/) {  
           if ($content eq 'block') {  
             $self->{onerror}->(node => $node, type => 'character not allowed');  
           } else {  
             $content = 'inline';  
             for (@block_not_inline) {  
               $self->{onerror}->(node => $_, type => 'element not allowed');  
             }  
           }  
           $todo->{flag}->{has_descendant}->{significant} = 1;  
         }  
       } elsif ($nt == 5) {  
         unshift @nodes, @{$node->child_nodes};  
       }  
     }  
1976    
1977      my $end = $self->_add_minuses      my $end = $self->_add_minuses
1978        ({$HTML_NS => {qw/h1 1 h2 1 h3 1 h4 1 h5 1 h6 1/}},          ({$HTML_NS => {footer => 1}},
1979         $HTMLSectioningElements);           $HTMLSectioningContent, $HTMLHeadingContent);
1980        my ($new_todos, $ch) = $HTMLProseContentChecker->($self, $todo);
1981      push @$new_todos, $end;      push @$new_todos, $end;
1982    
1983      if ($content eq 'inline') {      return ($new_todos, $ch);
       for (@$new_todos) {  
         $_->{inline} = 1;  
       }  
     }  
   
     push @$new_todos, {  
       type => 'descendant', node => $todo->{node}, flag => $todo->{flag},  
       old_values => $old_values,  
       errors => $HTMLSignificantContentErrors,  
     };  
   
     return ($new_todos);  
1984    },    },
1985  };  };
1986    
1987  $Element->{$HTML_NS}->{address} = {  $Element->{$HTML_NS}->{address} = {
1988    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
1989    checker => $HTMLInlineChecker,    checker => sub {
1990        my ($self, $todo) = @_;
1991    
1992        my $old_flags = {hn => $todo->{flag}->{has_descendant}->{hn}};
1993        $todo->{flag}->{has_descendant}->{hn} = 0;
1994    
1995        my $end = $self->_add_minuses
1996            ({$HTML_NS => {footer => 1, address => 1}},
1997             $HTMLSectioningContent, $HTMLHeadingContent);
1998        my ($new_todos, $ch) = $HTMLProseContentChecker->($self, $todo);
1999        push @$new_todos, $end;
2000    
2001        return ($new_todos, $ch);
2002      },
2003  };  };
2004    
2005  $Element->{$HTML_NS}->{p} = {  $Element->{$HTML_NS}->{p} = {
2006    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2007    checker => $HTMLInlineChecker,    checker => $HTMLPhrasingContentChecker,
2008  };  };
2009    
2010  $Element->{$HTML_NS}->{hr} = {  $Element->{$HTML_NS}->{hr} = {
# Line 1831  $Element->{$HTML_NS}->{hr} = { Line 2015  $Element->{$HTML_NS}->{hr} = {
2015  $Element->{$HTML_NS}->{br} = {  $Element->{$HTML_NS}->{br} = {
2016    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2017    checker => $HTMLEmptyChecker,    checker => $HTMLEmptyChecker,
2018      ## NOTE: Blank line MUST NOT be used for presentation purpose.
2019      ## (This requirement is semantic so that we cannot check.)
2020  };  };
2021    
2022  $Element->{$HTML_NS}->{dialog} = {  $Element->{$HTML_NS}->{dialog} = {
# Line 1896  $Element->{$HTML_NS}->{dialog} = { Line 2082  $Element->{$HTML_NS}->{dialog} = {
2082    
2083  $Element->{$HTML_NS}->{pre} = {  $Element->{$HTML_NS}->{pre} = {
2084    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2085    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2086  };  };
2087    
2088  $Element->{$HTML_NS}->{ol} = {  $Element->{$HTML_NS}->{ol} = {
# Line 1970  $Element->{$HTML_NS}->{li} = { Line 2156  $Element->{$HTML_NS}->{li} = {
2156    }),    }),
2157    checker => sub {    checker => sub {
2158      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2159      if ($todo->{inline}) {      if ($todo->{flag}->{in_menu}) {
2160        return $HTMLInlineChecker->($self, $todo);        return $HTMLPhrasingContentChecker->($self, $todo);
2161      } else {      } else {
2162        return $HTMLBlockOrInlineChecker->($self, $todo);        return $HTMLProseContentChecker->($self, $todo);
2163      }      }
2164    },    },
2165  };  };
# Line 2053  $Element->{$HTML_NS}->{dl} = { Line 2239  $Element->{$HTML_NS}->{dl} = {
2239    
2240  $Element->{$HTML_NS}->{dt} = {  $Element->{$HTML_NS}->{dt} = {
2241    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2242    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2243  };  };
2244    
2245  $Element->{$HTML_NS}->{dd} = {  $Element->{$HTML_NS}->{dd} = {
2246    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2247    checker => $Element->{$HTML_NS}->{li}->{checker},    checker => $HTMLProseContentChecker,
2248  };  };
2249    
2250  $Element->{$HTML_NS}->{a} = {  $Element->{$HTML_NS}->{a} = {
# Line 2112  $Element->{$HTML_NS}->{a} = { Line 2298  $Element->{$HTML_NS}->{a} = {
2298      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2299    
2300      my $end = $self->_add_minuses ($HTMLInteractiveElements);      my $end = $self->_add_minuses ($HTMLInteractiveElements);
2301      my ($new_todos, $ch)      my ($new_todos, $ch) = $HTMLPhrasingContentChecker->($self, $todo);
       = $HTMLInlineOrStrictlyInlineChecker->($self, $todo);  
2302      push @$new_todos, $end;      push @$new_todos, $end;
2303    
2304      if ($todo->{node}->has_attribute_ns (undef, 'href')) {      if ($todo->{node}->has_attribute_ns (undef, 'href')) {
# Line 2128  $Element->{$HTML_NS}->{q} = { Line 2313  $Element->{$HTML_NS}->{q} = {
2313    attrs_checker => $GetHTMLAttrsChecker->({    attrs_checker => $GetHTMLAttrsChecker->({
2314      cite => $HTMLURIAttrChecker,      cite => $HTMLURIAttrChecker,
2315    }),    }),
2316    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2317  };  };
2318    
2319  $Element->{$HTML_NS}->{cite} = {  $Element->{$HTML_NS}->{cite} = {
2320    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2321    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2322  };  };
2323    
2324  $Element->{$HTML_NS}->{em} = {  $Element->{$HTML_NS}->{em} = {
2325    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2326    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2327  };  };
2328    
2329  $Element->{$HTML_NS}->{strong} = {  $Element->{$HTML_NS}->{strong} = {
2330    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2331    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2332  };  };
2333    
2334  $Element->{$HTML_NS}->{small} = {  $Element->{$HTML_NS}->{small} = {
2335    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2336    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2337  };  };
2338    
2339  $Element->{$HTML_NS}->{m} = {  $Element->{$HTML_NS}->{m} = {
2340    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2341    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2342  };  };
2343    
2344  $Element->{$HTML_NS}->{dfn} = {  $Element->{$HTML_NS}->{dfn} = {
# Line 2162  $Element->{$HTML_NS}->{dfn} = { Line 2347  $Element->{$HTML_NS}->{dfn} = {
2347      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2348    
2349      my $end = $self->_add_minuses ({$HTML_NS => {dfn => 1}});      my $end = $self->_add_minuses ({$HTML_NS => {dfn => 1}});
2350      my ($sib, $ch) = $HTMLStrictlyInlineChecker->($self, $todo);      my ($sib, $ch) = $HTMLPhrasingContentChecker->($self, $todo);
2351      push @$sib, $end;      push @$sib, $end;
2352    
2353      my $node = $todo->{node};      my $node = $todo->{node};
# Line 2215  $Element->{$HTML_NS}->{abbr} = { Line 2400  $Element->{$HTML_NS}->{abbr} = {
2400      ## if there is a |dfn| whose defining term is the abbreviation,      ## if there is a |dfn| whose defining term is the abbreviation,
2401      ## but it does not prohibit |abbr| w/o |title| in other cases.      ## but it does not prohibit |abbr| w/o |title| in other cases.
2402    }),    }),
2403    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2404  };  };
2405    
2406  $Element->{$HTML_NS}->{time} = {  $Element->{$HTML_NS}->{time} = {
# Line 2345  $Element->{$HTML_NS}->{time} = { Line 2530  $Element->{$HTML_NS}->{time} = {
2530                           type => 'dateortime:syntax error');                           type => 'dateortime:syntax error');
2531      }      }
2532    
2533      return $HTMLStrictlyInlineChecker->($self, $todo);      return $HTMLPhrasingContentChecker->($self, $todo);
2534    },    },
2535  };  };
2536    
# Line 2358  $Element->{$HTML_NS}->{meter} = { ## TOD Line 2543  $Element->{$HTML_NS}->{meter} = { ## TOD
2543      max => $GetHTMLFloatingPointNumberAttrChecker->(sub { 1 }),      max => $GetHTMLFloatingPointNumberAttrChecker->(sub { 1 }),
2544      optimum => $GetHTMLFloatingPointNumberAttrChecker->(sub { 1 }),      optimum => $GetHTMLFloatingPointNumberAttrChecker->(sub { 1 }),
2545    }),    }),
2546    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2547  };  };
2548    
2549  $Element->{$HTML_NS}->{progress} = { ## TODO: recommended to use content  $Element->{$HTML_NS}->{progress} = { ## TODO: recommended to use content
# Line 2366  $Element->{$HTML_NS}->{progress} = { ## Line 2551  $Element->{$HTML_NS}->{progress} = { ##
2551      value => $GetHTMLFloatingPointNumberAttrChecker->(sub { shift >= 0 }),      value => $GetHTMLFloatingPointNumberAttrChecker->(sub { shift >= 0 }),
2552      max => $GetHTMLFloatingPointNumberAttrChecker->(sub { shift > 0 }),      max => $GetHTMLFloatingPointNumberAttrChecker->(sub { shift > 0 }),
2553    }),    }),
2554    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2555  };  };
2556    
2557  $Element->{$HTML_NS}->{code} = {  $Element->{$HTML_NS}->{code} = {
2558    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2559    ## NOTE: Though |title| has special semantics,    ## NOTE: Though |title| has special semantics,
2560    ## syntatically same as the |title| as global attribute.    ## syntatically same as the |title| as global attribute.
2561    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2562  };  };
2563    
2564  $Element->{$HTML_NS}->{var} = {  $Element->{$HTML_NS}->{var} = {
2565    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2566    ## NOTE: Though |title| has special semantics,    ## NOTE: Though |title| has special semantics,
2567    ## syntatically same as the |title| as global attribute.    ## syntatically same as the |title| as global attribute.
2568    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2569  };  };
2570    
2571  $Element->{$HTML_NS}->{samp} = {  $Element->{$HTML_NS}->{samp} = {
2572    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2573    ## NOTE: Though |title| has special semantics,    ## NOTE: Though |title| has special semantics,
2574    ## syntatically same as the |title| as global attribute.    ## syntatically same as the |title| as global attribute.
2575    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2576  };  };
2577    
2578  $Element->{$HTML_NS}->{kbd} = {  $Element->{$HTML_NS}->{kbd} = {
2579    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2580    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2581  };  };
2582    
2583  $Element->{$HTML_NS}->{sub} = {  $Element->{$HTML_NS}->{sub} = {
2584    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2585    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2586  };  };
2587    
2588  $Element->{$HTML_NS}->{sup} = {  $Element->{$HTML_NS}->{sup} = {
2589    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2590    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2591  };  };
2592    
2593  $Element->{$HTML_NS}->{span} = {  $Element->{$HTML_NS}->{span} = {
2594    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2595    ## NOTE: Though |title| has special semantics,    ## NOTE: Though |title| has special semantics,
2596    ## syntatically same as the |title| as global attribute.    ## syntatically same as the |title| as global attribute.
2597    checker => $HTMLInlineOrStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2598  };  };
2599    
2600  $Element->{$HTML_NS}->{i} = {  $Element->{$HTML_NS}->{i} = {
2601    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2602    ## NOTE: Though |title| has special semantics,    ## NOTE: Though |title| has special semantics,
2603    ## syntatically same as the |title| as global attribute.    ## syntatically same as the |title| as global attribute.
2604    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2605  };  };
2606    
2607  $Element->{$HTML_NS}->{b} = {  $Element->{$HTML_NS}->{b} = {
2608    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
2609    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2610  };  };
2611    
2612  $Element->{$HTML_NS}->{bdo} = {  $Element->{$HTML_NS}->{bdo} = {
# Line 2433  $Element->{$HTML_NS}->{bdo} = { Line 2618  $Element->{$HTML_NS}->{bdo} = {
2618      }      }
2619    },    },
2620    ## ISSUE: The spec does not directly say that |dir| is a enumerated attr.    ## ISSUE: The spec does not directly say that |dir| is a enumerated attr.
2621    checker => $HTMLStrictlyInlineChecker,    checker => $HTMLPhrasingContentChecker,
2622  };  };
2623    
2624    =pod
2625    
2626    ## TODO:
2627    
2628    +
2629    +  <p>Partly because of the confusion described above, authors are
2630    +  strongly recommended to always mark up all paragraphs with the
2631    +  <code>p</code> element, and to not have any <code>ins</code> or
2632    +  <code>del</code> elements that cross across any <span
2633    +  title="paragraph">implied paragraphs</span>.</p>
2634    +
2635    (An informative note)
2636    
2637    <p><code>ins</code> elements should not cross <span
2638    +  title="paragraph">implied paragraph</span> boundaries.</p>
2639    (normative)
2640    
2641    +  <p><code>del</code> elements should not cross <span
2642    +  title="paragraph">implied paragraph</span> boundaries.</p>
2643    (normative)
2644    
2645    =cut
2646    
2647  $Element->{$HTML_NS}->{ins} = {  $Element->{$HTML_NS}->{ins} = {
2648    attrs_checker => $GetHTMLAttrsChecker->({    attrs_checker => $GetHTMLAttrsChecker->({
2649      cite => $HTMLURIAttrChecker,      cite => $HTMLURIAttrChecker,
# Line 2451  $Element->{$HTML_NS}->{del} = { Line 2659  $Element->{$HTML_NS}->{del} = {
2659    }),    }),
2660    checker => sub {    checker => sub {
2661      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2662        my $sig_flag = $todo->{flag}->{has_descendant}->{significant};
2663      my $parent = $todo->{node}->manakai_parent_element;      my ($new_todos) = $HTMLTransparentChecker->($self, $todo);
2664      if (defined $parent) {      push @$new_todos, {type => 'code', code => sub {
2665        my $sig_flag = $todo->{flag}->{has_descendant}->{significant};                           $todo->{flag}->{has_descendant}->{significant} = 0;
2666        my $nsuri = $parent->namespace_uri;                         }} if not $sig_flag;
2667        $nsuri = '' unless defined $nsuri;      return $new_todos;
       my $ln = $parent->manakai_local_name;  
       my $eldef = $Element->{$nsuri}->{$ln} ||  
         $Element->{$nsuri}->{''} ||  
         $ElementDefault;  
       my ($new_todos) =  $eldef->{checker}->($self, $todo);  
       push @$new_todos, {type => 'code', code => sub {  
         $todo->{flag}->{has_descendant}->{significant} = 0;  
       }} if not $sig_flag;  
       return $new_todos;  
     } else {  
       return $HTMLBlockOrInlineChecker->($self, $todo);  
     }  
2668    },    },
2669  };  };
2670    
# Line 2581  $Element->{$HTML_NS}->{object} = { Line 2777  $Element->{$HTML_NS}->{object} = {
2777        }        }
2778      }      }
2779    },    },
2780      ## NOTE: param*, then transparent.
2781    checker => sub {    checker => sub {
2782      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2783      $todo->{flag}->{has_descendant}->{significant} = 1;      $todo->{flag}->{has_descendant}->{significant} = 1;
# Line 2623  $Element->{$HTML_NS}->{video} = { Line 2820  $Element->{$HTML_NS}->{video} = {
2820      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2821      $todo->{flag}->{has_descendant}->{significant} = 1;      $todo->{flag}->{has_descendant}->{significant} = 1;
2822    
2823    ## TODO:
2824      if ($todo->{node}->has_attribute_ns (undef, 'src')) {      if ($todo->{node}->has_attribute_ns (undef, 'src')) {
2825        return $HTMLBlockOrInlineChecker->($self, $todo);        return $HTMLBlockOrInlineChecker->($self, $todo);
2826      } else {      } else {
# Line 2661  $Element->{$HTML_NS}->{canvas} = { Line 2859  $Element->{$HTML_NS}->{canvas} = {
2859    checker => sub {    checker => sub {
2860      my ($self, $todo) = @_;      my ($self, $todo) = @_;
2861      $todo->{flag}->{has_descendant}->{significant} = 1;      $todo->{flag}->{has_descendant}->{significant} = 1;
2862      return $HTMLInlineChecker->($self, $todo);      return $HTMLTransparentChecker->($self, $todo);
2863    },    },
2864  };  };
2865    
# Line 2695  $Element->{$HTML_NS}->{map} = { Line 2893  $Element->{$HTML_NS}->{map} = {
2893      $self->{onerror}->(node => $todo->{node}, type => 'attribute missing:id')      $self->{onerror}->(node => $todo->{node}, type => 'attribute missing:id')
2894          unless $has_id;          unless $has_id;
2895    },    },
2896    checker => $HTMLBlockChecker,    checker => $HTMLProseContentChecker,
2897  };  };
2898    
2899  $Element->{$HTML_NS}->{area} = {  $Element->{$HTML_NS}->{area} = {
# Line 3127  $Element->{$HTML_NS}->{td} = { Line 3325  $Element->{$HTML_NS}->{td} = {
3325      colspan => $GetHTMLNonNegativeIntegerAttrChecker->(sub { shift > 0 }),      colspan => $GetHTMLNonNegativeIntegerAttrChecker->(sub { shift > 0 }),
3326      rowspan => $GetHTMLNonNegativeIntegerAttrChecker->(sub { shift > 0 }),      rowspan => $GetHTMLNonNegativeIntegerAttrChecker->(sub { shift > 0 }),
3327    }),    }),
3328    checker => $HTMLBlockOrInlineChecker,    checker => $HTMLProseContentChecker,
3329  };  };
3330    
3331  $Element->{$HTML_NS}->{th} = {  $Element->{$HTML_NS}->{th} = {
# Line 3137  $Element->{$HTML_NS}->{th} = { Line 3335  $Element->{$HTML_NS}->{th} = {
3335      scope => $GetHTMLEnumeratedAttrChecker      scope => $GetHTMLEnumeratedAttrChecker
3336          ->({row => 1, col => 1, rowgroup => 1, colgroup => 1}),          ->({row => 1, col => 1, rowgroup => 1, colgroup => 1}),
3337    }),    }),
3338    checker => $HTMLBlockOrInlineChecker,    checker => $HTMLProseContentChecker,
3339  };  };
3340    
3341  ## TODO: forms  ## TODO: forms
# Line 3241  $Element->{$HTML_NS}->{noscript} = { Line 3439  $Element->{$HTML_NS}->{noscript} = {
3439        return ($new_todos);        return ($new_todos);
3440      } else {      } else {
3441        my $end = $self->_add_minuses ({$HTML_NS => {noscript => 1}});        my $end = $self->_add_minuses ({$HTML_NS => {noscript => 1}});
3442        my ($sib, $ch) = $HTMLBlockOrInlineChecker->($self, $todo);        my ($sib, $ch) = $HTMLTransparentChecker->($self, $todo);
3443        push @$sib, $end;        push @$sib, $end;
3444        return ($sib, $ch);        return ($sib, $ch);
3445      }      }
# Line 3264  $Element->{$HTML_NS}->{details} = { Line 3462  $Element->{$HTML_NS}->{details} = {
3462    checker => sub {    checker => sub {
3463      my ($self, $todo) = @_;      my ($self, $todo) = @_;
3464    
3465      my $end = $self->_add_minuses ({$HTML_NS => {a => 1, datagrid => 1}});  ## TODO:
3466      my ($sib, $ch)      my ($sib, $ch)
3467        = $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'legend')        = $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'legend')
3468          ->($self, $todo);          ->($self, $todo);
     push @$sib, $end;  
3469      return ($sib, $ch);      return ($sib, $ch);
3470    },    },
3471  };  };
# Line 3290  $Element->{$HTML_NS}->{datagrid} = { Line 3487  $Element->{$HTML_NS}->{datagrid} = {
3487    
3488      my $end = $self->_add_minuses ({$HTML_NS => {a => 1, datagrid => 1}});      my $end = $self->_add_minuses ({$HTML_NS => {a => 1, datagrid => 1}});
3489            
3490      ## Block-table Block* | table | select | datalist | Empty      ## Prose -(text* table Prose*) | table | select | datalist | Empty
3491      my $mode = 'any';      my $mode = 'any';
3492      while (@nodes) {      while (@nodes) {
3493        my $node = shift @nodes;        my $node = shift @nodes;
# Line 3304  $Element->{$HTML_NS}->{datagrid} = { Line 3501  $Element->{$HTML_NS}->{datagrid} = {
3501          my $not_allowed = $self->{minuses}->{$node_ns}->{$node_ln};          my $not_allowed = $self->{minuses}->{$node_ns}->{$node_ln};
3502          if ($self->{pluses}->{$node_ns}->{$node_ln}) {          if ($self->{pluses}->{$node_ns}->{$node_ln}) {
3503            #            #
3504          } elsif ($mode eq 'block') {          } elsif ($mode eq 'prose') {
3505            $not_allowed = 1            $not_allowed = 1
3506                unless $HTMLBlockLevelElements->{$node_ns}->{$node_ln};                unless $HTMLProseContent->{$node_ns}->{$node_ln};
3507          } elsif ($mode eq 'any') {          } elsif ($mode eq 'any') {
3508            if ($node_ns eq $HTML_NS and            if ($node_ns eq $HTML_NS and
3509                {table => 1, select => 1, datalist => 1}->{$node_ln}) {                {table => 1, select => 1, datalist => 1}->{$node_ln}) {
3510              $mode = 'none';              $mode = 'none';
3511            } elsif ($HTMLBlockLevelElements->{$node_ns}->{$node_ln}) {            } elsif ($HTMLProseContent->{$node_ns}->{$node_ln}) {
3512              $mode = 'block';              $mode = 'prose';
3513            } else {            } else {
3514              $not_allowed = 1;              $not_allowed = 1;
3515            }            }
# Line 3326  $Element->{$HTML_NS}->{datagrid} = { Line 3523  $Element->{$HTML_NS}->{datagrid} = {
3523          push @$new_todos, @$ch;          push @$new_todos, @$ch;
3524        } elsif ($nt == 3 or $nt == 4) {        } elsif ($nt == 3 or $nt == 4) {
3525          if ($node->data =~ /[^\x09-\x0D\x20]/) {          if ($node->data =~ /[^\x09-\x0D\x20]/) {
3526            $self->{onerror}->(node => $node, type => 'character not allowed');            if ($mode eq 'prose') {
3527                #
3528              } elsif ($mode eq 'any') {
3529                $mode = 'prose';
3530              } else {
3531                $self->{onerror}->(node => $node, type => 'character not allowed');
3532              }
3533            $todo->{flag}->{has_descendant}->{significant} = 1;            $todo->{flag}->{has_descendant}->{significant} = 1;
3534          }          }
3535        } elsif ($nt == 5) {        } elsif ($nt == 5) {
# Line 3343  $Element->{$HTML_NS}->{datagrid} = { Line 3546  $Element->{$HTML_NS}->{datagrid} = {
3546      };      };
3547    
3548      return ($new_todos);      return ($new_todos);
3549    
3550        ## ISSUE: "xxx<table/>" is disallowed; "<select/>aaa" and "<datalist/>aa"
3551        ## are not disallowed (assuming that form control contents are also
3552        ## prose content).
3553    },    },
3554  };  };
3555    
# Line 3404  $Element->{$HTML_NS}->{menu} = { Line 3611  $Element->{$HTML_NS}->{menu} = {
3611                            $todo->{flag}->{has_descendant}->{significant}};                            $todo->{flag}->{has_descendant}->{significant}};
3612      $todo->{flag}->{has_descendant}->{significant} = 0;      $todo->{flag}->{has_descendant}->{significant} = 0;
3613            
3614      my $content = 'li or inline';      my $content = 'li or phrasing';
3615      while (@nodes) {      while (@nodes) {
3616        my $node = shift @nodes;        my $node = shift @nodes;
3617        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';        $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
# Line 3418  $Element->{$HTML_NS}->{menu} = { Line 3625  $Element->{$HTML_NS}->{menu} = {
3625          if ($self->{pluses}->{$node_ns}->{$node_ln}) {          if ($self->{pluses}->{$node_ns}->{$node_ln}) {
3626            #            #
3627          } elsif ($node_ns eq $HTML_NS and $node_ln eq 'li') {          } elsif ($node_ns eq $HTML_NS and $node_ln eq 'li') {
3628            if ($content eq 'inline') {            if ($content eq 'phrasing') {
3629              $not_allowed = 1;              $not_allowed = 1;
3630            } elsif ($content eq 'li or inline') {            } elsif ($content eq 'li or phrasing') {
3631              $content = 'li';              $content = 'li';
3632            }            }
3633          } else {          } else {
3634            if ($HTMLStrictlyInlineLevelElements->{$node_ns}->{$node_ln} or            if ($HTMLPhrasingContent->{$node_ns}->{$node_ln}) {
3635                $HTMLStructuredInlineLevelElements->{$node_ns}->{$node_ln}) {              $content = 'phrasing';
             $content = 'inline';  
3636            } else {            } else {
3637              $not_allowed = 1;              $not_allowed = 1;
3638            }            }
# Line 3440  $Element->{$HTML_NS}->{menu} = { Line 3646  $Element->{$HTML_NS}->{menu} = {
3646          if ($node->data =~ /[^\x09-\x0D\x20]/) {          if ($node->data =~ /[^\x09-\x0D\x20]/) {
3647            if ($content eq 'li') {            if ($content eq 'li') {
3648              $self->{onerror}->(node => $node, type => 'character not allowed');              $self->{onerror}->(node => $node, type => 'character not allowed');
3649            } elsif ($content eq 'li or inline') {            } elsif ($content eq 'li or phrasing') {
3650              $content = 'inline';              $content = 'phrasing';
3651            }            }
3652            $todo->{flag}->{has_descendant}->{significant} = 1;            $todo->{flag}->{has_descendant}->{significant} = 1;
3653          }          }
# Line 3451  $Element->{$HTML_NS}->{menu} = { Line 3657  $Element->{$HTML_NS}->{menu} = {
3657      }      }
3658    
3659      for (@$new_todos) {      for (@$new_todos) {
3660        $_->{inline} = 1;        $_->{flag}->{in_menu} = 1;
3661      }      }
3662    
3663      push @$new_todos, {      push @$new_todos, {
# Line 3539  $Element->{$HTML_NS}->{nest} = { Line 3745  $Element->{$HTML_NS}->{nest} = {
3745    
3746  $Element->{$HTML_NS}->{legend} = {  $Element->{$HTML_NS}->{legend} = {
3747    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
3748    checker => sub {    checker => $HTMLPhrasingContentChecker,
     my ($self, $todo) = @_;  
   
     my $parent = $todo->{node}->manakai_parent_element;  
     if (defined $parent) {  
       my $nsuri = $parent->namespace_uri;  
       $nsuri = '' unless defined $nsuri;  
       my $ln = $parent->manakai_local_name;  
       if ($nsuri eq $HTML_NS and $ln eq 'figure') {  
         return $HTMLInlineChecker->($self, $todo);  
       } else {  
         return $HTMLStrictlyInlineChecker->($self, $todo);  
       }  
     } else {  
       return $HTMLInlineChecker->($self, $todo);  
     }  
   
     ## ISSUE: Content model is defined only for fieldset/legend,  
     ## details/legend, and figure/legend.  
   },  
3749  };  };
3750    
3751  $Element->{$HTML_NS}->{div} = {  $Element->{$HTML_NS}->{div} = {
3752    attrs_checker => $GetHTMLAttrsChecker->({}),    attrs_checker => $GetHTMLAttrsChecker->({}),
3753    checker => $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'style'),    checker => $HTMLTransparentChecker,
3754  };  };
3755    
3756  $Element->{$HTML_NS}->{font} = {  $Element->{$HTML_NS}->{font} = {

Legend:
Removed from v.1.28  
changed lines
  Added in v.1.29

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24