1 |
wakaba |
1.1 |
package WebHACC::Language::CSS; |
2 |
|
|
use strict; |
3 |
|
|
require WebHACC::Langauge::Base; |
4 |
|
|
push our @ISA, 'WebHACC::Language::Base'; |
5 |
|
|
|
6 |
|
|
sub new ($) { |
7 |
|
|
my $self = bless {}, shift; |
8 |
|
|
return $self; |
9 |
|
|
} # new |
10 |
|
|
|
11 |
|
|
sub generate_syntax_error_section ($) { |
12 |
|
|
my $self = shift; |
13 |
|
|
|
14 |
|
|
my $out = $self->output; |
15 |
|
|
$out->start_section (id => 'parse-errors', title => 'Parse Errors'); |
16 |
|
|
$out->start_tag ('dl', id => 'parse-errors-list'); |
17 |
|
|
|
18 |
|
|
my $input = $self->input; |
19 |
|
|
my $result = $self->result; |
20 |
|
|
|
21 |
|
|
my $p = $self->get_css_parser (); |
22 |
|
|
$p->init; |
23 |
|
|
$p->{onerror} = sub { |
24 |
|
|
my (%opt) = @_; |
25 |
wakaba |
1.2 |
if (not defined $opt{value} and defined $opt{token}) { |
26 |
|
|
$opt{value} = Whatpm::CSS::Tokenizer->serialize_token ($opt{token}); |
27 |
wakaba |
1.1 |
} |
28 |
wakaba |
1.2 |
$result->add_error (%opt, layer => 'syntax'); |
29 |
wakaba |
1.1 |
}; |
30 |
|
|
$p->{href} = $input->{uri}; |
31 |
|
|
$p->{base_uri} = $input->{base_uri}; |
32 |
|
|
|
33 |
|
|
# if ($parse_mode eq 'q') { |
34 |
|
|
# $p->{unitless_px} = 1; |
35 |
|
|
# $p->{hashless_color} = 1; |
36 |
|
|
# } |
37 |
|
|
|
38 |
|
|
## TODO: Make $input->{s} a ref. |
39 |
|
|
|
40 |
|
|
my $s = \$input->{s}; |
41 |
|
|
my $charset; |
42 |
|
|
unless ($input->{is_char_string}) { |
43 |
|
|
require Encode; |
44 |
|
|
if (defined $input->{charset}) {## TODO: IANA->Perl |
45 |
|
|
$charset = $input->{charset}; |
46 |
|
|
$s = \(Encode::decode ($input->{charset}, $$s)); |
47 |
|
|
} else { |
48 |
|
|
## TODO: charset detection |
49 |
|
|
$s = \(Encode::decode ($charset = 'utf-8', $$s)); |
50 |
|
|
} |
51 |
|
|
} |
52 |
|
|
|
53 |
|
|
$self->{structure} = $p->parse_char_string ($$s); |
54 |
|
|
$self->{structure}->manakai_input_encoding ($charset) if defined $charset; |
55 |
|
|
|
56 |
|
|
$out->end_tag ('dl'); |
57 |
|
|
$out->end_section; |
58 |
|
|
} # generate_syntax_error_section |
59 |
|
|
|
60 |
|
|
sub source_charset ($) { |
61 |
|
|
return shift->{structure}->manakai_input_encoding; |
62 |
|
|
} # source_charset |
63 |
|
|
|
64 |
|
|
sub generate_structure_dump_section ($) { |
65 |
|
|
my $self = shift; |
66 |
|
|
|
67 |
|
|
my $out = $self->input; |
68 |
|
|
$out->start_section (id => 'document-tree', title => 'Document Tree', |
69 |
|
|
short_title => 'Tree'); |
70 |
|
|
|
71 |
|
|
$out->start_code_block; |
72 |
|
|
$out->text ($cssom->css_text); |
73 |
|
|
$out->end_code_block; |
74 |
|
|
|
75 |
|
|
$out->end_section; |
76 |
|
|
} # generate_structure_dump_section |
77 |
|
|
|
78 |
|
|
sub generate_structure_error_section ($) { |
79 |
wakaba |
1.2 |
my $self = shift; |
80 |
|
|
|
81 |
|
|
my $out = $self->output; |
82 |
|
|
|
83 |
|
|
$out->start_section (id => 'document-errors', title => 'Document Errors'); |
84 |
|
|
$out->start_tag ('dl', class => 'document-errors-list'); |
85 |
|
|
|
86 |
|
|
$self->result->add_error (level => 'u', |
87 |
|
|
layer => 'structure', |
88 |
|
|
type => 'CSSOM validation not supported'); |
89 |
|
|
|
90 |
|
|
$out->end_tag ('dl'); |
91 |
|
|
$out->end_section; |
92 |
wakaba |
1.1 |
} # generate_structure_error_section |
93 |
|
|
|
94 |
|
|
sub get_css_parser () { |
95 |
|
|
our $CSSParser; |
96 |
|
|
return $CSSParser if $CSSParser; |
97 |
|
|
|
98 |
|
|
require Whatpm::CSS::Parser; |
99 |
|
|
my $p = Whatpm::CSS::Parser->new; |
100 |
|
|
|
101 |
|
|
$p->{prop}->{$_} = 1 for qw/ |
102 |
|
|
alignment-baseline |
103 |
|
|
background background-attachment background-color background-image |
104 |
|
|
background-position background-position-x background-position-y |
105 |
|
|
background-repeat border border-bottom border-bottom-color |
106 |
|
|
border-bottom-style border-bottom-width border-collapse border-color |
107 |
|
|
border-left border-left-color |
108 |
|
|
border-left-style border-left-width border-right border-right-color |
109 |
|
|
border-right-style border-right-width |
110 |
|
|
border-spacing -manakai-border-spacing-x -manakai-border-spacing-y |
111 |
|
|
border-style border-top border-top-color border-top-style border-top-width |
112 |
|
|
border-width bottom |
113 |
|
|
caption-side clear clip color content counter-increment counter-reset |
114 |
|
|
cursor direction display dominant-baseline empty-cells float font |
115 |
|
|
font-family font-size font-size-adjust font-stretch |
116 |
|
|
font-style font-variant font-weight height left |
117 |
|
|
letter-spacing line-height |
118 |
|
|
list-style list-style-image list-style-position list-style-type |
119 |
|
|
margin margin-bottom margin-left margin-right margin-top marker-offset |
120 |
|
|
marks max-height max-width min-height min-width opacity -moz-opacity |
121 |
|
|
orphans outline outline-color outline-style outline-width overflow |
122 |
|
|
overflow-x overflow-y |
123 |
|
|
padding padding-bottom padding-left padding-right padding-top |
124 |
|
|
page page-break-after page-break-before page-break-inside |
125 |
|
|
position quotes right size table-layout |
126 |
|
|
text-align text-anchor text-decoration text-indent text-transform |
127 |
|
|
top unicode-bidi vertical-align visibility white-space width widows |
128 |
|
|
word-spacing writing-mode z-index |
129 |
|
|
/; |
130 |
|
|
$p->{prop_value}->{display}->{$_} = 1 for qw/ |
131 |
|
|
block clip inline inline-block inline-table list-item none |
132 |
|
|
table table-caption table-cell table-column table-column-group |
133 |
|
|
table-header-group table-footer-group table-row table-row-group |
134 |
|
|
compact marker |
135 |
|
|
/; |
136 |
|
|
$p->{prop_value}->{position}->{$_} = 1 for qw/ |
137 |
|
|
absolute fixed relative static |
138 |
|
|
/; |
139 |
|
|
$p->{prop_value}->{float}->{$_} = 1 for qw/ |
140 |
|
|
left right none |
141 |
|
|
/; |
142 |
|
|
$p->{prop_value}->{clear}->{$_} = 1 for qw/ |
143 |
|
|
left right none both |
144 |
|
|
/; |
145 |
|
|
$p->{prop_value}->{direction}->{ltr} = 1; |
146 |
|
|
$p->{prop_value}->{direction}->{rtl} = 1; |
147 |
|
|
$p->{prop_value}->{marks}->{crop} = 1; |
148 |
|
|
$p->{prop_value}->{marks}->{cross} = 1; |
149 |
|
|
$p->{prop_value}->{'unicode-bidi'}->{$_} = 1 for qw/ |
150 |
|
|
normal bidi-override embed |
151 |
|
|
/; |
152 |
|
|
for my $prop_name (qw/overflow overflow-x overflow-y/) { |
153 |
|
|
$p->{prop_value}->{$prop_name}->{$_} = 1 for qw/ |
154 |
|
|
visible hidden scroll auto -webkit-marquee -moz-hidden-unscrollable |
155 |
|
|
/; |
156 |
|
|
} |
157 |
|
|
$p->{prop_value}->{visibility}->{$_} = 1 for qw/ |
158 |
|
|
visible hidden collapse |
159 |
|
|
/; |
160 |
|
|
$p->{prop_value}->{'list-style-type'}->{$_} = 1 for qw/ |
161 |
|
|
disc circle square decimal decimal-leading-zero |
162 |
|
|
lower-roman upper-roman lower-greek lower-latin |
163 |
|
|
upper-latin armenian georgian lower-alpha upper-alpha none |
164 |
|
|
hebrew cjk-ideographic hiragana katakana hiragana-iroha |
165 |
|
|
katakana-iroha |
166 |
|
|
/; |
167 |
|
|
$p->{prop_value}->{'list-style-position'}->{outside} = 1; |
168 |
|
|
$p->{prop_value}->{'list-style-position'}->{inside} = 1; |
169 |
|
|
$p->{prop_value}->{'page-break-before'}->{$_} = 1 for qw/ |
170 |
|
|
auto always avoid left right |
171 |
|
|
/; |
172 |
|
|
$p->{prop_value}->{'page-break-after'}->{$_} = 1 for qw/ |
173 |
|
|
auto always avoid left right |
174 |
|
|
/; |
175 |
|
|
$p->{prop_value}->{'page-break-inside'}->{auto} = 1; |
176 |
|
|
$p->{prop_value}->{'page-break-inside'}->{avoid} = 1; |
177 |
|
|
$p->{prop_value}->{'background-repeat'}->{$_} = 1 for qw/ |
178 |
|
|
repeat repeat-x repeat-y no-repeat |
179 |
|
|
/; |
180 |
|
|
$p->{prop_value}->{'background-attachment'}->{scroll} = 1; |
181 |
|
|
$p->{prop_value}->{'background-attachment'}->{fixed} = 1; |
182 |
|
|
$p->{prop_value}->{'font-size'}->{$_} = 1 for qw/ |
183 |
|
|
xx-small x-small small medium large x-large xx-large |
184 |
|
|
-manakai-xxx-large -webkit-xxx-large |
185 |
|
|
larger smaller |
186 |
|
|
/; |
187 |
|
|
$p->{prop_value}->{'font-style'}->{normal} = 1; |
188 |
|
|
$p->{prop_value}->{'font-style'}->{italic} = 1; |
189 |
|
|
$p->{prop_value}->{'font-style'}->{oblique} = 1; |
190 |
|
|
$p->{prop_value}->{'font-variant'}->{normal} = 1; |
191 |
|
|
$p->{prop_value}->{'font-variant'}->{'small-caps'} = 1; |
192 |
|
|
$p->{prop_value}->{'font-stretch'}->{$_} = 1 for |
193 |
|
|
qw/normal wider narrower ultra-condensed extra-condensed |
194 |
|
|
condensed semi-condensed semi-expanded expanded |
195 |
|
|
extra-expanded ultra-expanded/; |
196 |
|
|
$p->{prop_value}->{'text-align'}->{$_} = 1 for qw/ |
197 |
|
|
left right center justify begin end |
198 |
|
|
/; |
199 |
|
|
$p->{prop_value}->{'text-transform'}->{$_} = 1 for qw/ |
200 |
|
|
capitalize uppercase lowercase none |
201 |
|
|
/; |
202 |
|
|
$p->{prop_value}->{'white-space'}->{$_} = 1 for qw/ |
203 |
|
|
normal pre nowrap pre-line pre-wrap -moz-pre-wrap |
204 |
|
|
/; |
205 |
|
|
$p->{prop_value}->{'writing-mode'}->{$_} = 1 for qw/ |
206 |
|
|
lr rl tb lr-tb rl-tb tb-rl |
207 |
|
|
/; |
208 |
|
|
$p->{prop_value}->{'text-anchor'}->{$_} = 1 for qw/ |
209 |
|
|
start middle end |
210 |
|
|
/; |
211 |
|
|
$p->{prop_value}->{'dominant-baseline'}->{$_} = 1 for qw/ |
212 |
|
|
auto use-script no-change reset-size ideographic alphabetic |
213 |
|
|
hanging mathematical central middle text-after-edge text-before-edge |
214 |
|
|
/; |
215 |
|
|
$p->{prop_value}->{'alignment-baseline'}->{$_} = 1 for qw/ |
216 |
|
|
auto baseline before-edge text-before-edge middle central |
217 |
|
|
after-edge text-after-edge ideographic alphabetic hanging |
218 |
|
|
mathematical |
219 |
|
|
/; |
220 |
|
|
$p->{prop_value}->{'text-decoration'}->{$_} = 1 for qw/ |
221 |
|
|
none blink underline overline line-through |
222 |
|
|
/; |
223 |
|
|
$p->{prop_value}->{'caption-side'}->{$_} = 1 for qw/ |
224 |
|
|
top bottom left right |
225 |
|
|
/; |
226 |
|
|
$p->{prop_value}->{'table-layout'}->{auto} = 1; |
227 |
|
|
$p->{prop_value}->{'table-layout'}->{fixed} = 1; |
228 |
|
|
$p->{prop_value}->{'border-collapse'}->{collapse} = 1; |
229 |
|
|
$p->{prop_value}->{'border-collapse'}->{separate} = 1; |
230 |
|
|
$p->{prop_value}->{'empty-cells'}->{show} = 1; |
231 |
|
|
$p->{prop_value}->{'empty-cells'}->{hide} = 1; |
232 |
|
|
$p->{prop_value}->{cursor}->{$_} = 1 for qw/ |
233 |
|
|
auto crosshair default pointer move e-resize ne-resize nw-resize n-resize |
234 |
|
|
se-resize sw-resize s-resize w-resize text wait help progress |
235 |
|
|
/; |
236 |
|
|
for my $prop (qw/border-top-style border-left-style |
237 |
|
|
border-bottom-style border-right-style outline-style/) { |
238 |
|
|
$p->{prop_value}->{$prop}->{$_} = 1 for qw/ |
239 |
|
|
none hidden dotted dashed solid double groove ridge inset outset |
240 |
|
|
/; |
241 |
|
|
} |
242 |
|
|
for my $prop (qw/color background-color |
243 |
|
|
border-bottom-color border-left-color border-right-color |
244 |
|
|
border-top-color border-color/) { |
245 |
|
|
$p->{prop_value}->{$prop}->{transparent} = 1; |
246 |
|
|
$p->{prop_value}->{$prop}->{flavor} = 1; |
247 |
|
|
$p->{prop_value}->{$prop}->{'-manakai-default'} = 1; |
248 |
|
|
} |
249 |
|
|
$p->{prop_value}->{'outline-color'}->{invert} = 1; |
250 |
|
|
$p->{prop_value}->{'outline-color'}->{'-manakai-invert-or-currentcolor'} = 1; |
251 |
|
|
$p->{pseudo_class}->{$_} = 1 for qw/ |
252 |
|
|
active checked disabled empty enabled first-child first-of-type |
253 |
|
|
focus hover indeterminate last-child last-of-type link only-child |
254 |
|
|
only-of-type root target visited |
255 |
|
|
lang nth-child nth-last-child nth-of-type nth-last-of-type not |
256 |
|
|
-manakai-contains -manakai-current |
257 |
|
|
/; |
258 |
|
|
$p->{pseudo_element}->{$_} = 1 for qw/ |
259 |
|
|
after before first-letter first-line |
260 |
|
|
/; |
261 |
|
|
|
262 |
|
|
return $CSSParser = $p; |
263 |
|
|
} # get_css_parser |
264 |
|
|
|
265 |
|
|
1; |