/[pub]/test/html-webhacc/cc.cgi
Suika

Contents of /test/html-webhacc/cc.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.42 - (hide annotations) (download)
Mon Mar 17 13:25:19 2008 UTC (18 years, 4 months ago) by wakaba
Branch: MAIN
Changes since 1.41: +38 -15 lines
++ ChangeLog	17 Mar 2008 13:25:16 -0000
2008-03-17  Wakaba  <wakaba@suika.fam.cx>

	* cc-script.js: The ID of the list is now given as an argument.

	* cc.cgi: List of document errors now also expanded by source
	code fragment generated by scripting.
	(get_error_label): Use line/column information from the error
	context node, if any.

1 wakaba 1.1 #!/usr/bin/perl
2     use strict;
3 wakaba 1.23 use utf8;
4 wakaba 1.1
5     use lib qw[/home/httpd/html/www/markup/html/whatpm
6 wakaba 1.16 /home/wakaba/work/manakai2/lib];
7 wakaba 1.1 use CGI::Carp qw[fatalsToBrowser];
8 wakaba 1.2 use Scalar::Util qw[refaddr];
9 wakaba 1.16 use Time::HiRes qw/time/;
10 wakaba 1.1
11 wakaba 1.2 sub htescape ($) {
12     my $s = $_[0];
13     $s =~ s/&/&amp;/g;
14     $s =~ s/</&lt;/g;
15     $s =~ s/>/&gt;/g;
16     $s =~ s/"/&quot;/g;
17 wakaba 1.12 $s =~ s{([\x00-\x09\x0B-\x1F\x7F-\xA0\x{FEFF}\x{FFFC}-\x{FFFF}])}{
18     sprintf '<var>U+%04X</var>', ord $1;
19     }ge;
20 wakaba 1.2 return $s;
21     } # htescape
22    
23 wakaba 1.35 my @nav;
24     my %time;
25     require Message::DOM::DOMImplementation;
26     my $dom = Message::DOM::DOMImplementation->new;
27     {
28 wakaba 1.16 use Message::CGI::HTTP;
29     my $http = Message::CGI::HTTP->new;
30 wakaba 1.1
31 wakaba 1.16 if ($http->get_meta_variable ('PATH_INFO') ne '/') {
32 wakaba 1.8 print STDOUT "Status: 404 Not Found\nContent-Type: text/plain; charset=us-ascii\n\n400";
33     exit;
34     }
35    
36 wakaba 1.12 binmode STDOUT, ':utf8';
37 wakaba 1.14 $| = 1;
38 wakaba 1.12
39 wakaba 1.7 load_text_catalog ('en'); ## TODO: conneg
40    
41 wakaba 1.2 print STDOUT qq[Content-Type: text/html; charset=utf-8
42    
43     <!DOCTYPE html>
44     <html lang="en">
45     <head>
46     <title>Web Document Conformance Checker (BETA)</title>
47 wakaba 1.3 <link rel="stylesheet" href="../cc-style.css" type="text/css">
48 wakaba 1.2 </head>
49     <body>
50 wakaba 1.13 <h1><a href="../cc-interface">Web Document Conformance Checker</a>
51     (<em>beta</em>)</h1>
52 wakaba 1.14 ];
53 wakaba 1.2
54 wakaba 1.14 $| = 0;
55     my $input = get_input_document ($http, $dom);
56 wakaba 1.16 my $char_length = 0;
57 wakaba 1.14
58     print qq[
59 wakaba 1.4 <div id="document-info" class="section">
60 wakaba 1.2 <dl>
61 wakaba 1.9 <dt>Request URI</dt>
62     <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{request_uri}]}">@{[htescape $input->{request_uri}]}</a>&gt;</code></dd>
63 wakaba 1.2 <dt>Document URI</dt>
64 wakaba 1.25 <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{uri}]}" id=anchor-document-uri>@{[htescape $input->{uri}]}</a>&gt;</code>
65     <script>
66     document.title = '<'
67     + document.getElementById ('anchor-document-uri').href + '> \\u2014 '
68     + document.title;
69     </script></dd>
70 wakaba 1.2 ]; # no </dl> yet
71 wakaba 1.3 push @nav, ['#document-info' => 'Information'];
72 wakaba 1.1
73 wakaba 1.9 if (defined $input->{s}) {
74 wakaba 1.16 $char_length = length $input->{s};
75 wakaba 1.9
76     print STDOUT qq[
77     <dt>Base URI</dt>
78     <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{base_uri}]}">@{[htescape $input->{base_uri}]}</a>&gt;</code></dd>
79     <dt>Internet Media Type</dt>
80     <dd><code class="MIME" lang="en">@{[htescape $input->{media_type}]}</code>
81 wakaba 1.25 @{[$input->{media_type_overridden} ? '<em>(overridden)</em>' : defined $input->{official_type} ? $input->{media_type} eq $input->{official_type} ? '' : '<em>(sniffed; official type is: <code class=MIME lang=en>'.htescape ($input->{official_type}).'</code>)' : '<em>(sniffed)</em>']}</dd>
82 wakaba 1.9 <dt>Character Encoding</dt>
83     <dd>@{[defined $input->{charset} ? '<code class="charset" lang="en">'.htescape ($input->{charset}).'</code>' : '(none)']}
84     @{[$input->{charset_overridden} ? '<em>(overridden)</em>' : '']}</dd>
85 wakaba 1.16 <dt>Length</dt>
86     <dd>$char_length byte@{[$char_length == 1 ? '' : 's']}</dd>
87 wakaba 1.9 </dl>
88     </div>
89 wakaba 1.39
90     <script src="../cc-script.js"></script>
91 wakaba 1.9 ];
92    
93 wakaba 1.35 $input->{id_prefix} = '';
94     #$input->{nested} = 0;
95 wakaba 1.20 my $result = {conforming_min => 1, conforming_max => 1};
96 wakaba 1.31 check_and_print ($input => $result);
97 wakaba 1.19 print_result_section ($result);
98 wakaba 1.9 } else {
99 wakaba 1.18 print STDOUT qq[</dl></div>];
100     print_result_input_error_section ($input);
101 wakaba 1.9 }
102 wakaba 1.3
103 wakaba 1.2 print STDOUT qq[
104 wakaba 1.3 <ul class="navigation" id="nav-items">
105     ];
106     for (@nav) {
107     print STDOUT qq[<li><a href="$_->[0]">$_->[1]</a></li>];
108     }
109     print STDOUT qq[
110     </ul>
111 wakaba 1.2 </body>
112     </html>
113     ];
114 wakaba 1.1
115 wakaba 1.24 for (qw/decode parse parse_html parse_xml parse_manifest
116     check check_manifest/) {
117 wakaba 1.16 next unless defined $time{$_};
118     open my $file, '>>', ".cc-$_.txt" or die ".cc-$_.txt: $!";
119     print $file $char_length, "\t", $time{$_}, "\n";
120     }
121    
122 wakaba 1.1 exit;
123 wakaba 1.35 }
124 wakaba 1.1
125 wakaba 1.19 sub add_error ($$$) {
126     my ($layer, $err, $result) = @_;
127     if (defined $err->{level}) {
128     if ($err->{level} eq 's') {
129     $result->{$layer}->{should}++;
130     $result->{$layer}->{score_min} -= 2;
131     $result->{conforming_min} = 0;
132     } elsif ($err->{level} eq 'w' or $err->{level} eq 'g') {
133     $result->{$layer}->{warning}++;
134 wakaba 1.30 } elsif ($err->{level} eq 'u' or $err->{level} eq 'unsupported') {
135 wakaba 1.19 $result->{$layer}->{unsupported}++;
136     $result->{unsupported} = 1;
137 wakaba 1.37 } elsif ($err->{level} eq 'i') {
138     #
139 wakaba 1.19 } else {
140     $result->{$layer}->{must}++;
141     $result->{$layer}->{score_max} -= 2;
142     $result->{$layer}->{score_min} -= 2;
143     $result->{conforming_min} = 0;
144     $result->{conforming_max} = 0;
145     }
146     } else {
147     $result->{$layer}->{must}++;
148     $result->{$layer}->{score_max} -= 2;
149     $result->{$layer}->{score_min} -= 2;
150     $result->{conforming_min} = 0;
151     $result->{conforming_max} = 0;
152     }
153     } # add_error
154    
155 wakaba 1.31 sub check_and_print ($$) {
156     my ($input, $result) = @_;
157    
158     print_http_header_section ($input, $result);
159    
160     my $doc;
161     my $el;
162 wakaba 1.35 my $cssom;
163 wakaba 1.31 my $manifest;
164 wakaba 1.34 my @subdoc;
165 wakaba 1.31
166     if ($input->{media_type} eq 'text/html') {
167     ($doc, $el) = print_syntax_error_html_section ($input, $result);
168     print_source_string_section
169 wakaba 1.35 ($input,
170     \($input->{s}),
171     $input->{charset} || $doc->input_encoding);
172 wakaba 1.31 } elsif ({
173     'text/xml' => 1,
174     'application/atom+xml' => 1,
175     'application/rss+xml' => 1,
176     'application/svg+xml' => 1,
177     'application/xhtml+xml' => 1,
178     'application/xml' => 1,
179     }->{$input->{media_type}}) {
180     ($doc, $el) = print_syntax_error_xml_section ($input, $result);
181 wakaba 1.35 print_source_string_section ($input,
182     \($input->{s}),
183     $doc->input_encoding);
184     } elsif ($input->{media_type} eq 'text/css') {
185     $cssom = print_syntax_error_css_section ($input, $result);
186     print_source_string_section
187     ($input, \($input->{s}),
188     $cssom->manakai_input_encoding);
189 wakaba 1.31 } elsif ($input->{media_type} eq 'text/cache-manifest') {
190     ## TODO: MUST be text/cache-manifest
191     $manifest = print_syntax_error_manifest_section ($input, $result);
192 wakaba 1.35 print_source_string_section ($input, \($input->{s}),
193     'utf-8');
194 wakaba 1.31 } else {
195     ## TODO: Change HTTP status code??
196     print_result_unknown_type_section ($input, $result);
197     }
198    
199     if (defined $doc or defined $el) {
200 wakaba 1.34 $doc->document_uri ($input->{uri});
201     $doc->manakai_entity_base_uri ($input->{base_uri});
202 wakaba 1.32 print_structure_dump_dom_section ($input, $doc, $el);
203     my $elements = print_structure_error_dom_section
204 wakaba 1.34 ($input, $doc, $el, $result, sub {
205     push @subdoc, shift;
206     });
207 wakaba 1.32 print_table_section ($input, $elements->{table}) if @{$elements->{table}};
208 wakaba 1.33 print_listing_section ({
209     id => 'identifiers', label => 'IDs', heading => 'Identifiers',
210     }, $input, $elements->{id}) if keys %{$elements->{id}};
211     print_listing_section ({
212     id => 'terms', label => 'Terms', heading => 'Terms',
213     }, $input, $elements->{term}) if keys %{$elements->{term}};
214     print_listing_section ({
215     id => 'classes', label => 'Classes', heading => 'Classes',
216     }, $input, $elements->{class}) if keys %{$elements->{class}};
217 wakaba 1.35 } elsif (defined $cssom) {
218     print_structure_dump_cssom_section ($input, $cssom);
219     ## TODO: CSSOM validation
220 wakaba 1.36 add_error ('structure', {level => 'u'} => $result);
221 wakaba 1.31 } elsif (defined $manifest) {
222 wakaba 1.32 print_structure_dump_manifest_section ($input, $manifest);
223     print_structure_error_manifest_section ($input, $manifest, $result);
224 wakaba 1.31 }
225 wakaba 1.34
226     my $id_prefix = 0;
227     for my $subinput (@subdoc) {
228     $subinput->{id_prefix} = 'subdoc-' . ++$id_prefix;
229     $subinput->{nested} = 1;
230     $subinput->{base_uri} = $subinput->{container_node}->base_uri
231     unless defined $subinput->{base_uri};
232     my $ebaseuri = htescape ($subinput->{base_uri});
233     push @nav, ['#' . $subinput->{id_prefix} => 'Sub #' . $id_prefix];
234     print STDOUT qq[<div id="$subinput->{id_prefix}" class=section>
235     <h2>Subdocument #$id_prefix</h2>
236    
237     <dl>
238     <dt>Internet Media Type</dt>
239     <dd><code class="MIME" lang="en">@{[htescape $subinput->{media_type}]}</code>
240     <dt>Container Node</dt>
241     <dd>@{[get_node_link ($input, $subinput->{container_node})]}</dd>
242     <dt>Base <abbr title="Uniform Resource Identifiers">URI</abbr></dt>
243     <dd><code class=URI>&lt;<a href="$ebaseuri">$ebaseuri</a>></code></dd>
244     </dl>];
245    
246 wakaba 1.35 $subinput->{id_prefix} .= '-';
247 wakaba 1.34 check_and_print ($subinput => $result);
248    
249     print STDOUT qq[</div>];
250     }
251 wakaba 1.31 } # check_and_print
252    
253 wakaba 1.19 sub print_http_header_section ($$) {
254     my ($input, $result) = @_;
255 wakaba 1.9 return unless defined $input->{header_status_code} or
256     defined $input->{header_status_text} or
257 wakaba 1.34 @{$input->{header_field} or []};
258 wakaba 1.9
259 wakaba 1.32 push @nav, ['#source-header' => 'HTTP Header'] unless $input->{nested};
260     print STDOUT qq[<div id="$input->{id_prefix}source-header" class="section">
261 wakaba 1.9 <h2>HTTP Header</h2>
262    
263     <p><strong>Note</strong>: Due to the limitation of the
264     network library in use, the content of this section might
265     not be the real header.</p>
266    
267     <table><tbody>
268     ];
269    
270     if (defined $input->{header_status_code}) {
271     print STDOUT qq[<tr><th scope="row">Status code</th>];
272     print STDOUT qq[<td><code>@{[htescape ($input->{header_status_code})]}</code></td></tr>];
273     }
274     if (defined $input->{header_status_text}) {
275     print STDOUT qq[<tr><th scope="row">Status text</th>];
276     print STDOUT qq[<td><code>@{[htescape ($input->{header_status_text})]}</code></td></tr>];
277     }
278    
279     for (@{$input->{header_field}}) {
280     print STDOUT qq[<tr><th scope="row"><code>@{[htescape ($_->[0])]}</code></th>];
281     print STDOUT qq[<td><code>@{[htescape ($_->[1])]}</code></td></tr>];
282     }
283    
284     print STDOUT qq[</tbody></table></div>];
285     } # print_http_header_section
286    
287 wakaba 1.19 sub print_syntax_error_html_section ($$) {
288     my ($input, $result) = @_;
289 wakaba 1.18
290     require Encode;
291     require Whatpm::HTML;
292    
293     print STDOUT qq[
294 wakaba 1.32 <div id="$input->{id_prefix}parse-errors" class="section">
295 wakaba 1.18 <h2>Parse Errors</h2>
296    
297 wakaba 1.39 <dl id="$input->{id_prefix}parse-errors-list">];
298 wakaba 1.32 push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};
299 wakaba 1.18
300     my $onerror = sub {
301     my (%opt) = @_;
302     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});
303 wakaba 1.38 print STDOUT qq[<dt class="$cls">], get_error_label ($input, \%opt),
304     qq[</dt>];
305 wakaba 1.18 $type =~ tr/ /-/;
306     $type =~ s/\|/%7C/g;
307     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];
308 wakaba 1.23 print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);
309     print STDOUT qq[$msg</dd>\n];
310 wakaba 1.19
311     add_error ('syntax', \%opt => $result);
312 wakaba 1.18 };
313    
314     my $doc = $dom->create_document;
315     my $el;
316 wakaba 1.35 my $inner_html_element = $input->{inner_html_element};
317 wakaba 1.18 if (defined $inner_html_element and length $inner_html_element) {
318 wakaba 1.26 $input->{charset} ||= 'windows-1252'; ## TODO: for now.
319 wakaba 1.24 my $time1 = time;
320     my $t = Encode::decode ($input->{charset}, $input->{s});
321     $time{decode} = time - $time1;
322    
323 wakaba 1.18 $el = $doc->create_element_ns
324     ('http://www.w3.org/1999/xhtml', [undef, $inner_html_element]);
325 wakaba 1.24 $time1 = time;
326 wakaba 1.18 Whatpm::HTML->set_inner_html ($el, $t, $onerror);
327 wakaba 1.24 $time{parse} = time - $time1;
328 wakaba 1.18 } else {
329 wakaba 1.24 my $time1 = time;
330     Whatpm::HTML->parse_byte_string
331     ($input->{charset}, $input->{s} => $doc, $onerror);
332     $time{parse_html} = time - $time1;
333 wakaba 1.18 }
334 wakaba 1.26 $doc->manakai_charset ($input->{official_charset})
335     if defined $input->{official_charset};
336 wakaba 1.24
337 wakaba 1.18 print STDOUT qq[</dl></div>];
338    
339     return ($doc, $el);
340     } # print_syntax_error_html_section
341    
342 wakaba 1.19 sub print_syntax_error_xml_section ($$) {
343     my ($input, $result) = @_;
344 wakaba 1.18
345     require Message::DOM::XMLParserTemp;
346    
347     print STDOUT qq[
348 wakaba 1.32 <div id="$input->{id_prefix}parse-errors" class="section">
349 wakaba 1.18 <h2>Parse Errors</h2>
350    
351 wakaba 1.39 <dl id="$input->{id_prefix}parse-errors-list">];
352 wakaba 1.32 push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{prefix};
353 wakaba 1.18
354     my $onerror = sub {
355     my $err = shift;
356     my $line = $err->location->line_number;
357 wakaba 1.35 print STDOUT qq[<dt><a href="#$input->{id_prefix}line-$line">Line $line</a> column ];
358 wakaba 1.18 print STDOUT $err->location->column_number, "</dt><dd>";
359     print STDOUT htescape $err->text, "</dd>\n";
360 wakaba 1.19
361     add_error ('syntax', {type => $err->text,
362     level => [
363     $err->SEVERITY_FATAL_ERROR => 'm',
364     $err->SEVERITY_ERROR => 'm',
365     $err->SEVERITY_WARNING => 's',
366     ]->[$err->severity]} => $result);
367    
368 wakaba 1.18 return 1;
369     };
370    
371     my $time1 = time;
372     open my $fh, '<', \($input->{s});
373     my $doc = Message::DOM::XMLParserTemp->parse_byte_stream
374     ($fh => $dom, $onerror, charset => $input->{charset});
375     $time{parse_xml} = time - $time1;
376 wakaba 1.26 $doc->manakai_charset ($input->{official_charset})
377     if defined $input->{official_charset};
378 wakaba 1.18
379     print STDOUT qq[</dl></div>];
380    
381     return ($doc, undef);
382     } # print_syntax_error_xml_section
383    
384 wakaba 1.35 sub get_css_parser () {
385     our $CSSParser;
386     return $CSSParser if $CSSParser;
387    
388     require Whatpm::CSS::Parser;
389     my $p = Whatpm::CSS::Parser->new;
390    
391     $p->{prop}->{$_} = 1 for qw/
392 wakaba 1.37 alignment-baseline
393 wakaba 1.35 background background-attachment background-color background-image
394     background-position background-position-x background-position-y
395     background-repeat border border-bottom border-bottom-color
396     border-bottom-style border-bottom-width border-collapse border-color
397     border-left border-left-color
398     border-left-style border-left-width border-right border-right-color
399     border-right-style border-right-width
400     border-spacing -manakai-border-spacing-x -manakai-border-spacing-y
401     border-style border-top border-top-color border-top-style border-top-width
402     border-width bottom
403     caption-side clear clip color content counter-increment counter-reset
404 wakaba 1.37 cursor direction display dominant-baseline empty-cells float font
405 wakaba 1.35 font-family font-size font-size-adjust font-stretch
406     font-style font-variant font-weight height left
407     letter-spacing line-height
408     list-style list-style-image list-style-position list-style-type
409     margin margin-bottom margin-left margin-right margin-top marker-offset
410     marks max-height max-width min-height min-width opacity -moz-opacity
411     orphans outline outline-color outline-style outline-width overflow
412     overflow-x overflow-y
413     padding padding-bottom padding-left padding-right padding-top
414     page page-break-after page-break-before page-break-inside
415     position quotes right size table-layout
416 wakaba 1.37 text-align text-anchor text-decoration text-indent text-transform
417 wakaba 1.35 top unicode-bidi vertical-align visibility white-space width widows
418 wakaba 1.37 word-spacing writing-mode z-index
419 wakaba 1.35 /;
420     $p->{prop_value}->{display}->{$_} = 1 for qw/
421     block clip inline inline-block inline-table list-item none
422     table table-caption table-cell table-column table-column-group
423     table-header-group table-footer-group table-row table-row-group
424     compact marker
425     /;
426     $p->{prop_value}->{position}->{$_} = 1 for qw/
427     absolute fixed relative static
428     /;
429     $p->{prop_value}->{float}->{$_} = 1 for qw/
430     left right none
431     /;
432     $p->{prop_value}->{clear}->{$_} = 1 for qw/
433     left right none both
434     /;
435     $p->{prop_value}->{direction}->{ltr} = 1;
436     $p->{prop_value}->{direction}->{rtl} = 1;
437     $p->{prop_value}->{marks}->{crop} = 1;
438     $p->{prop_value}->{marks}->{cross} = 1;
439     $p->{prop_value}->{'unicode-bidi'}->{$_} = 1 for qw/
440     normal bidi-override embed
441     /;
442     for my $prop_name (qw/overflow overflow-x overflow-y/) {
443     $p->{prop_value}->{$prop_name}->{$_} = 1 for qw/
444     visible hidden scroll auto -webkit-marquee -moz-hidden-unscrollable
445     /;
446     }
447     $p->{prop_value}->{visibility}->{$_} = 1 for qw/
448     visible hidden collapse
449     /;
450     $p->{prop_value}->{'list-style-type'}->{$_} = 1 for qw/
451     disc circle square decimal decimal-leading-zero
452     lower-roman upper-roman lower-greek lower-latin
453     upper-latin armenian georgian lower-alpha upper-alpha none
454     hebrew cjk-ideographic hiragana katakana hiragana-iroha
455     katakana-iroha
456     /;
457     $p->{prop_value}->{'list-style-position'}->{outside} = 1;
458     $p->{prop_value}->{'list-style-position'}->{inside} = 1;
459     $p->{prop_value}->{'page-break-before'}->{$_} = 1 for qw/
460     auto always avoid left right
461     /;
462     $p->{prop_value}->{'page-break-after'}->{$_} = 1 for qw/
463     auto always avoid left right
464     /;
465     $p->{prop_value}->{'page-break-inside'}->{auto} = 1;
466     $p->{prop_value}->{'page-break-inside'}->{avoid} = 1;
467     $p->{prop_value}->{'background-repeat'}->{$_} = 1 for qw/
468     repeat repeat-x repeat-y no-repeat
469     /;
470     $p->{prop_value}->{'background-attachment'}->{scroll} = 1;
471     $p->{prop_value}->{'background-attachment'}->{fixed} = 1;
472     $p->{prop_value}->{'font-size'}->{$_} = 1 for qw/
473     xx-small x-small small medium large x-large xx-large
474     -manakai-xxx-large -webkit-xxx-large
475     larger smaller
476     /;
477     $p->{prop_value}->{'font-style'}->{normal} = 1;
478     $p->{prop_value}->{'font-style'}->{italic} = 1;
479     $p->{prop_value}->{'font-style'}->{oblique} = 1;
480     $p->{prop_value}->{'font-variant'}->{normal} = 1;
481     $p->{prop_value}->{'font-variant'}->{'small-caps'} = 1;
482     $p->{prop_value}->{'font-stretch'}->{$_} = 1 for
483     qw/normal wider narrower ultra-condensed extra-condensed
484     condensed semi-condensed semi-expanded expanded
485     extra-expanded ultra-expanded/;
486     $p->{prop_value}->{'text-align'}->{$_} = 1 for qw/
487     left right center justify begin end
488     /;
489     $p->{prop_value}->{'text-transform'}->{$_} = 1 for qw/
490     capitalize uppercase lowercase none
491     /;
492     $p->{prop_value}->{'white-space'}->{$_} = 1 for qw/
493 wakaba 1.36 normal pre nowrap pre-line pre-wrap -moz-pre-wrap
494 wakaba 1.35 /;
495 wakaba 1.37 $p->{prop_value}->{'writing-mode'}->{$_} = 1 for qw/
496     lr rl tb lr-tb rl-tb tb-rl
497     /;
498     $p->{prop_value}->{'text-anchor'}->{$_} = 1 for qw/
499     start middle end
500     /;
501     $p->{prop_value}->{'dominant-baseline'}->{$_} = 1 for qw/
502     auto use-script no-change reset-size ideographic alphabetic
503     hanging mathematical central middle text-after-edge text-before-edge
504     /;
505     $p->{prop_value}->{'alignment-baseline'}->{$_} = 1 for qw/
506     auto baseline before-edge text-before-edge middle central
507     after-edge text-after-edge ideographic alphabetic hanging
508     mathematical
509     /;
510 wakaba 1.35 $p->{prop_value}->{'text-decoration'}->{$_} = 1 for qw/
511     none blink underline overline line-through
512     /;
513     $p->{prop_value}->{'caption-side'}->{$_} = 1 for qw/
514     top bottom left right
515     /;
516     $p->{prop_value}->{'table-layout'}->{auto} = 1;
517     $p->{prop_value}->{'table-layout'}->{fixed} = 1;
518 wakaba 1.36 $p->{prop_value}->{'border-collapse'}->{collapse} = 1;
519 wakaba 1.35 $p->{prop_value}->{'border-collapse'}->{separate} = 1;
520     $p->{prop_value}->{'empty-cells'}->{show} = 1;
521     $p->{prop_value}->{'empty-cells'}->{hide} = 1;
522     $p->{prop_value}->{cursor}->{$_} = 1 for qw/
523     auto crosshair default pointer move e-resize ne-resize nw-resize n-resize
524     se-resize sw-resize s-resize w-resize text wait help progress
525     /;
526     for my $prop (qw/border-top-style border-left-style
527     border-bottom-style border-right-style outline-style/) {
528     $p->{prop_value}->{$prop}->{$_} = 1 for qw/
529     none hidden dotted dashed solid double groove ridge inset outset
530     /;
531     }
532     for my $prop (qw/color background-color
533     border-bottom-color border-left-color border-right-color
534     border-top-color border-color/) {
535     $p->{prop_value}->{$prop}->{transparent} = 1;
536     $p->{prop_value}->{$prop}->{flavor} = 1;
537     $p->{prop_value}->{$prop}->{'-manakai-default'} = 1;
538     }
539     $p->{prop_value}->{'outline-color'}->{invert} = 1;
540     $p->{prop_value}->{'outline-color'}->{'-manakai-invert-or-currentcolor'} = 1;
541     $p->{pseudo_class}->{$_} = 1 for qw/
542     active checked disabled empty enabled first-child first-of-type
543     focus hover indeterminate last-child last-of-type link only-child
544     only-of-type root target visited
545     lang nth-child nth-last-child nth-of-type nth-last-of-type not
546     -manakai-contains -manakai-current
547     /;
548     $p->{pseudo_element}->{$_} = 1 for qw/
549     after before first-letter first-line
550     /;
551    
552     return $CSSParser = $p;
553     } # get_css_parser
554    
555     sub print_syntax_error_css_section ($$) {
556     my ($input, $result) = @_;
557    
558     print STDOUT qq[
559     <div id="$input->{id_prefix}parse-errors" class="section">
560     <h2>Parse Errors</h2>
561    
562 wakaba 1.39 <dl id="$input->{id_prefix}parse-errors-list">];
563 wakaba 1.35 push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};
564    
565     my $p = get_css_parser ();
566 wakaba 1.37 $p->init;
567 wakaba 1.35 $p->{onerror} = sub {
568     my (%opt) = @_;
569     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});
570     if ($opt{token}) {
571     print STDOUT qq[<dt class="$cls"><a href="#$input->{id_prefix}line-$opt{token}->{line}">Line $opt{token}->{line}</a> column $opt{token}->{column}];
572     } else {
573     print STDOUT qq[<dt class="$cls">Unknown location];
574     }
575     if (defined $opt{value}) {
576     print STDOUT qq[ (<code>@{[htescape ($opt{value})]}</code>)];
577     } elsif (defined $opt{token}) {
578     print STDOUT qq[ (<code>@{[htescape (Whatpm::CSS::Tokenizer->serialize_token ($opt{token}))]}</code>)];
579     }
580     $type =~ tr/ /-/;
581     $type =~ s/\|/%7C/g;
582     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];
583     print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);
584     print STDOUT qq[$msg</dd>\n];
585    
586     add_error ('syntax', \%opt => $result);
587     };
588     $p->{href} = $input->{uri};
589     $p->{base_uri} = $input->{base_uri};
590    
591 wakaba 1.37 # if ($parse_mode eq 'q') {
592     # $p->{unitless_px} = 1;
593     # $p->{hashless_color} = 1;
594     # }
595    
596     ## TODO: Make $input->{s} a ref.
597    
598 wakaba 1.35 my $s = \$input->{s};
599     my $charset;
600     unless ($input->{is_char_string}) {
601     require Encode;
602     if (defined $input->{charset}) {## TODO: IANA->Perl
603     $charset = $input->{charset};
604     $s = \(Encode::decode ($input->{charset}, $$s));
605     } else {
606     ## TODO: charset detection
607     $s = \(Encode::decode ($charset = 'utf-8', $$s));
608     }
609     }
610    
611     my $cssom = $p->parse_char_string ($$s);
612     $cssom->manakai_input_encoding ($charset) if defined $charset;
613    
614     print STDOUT qq[</dl></div>];
615    
616     return $cssom;
617     } # print_syntax_error_css_section
618    
619 wakaba 1.22 sub print_syntax_error_manifest_section ($$) {
620     my ($input, $result) = @_;
621    
622     require Whatpm::CacheManifest;