/[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.55 - (hide annotations) (download)
Sat Feb 9 11:58:16 2008 UTC (18 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.54: +163 -2 lines
++ whatpm/Whatpm/ChangeLog	9 Feb 2008 11:57:29 -0000
2008-02-09  Wakaba  <wakaba@suika.fam.cx>

	* ContentChecker.pm (_get_css_parser): New.

++ whatpm/Whatpm/ContentChecker/ChangeLog	9 Feb 2008 11:58:10 -0000
2008-02-09  Wakaba  <wakaba@suika.fam.cx>

	* HTML.pm (<style>): Initial version of CSS validation support.

1 wakaba 1.1 package Whatpm::ContentChecker;
2     use strict;
3 wakaba 1.55 our $VERSION=do{my @r=(q$Revision: 1.54 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.1
5 wakaba 1.18 require Whatpm::URIChecker;
6    
7 wakaba 1.13 ## ISSUE: How XML and XML Namespaces conformance can (or cannot)
8     ## be applied to an in-memory representation (i.e. DOM)?
9    
10 wakaba 1.50 ## TODO: Conformance of an HTML document with non-html root element.
11    
12 wakaba 1.42 my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
13 wakaba 1.9 my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;
14     my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;
15    
16 wakaba 1.42 my $Namespace = {
17 wakaba 1.43 q<http://www.w3.org/2005/Atom> => {module => 'Whatpm::ContentChecker::Atom'},
18 wakaba 1.42 $HTML_NS => {module => 'Whatpm::ContentChecker::HTML'},
19     $XML_NS => {loaded => 1},
20     $XMLNS_NS => {loaded => 1},
21     };
22    
23     our $AttrChecker = {
24 wakaba 1.9 $XML_NS => {
25 wakaba 1.13 space => sub {
26     my ($self, $attr) = @_;
27     my $value = $attr->value;
28     if ($value eq 'default' or $value eq 'preserve') {
29     #
30     } else {
31     ## NOTE: An XML "error"
32 wakaba 1.33 $self->{onerror}->(node => $attr, level => 'error',
33     type => 'invalid attribute value');
34 wakaba 1.13 }
35     },
36     lang => sub {
37 wakaba 1.35 my ($self, $attr) = @_;
38 wakaba 1.47 my $value = $attr->value;
39     if ($value eq '') {
40     #
41     } else {
42     require Whatpm::LangTag;
43     Whatpm::LangTag->check_rfc3066_language_tag ($value, sub {
44     my %opt = @_;
45     my $type = 'LangTag:'.$opt{type};
46     $type .= ':' . $opt{subtag} if defined $opt{subtag};
47     $self->{onerror}->(node => $attr, type => $type,
48     value => $opt{value}, level => $opt{level});
49     });
50     }
51    
52 wakaba 1.13 ## NOTE: "The values of the attribute are language identifiers
53     ## as defined by [IETF RFC 3066], Tags for the Identification
54     ## of Languages, or its successor; in addition, the empty string
55     ## may be specified." ("may" in lower case)
56 wakaba 1.47 ## NOTE: Is an RFC 3066-valid (but RFC 4647-invalid) language tag
57     ## allowed today?
58    
59     ## TODO: test data
60    
61 wakaba 1.35 if ($attr->owner_document->manakai_is_html) { # MUST NOT
62 wakaba 1.36 $self->{onerror}->(node => $attr, type => 'in HTML:xml:lang');
63 wakaba 1.35 ## TODO: Test data...
64     }
65 wakaba 1.13 },
66     base => sub {
67     my ($self, $attr) = @_;
68     my $value = $attr->value;
69     if ($value =~ /[^\x{0000}-\x{10FFFF}]/) { ## ISSUE: Should we disallow noncharacters?
70     $self->{onerror}->(node => $attr,
71 wakaba 1.33 type => 'invalid attribute value');
72 wakaba 1.13 }
73 wakaba 1.18 ## NOTE: Conformance to URI standard is not checked since there is
74     ## no author requirement on conformance in the XML Base specification.
75 wakaba 1.13 },
76     id => sub {
77     my ($self, $attr) = @_;
78     my $value = $attr->value;
79     $value =~ s/[\x09\x0A\x0D\x20]+/ /g;
80     $value =~ s/^\x20//;
81     $value =~ s/\x20$//;
82     ## TODO: NCName in XML 1.0 or 1.1
83     ## TODO: declared type is ID?
84 wakaba 1.33 if ($self->{id}->{$value}) { ## NOTE: An xml:id error
85     $self->{onerror}->(node => $attr, level => 'error',
86     type => 'duplicate ID');
87 wakaba 1.37 push @{$self->{id}->{$value}}, $attr;
88 wakaba 1.13 } else {
89 wakaba 1.37 $self->{id}->{$value} = [$attr];
90 wakaba 1.13 }
91     },
92 wakaba 1.9 },
93     $XMLNS_NS => {
94 wakaba 1.13 '' => sub {
95     my ($self, $attr) = @_;
96     my $ln = $attr->manakai_local_name;
97     my $value = $attr->value;
98     if ($value eq $XML_NS and $ln ne 'xml') {
99     $self->{onerror}
100 wakaba 1.33 ->(node => $attr, level => 'NC',
101     type => 'Reserved Prefixes and Namespace Names:=xml');
102 wakaba 1.13 } elsif ($value eq $XMLNS_NS) {
103     $self->{onerror}
104 wakaba 1.33 ->(node => $attr, level => 'NC',
105     type => 'Reserved Prefixes and Namespace Names:=xmlns');
106 wakaba 1.13 }
107     if ($ln eq 'xml' and $value ne $XML_NS) {
108     $self->{onerror}
109 wakaba 1.33 ->(node => $attr, level => 'NC',
110     type => 'Reserved Prefixes and Namespace Names:xmlns:xml=');
111 wakaba 1.13 } elsif ($ln eq 'xmlns') {
112     $self->{onerror}
113 wakaba 1.33 ->(node => $attr, level => 'NC',
114     type => 'Reserved Prefixes and Namespace Names:xmlns:xmlns=');
115 wakaba 1.13 }
116     ## TODO: If XML 1.0 and empty
117     },
118     xmlns => sub {
119     my ($self, $attr) = @_;
120     ## TODO: In XML 1.0, URI reference [RFC 3986] or an empty string
121     ## TODO: In XML 1.1, IRI reference [RFC 3987] or an empty string
122 wakaba 1.18 ## TODO: relative references are deprecated
123 wakaba 1.13 my $value = $attr->value;
124     if ($value eq $XML_NS) {
125     $self->{onerror}
126 wakaba 1.33 ->(node => $attr, level => 'NC',
127     type => 'Reserved Prefixes and Namespace Names:=xml');
128 wakaba 1.13 } elsif ($value eq $XMLNS_NS) {
129     $self->{onerror}
130 wakaba 1.33 ->(node => $attr, level => 'NC',
131     type => 'Reserved Prefixes and Namespace Names:=xmlns');
132 wakaba 1.13 }
133     },
134 wakaba 1.9 },
135     };
136    
137 wakaba 1.14 ## ISSUE: Should we really allow these attributes?
138 wakaba 1.13 $AttrChecker->{''}->{'xml:space'} = $AttrChecker->{$XML_NS}->{space};
139     $AttrChecker->{''}->{'xml:lang'} = $AttrChecker->{$XML_NS}->{lang};
140     $AttrChecker->{''}->{'xml:base'} = $AttrChecker->{$XML_NS}->{base};
141     $AttrChecker->{''}->{'xml:id'} = $AttrChecker->{$XML_NS}->{id};
142    
143 wakaba 1.3 ## ANY
144 wakaba 1.42 our $AnyChecker = sub {
145 wakaba 1.4 my ($self, $todo) = @_;
146     my $el = $todo->{node};
147     my $new_todos = [];
148 wakaba 1.3 my @nodes = (@{$el->child_nodes});
149     while (@nodes) {
150     my $node = shift @nodes;
151     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
152    
153     my $nt = $node->node_type;
154     if ($nt == 1) {
155     my $node_ns = $node->namespace_uri;
156     $node_ns = '' unless defined $node_ns;
157     my $node_ln = $node->manakai_local_name;
158     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
159     $self->{onerror}->(node => $node, type => 'element not allowed');
160     }
161 wakaba 1.54 my ($sib, $ch) = $self->_check_get_children ($node, $todo);
162     unshift @nodes, @$sib;
163     push @$new_todos, @$ch;
164     } elsif ($nt == 3 or $nt == 4) {
165     if ($node->data =~ /[^\x09-\x0D\x20]/) {
166     $todo->{flag}->{has_descendant}->{significant} = 1;
167     }
168 wakaba 1.3 } elsif ($nt == 5) {
169     unshift @nodes, @{$node->child_nodes};
170     }
171     }
172 wakaba 1.4 return ($new_todos);
173 wakaba 1.3 }; # $AnyChecker
174    
175 wakaba 1.42 our $ElementDefault = {
176 wakaba 1.1 checker => sub {
177 wakaba 1.4 my ($self, $todo) = @_;
178 wakaba 1.33 $self->{onerror}->(node => $todo->{node}, level => 'unsupported',
179     type => 'element');
180 wakaba 1.4 return $AnyChecker->($self, $todo);
181 wakaba 1.1 },
182 wakaba 1.9 attrs_checker => sub {
183     my ($self, $todo) = @_;
184     for my $attr (@{$todo->{node}->attributes}) {
185     my $attr_ns = $attr->namespace_uri;
186     $attr_ns = '' unless defined $attr_ns;
187     my $attr_ln = $attr->manakai_local_name;
188     my $checker = $AttrChecker->{$attr_ns}->{$attr_ln}
189     || $AttrChecker->{$attr_ns}->{''};
190     if ($checker) {
191     $checker->($self, $attr);
192 wakaba 1.17 } else {
193 wakaba 1.33 $self->{onerror}->(node => $attr, level => 'unsupported',
194     type => 'attribute');
195 wakaba 1.9 }
196     }
197     },
198 wakaba 1.1 };
199    
200 wakaba 1.7 my $HTMLTransparentElements = {
201     $HTML_NS => {qw/ins 1 font 1 noscript 1/},
202 wakaba 1.29 ## NOTE: |html:noscript| is transparent if scripting is disabled
203     ## and not in |head|.
204 wakaba 1.7 };
205    
206 wakaba 1.42 our $Element = {};
207 wakaba 1.7
208 wakaba 1.42 sub check_document ($$$) {
209     my ($self, $doc, $onerror) = @_;
210     $self = bless {}, $self unless ref $self;
211     $self->{onerror} = $onerror;
212 wakaba 1.1
213 wakaba 1.48 $self->{must_level} = 'm';
214     $self->{fact_level} = 'f';
215     $self->{should_level} = 's';
216 wakaba 1.51 $self->{good_level} = 'w';
217 wakaba 1.48
218 wakaba 1.42 my $docel = $doc->document_element;
219     unless (defined $docel) {
220     ## ISSUE: Should we check content of Document node?
221     $onerror->(node => $doc, type => 'no document element');
222     ## ISSUE: Is this non-conforming (to what spec)? Or just a warning?
223     return {
224     class => {},
225     id => {}, table => [], term => {},
226     };
227 wakaba 1.1 }
228    
229 wakaba 1.42 ## ISSUE: Unexpanded entity references and HTML5 conformance
230 wakaba 1.1
231 wakaba 1.42 my $docel_nsuri = $docel->namespace_uri;
232     $docel_nsuri = '' unless defined $docel_nsuri;
233 wakaba 1.43 unless ($Namespace->{$docel_nsuri}->{loaded}) {
234     if ($Namespace->{$docel_nsuri}->{module}) {
235     eval qq{ require $Namespace->{$docel_nsuri}->{module} } or die $@;
236     } else {
237     $Namespace->{$docel_nsuri}->{loaded} = 1;
238     }
239     }
240 wakaba 1.42 my $docel_def = $Element->{$docel_nsuri}->{$docel->manakai_local_name} ||
241     $Element->{$docel_nsuri}->{''} ||
242     $ElementDefault;
243     if ($docel_def->{is_root}) {
244     #
245 wakaba 1.50 } elsif ($docel_def->{is_xml_root}) {
246     unless ($doc->manakai_is_html) {
247     #
248     } else {
249     $onerror->(node => $docel, type => 'element not allowed:root:xml');
250     }
251 wakaba 1.42 } else {
252 wakaba 1.49 $onerror->(node => $docel, type => 'element not allowed:root');
253 wakaba 1.1 }
254    
255 wakaba 1.42 ## TODO: Check for other items other than document element
256     ## (second (errorous) element, text nodes, PI nodes, doctype nodes)
257 wakaba 1.2
258 wakaba 1.51 my $return = $self->check_element ($docel, $onerror);
259    
260 wakaba 1.52 ## TODO: Test for these checks are necessary.
261 wakaba 1.51 my $charset_name = $doc->input_encoding;
262     if (defined $charset_name) {
263     require Message::Charset::Info;
264     my $charset = $Message::Charset::Info::IANACharset->{$charset_name};
265    
266     if ($doc->manakai_is_html and
267     not $doc->manakai_has_bom and
268     not defined $doc->manakai_charset) {
269     unless ($charset->{is_html_ascii_superset}) {
270     $onerror->(node => $doc, level => $self->{must_level},
271     type => 'non ascii superset:'.$charset_name);
272     }
273    
274     if (not $self->{has_charset} and
275     not $charset->{iana_names}->{'us-ascii'}) {
276     $onerror->(node => $doc, level => $self->{must_level},
277     type => 'no character encoding declaration:'.$charset_name);
278     }
279     }
280    
281     if ($charset->{iana_names}->{'utf-8'}) {
282     #
283     } elsif ($charset->{iana_names}->{'jis_x0212-1990'} or
284     $charset->{iana_names}->{'x-jis0208'} or
285     $charset->{iana_names}->{'utf-32'} or ## ISSUE: UTF-32BE? UTF-32LE?
286     $charset->{is_ebcdic_based}) {
287     $onerror->(node => $doc,
288     type => 'character encoding:'.$charset_name,
289     level => $self->{should_level});
290     } elsif ($charset->{iana_names}->{'cesu-8'} or
291     $charset->{iana_names}->{'utf-8'} or ## ISSUE: UNICODE-1-1-UTF-7?
292     $charset->{iana_names}->{'bocu-1'} or
293     $charset->{iana_names}->{'scsu'}) {
294     $onerror->(node => $doc,
295     type => 'character encoding:'.$charset_name,
296     level => $self->{must_level});
297     } else {
298     $onerror->(node => $doc,
299     type => 'character encoding:'.$charset_name,
300     level => $self->{good_level});
301     }
302 wakaba 1.52 } elsif ($doc->manakai_is_html) {
303     ## NOTE: MUST and SHOULD requirements above cannot be tested,
304     ## since the document has no input charset encoding information.
305     $onerror->(node => $doc,
306     type => 'character encoding:',
307     level => 'unsupported');
308 wakaba 1.51 }
309    
310     return $return;
311 wakaba 1.42 } # check_document
312 wakaba 1.1
313 wakaba 1.42 sub check_element ($$$) {
314     my ($self, $el, $onerror) = @_;
315     $self = bless {}, $self unless ref $self;
316     $self->{onerror} = $onerror;
317 wakaba 1.2
318 wakaba 1.48 $self->{must_level} = 'm';
319     $self->{fact_level} = 'f';
320     $self->{should_level} = 's';
321 wakaba 1.51 $self->{good_level} = 'w';
322 wakaba 1.48
323 wakaba 1.50 $self->{pluses} = {};
324 wakaba 1.42 $self->{minuses} = {};
325     $self->{id} = {};
326     $self->{term} = {};
327     $self->{usemap} = [];
328     $self->{contextmenu} = [];
329     $self->{map} = {};
330     $self->{menu} = {};
331     $self->{has_link_type} = {};
332 wakaba 1.46 #$self->{has_uri_attr};
333     #$self->{has_hyperlink_element};
334 wakaba 1.51 #$self->{has_charset};
335 wakaba 1.42 $self->{return} = {
336     class => {},
337     id => $self->{id}, table => [], term => $self->{term},
338     };
339 wakaba 1.4
340 wakaba 1.42 my @todo = ({type => 'element', node => $el});
341     while (@todo) {
342     my $todo = shift @todo;
343     if ($todo->{type} eq 'element') {
344     my $prefix = $todo->{node}->prefix;
345     if (defined $prefix and $prefix eq 'xmlns') {
346     $self->{onerror}
347     ->(node => $todo->{node}, level => 'NC',
348     type => 'Reserved Prefixes and Namespace Names:<xmlns:>');
349 wakaba 1.7 }
350 wakaba 1.42 my $nsuri = $todo->{node}->namespace_uri;
351     $nsuri = '' unless defined $nsuri;
352     unless ($Namespace->{$nsuri}->{loaded}) {
353     if ($Namespace->{$nsuri}->{module}) {
354     eval qq{ require $Namespace->{$nsuri}->{module} } or die $@;
355     } else {
356     $Namespace->{$nsuri}->{loaded} = 1;
357 wakaba 1.1 }
358     }
359 wakaba 1.42 my $ln = $todo->{node}->manakai_local_name;
360     my $eldef = $Element->{$nsuri}->{$ln} ||
361     $Element->{$nsuri}->{''} ||
362     $ElementDefault;
363     $eldef->{attrs_checker}->($self, $todo);
364     my ($new_todos) = $eldef->{checker}->($self, $todo);
365     unshift @todo, @$new_todos;
366     } elsif ($todo->{type} eq 'element-attributes') {
367     my $prefix = $todo->{node}->prefix;
368     if (defined $prefix and $prefix eq 'xmlns') {
369     $self->{onerror}
370     ->(node => $todo->{node}, level => 'NC',
371     type => 'Reserved Prefixes and Namespace Names:<xmlns:>');
372     }
373     my $nsuri = $todo->{node}->namespace_uri;
374     $nsuri = '' unless defined $nsuri;
375     unless ($Namespace->{$nsuri}->{loaded}) {
376     if ($Namespace->{$nsuri}->{module}) {
377     eval qq{ require $Namespace->{$nsuri}->{module} } or die $@;
378 wakaba 1.1 } else {
379 wakaba 1.42 $Namespace->{$nsuri}->{loaded} = 1;
380 wakaba 1.1 }
381     }
382 wakaba 1.9 my $ln = $todo->{node}->manakai_local_name;
383     my $eldef = $Element->{$nsuri}->{$ln} ||
384     $Element->{$nsuri}->{''} ||
385     $ElementDefault;
386     $eldef->{attrs_checker}->($self, $todo);
387 wakaba 1.53 } elsif ($todo->{type} eq 'descendant') {
388     for my $key (keys %{$todo->{errors}}) {
389     unless ($todo->{flag}->{has_descendant}->{$key}) {
390     $todo->{errors}->{$key}->($self, $todo);
391     }
392     for my $key (keys %{$todo->{old_values}}) {
393     $todo->{flag}->{has_descendant}->{$key}
394     ||= $todo->{old_values}->{$key};
395     }
396     }
397 wakaba 1.50 } elsif ($todo->{type} eq 'plus' or $todo->{type} eq 'minus') {
398 wakaba 1.4 $self->_remove_minuses ($todo);
399 wakaba 1.30 } elsif ($todo->{type} eq 'code') {
400     $todo->{code}->();
401     } else {
402     die "$0: Internal error: Unsupported checking action type |$todo->{type}|";
403 wakaba 1.4 }
404 wakaba 1.1 }
405 wakaba 1.17
406     for (@{$self->{usemap}}) {
407     unless ($self->{map}->{$_->[0]}) {
408     $self->{onerror}->(node => $_->[1], type => 'no referenced map');
409     }
410     }
411    
412 wakaba 1.32 for (@{$self->{contextmenu}}) {
413     unless ($self->{menu}->{$_->[0]}) {
414     $self->{onerror}->(node => $_->[1], type => 'no referenced menu');
415     }
416     }
417    
418 wakaba 1.50 delete $self->{pluses};
419 wakaba 1.17 delete $self->{minuses};
420     delete $self->{onerror};
421     delete $self->{id};
422     delete $self->{usemap};
423     delete $self->{map};
424 wakaba 1.33 return $self->{return};
425 wakaba 1.1 } # check_element
426    
427 wakaba 1.2 sub _add_minuses ($@) {
428     my $self = shift;
429     my $r = {};
430     for my $list (@_) {
431     for my $ns (keys %$list) {
432     for my $ln (keys %{$list->{$ns}}) {
433     unless ($self->{minuses}->{$ns}->{$ln}) {
434     $self->{minuses}->{$ns}->{$ln} = 1;
435     $r->{$ns}->{$ln} = 1;
436     }
437     }
438     }
439     }
440 wakaba 1.4 return {type => 'plus', list => $r};
441 wakaba 1.2 } # _add_minuses
442    
443 wakaba 1.50 sub _add_pluses ($@) {
444     my $self = shift;
445     my $r = {};
446     for my $list (@_) {
447     for my $ns (keys %$list) {
448     for my $ln (keys %{$list->{$ns}}) {
449     unless ($self->{pluses}->{$ns}->{$ln}) {
450     $self->{pluses}->{$ns}->{$ln} = 1;
451     $r->{$ns}->{$ln} = 1;
452     }
453     }
454     }
455     }
456     return {type => 'minus', list => $r};
457     } # _add_pluses
458    
459 wakaba 1.2 sub _remove_minuses ($$) {
460 wakaba 1.4 my ($self, $todo) = @_;
461 wakaba 1.50 if ($todo->{type} eq 'minus') {
462     for my $ns (keys %{$todo->{list}}) {
463     for my $ln (keys %{$todo->{list}->{$ns}}) {
464     delete $self->{pluses}->{$ns}->{$ln} if $todo->{list}->{$ns}->{$ln};
465     }
466 wakaba 1.2 }
467 wakaba 1.50 } elsif ($todo->{type} eq 'plus') {
468     for my $ns (keys %{$todo->{list}}) {
469     for my $ln (keys %{$todo->{list}->{$ns}}) {
470     delete $self->{minuses}->{$ns}->{$ln} if $todo->{list}->{$ns}->{$ln};
471     }
472     }
473     } else {
474     die "$0: Unknown +- type: $todo->{type}";
475 wakaba 1.2 }
476     1;
477     } # _remove_minuses
478    
479 wakaba 1.50 ## NOTE: Priority for "minuses" and "pluses" are currently left
480     ## undefined and implemented inconsistently; it is not a problem for
481     ## now, since no element belongs to both lists.
482    
483 wakaba 1.30 sub _check_get_children ($$$) {
484     my ($self, $node, $parent_todo) = @_;
485 wakaba 1.4 my $new_todos = [];
486 wakaba 1.2 my $sib = [];
487     TP: {
488     my $node_ns = $node->namespace_uri;
489     $node_ns = '' unless defined $node_ns;
490     my $node_ln = $node->manakai_local_name;
491 wakaba 1.45 if ($HTMLTransparentElements->{$node_ns}->{$node_ln}) {
492     if ($node_ns eq $HTML_NS and $node_ln eq 'noscript') {
493     if ($parent_todo->{flag}->{in_head}) {
494     #
495     } else {
496     my $end = $self->_add_minuses ({$HTML_NS, {noscript => 1}});
497     push @$sib, $end;
498    
499     unshift @$sib, @{$node->child_nodes};
500     push @$new_todos, {type => 'element-attributes', node => $node};
501     last TP;
502     }
503     } else {
504     unshift @$sib, @{$node->child_nodes};
505     push @$new_todos, {type => 'element-attributes', node => $node};
506     last TP;
507 wakaba 1.2 }
508     }
509 wakaba 1.8 if ($node_ns eq $HTML_NS and ($node_ln eq 'video' or $node_ln eq 'audio')) {
510 wakaba 1.2 if ($node->has_attribute_ns (undef, 'src')) {
511     unshift @$sib, @{$node->child_nodes};
512 wakaba 1.9 push @$new_todos, {type => 'element-attributes', node => $node};
513 wakaba 1.2 last TP;
514     } else {
515     my @cn = @{$node->child_nodes};
516     CN: while (@cn) {
517     my $cn = shift @cn;
518     my $cnt = $cn->node_type;
519     if ($cnt == 1) {
520 wakaba 1.8 my $cn_nsuri = $cn->namespace_uri;
521     $cn_nsuri = '' unless defined $cn_nsuri;
522     if ($cn_nsuri eq $HTML_NS and $cn->manakai_local_name eq 'source') {
523 wakaba 1.2 #
524     } else {
525     last CN;
526     }
527     } elsif ($cnt == 3 or $cnt == 4) {
528     if ($cn->data =~ /[^\x09-\x0D\x20]/) {
529     last CN;
530     }
531     }
532     } # CN
533     unshift @$sib, @cn;
534     }
535     }
536 wakaba 1.4 push @$new_todos, {type => 'element', node => $node};
537 wakaba 1.2 } # TP
538 wakaba 1.30
539     for my $new_todo (@$new_todos) {
540     $new_todo->{flag} = {%{$parent_todo->{flag} or {}}};
541     }
542    
543 wakaba 1.4 return ($sib, $new_todos);
544 wakaba 1.2 } # _check_get_children
545    
546 wakaba 1.55 sub _get_css_parser ($) {
547     my $self = shift;
548    
549     return $self->{css_parser} if $self->{css_parser};
550    
551     require Whatpm::CSS::Parser;
552     my $p = Whatpm::CSS::Parser->new;
553    
554     # if ($parse_mode eq 'q') {
555     # $p->{unitless_px} = 1;
556     # $p->{hashless_color} = 1;
557     # }
558    
559     $p->{prop}->{$_} = 1 for qw/
560     background background-attachment background-color background-image
561     background-position background-position-x background-position-y
562     background-repeat border border-bottom border-bottom-color
563     border-bottom-style border-bottom-width border-collapse border-color
564     border-left border-left-color
565     border-left-style border-left-width border-right border-right-color
566     border-right-style border-right-width
567     border-spacing -manakai-border-spacing-x -manakai-border-spacing-y
568     border-style border-top border-top-color border-top-style border-top-width
569     border-width bottom
570     caption-side clear clip color content counter-increment counter-reset
571     cursor direction display empty-cells float font
572     font-family font-size font-size-adjust font-stretch
573     font-style font-variant font-weight height left
574     letter-spacing line-height
575     list-style list-style-image list-style-position list-style-type
576     margin margin-bottom margin-left margin-right margin-top marker-offset
577     marks max-height max-width min-height min-width opacity -moz-opacity
578     orphans outline outline-color outline-style outline-width overflow
579     overflow-x overflow-y
580     padding padding-bottom padding-left padding-right padding-top
581     page page-break-after page-break-before page-break-inside
582     position quotes right size table-layout
583     text-align text-decoration text-indent text-transform
584     top unicode-bidi vertical-align visibility white-space width widows
585     word-spacing z-index
586     /;
587     $p->{prop_value}->{display}->{$_} = 1 for qw/
588     block clip inline inline-block inline-table list-item none
589     table table-caption table-cell table-column table-column-group
590     table-header-group table-footer-group table-row table-row-group
591     compact marker
592     /;
593     $p->{prop_value}->{position}->{$_} = 1 for qw/
594     absolute fixed relative static
595     /;
596     $p->{prop_value}->{float}->{$_} = 1 for qw/
597     left right none
598     /;
599     $p->{prop_value}->{clear}->{$_} = 1 for qw/
600     left right none both
601     /;
602     $p->{prop_value}->{direction}->{ltr} = 1;
603     $p->{prop_value}->{direction}->{rtl} = 1;
604     $p->{prop_value}->{marks}->{crop} = 1;
605     $p->{prop_value}->{marks}->{cross} = 1;
606     $p->{prop_value}->{'unicode-bidi'}->{$_} = 1 for qw/
607     normal bidi-override embed
608     /;
609     for my $prop_name (qw/overflow overflow-x overflow-y/) {
610     $p->{prop_value}->{$prop_name}->{$_} = 1 for qw/
611     visible hidden scroll auto -webkit-marquee -moz-hidden-unscrollable
612     /;
613     }
614     $p->{prop_value}->{visibility}->{$_} = 1 for qw/
615     visible hidden collapse
616     /;
617     $p->{prop_value}->{'list-style-type'}->{$_} = 1 for qw/
618     disc circle square decimal decimal-leading-zero
619     lower-roman upper-roman lower-greek lower-latin
620     upper-latin armenian georgian lower-alpha upper-alpha none
621     hebrew cjk-ideographic hiragana katakana hiragana-iroha
622     katakana-iroha
623     /;
624     $p->{prop_value}->{'list-style-position'}->{outside} = 1;
625     $p->{prop_value}->{'list-style-position'}->{inside} = 1;
626     $p->{prop_value}->{'page-break-before'}->{$_} = 1 for qw/
627     auto always avoid left right
628     /;
629     $p->{prop_value}->{'page-break-after'}->{$_} = 1 for qw/
630     auto always avoid left right
631     /;
632     $p->{prop_value}->{'page-break-inside'}->{auto} = 1;
633     $p->{prop_value}->{'page-break-inside'}->{avoid} = 1;
634     $p->{prop_value}->{'background-repeat'}->{$_} = 1 for qw/
635     repeat repeat-x repeat-y no-repeat
636     /;
637     $p->{prop_value}->{'background-attachment'}->{scroll} = 1;
638     $p->{prop_value}->{'background-attachment'}->{fixed} = 1;
639     $p->{prop_value}->{'font-size'}->{$_} = 1 for qw/
640     xx-small x-small small medium large x-large xx-large
641     -manakai-xxx-large -webkit-xxx-large
642     larger smaller
643     /;
644     $p->{prop_value}->{'font-style'}->{normal} = 1;
645     $p->{prop_value}->{'font-style'}->{italic} = 1;
646     $p->{prop_value}->{'font-style'}->{oblique} = 1;
647     $p->{prop_value}->{'font-variant'}->{normal} = 1;
648     $p->{prop_value}->{'font-variant'}->{'small-caps'} = 1;
649     $p->{prop_value}->{'font-stretch'}->{$_} = 1 for
650     qw/normal wider narrower ultra-condensed extra-condensed
651     condensed semi-condensed semi-expanded expanded
652     extra-expanded ultra-expanded/;
653     $p->{prop_value}->{'text-align'}->{$_} = 1 for qw/
654     left right center justify begin end
655     /;
656     $p->{prop_value}->{'text-transform'}->{$_} = 1 for qw/
657     capitalize uppercase lowercase none
658     /;
659     $p->{prop_value}->{'white-space'}->{$_} = 1 for qw/
660     normal pre nowrap pre-line pre-wrap
661     /;
662     $p->{prop_value}->{'text-decoration'}->{$_} = 1 for qw/
663     none blink underline overline line-through
664     /;
665     $p->{prop_value}->{'caption-side'}->{$_} = 1 for qw/
666     top bottom left right
667     /;
668     $p->{prop_value}->{'table-layout'}->{auto} = 1;
669     $p->{prop_value}->{'table-layout'}->{fixed} = 1;
670     $p->{prop_value}->{'border-collapse'}->{collapase} = 1;
671     $p->{prop_value}->{'border-collapse'}->{separate} = 1;
672     $p->{prop_value}->{'empty-cells'}->{show} = 1;
673     $p->{prop_value}->{'empty-cells'}->{hide} = 1;
674     $p->{prop_value}->{cursor}->{$_} = 1 for qw/
675     auto crosshair default pointer move e-resize ne-resize nw-resize n-resize
676     se-resize sw-resize s-resize w-resize text wait help progress
677     /;
678     for my $prop (qw/border-top-style border-left-style
679     border-bottom-style border-right-style outline-style/) {
680     $p->{prop_value}->{$prop}->{$_} = 1 for qw/
681     none hidden dotted dashed solid double groove ridge inset outset
682     /;
683     }
684     for my $prop (qw/color background-color
685     border-bottom-color border-left-color border-right-color
686     border-top-color border-color/) {
687     $p->{prop_value}->{$prop}->{transparent} = 1;
688     $p->{prop_value}->{$prop}->{flavor} = 1;
689     $p->{prop_value}->{$prop}->{'-manakai-default'} = 1;
690     }
691     $p->{prop_value}->{'outline-color'}->{invert} = 1;
692     $p->{prop_value}->{'outline-color'}->{'-manakai-invert-or-currentcolor'} = 1;
693     $p->{pseudo_class}->{$_} = 1 for qw/
694     active checked disabled empty enabled first-child first-of-type
695     focus hover indeterminate last-child last-of-type link only-child
696     only-of-type root target visited
697     lang nth-child nth-last-child nth-of-type nth-last-of-type not
698     -manakai-contains -manakai-current
699     /;
700     $p->{pseudo_element}->{$_} = 1 for qw/
701     after before first-letter first-line
702     /;
703    
704     return $self->{css_parser} = $p;
705     } # _get_css_parser
706    
707 wakaba 1.44 =head1 LICENSE
708    
709     Copyright 2007 Wakaba <[email protected]>
710    
711     This library is free software; you can redistribute it
712     and/or modify it under the same terms as Perl itself.
713    
714     =cut
715    
716 wakaba 1.1 1;
717 wakaba 1.55 # $Date: 2007/11/25 08:04:20 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24