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

Contents of /markup/html/whatpm/Whatpm/ContentChecker.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations) (download)
Sun May 13 08:45:47 2007 UTC (17 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +13 -10 lines
++ whatpm/t/ChangeLog	13 May 2007 08:45:31 -0000
	* content-model-1.dat: Tests for |li| content model are added.

2007-05-13  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ChangeLog	13 May 2007 08:45:15 -0000
	* ContentChecker.pm (html:li checker): Implemented.

2007-05-13  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Whatpm::ContentChecker;
2     use strict;
3    
4 wakaba 1.3 ## ANY
5     my $AnyChecker = sub {
6 wakaba 1.4 my ($self, $todo) = @_;
7     my $el = $todo->{node};
8     my $new_todos = [];
9 wakaba 1.3 my @nodes = (@{$el->child_nodes});
10     while (@nodes) {
11     my $node = shift @nodes;
12     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
13    
14     my $nt = $node->node_type;
15     if ($nt == 1) {
16     my $node_ns = $node->namespace_uri;
17     $node_ns = '' unless defined $node_ns;
18     my $node_ln = $node->manakai_local_name;
19     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
20     $self->{onerror}->(node => $node, type => 'element not allowed');
21     }
22 wakaba 1.4 push @$new_todos, {type => 'element', node => $node};
23 wakaba 1.3 } elsif ($nt == 5) {
24     unshift @nodes, @{$node->child_nodes};
25     }
26     }
27 wakaba 1.4 return ($new_todos);
28 wakaba 1.3 }; # $AnyChecker
29    
30 wakaba 1.1 my $ElementDefault = {
31     checker => sub {
32 wakaba 1.4 my ($self, $todo) = @_;
33     $self->{onerror}->(node => $todo->{node}, type => 'element not supported');
34     return $AnyChecker->($self, $todo);
35 wakaba 1.1 },
36     };
37    
38     my $Element = {};
39    
40     my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
41    
42     my $HTMLMetadataElements = [
43     [$HTML_NS, 'link'],
44     [$HTML_NS, 'meta'],
45     [$HTML_NS, 'style'],
46     [$HTML_NS, 'script'],
47     [$HTML_NS, 'event-source'],
48     [$HTML_NS, 'command'],
49 wakaba 1.3 [$HTML_NS, 'base'],
50 wakaba 1.1 [$HTML_NS, 'title'],
51     ];
52    
53 wakaba 1.2 my $HTMLSectioningElements = {
54     $HTML_NS => {qw/body 1 section 1 nav 1 article 1 blockquote 1 aside 1/},
55     };
56 wakaba 1.1
57     my $HTMLBlockLevelElements = [
58     [$HTML_NS, 'section'],
59     [$HTML_NS, 'nav'],
60     [$HTML_NS, 'article'],
61     [$HTML_NS, 'blockquote'],
62     [$HTML_NS, 'aside'],
63 wakaba 1.2 [$HTML_NS, 'h1'],
64     [$HTML_NS, 'h2'],
65     [$HTML_NS, 'h3'],
66     [$HTML_NS, 'h4'],
67     [$HTML_NS, 'h5'],
68     [$HTML_NS, 'h6'],
69 wakaba 1.1 [$HTML_NS, 'header'],
70     [$HTML_NS, 'footer'],
71     [$HTML_NS, 'address'],
72     [$HTML_NS, 'p'],
73     [$HTML_NS, 'hr'],
74     [$HTML_NS, 'dialog'],
75     [$HTML_NS, 'pre'],
76     [$HTML_NS, 'ol'],
77     [$HTML_NS, 'ul'],
78     [$HTML_NS, 'dl'],
79     [$HTML_NS, 'ins'],
80     [$HTML_NS, 'del'],
81     [$HTML_NS, 'figure'],
82     [$HTML_NS, 'map'],
83     [$HTML_NS, 'table'],
84     [$HTML_NS, 'script'],
85     [$HTML_NS, 'noscript'],
86     [$HTML_NS, 'event-source'],
87     [$HTML_NS, 'details'],
88     [$HTML_NS, 'datagrid'],
89     [$HTML_NS, 'menu'],
90     [$HTML_NS, 'div'],
91     [$HTML_NS, 'font'],
92     ];
93    
94     my $HTMLStrictlyInlineLevelElements = [
95     [$HTML_NS, 'br'],
96     [$HTML_NS, 'a'],
97     [$HTML_NS, 'q'],
98     [$HTML_NS, 'cite'],
99     [$HTML_NS, 'em'],
100     [$HTML_NS, 'strong'],
101     [$HTML_NS, 'small'],
102     [$HTML_NS, 'm'],
103     [$HTML_NS, 'dfn'],
104     [$HTML_NS, 'abbr'],
105     [$HTML_NS, 'time'],
106     [$HTML_NS, 'meter'],
107     [$HTML_NS, 'progress'],
108     [$HTML_NS, 'code'],
109     [$HTML_NS, 'var'],
110     [$HTML_NS, 'samp'],
111     [$HTML_NS, 'kbd'],
112     [$HTML_NS, 'sub'],
113     [$HTML_NS, 'sup'],
114     [$HTML_NS, 'span'],
115     [$HTML_NS, 'i'],
116     [$HTML_NS, 'b'],
117     [$HTML_NS, 'bdo'],
118     [$HTML_NS, 'ins'],
119     [$HTML_NS, 'del'],
120     [$HTML_NS, 'img'],
121     [$HTML_NS, 'iframe'],
122     [$HTML_NS, 'embed'],
123     [$HTML_NS, 'object'],
124     [$HTML_NS, 'video'],
125     [$HTML_NS, 'audio'],
126     [$HTML_NS, 'canvas'],
127     [$HTML_NS, 'area'],
128     [$HTML_NS, 'script'],
129     [$HTML_NS, 'noscript'],
130     [$HTML_NS, 'event-source'],
131     [$HTML_NS, 'command'],
132     [$HTML_NS, 'font'],
133     ];
134    
135     my $HTMLStructuredInlineLevelElements = [
136     [$HTML_NS, 'blockquote'],
137     [$HTML_NS, 'pre'],
138     [$HTML_NS, 'ol'],
139     [$HTML_NS, 'ul'],
140     [$HTML_NS, 'dl'],
141     [$HTML_NS, 'table'],
142     [$HTML_NS, 'menu'],
143     ];
144    
145     my $HTMLInteractiveElements = [
146     [$HTML_NS, 'a'],
147     [$HTML_NS, 'details'],
148     [$HTML_NS, 'datagrid'],
149     ];
150    
151     my $HTMLTransparentElements = [
152     [$HTML_NS, 'ins'],
153     [$HTML_NS, 'font'],
154 wakaba 1.2 [$HTML_NS, 'noscript'], ## NOTE: If scripting is disabled.
155 wakaba 1.1 ];
156    
157 wakaba 1.2 #my $HTMLSemiTransparentElements = [
158     # [$HTML_NS, 'video'],
159     # [$HTML_NS, 'audio'],
160     #];
161 wakaba 1.1
162     my $HTMLEmbededElements = [
163     [$HTML_NS, 'img'],
164     [$HTML_NS, 'iframe'],
165     [$HTML_NS, 'embed'],
166     [$HTML_NS, 'object'],
167     [$HTML_NS, 'video'],
168     [$HTML_NS, 'audio'],
169     [$HTML_NS, 'canvas'],
170     ];
171    
172     ## Empty
173     my $HTMLEmptyChecker = sub {
174 wakaba 1.4 my ($self, $todo) = @_;
175     my $el = $todo->{node};
176     my $new_todos = [];
177 wakaba 1.1 my @nodes = (@{$el->child_nodes});
178    
179     while (@nodes) {
180     my $node = shift @nodes;
181 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
182    
183 wakaba 1.1 my $nt = $node->node_type;
184     if ($nt == 1) {
185 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
186     $self->{onerror}->(node => $node, type => 'element not allowed');
187     my ($sib, $ch) = $self->_check_get_children ($node);
188     unshift @nodes, @$sib;
189 wakaba 1.4 push @$new_todos, @$ch;
190 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
191 wakaba 1.3 if ($node->data =~ /[^\x09-\x0D\x20]/) {
192     $self->{onerror}->(node => $node, type => 'character not allowed');
193     }
194 wakaba 1.1 } elsif ($nt == 5) {
195     unshift @nodes, @{$node->child_nodes};
196     }
197     }
198 wakaba 1.4 return ($new_todos);
199 wakaba 1.1 };
200    
201     ## Text
202     my $HTMLTextChecker = sub {
203 wakaba 1.4 my ($self, $todo) = @_;
204     my $el = $todo->{node};
205     my $new_todos = [];
206 wakaba 1.1 my @nodes = (@{$el->child_nodes});
207    
208     while (@nodes) {
209     my $node = shift @nodes;
210 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
211    
212 wakaba 1.1 my $nt = $node->node_type;
213     if ($nt == 1) {
214 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
215     $self->{onerror}->(node => $node, type => 'element not allowed');
216     my ($sib, $ch) = $self->_check_get_children ($node);
217     unshift @nodes, @$sib;
218 wakaba 1.4 push @$new_todos, @$ch;
219 wakaba 1.1 } elsif ($nt == 5) {
220     unshift @nodes, @{$node->child_nodes};
221     }
222     }
223 wakaba 1.4 return ($new_todos);
224 wakaba 1.1 };
225    
226     ## Zero or more |html:style| elements,
227     ## followed by zero or more block-level elements
228     my $HTMLStylableBlockChecker = sub {
229 wakaba 1.4 my ($self, $todo) = @_;
230     my $el = $todo->{node};
231     my $new_todos = [];
232 wakaba 1.1 my @nodes = (@{$el->child_nodes});
233    
234     my $has_non_style;
235     while (@nodes) {
236     my $node = shift @nodes;
237 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
238    
239 wakaba 1.1 my $nt = $node->node_type;
240     if ($nt == 1) {
241 wakaba 1.2 my $node_ns = $node->namespace_uri;
242     $node_ns = '' unless defined $node_ns;
243     my $node_ln = $node->manakai_local_name;
244     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
245     $self->{onerror}->(node => $node, type => 'element not allowed');
246     }
247 wakaba 1.1 if ($node->manakai_element_type_match ($HTML_NS, 'style')) {
248     if ($has_non_style) {
249 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
250 wakaba 1.1 }
251     } else {
252     $has_non_style = 1;
253     CHK: {
254     for (@{$HTMLBlockLevelElements}) {
255     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
256     last CHK;
257     }
258     }
259 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
260 wakaba 1.1 } # CHK
261     }
262 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
263     unshift @nodes, @$sib;
264 wakaba 1.4 push @$new_todos, @$ch;
265 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
266     if ($node->data =~ /[^\x09-\x0D\x20]/) {
267 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
268 wakaba 1.1 }
269     } elsif ($nt == 5) {
270     unshift @nodes, @{$node->child_nodes};
271     }
272     }
273 wakaba 1.4 return ($new_todos);
274 wakaba 1.1 }; # $HTMLStylableBlockChecker
275    
276     ## Zero or more block-level elements
277     my $HTMLBlockChecker = sub {
278 wakaba 1.4 my ($self, $todo) = @_;
279     my $el = $todo->{node};
280     my $new_todos = [];
281 wakaba 1.1 my @nodes = (@{$el->child_nodes});
282    
283     while (@nodes) {
284     my $node = shift @nodes;
285 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
286    
287 wakaba 1.1 my $nt = $node->node_type;
288     if ($nt == 1) {
289 wakaba 1.2 my $node_ns = $node->namespace_uri;
290     $node_ns = '' unless defined $node_ns;
291     my $node_ln = $node->manakai_local_name;
292     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
293     $self->{onerror}->(node => $node, type => 'element not allowed');
294     }
295 wakaba 1.1 CHK: {
296     for (@{$HTMLBlockLevelElements}) {
297     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
298     last CHK;
299     }
300     }
301 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
302 wakaba 1.1 } # CHK
303 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
304     unshift @nodes, @$sib;
305 wakaba 1.4 push @$new_todos, @$ch;
306 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
307     if ($node->data =~ /[^\x09-\x0D\x20]/) {
308 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
309 wakaba 1.1 }
310     } elsif ($nt == 5) {
311     unshift @nodes, @{$node->child_nodes};
312     }
313     }
314 wakaba 1.4 return ($new_todos);
315 wakaba 1.1 }; # $HTMLBlockChecker
316    
317     ## Inline-level content
318     my $HTMLInlineChecker = sub {
319 wakaba 1.4 my ($self, $todo) = @_;
320     my $el = $todo->{node};
321     my $new_todos = [];
322 wakaba 1.1 my @nodes = (@{$el->child_nodes});
323    
324     while (@nodes) {
325     my $node = shift @nodes;
326 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
327    
328 wakaba 1.1 my $nt = $node->node_type;
329     if ($nt == 1) {
330 wakaba 1.2 my $node_ns = $node->namespace_uri;
331     $node_ns = '' unless defined $node_ns;
332     my $node_ln = $node->manakai_local_name;
333     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
334     $self->{onerror}->(node => $node, type => 'element not allowed');
335     }
336 wakaba 1.1 CHK: {
337     for (@{$HTMLStrictlyInlineLevelElements},
338     @{$HTMLStructuredInlineLevelElements}) {
339     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
340     last CHK;
341     }
342     }
343 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
344 wakaba 1.1 } # CHK
345 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
346     unshift @nodes, @$sib;
347 wakaba 1.4 push @$new_todos, @$ch;
348 wakaba 1.1 } elsif ($nt == 5) {
349     unshift @nodes, @{$node->child_nodes};
350     }
351     }
352 wakaba 1.4
353     for (@$new_todos) {
354     $_->{inline} = 1;
355     }
356     return ($new_todos);
357     }; # $HTMLInlineChecker
358 wakaba 1.1
359     my $HTMLSignificantInlineChecker = $HTMLInlineChecker;
360     ## TODO: check significant content
361    
362     ## Strictly inline-level content
363     my $HTMLStrictlyInlineChecker = sub {
364 wakaba 1.4 my ($self, $todo) = @_;
365     my $el = $todo->{node};
366     my $new_todos = [];
367 wakaba 1.1 my @nodes = (@{$el->child_nodes});
368    
369     while (@nodes) {
370     my $node = shift @nodes;
371 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
372    
373 wakaba 1.1 my $nt = $node->node_type;
374     if ($nt == 1) {
375 wakaba 1.2 my $node_ns = $node->namespace_uri;
376     $node_ns = '' unless defined $node_ns;
377     my $node_ln = $node->manakai_local_name;
378     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
379     $self->{onerror}->(node => $node, type => 'element not allowed');
380     }
381 wakaba 1.1 CHK: {
382     for (@{$HTMLStrictlyInlineLevelElements}) {
383     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
384     last CHK;
385     }
386     }
387 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
388 wakaba 1.1 } # CHK
389 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
390     unshift @nodes, @$sib;
391 wakaba 1.4 push @$new_todos, @$ch;
392 wakaba 1.1 } elsif ($nt == 5) {
393     unshift @nodes, @{$node->child_nodes};
394     }
395     }
396 wakaba 1.4
397     for (@$new_todos) {
398     $_->{inline} = 1;
399     $_->{strictly_inline} = 1;
400     }
401     return ($new_todos);
402 wakaba 1.1 }; # $HTMLStrictlyInlineChecker
403    
404     my $HTMLSignificantStrictlyInlineChecker = $HTMLStrictlyInlineChecker;
405     ## TODO: check significant content
406    
407 wakaba 1.4 ## Inline-level or strictly inline-kevek content
408     my $HTMLInlineOrStrictlyInlineChecker = sub {
409     my ($self, $todo) = @_;
410     my $el = $todo->{node};
411     my $new_todos = [];
412     my @nodes = (@{$el->child_nodes});
413    
414     while (@nodes) {
415     my $node = shift @nodes;
416     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
417    
418     my $nt = $node->node_type;
419     if ($nt == 1) {
420     my $node_ns = $node->namespace_uri;
421     $node_ns = '' unless defined $node_ns;
422     my $node_ln = $node->manakai_local_name;
423     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
424     $self->{onerror}->(node => $node, type => 'element not allowed');
425     }
426     CHK: {
427     for (@{$HTMLStrictlyInlineLevelElements},
428     $todo->{strictly_inline} ? () : @{$HTMLStructuredInlineLevelElements}) {
429     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
430     last CHK;
431     }
432     }
433     $self->{onerror}->(node => $node, type => 'element not allowed');
434     } # CHK
435     my ($sib, $ch) = $self->_check_get_children ($node);
436     unshift @nodes, @$sib;
437     push @$new_todos, @$ch;
438     } elsif ($nt == 5) {
439     unshift @nodes, @{$node->child_nodes};
440     }
441     }
442    
443     for (@$new_todos) {
444     $_->{inline} = 1;
445     $_->{strictly_inline} = 1;
446     }
447     return ($new_todos);
448     }; # $HTMLInlineOrStrictlyInlineChecker
449    
450 wakaba 1.1 my $HTMLBlockOrInlineChecker = sub {
451 wakaba 1.4 my ($self, $todo) = @_;
452     my $el = $todo->{node};
453     my $new_todos = [];
454 wakaba 1.1 my @nodes = (@{$el->child_nodes});
455    
456     my $content = 'block-or-inline'; # or 'block' or 'inline'
457     my @block_not_inline;
458     while (@nodes) {
459     my $node = shift @nodes;
460 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
461    
462 wakaba 1.1 my $nt = $node->node_type;
463     if ($nt == 1) {
464 wakaba 1.2 my $node_ns = $node->namespace_uri;
465     $node_ns = '' unless defined $node_ns;
466     my $node_ln = $node->manakai_local_name;
467     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
468     $self->{onerror}->(node => $node, type => 'element not allowed');
469     }
470 wakaba 1.1 if ($content eq 'block') {
471     CHK: {
472     for (@{$HTMLBlockLevelElements}) {
473     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
474     last CHK;
475     }
476     }
477 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
478 wakaba 1.1 } # CHK
479     } elsif ($content eq 'inline') {
480     CHK: {
481     for (@{$HTMLStrictlyInlineLevelElements},
482     @{$HTMLStructuredInlineLevelElements}) {
483     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
484     last CHK;
485     }
486     }
487 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
488 wakaba 1.1 } # CHK
489     } else {
490     my $is_block;
491     my $is_inline;
492     for (@{$HTMLBlockLevelElements}) {
493     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
494     $is_block = 1;
495     last;
496     }
497     }
498    
499     for (@{$HTMLStrictlyInlineLevelElements},
500     @{$HTMLStructuredInlineLevelElements}) {
501     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
502     $is_inline = 1;
503     last;
504     }
505     }
506    
507     push @block_not_inline, $node if $is_block and not $is_inline;
508     unless ($is_block) {
509     $content = 'inline';
510     for (@block_not_inline) {
511 wakaba 1.2 $self->{onerror}->(node => $_, type => 'element not allowed');
512 wakaba 1.1 }
513     unless ($is_inline) {
514 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
515 wakaba 1.1 }
516     }
517     }
518 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
519     unshift @nodes, @$sib;
520 wakaba 1.4 push @$new_todos, @$ch;
521 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
522     if ($node->data =~ /[^\x09-\x0D\x20]/) {
523     if ($content eq 'block') {
524 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
525 wakaba 1.1 } else {
526     $content = 'inline';
527     for (@block_not_inline) {
528 wakaba 1.2 $self->{onerror}->(node => $_, type => 'element not allowed');
529 wakaba 1.1 }
530     }
531     }
532     } elsif ($nt == 5) {
533     unshift @nodes, @{$node->child_nodes};
534     }
535     }
536 wakaba 1.4
537     if ($content eq 'inline') {
538     for (@$new_todos) {
539     $_->{inline} = 1;
540     }
541     }
542     return ($new_todos);
543 wakaba 1.1 };
544    
545 wakaba 1.2 ## Zero or more XXX element, then either block-level or inline-level
546     my $GetHTMLZeroOrMoreThenBlockOrInlineChecker = sub ($$) {
547     my ($elnsuri, $ellname) = @_;
548     return sub {
549 wakaba 1.4 my ($self, $todo) = @_;
550     my $el = $todo->{node};
551     my $new_todos = [];
552 wakaba 1.2 my @nodes = (@{$el->child_nodes});
553    
554     my $has_non_style;
555     my $content = 'block-or-inline'; # or 'block' or 'inline'
556     my @block_not_inline;
557     while (@nodes) {
558     my $node = shift @nodes;
559     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
560    
561     my $nt = $node->node_type;
562     if ($nt == 1) {
563     my $node_ns = $node->namespace_uri;
564     $node_ns = '' unless defined $node_ns;
565     my $node_ln = $node->manakai_local_name;
566     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
567     $self->{onerror}->(node => $node, type => 'element not allowed');
568     }
569     if ($node->manakai_element_type_match ($elnsuri, $ellname)) {
570     if ($has_non_style) {
571     $self->{onerror}->(node => $node, type => 'element not allowed');
572     }
573     } elsif ($content eq 'block') {
574     $has_non_style = 1;
575     CHK: {
576     for (@{$HTMLBlockLevelElements}) {
577     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
578     last CHK;
579     }
580     }
581     $self->{onerror}->(node => $node, type => 'element not allowed');
582     } # CHK
583     } elsif ($content eq 'inline') {
584     $has_non_style = 1;
585     CHK: {
586     for (@{$HTMLStrictlyInlineLevelElements},
587     @{$HTMLStructuredInlineLevelElements}) {
588     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
589     last CHK;
590     }
591     }
592     $self->{onerror}->(node => $node, type => 'element not allowed');
593     } # CHK
594     } else {
595     $has_non_style = 1;
596     my $is_block;
597     my $is_inline;
598 wakaba 1.1 for (@{$HTMLBlockLevelElements}) {
599     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
600 wakaba 1.2 $is_block = 1;
601     last;
602 wakaba 1.1 }
603     }
604 wakaba 1.2
605 wakaba 1.1 for (@{$HTMLStrictlyInlineLevelElements},
606     @{$HTMLStructuredInlineLevelElements}) {
607     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
608 wakaba 1.2 $is_inline = 1;
609     last;
610 wakaba 1.1 }
611     }
612 wakaba 1.2
613     push @block_not_inline, $node if $is_block and not $is_inline;
614     unless ($is_block) {
615     $content = 'inline';
616     for (@block_not_inline) {
617     $self->{onerror}->(node => $_, type => 'element not allowed');
618     }
619     unless ($is_inline) {
620     $self->{onerror}->(node => $node, type => 'element not allowed');
621     }
622 wakaba 1.1 }
623     }
624 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
625     unshift @nodes, @$sib;
626 wakaba 1.4 push @$new_todos, @$ch;
627 wakaba 1.2 } elsif ($nt == 3 or $nt == 4) {
628     if ($node->data =~ /[^\x09-\x0D\x20]/) {
629     $has_non_style = 1;
630     if ($content eq 'block') {
631     $self->{onerror}->(node => $node, type => 'character not allowed');
632     } else {
633     $content = 'inline';
634     for (@block_not_inline) {
635     $self->{onerror}->(node => $_, type => 'element not allowed');
636     }
637 wakaba 1.1 }
638     }
639 wakaba 1.2 } elsif ($nt == 5) {
640     unshift @nodes, @{$node->child_nodes};
641 wakaba 1.1 }
642     }
643 wakaba 1.4
644     if ($content eq 'inline') {
645     for (@$new_todos) {
646     $_->{inline} = 1;
647     }
648     }
649     return ($new_todos);
650 wakaba 1.2 };
651     }; # $GetHTMLZeroOrMoreThenBlockOrInlineChecker
652 wakaba 1.1
653     my $HTMLTransparentChecker = $HTMLBlockOrInlineChecker;
654    
655     $Element->{$HTML_NS}->{html} = {
656     checker => sub {
657 wakaba 1.4 my ($self, $todo) = @_;
658     my $el = $todo->{node};
659     my $new_todos = [];
660 wakaba 1.1 my @nodes = (@{$el->child_nodes});
661    
662     my $phase = 'before head';
663     while (@nodes) {
664     my $node = shift @nodes;
665 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
666    
667 wakaba 1.1 my $nt = $node->node_type;
668     if ($nt == 1) {
669 wakaba 1.2 my $node_ns = $node->namespace_uri;
670     $node_ns = '' unless defined $node_ns;
671     my $node_ln = $node->manakai_local_name;
672     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
673     $self->{onerror}->(node => $node, type => 'element not allowed');
674     }
675 wakaba 1.1 if ($phase eq 'before head') {
676     if ($node->manakai_element_type_match ($HTML_NS, 'head')) {
677     $phase = 'after head';
678     } elsif ($node->manakai_element_type_match ($HTML_NS, 'body')) {
679 wakaba 1.2 $self->{onerror}
680 wakaba 1.3 ->(node => $node, type => 'ps element missing:head');
681 wakaba 1.1 $phase = 'after body';
682     } else {
683 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
684 wakaba 1.1 # before head
685     }
686     } elsif ($phase eq 'after head') {
687     if ($node->manakai_element_type_match ($HTML_NS, 'body')) {
688     $phase = 'after body';
689     } else {
690 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
691 wakaba 1.1 # after head
692     }
693     } else { #elsif ($phase eq 'after body') {
694 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
695 wakaba 1.1 # after body
696     }
697 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
698     unshift @nodes, @$sib;
699 wakaba 1.4 push @$new_todos, @$ch;
700 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
701     if ($node->data =~ /[^\x09-\x0D\x20]/) {
702 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
703 wakaba 1.1 }
704     } elsif ($nt == 5) {
705     unshift @nodes, @{$node->child_nodes};
706     }
707     }
708 wakaba 1.3
709     if ($phase eq 'before head') {
710     $self->{onerror}->(node => $el, type => 'child element missing:head');
711     $self->{onerror}->(node => $el, type => 'child element missing:body');
712     } elsif ($phase eq 'after head') {
713     $self->{onerror}->(node => $el, type => 'child element missing:body');
714     }
715    
716 wakaba 1.4 return ($new_todos);
717 wakaba 1.1 },
718     };
719    
720     $Element->{$HTML_NS}->{head} = {
721     checker => sub {
722 wakaba 1.4 my ($self, $todo) = @_;
723     my $el = $todo->{node};
724     my $new_todos = [];
725 wakaba 1.1 my @nodes = (@{$el->child_nodes});
726    
727     my $has_title;
728 wakaba 1.3 my $phase = 'initial'; # 'after charset', 'after base'
729 wakaba 1.1 while (@nodes) {
730     my $node = shift @nodes;
731 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
732    
733 wakaba 1.1 my $nt = $node->node_type;
734     if ($nt == 1) {
735 wakaba 1.2 my $node_ns = $node->namespace_uri;
736     $node_ns = '' unless defined $node_ns;
737     my $node_ln = $node->manakai_local_name;
738     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
739     $self->{onerror}->(node => $node, type => 'element not allowed');
740     }
741 wakaba 1.1 if ($node->manakai_element_type_match ($HTML_NS, 'title')) {
742 wakaba 1.3 $phase = 'after base';
743 wakaba 1.1 unless ($has_title) {
744     $has_title = 1;
745     } else {
746 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
747 wakaba 1.1 }
748     } elsif ($node->manakai_element_type_match ($HTML_NS, 'meta')) {
749     if ($node->has_attribute_ns (undef, 'charset')) {
750 wakaba 1.3 if ($phase eq 'initial') {
751     $phase = 'after charset';
752 wakaba 1.1 } else {
753 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
754 wakaba 1.3 ## NOTE: See also |base|'s "contexts" field in the spec
755 wakaba 1.1 }
756     } else {
757 wakaba 1.3 $phase = 'after base';
758 wakaba 1.1 }
759     } elsif ($node->manakai_element_type_match ($HTML_NS, 'base')) {
760 wakaba 1.3 if ($phase eq 'initial' or $phase eq 'after charset') {
761     $phase = 'after base';
762 wakaba 1.1 } else {
763 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
764 wakaba 1.1 }
765     } else {
766 wakaba 1.3 $phase = 'after base';
767 wakaba 1.1 CHK: {
768     for (@{$HTMLMetadataElements}) {
769     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
770     last CHK;
771     }
772     }
773 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
774 wakaba 1.1 } # CHK
775     }
776 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
777     unshift @nodes, @$sib;
778 wakaba 1.4 push @$new_todos, @$ch;
779 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
780     if ($node->data =~ /[^\x09-\x0D\x20]/) {
781 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
782 wakaba 1.1 }
783     } elsif ($nt == 5) {
784     unshift @nodes, @{$node->child_nodes};
785     }
786     }
787     unless ($has_title) {
788 wakaba 1.3 $self->{onerror}->(node => $el, type => 'child element missing:title');
789 wakaba 1.1 }
790 wakaba 1.4 return ($new_todos);
791 wakaba 1.1 },
792     };
793    
794     $Element->{$HTML_NS}->{title} = {
795     checker => $HTMLTextChecker,
796     };
797    
798     $Element->{$HTML_NS}->{base} = {
799     checker => $HTMLEmptyChecker,
800     };
801    
802     $Element->{$HTML_NS}->{link} = {
803     checker => $HTMLEmptyChecker,
804     };
805    
806     $Element->{$HTML_NS}->{meta} = {
807     checker => $HTMLEmptyChecker,
808     };
809    
810     ## NOTE: |html:style| has no conformance creteria on content model
811 wakaba 1.3 $Element->{$HTML_NS}->{style} = {
812     checker => $AnyChecker,
813     };
814 wakaba 1.1
815     $Element->{$HTML_NS}->{body} = {
816     checker => $HTMLBlockChecker,
817     };
818    
819     $Element->{$HTML_NS}->{section} = {
820     checker => $HTMLStylableBlockChecker,
821     };
822    
823     $Element->{$HTML_NS}->{nav} = {
824     checker => $HTMLBlockOrInlineChecker,
825     };
826    
827     $Element->{$HTML_NS}->{article} = {
828     checker => $HTMLStylableBlockChecker,
829     };
830    
831     $Element->{$HTML_NS}->{blockquote} = {
832     checker => $HTMLBlockChecker,
833     };
834    
835     $Element->{$HTML_NS}->{aside} = {
836 wakaba 1.2 checker => $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'style'),
837 wakaba 1.1 };
838    
839     $Element->{$HTML_NS}->{h1} = {
840     checker => $HTMLSignificantStrictlyInlineChecker,
841     };
842    
843     $Element->{$HTML_NS}->{h2} = {
844     checker => $HTMLSignificantStrictlyInlineChecker,
845     };
846    
847     $Element->{$HTML_NS}->{h3} = {
848     checker => $HTMLSignificantStrictlyInlineChecker,
849     };
850    
851     $Element->{$HTML_NS}->{h4} = {
852     checker => $HTMLSignificantStrictlyInlineChecker,
853     };
854    
855     $Element->{$HTML_NS}->{h5} = {
856     checker => $HTMLSignificantStrictlyInlineChecker,
857     };
858    
859     $Element->{$HTML_NS}->{h6} = {
860     checker => $HTMLSignificantStrictlyInlineChecker,
861     };
862    
863     ## TODO: header
864    
865 wakaba 1.2 $Element->{$HTML_NS}->{footer} = {
866     checker => sub { ## block -hn -header -footer -sectioning or inline
867 wakaba 1.4 my ($self, $todo) = @_;
868     my $el = $todo->{node};
869     my $new_todos = [];
870 wakaba 1.2 my @nodes = (@{$el->child_nodes});
871    
872     my $content = 'block-or-inline'; # or 'block' or 'inline'
873     my @block_not_inline;
874     while (@nodes) {
875     my $node = shift @nodes;
876     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
877    
878     my $nt = $node->node_type;
879     if ($nt == 1) {
880     my $node_ns = $node->namespace_uri;
881     $node_ns = '' unless defined $node_ns;
882     my $node_ln = $node->manakai_local_name;
883     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
884     $self->{onerror}->(node => $node, type => 'element not allowed');
885     } elsif ($node_ns eq $HTML_NS and
886     {
887     qw/h1 1 h2 1 h3 1 h4 1 h5 1 h6 1 header 1 footer 1/
888     }->{$node_ln}) {
889     $self->{onerror}->(node => $node, type => 'element not allowed');
890     } elsif ($HTMLSectioningElements->{$node_ns}->{$node_ln}) {
891     $self->{onerror}->(node => $node, type => 'element not allowed');
892     }
893     if ($content eq 'block') {
894     CHK: {
895     for (@{$HTMLBlockLevelElements}) {
896     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
897     last CHK;
898     }
899     }
900     $self->{onerror}->(node => $node, type => 'element not allowed');
901     } # CHK
902     } elsif ($content eq 'inline') {
903     CHK: {
904     for (@{$HTMLStrictlyInlineLevelElements},
905     @{$HTMLStructuredInlineLevelElements}) {
906     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
907     last CHK;
908     }
909     }
910     $self->{onerror}->(node => $node, type => 'element not allowed');
911     } # CHK
912     } else {
913     my $is_block;
914     my $is_inline;
915     for (@{$HTMLBlockLevelElements}) {
916     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
917     $is_block = 1;
918     last;
919     }
920     }
921    
922     for (@{$HTMLStrictlyInlineLevelElements},
923     @{$HTMLStructuredInlineLevelElements}) {
924     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
925     $is_inline = 1;
926     last;
927     }
928     }
929    
930     push @block_not_inline, $node if $is_block and not $is_inline;
931     unless ($is_block) {
932     $content = 'inline';
933     for (@block_not_inline) {
934     $self->{onerror}->(node => $_, type => 'element not allowed');
935     }
936     unless ($is_inline) {
937     $self->{onerror}->(node => $node, type => 'element not allowed');
938     }
939     }
940     }
941     my ($sib, $ch) = $self->_check_get_children ($node);
942     unshift @nodes, @$sib;
943 wakaba 1.4 push @$new_todos, @$ch;
944 wakaba 1.2 } elsif ($nt == 3 or $nt == 4) {
945     if ($node->data =~ /[^\x09-\x0D\x20]/) {
946     if ($content eq 'block') {
947     $self->{onerror}->(node => $node, type => 'character not allowed');
948     } else {
949     $content = 'inline';
950     for (@block_not_inline) {
951     $self->{onerror}->(node => $_, type => 'element not allowed');
952     }
953     }
954     }
955     } elsif ($nt == 5) {
956     unshift @nodes, @{$node->child_nodes};
957     }
958     }
959    
960     my $end = $self->_add_minuses
961     ({$HTML_NS => {qw/h1 1 h2 1 h3 1 h4 1 h5 1 h6 1/}},
962     $HTMLSectioningElements);
963 wakaba 1.4 push @$new_todos, $end;
964 wakaba 1.2
965 wakaba 1.4 if ($content eq 'inline') {
966     for (@$new_todos) {
967     $_->{inline} = 1;
968     }
969     }
970    
971     return ($new_todos);
972 wakaba 1.2 },
973     };
974 wakaba 1.1
975     $Element->{$HTML_NS}->{address} = {
976     checker => $HTMLInlineChecker,
977     };
978    
979     $Element->{$HTML_NS}->{p} = {
980     checker => $HTMLSignificantInlineChecker,
981     };
982    
983     $Element->{$HTML_NS}->{hr} = {
984     checker => $HTMLEmptyChecker,
985     };
986    
987     $Element->{$HTML_NS}->{br} = {
988     checker => $HTMLEmptyChecker,
989     };
990    
991     $Element->{$HTML_NS}->{dialog} = {
992     checker => sub {
993 wakaba 1.4 my ($self, $todo) = @_;
994     my $el = $todo->{node};
995     my $new_todos = [];
996 wakaba 1.1 my @nodes = (@{$el->child_nodes});
997    
998     my $phase = 'before dt';
999     while (@nodes) {
1000     my $node = shift @nodes;
1001 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1002    
1003 wakaba 1.1 my $nt = $node->node_type;
1004     if ($nt == 1) {
1005 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1006 wakaba 1.1 if ($phase eq 'before dt') {
1007     if ($node->manakai_element_type_match ($HTML_NS, 'dt')) {
1008     $phase = 'before dd';
1009     } elsif ($node->manakai_element_type_match ($HTML_NS, 'dd')) {
1010 wakaba 1.2 $self->{onerror}
1011 wakaba 1.3 ->(node => $node, type => 'ps element missing:dt');
1012 wakaba 1.1 $phase = 'before dt';
1013     } else {
1014 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1015 wakaba 1.1 }
1016     } else { # before dd
1017     if ($node->manakai_element_type_match ($HTML_NS, 'dd')) {
1018     $phase = 'before dt';
1019     } elsif ($node->manakai_element_type_match ($HTML_NS, 'dt')) {
1020 wakaba 1.2 $self->{onerror}
1021 wakaba 1.3 ->(node => $node, type => 'ps element missing:dd');
1022 wakaba 1.1 $phase = 'before dd';
1023     } else {
1024 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1025 wakaba 1.1 }
1026     }
1027 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1028     unshift @nodes, @$sib;
1029 wakaba 1.4 push @$new_todos, @$ch;
1030 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1031     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1032 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1033 wakaba 1.1 }
1034     } elsif ($nt == 5) {
1035     unshift @nodes, @{$node->child_nodes};
1036     }
1037     }
1038     if ($phase eq 'before dd') {
1039 wakaba 1.3 $self->{onerror}->(node => $el, type => 'ps element missing:dd');
1040 wakaba 1.1 }
1041 wakaba 1.4 return ($new_todos);
1042 wakaba 1.1 },
1043     };
1044    
1045     $Element->{$HTML_NS}->{pre} = {
1046     checker => $HTMLStrictlyInlineChecker,
1047     };
1048    
1049     $Element->{$HTML_NS}->{ol} = {
1050     checker => sub {
1051 wakaba 1.4 my ($self, $todo) = @_;
1052     my $el = $todo->{node};
1053     my $new_todos = [];
1054 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1055    
1056     while (@nodes) {
1057     my $node = shift @nodes;
1058 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1059    
1060 wakaba 1.1 my $nt = $node->node_type;
1061     if ($nt == 1) {
1062 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1063 wakaba 1.1 unless ($node->manakai_element_type_match ($HTML_NS, 'li')) {
1064 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1065 wakaba 1.1 }
1066 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1067     unshift @nodes, @$sib;
1068 wakaba 1.4 push @$new_todos, @$ch;
1069 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1070     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1071 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1072 wakaba 1.1 }
1073     } elsif ($nt == 5) {
1074     unshift @nodes, @{$node->child_nodes};
1075     }
1076     }
1077 wakaba 1.4
1078     if ($todo->{inline}) {
1079     for (@$new_todos) {
1080     $_->{inline} = 1;
1081     }
1082     }
1083     return ($new_todos);
1084 wakaba 1.1 },
1085     };
1086    
1087     $Element->{$HTML_NS}->{ul} = {
1088     checker => $Element->{$HTML_NS}->{ol}->{checker},
1089     };
1090    
1091 wakaba 1.5
1092     $Element->{$HTML_NS}->{li} = {
1093     checker => sub {
1094     my ($self, $todo) = @_;
1095     if ($todo->{inline}) {
1096     return $HTMLInlineChecker->($self, $todo);
1097     } else {
1098     return $HTMLBlockOrInlineChecker->($self, $todo);
1099     }
1100     },
1101     };
1102 wakaba 1.1
1103     $Element->{$HTML_NS}->{dl} = {
1104     checker => sub {
1105 wakaba 1.4 my ($self, $todo) = @_;
1106     my $el = $todo->{node};
1107     my $new_todos = [];
1108 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1109    
1110     my $phase = 'before dt';
1111     while (@nodes) {
1112     my $node = shift @nodes;
1113 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1114    
1115 wakaba 1.1 my $nt = $node->node_type;
1116     if ($nt == 1) {
1117 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1118 wakaba 1.1 if ($phase eq 'in dds') {
1119     if ($node->manakai_element_type_match ($HTML_NS, 'dd')) {
1120     #$phase = 'in dds';
1121     } elsif ($node->manakai_element_type_match ($HTML_NS, 'dt')) {
1122     $phase = 'in dts';
1123     } else {
1124 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1125 wakaba 1.1 }
1126     } elsif ($phase eq 'in dts') {
1127     if ($node->manakai_element_type_match ($HTML_NS, 'dt')) {
1128     #$phase = 'in dts';
1129     } elsif ($node->manakai_element_type_match ($HTML_NS, 'dd')) {
1130     $phase = 'in dds';
1131     } else {
1132 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1133 wakaba 1.1 }
1134     } else { # before dt
1135     if ($node->manakai_element_type_match ($HTML_NS, 'dt')) {
1136     $phase = 'in dts';
1137     } elsif ($node->manakai_element_type_match ($HTML_NS, 'dd')) {
1138 wakaba 1.2 $self->{onerror}
1139 wakaba 1.3 ->(node => $node, type => 'ps element missing:dt');
1140 wakaba 1.1 $phase = 'in dds';
1141     } else {
1142 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1143 wakaba 1.1 }
1144     }
1145 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1146     unshift @nodes, @$sib;
1147 wakaba 1.4 push @$new_todos, @$ch;
1148 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1149     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1150 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1151 wakaba 1.1 }
1152     } elsif ($nt == 5) {
1153     unshift @nodes, @{$node->child_nodes};
1154     }
1155     }
1156     if ($phase eq 'in dts') {
1157 wakaba 1.3 $self->{onerror}->(node => $el, type => 'ps element missing:dd');
1158 wakaba 1.1 }
1159 wakaba 1.4
1160     if ($todo->{inline}) {
1161     for (@$new_todos) {
1162     $_->{inline} = 1;
1163     }
1164     }
1165     return ($new_todos);
1166 wakaba 1.1 },
1167     };
1168    
1169     $Element->{$HTML_NS}->{dt} = {
1170     checker => $HTMLStrictlyInlineChecker,
1171     };
1172    
1173 wakaba 1.4 $Element->{$HTML_NS}->{dd} = {
1174 wakaba 1.5 checker => $Element->{$HTML_NS}->{li}->{checker},
1175 wakaba 1.4 };
1176 wakaba 1.1
1177     ## TODO: a
1178    
1179 wakaba 1.4 $Element->{$HTML_NS}->{q} = {
1180     checker => $HTMLInlineOrStrictlyInlineChecker,
1181     };
1182 wakaba 1.1
1183     $Element->{$HTML_NS}->{cite} = {
1184     checker => $HTMLStrictlyInlineChecker,
1185     };
1186    
1187 wakaba 1.4 $Element->{$HTML_NS}->{em} = {
1188     checker => $HTMLInlineOrStrictlyInlineChecker,
1189     };
1190    
1191     $Element->{$HTML_NS}->{strong} = {
1192     checker => $HTMLInlineOrStrictlyInlineChecker,
1193     };
1194 wakaba 1.1
1195 wakaba 1.4 $Element->{$HTML_NS}->{small} = {
1196     checker => $HTMLInlineOrStrictlyInlineChecker,
1197     };
1198    
1199     $Element->{$HTML_NS}->{m} = {
1200     checker => $HTMLInlineOrStrictlyInlineChecker,
1201     };
1202    
1203     $Element->{$HTML_NS}->{dfn} = {
1204     checker => sub {
1205     my ($self, $todo) = @_;
1206    
1207     my $end = $self->_add_minuses ({$HTML_NS => {dfn => 1}});
1208     my ($sib, $ch) = $HTMLStrictlyInlineChecker->($self, $todo);
1209     push @$sib, $end;
1210     return ($sib, $ch);
1211     },
1212     };
1213 wakaba 1.1
1214     $Element->{$HTML_NS}->{abbr} = {
1215     checker => $HTMLStrictlyInlineChecker,
1216     };
1217    
1218     $Element->{$HTML_NS}->{time} = {
1219     checker => $HTMLStrictlyInlineChecker,
1220     };
1221    
1222     $Element->{$HTML_NS}->{meter} = {
1223     checker => $HTMLStrictlyInlineChecker,
1224     };
1225    
1226     $Element->{$HTML_NS}->{progress} = {
1227     checker => $HTMLStrictlyInlineChecker,
1228     };
1229    
1230 wakaba 1.4 $Element->{$HTML_NS}->{code} = {
1231     checker => $HTMLInlineOrStrictlyInlineChecker,
1232     };
1233 wakaba 1.1
1234     $Element->{$HTML_NS}->{var} = {
1235     checker => $HTMLStrictlyInlineChecker,
1236     };
1237    
1238 wakaba 1.4 $Element->{$HTML_NS}->{samp} = {
1239     checker => $HTMLInlineOrStrictlyInlineChecker,
1240     };
1241 wakaba 1.1
1242     $Element->{$HTML_NS}->{kbd} = {
1243     checker => $HTMLStrictlyInlineChecker,
1244     };
1245    
1246     $Element->{$HTML_NS}->{sub} = {
1247     checker => $HTMLStrictlyInlineChecker,
1248     };
1249    
1250     $Element->{$HTML_NS}->{sup} = {
1251     checker => $HTMLStrictlyInlineChecker,
1252     };
1253    
1254 wakaba 1.4 $Element->{$HTML_NS}->{span} = {
1255     checker => $HTMLInlineOrStrictlyInlineChecker,
1256     };
1257 wakaba 1.1
1258     $Element->{$HTML_NS}->{i} = {
1259     checker => $HTMLStrictlyInlineChecker,
1260     };
1261    
1262     $Element->{$HTML_NS}->{b} = {
1263     checker => $HTMLStrictlyInlineChecker,
1264     };
1265    
1266     $Element->{$HTML_NS}->{bdo} = {
1267     checker => $HTMLStrictlyInlineChecker,
1268     };
1269    
1270     $Element->{$HTML_NS}->{ins} = {
1271     checker => $HTMLTransparentChecker,
1272     };
1273    
1274     $Element->{$HTML_NS}->{del} = {
1275     checker => sub {
1276 wakaba 1.4 my ($self, $todo) = @_;
1277 wakaba 1.1
1278 wakaba 1.4 my $parent = $todo->{node}->manakai_parent_element;
1279 wakaba 1.1 if (defined $parent) {
1280     my $nsuri = $parent->namespace_uri;
1281     $nsuri = '' unless defined $nsuri;
1282     my $ln = $parent->manakai_local_name;
1283     my $eldef = $Element->{$nsuri}->{$ln} ||
1284     $Element->{$nsuri}->{''} ||
1285     $ElementDefault;
1286 wakaba 1.4 return $eldef->{checker}->($self, $todo);
1287 wakaba 1.1 } else {
1288 wakaba 1.4 return $HTMLBlockOrInlineChecker->($self, $todo);
1289 wakaba 1.1 }
1290     },
1291     };
1292    
1293     ## TODO: figure
1294    
1295     $Element->{$HTML_NS}->{img} = {
1296     checker => $HTMLEmptyChecker,
1297     };
1298    
1299     $Element->{$HTML_NS}->{iframe} = {
1300     checker => $HTMLTextChecker,
1301     };
1302    
1303     $Element->{$HTML_NS}->{embed} = {
1304     checker => $HTMLEmptyChecker,
1305     };
1306    
1307     $Element->{$HTML_NS}->{param} = {
1308     checker => $HTMLEmptyChecker,
1309     };
1310    
1311     ## TODO: object
1312    
1313 wakaba 1.2 $Element->{$HTML_NS}->{video} = {
1314     checker => sub {
1315 wakaba 1.4 my ($self, $todo) = @_;
1316 wakaba 1.2
1317 wakaba 1.4 if ($todo->{node}->has_attribute_ns (undef, 'src')) {
1318     return $HTMLBlockOrInlineChecker->($self, $todo);
1319 wakaba 1.2 } else {
1320     return $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'source')
1321 wakaba 1.4 ->($self, $todo);
1322 wakaba 1.2 }
1323     },
1324     };
1325    
1326     $Element->{$HTML_NS}->{audio} = {
1327     checker => $Element->{$HTML_NS}->{audio}->{checker},
1328     };
1329 wakaba 1.1
1330     $Element->{$HTML_NS}->{source} = {
1331     checker => $HTMLEmptyChecker,
1332     };
1333    
1334     $Element->{$HTML_NS}->{canvas} = {
1335     checker => $HTMLInlineChecker,
1336     };
1337    
1338     $Element->{$HTML_NS}->{map} = {
1339     checker => $HTMLBlockChecker,
1340     };
1341    
1342     $Element->{$HTML_NS}->{area} = {
1343     checker => $HTMLEmptyChecker,
1344     };
1345     ## TODO: only in map
1346    
1347     $Element->{$HTML_NS}->{table} = {
1348     checker => sub {
1349 wakaba 1.4 my ($self, $todo) = @_;
1350     my $el = $todo->{node};
1351     my $new_todos = [];
1352 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1353    
1354     my $phase = 'before caption';
1355     my $has_tfoot;
1356     while (@nodes) {
1357     my $node = shift @nodes;
1358 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1359    
1360 wakaba 1.1 my $nt = $node->node_type;
1361     if ($nt == 1) {
1362 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1363 wakaba 1.1 if ($phase eq 'in tbodys') {
1364     if ($node->manakai_element_type_match ($HTML_NS, 'tbody')) {
1365     #$phase = 'in tbodys';
1366     } elsif (not $has_tfoot and
1367     $node->manakai_element_type_match ($HTML_NS, 'tfoot')) {
1368     $phase = 'after tfoot';
1369     $has_tfoot = 1;
1370     } else {
1371 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1372 wakaba 1.1 }
1373     } elsif ($phase eq 'in trs') {
1374     if ($node->manakai_element_type_match ($HTML_NS, 'tr')) {
1375     #$phase = 'in trs';
1376     } elsif (not $has_tfoot and
1377     $node->manakai_element_type_match ($HTML_NS, 'tfoot')) {
1378     $phase = 'after tfoot';
1379     $has_tfoot = 1;
1380     } else {
1381 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1382 wakaba 1.1 }
1383     } elsif ($phase eq 'after thead') {
1384     if ($node->manakai_element_type_match ($HTML_NS, 'tbody')) {
1385     $phase = 'in tbodys';
1386     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tr')) {
1387     $phase = 'in trs';
1388     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tfoot')) {
1389     $phase = 'in tbodys';
1390     $has_tfoot = 1;
1391     } else {
1392 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1393 wakaba 1.1 }
1394     } elsif ($phase eq 'in colgroup') {
1395     if ($node->manakai_element_type_match ($HTML_NS, 'colgroup')) {
1396     $phase = 'in colgroup';
1397     } elsif ($node->manakai_element_type_match ($HTML_NS, 'thead')) {
1398     $phase = 'after thead';
1399     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tbody')) {
1400     $phase = 'in tbodys';
1401     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tr')) {
1402     $phase = 'in trs';
1403     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tfoot')) {
1404     $phase = 'in tbodys';
1405     $has_tfoot = 1;
1406     } else {
1407 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1408 wakaba 1.1 }
1409     } elsif ($phase eq 'before caption') {
1410     if ($node->manakai_element_type_match ($HTML_NS, 'caption')) {
1411     $phase = 'in colgroup';
1412     } elsif ($node->manakai_element_type_match ($HTML_NS, 'colgroup')) {
1413     $phase = 'in colgroup';
1414     } elsif ($node->manakai_element_type_match ($HTML_NS, 'thead')) {
1415     $phase = 'after thead';
1416     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tbody')) {
1417     $phase = 'in tbodys';
1418     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tr')) {
1419     $phase = 'in trs';
1420     } elsif ($node->manakai_element_type_match ($HTML_NS, 'tfoot')) {
1421     $phase = 'in tbodys';
1422     $has_tfoot = 1;
1423     } else {
1424 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1425 wakaba 1.1 }
1426     } else { # after tfoot
1427 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1428 wakaba 1.1 }
1429 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1430     unshift @nodes, @$sib;
1431 wakaba 1.4 push @$new_todos, @$ch;
1432 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1433     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1434 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1435 wakaba 1.1 }
1436     } elsif ($nt == 5) {
1437     unshift @nodes, @{$node->child_nodes};
1438     }
1439     }
1440 wakaba 1.4 return ($new_todos);
1441 wakaba 1.1 },
1442     };
1443    
1444     $Element->{$HTML_NS}->{caption} = {
1445     checker => $HTMLSignificantStrictlyInlineChecker,
1446     };
1447    
1448     $Element->{$HTML_NS}->{colgroup} = {
1449     checker => sub {
1450 wakaba 1.4 my ($self, $todo) = @_;
1451     my $el = $todo->{node};
1452     my $new_todos = [];
1453 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1454    
1455     while (@nodes) {
1456     my $node = shift @nodes;
1457 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1458    
1459 wakaba 1.1 my $nt = $node->node_type;
1460     if ($nt == 1) {
1461 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1462 wakaba 1.1 unless ($node->manakai_element_type_match ($HTML_NS, 'col')) {
1463 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1464 wakaba 1.1 }
1465 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1466     unshift @nodes, @$sib;
1467 wakaba 1.4 push @$new_todos, @$ch;
1468 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1469     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1470 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1471 wakaba 1.1 }
1472     } elsif ($nt == 5) {
1473     unshift @nodes, @{$node->child_nodes};
1474     }
1475     }
1476 wakaba 1.4 return ($new_todos);
1477 wakaba 1.1 },
1478     };
1479    
1480     $Element->{$HTML_NS}->{col} = {
1481     checker => $HTMLEmptyChecker,
1482     };
1483    
1484     $Element->{$HTML_NS}->{tbody} = {
1485     checker => sub {
1486 wakaba 1.4 my ($self, $todo) = @_;
1487     my $el = $todo->{node};
1488     my $new_todos = [];
1489 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1490    
1491     my $has_tr;
1492     while (@nodes) {
1493     my $node = shift @nodes;
1494 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1495    
1496 wakaba 1.1 my $nt = $node->node_type;
1497     if ($nt == 1) {
1498 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1499 wakaba 1.1 if ($node->manakai_element_type_match ($HTML_NS, 'tr')) {
1500     $has_tr = 1;
1501     } else {
1502 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1503 wakaba 1.1 }
1504 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1505     unshift @nodes, @$sib;
1506 wakaba 1.4 push @$new_todos, @$ch;
1507 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1508     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1509 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1510 wakaba 1.1 }
1511     } elsif ($nt == 5) {
1512     unshift @nodes, @{$node->child_nodes};
1513     }
1514     }
1515     unless ($has_tr) {
1516 wakaba 1.3 $self->{onerror}->(node => $el, type => 'child element missing:tr');
1517 wakaba 1.1 }
1518 wakaba 1.4 return ($new_todos);
1519 wakaba 1.1 },
1520     };
1521    
1522     $Element->{$HTML_NS}->{thead} = {
1523     checker => $Element->{$HTML_NS}->{tbody},
1524     };
1525    
1526     $Element->{$HTML_NS}->{tfoot} = {
1527     checker => $Element->{$HTML_NS}->{tbody},
1528     };
1529    
1530     $Element->{$HTML_NS}->{tr} = {
1531     checker => sub {
1532 wakaba 1.4 my ($self, $todo) = @_;
1533     my $el = $todo->{node};
1534     my $new_todos = [];
1535 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1536    
1537     my $has_td;
1538     while (@nodes) {
1539     my $node = shift @nodes;
1540 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1541    
1542 wakaba 1.1 my $nt = $node->node_type;
1543     if ($nt == 1) {
1544 wakaba 1.2 ## NOTE: |minuses| list is not checked since redundant
1545 wakaba 1.1 if ($node->manakai_element_type_match ($HTML_NS, 'td') or
1546     $node->manakai_element_type_match ($HTML_NS, 'th')) {
1547     $has_td = 1;
1548     } else {
1549 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1550 wakaba 1.1 }
1551 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1552     unshift @nodes, @$sib;
1553 wakaba 1.4 push @$new_todos, @$ch;
1554 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1555     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1556 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1557 wakaba 1.1 }
1558     } elsif ($nt == 5) {
1559     unshift @nodes, @{$node->child_nodes};
1560     }
1561     }
1562     unless ($has_td) {
1563 wakaba 1.3 $self->{onerror}->(node => $el, type => 'child element missing:td|th');
1564 wakaba 1.1 }
1565 wakaba 1.4 return ($new_todos);
1566 wakaba 1.1 },
1567     };
1568    
1569     $Element->{$HTML_NS}->{td} = {
1570     checker => $HTMLBlockOrInlineChecker,
1571     };
1572    
1573     $Element->{$HTML_NS}->{th} = {
1574     checker => $HTMLBlockOrInlineChecker,
1575     };
1576    
1577     ## TODO: forms
1578    
1579 wakaba 1.2 $Element->{$HTML_NS}->{script} = {
1580     checker => sub {
1581 wakaba 1.4 my ($self, $todo) = @_;
1582 wakaba 1.2
1583 wakaba 1.4 if ($todo->{node}->has_attribute_ns (undef, 'src')) {
1584     return $HTMLEmptyChecker->($self, $todo);
1585 wakaba 1.2 } else {
1586     ## NOTE: No content model conformance in HTML5 spec.
1587 wakaba 1.4 return $AnyChecker->($self, $todo);
1588 wakaba 1.2 }
1589     },
1590     };
1591    
1592     ## NOTE: When script is disabled.
1593     $Element->{$HTML_NS}->{noscript} = {
1594     checker => sub {
1595 wakaba 1.4 my ($self, $todo) = @_;
1596 wakaba 1.1
1597 wakaba 1.2 my $end = $self->_add_minuses ({$HTML_NS => {noscript => 1}});
1598 wakaba 1.4 my ($sib, $ch) = $HTMLBlockOrInlineChecker->($self, $todo);
1599 wakaba 1.2 push @$sib, $end;
1600     return ($sib, $ch);
1601     },
1602     };
1603 wakaba 1.1
1604     $Element->{$HTML_NS}->{'event-source'} = {
1605     checker => $HTMLEmptyChecker,
1606     };
1607    
1608     $Element->{$HTML_NS}->{details} = {
1609 wakaba 1.2 checker => $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'legend'),
1610 wakaba 1.1 };
1611    
1612     $Element->{$HTML_NS}->{datagrid} = {
1613     checker => $HTMLBlockChecker,
1614     };
1615    
1616     $Element->{$HTML_NS}->{command} = {
1617     checker => $HTMLEmptyChecker,
1618     };
1619    
1620     $Element->{$HTML_NS}->{menu} = {
1621     checker => sub {
1622 wakaba 1.4 my ($self, $todo) = @_;
1623     my $el = $todo->{node};
1624     my $new_todos = [];
1625 wakaba 1.1 my @nodes = (@{$el->child_nodes});
1626    
1627     my $content = 'li or inline';
1628     while (@nodes) {
1629     my $node = shift @nodes;
1630 wakaba 1.2 $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1631    
1632 wakaba 1.1 my $nt = $node->node_type;
1633     if ($nt == 1) {
1634 wakaba 1.2 my $node_ns = $node->namespace_uri;
1635     $node_ns = '' unless defined $node_ns;
1636     my $node_ln = $node->manakai_local_name;
1637     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
1638     $self->{onerror}->(node => $node, type => 'element not allowed');
1639     }
1640 wakaba 1.1 if ($node->manakai_element_type_match ($HTML_NS, 'li')) {
1641     if ($content eq 'inline') {
1642 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1643 wakaba 1.1 } elsif ($content eq 'li or inline') {
1644     $content = 'li';
1645     }
1646     } else {
1647     CHK: {
1648     for (@{$HTMLStrictlyInlineLevelElements},
1649     @{$HTMLStructuredInlineLevelElements}) {
1650     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
1651     $content = 'inline';
1652     last CHK;
1653     }
1654     }
1655 wakaba 1.2 $self->{onerror}->(node => $node, type => 'element not allowed');
1656 wakaba 1.1 } # CHK
1657     }
1658 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node);
1659     unshift @nodes, @$sib;
1660 wakaba 1.4 push @$new_todos, @$ch;
1661 wakaba 1.1 } elsif ($nt == 3 or $nt == 4) {
1662     if ($node->data =~ /[^\x09-\x0D\x20]/) {
1663     if ($content eq 'li') {
1664 wakaba 1.2 $self->{onerror}->(node => $node, type => 'character not allowed');
1665 wakaba 1.1 } elsif ($content eq 'li or inline') {
1666     $content = 'inline';
1667     }
1668     }
1669     } elsif ($nt == 5) {
1670     unshift @nodes, @{$node->child_nodes};
1671     }
1672     }
1673 wakaba 1.4
1674     for (@$new_todos) {
1675     $_->{inline} = 1;
1676     }
1677     return ($new_todos);
1678 wakaba 1.1 },
1679     };
1680    
1681     ## TODO: legend
1682    
1683     $Element->{$HTML_NS}->{div} = {
1684 wakaba 1.2 checker => $GetHTMLZeroOrMoreThenBlockOrInlineChecker->($HTML_NS, 'style'),
1685 wakaba 1.1 };
1686    
1687     $Element->{$HTML_NS}->{font} = {
1688     checker => $HTMLTransparentChecker,
1689     };
1690    
1691     my $Attr = {
1692    
1693     };
1694    
1695 wakaba 1.2 sub new ($) {
1696     return bless {}, shift;
1697     } # new
1698    
1699 wakaba 1.1 sub check_element ($$$) {
1700     my ($self, $el, $onerror) = @_;
1701    
1702 wakaba 1.2 $self->{minuses} = {};
1703     $self->{onerror} = $onerror;
1704    
1705 wakaba 1.4 my @todo = ({type => 'element', node => $el});
1706     while (@todo) {
1707     my $todo = shift @todo;
1708     if ($todo->{type} eq 'element') {
1709     my $nsuri = $todo->{node}->namespace_uri;
1710     $nsuri = '' unless defined $nsuri;
1711     my $ln = $todo->{node}->manakai_local_name;
1712     my $eldef = $Element->{$nsuri}->{$ln} ||
1713     $Element->{$nsuri}->{''} ||
1714     $ElementDefault;
1715     my ($new_todos) = $eldef->{checker}->($self, $todo);
1716     push @todo, @$new_todos;
1717     } elsif ($todo->{type} eq 'plus') {
1718     $self->_remove_minuses ($todo);
1719     }
1720 wakaba 1.1 }
1721     } # check_element
1722    
1723 wakaba 1.2 sub _add_minuses ($@) {
1724     my $self = shift;
1725     my $r = {};
1726     for my $list (@_) {
1727     for my $ns (keys %$list) {
1728     for my $ln (keys %{$list->{$ns}}) {
1729     unless ($self->{minuses}->{$ns}->{$ln}) {
1730     $self->{minuses}->{$ns}->{$ln} = 1;
1731     $r->{$ns}->{$ln} = 1;
1732     }
1733     }
1734     }
1735     }
1736 wakaba 1.4 return {type => 'plus', list => $r};
1737 wakaba 1.2 } # _add_minuses
1738    
1739     sub _remove_minuses ($$) {
1740 wakaba 1.4 my ($self, $todo) = @_;
1741     for my $ns (keys %{$todo->{list}}) {
1742     for my $ln (keys %{$todo->{list}->{$ns}}) {
1743     delete $self->{minuses}->{$ns}->{$ln} if $todo->{list}->{$ns}->{$ln};
1744 wakaba 1.2 }
1745     }
1746     1;
1747     } # _remove_minuses
1748    
1749     sub _check_get_children ($$) {
1750     my ($self, $node) = @_;
1751 wakaba 1.4 my $new_todos = [];
1752 wakaba 1.2 my $sib = [];
1753     TP: {
1754     my $node_ns = $node->namespace_uri;
1755     $node_ns = '' unless defined $node_ns;
1756     my $node_ln = $node->manakai_local_name;
1757     if ($node_ns eq $HTML_NS) {
1758     if ($node_ln eq 'noscript') {
1759     my $end = $self->_add_minuses ({$HTML_NS, {noscript => 1}});
1760     push @$sib, $end;
1761     }
1762     }
1763     for (@{$HTMLTransparentElements}) {
1764     if ($node->manakai_element_type_match ($_->[0], $_->[1])) {
1765     unshift @$sib, @{$node->child_nodes};
1766     last TP;
1767     }
1768     }
1769     if ($node->manakai_element_type_match ($HTML_NS, 'video') or
1770     $node->manakai_element_type_match ($HTML_NS, 'audio')) {
1771     if ($node->has_attribute_ns (undef, 'src')) {
1772     unshift @$sib, @{$node->child_nodes};
1773     last TP;
1774     } else {
1775     my @cn = @{$node->child_nodes};
1776     CN: while (@cn) {
1777     my $cn = shift @cn;
1778     my $cnt = $cn->node_type;
1779     if ($cnt == 1) {
1780     if ($cn->manakai_element_type_match ($HTML_NS, 'source')) {
1781     #
1782     } else {
1783     last CN;
1784     }
1785     } elsif ($cnt == 3 or $cnt == 4) {
1786     if ($cn->data =~ /[^\x09-\x0D\x20]/) {
1787     last CN;
1788     }
1789     }
1790     } # CN
1791     unshift @$sib, @cn;
1792     }
1793     }
1794 wakaba 1.4 push @$new_todos, {type => 'element', node => $node};
1795 wakaba 1.2 } # TP
1796 wakaba 1.4 return ($sib, $new_todos);
1797 wakaba 1.2 } # _check_get_children
1798    
1799 wakaba 1.1 1;
1800 wakaba 1.5 # $Date: 2007/05/13 08:09:15 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24