1 |
wakaba |
1.1 |
#!/usr/bin/perl |
2 |
|
|
use strict; |
3 |
|
|
|
4 |
|
|
use lib qw[/home/wakaba/work/manakai2/lib]; ## TODO: ... |
5 |
|
|
|
6 |
|
|
use Test; |
7 |
|
|
|
8 |
wakaba |
1.22 |
BEGIN { plan tests => 2210 } |
9 |
wakaba |
1.1 |
|
10 |
|
|
require Whatpm::CSS::Parser; |
11 |
|
|
require Message::DOM::Window; |
12 |
|
|
|
13 |
|
|
require Message::DOM::DOMImplementation; |
14 |
|
|
my $dom = Message::DOM::DOMImplementation->new; |
15 |
|
|
|
16 |
|
|
my $DefaultComputed; |
17 |
|
|
my $DefaultComputedText; |
18 |
|
|
|
19 |
|
|
for my $file_name (map {"t/$_"} qw( |
20 |
|
|
css-1.dat |
21 |
wakaba |
1.17 |
css-2.dat |
22 |
wakaba |
1.18 |
css-3.dat |
23 |
wakaba |
1.20 |
css-4.dat |
24 |
wakaba |
1.4 |
css-visual.dat |
25 |
wakaba |
1.6 |
css-generated.dat |
26 |
wakaba |
1.9 |
css-paged.dat |
27 |
|
|
css-text.dat |
28 |
wakaba |
1.7 |
css-font.dat |
29 |
wakaba |
1.10 |
css-table.dat |
30 |
|
|
css-interactive.dat |
31 |
wakaba |
1.1 |
)) { |
32 |
|
|
print "# $file_name\n"; |
33 |
wakaba |
1.13 |
open my $file, '<:utf8', $file_name or die "$0: $file_name: $!"; |
34 |
wakaba |
1.1 |
|
35 |
|
|
my $all_test = {document => {}, test => []}; |
36 |
|
|
my $test; |
37 |
|
|
my $mode = 'data'; |
38 |
|
|
my $doc_id; |
39 |
|
|
my $selectors; |
40 |
|
|
while (<$file>) { |
41 |
|
|
s/\x0D\x0A/\x0A/; |
42 |
|
|
if (/^#data$/) { |
43 |
|
|
undef $test; |
44 |
|
|
$test->{data} = ''; |
45 |
|
|
push @{$all_test->{test}}, $test; |
46 |
|
|
$mode = 'data'; |
47 |
|
|
} elsif (/#(csstext|cssom)$/) { |
48 |
|
|
$test->{$1} = ''; |
49 |
|
|
$mode = $1; |
50 |
|
|
} elsif (/#(computed(?>text)?) (\S+) (.+)$/) { |
51 |
|
|
$test->{$1}->{$doc_id = $2}->{$selectors = $3} = ''; |
52 |
|
|
$mode = $1; |
53 |
|
|
} elsif (/^#html (\S+)$/) { |
54 |
|
|
undef $test; |
55 |
|
|
$test->{format} = 'html'; |
56 |
|
|
$test->{data} = ''; |
57 |
|
|
$all_test->{document}->{$1} = $test; |
58 |
|
|
$mode = 'data'; |
59 |
wakaba |
1.2 |
} elsif (/^#errors$/) { |
60 |
|
|
$test->{errors} = []; |
61 |
|
|
$mode = 'errors'; |
62 |
|
|
$test->{data} =~ s/\x0D?\x0A\z//; |
63 |
wakaba |
1.4 |
} elsif (/^#option q$/) { |
64 |
|
|
$test->{option}->{parse_mode} = 'q'; |
65 |
wakaba |
1.1 |
} elsif (defined $test->{data} and /^$/) { |
66 |
|
|
undef $test; |
67 |
|
|
} else { |
68 |
|
|
if ({data => 1, cssom => 1, csstext => 1}->{$mode}) { |
69 |
|
|
$test->{$mode} .= $_; |
70 |
|
|
} elsif ($mode eq 'computed' or $mode eq 'computedtext') { |
71 |
|
|
$test->{$mode}->{$doc_id}->{$selectors} .= $_; |
72 |
wakaba |
1.2 |
} elsif ($mode eq 'errors') { |
73 |
|
|
tr/\x0D\x0A//d; |
74 |
|
|
push @{$test->{errors}}, $_; |
75 |
wakaba |
1.1 |
} else { |
76 |
|
|
die "Line $.: $_"; |
77 |
|
|
} |
78 |
|
|
} |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
for my $data (values %{$all_test->{document}}) { |
82 |
|
|
if ($data->{format} eq 'html') { |
83 |
|
|
my $doc = $dom->create_document; |
84 |
|
|
$doc->manakai_is_html (1); |
85 |
|
|
$doc->inner_html ($data->{data}); |
86 |
|
|
$data->{document} = $doc; |
87 |
|
|
} else { |
88 |
|
|
die "Test data format $data->{format} is not supported"; |
89 |
|
|
} |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
for my $test (@{$all_test->{test}}) { |
93 |
wakaba |
1.4 |
my ($p, $css_options) = get_parser ($test->{option}->{parse_mode}); |
94 |
wakaba |
1.1 |
|
95 |
wakaba |
1.2 |
my @actual_error; |
96 |
wakaba |
1.1 |
$p->{onerror} = sub { |
97 |
|
|
my (%opt) = @_; |
98 |
wakaba |
1.2 |
my $uri = ${$opt{uri}}; |
99 |
|
|
$uri =~ s[^thismessage:/][]; |
100 |
|
|
push @actual_error, join ';', |
101 |
|
|
$uri, $opt{token}->{line}, $opt{token}->{column}, |
102 |
|
|
$opt{level}, |
103 |
wakaba |
1.22 |
$opt{type} . |
104 |
|
|
(defined $opt{text} ? ';'.$opt{text} : ''); |
105 |
wakaba |
1.1 |
}; |
106 |
|
|
|
107 |
|
|
my $ss = $p->parse_char_string ($test->{data}); |
108 |
wakaba |
1.2 |
|
109 |
|
|
ok ((join "\n", @actual_error), (join "\n", @{$test->{errors} or []}), |
110 |
|
|
"#result ($test->{data})"); |
111 |
wakaba |
1.1 |
|
112 |
|
|
if (defined $test->{cssom}) { |
113 |
|
|
my $actual = serialize_cssom ($ss); |
114 |
|
|
ok $actual, $test->{cssom}, "#cssom ($test->{data})"; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
if (defined $test->{csstext}) { |
118 |
|
|
my $actual = $ss->css_text; |
119 |
|
|
ok $actual, $test->{csstext}, "#csstext ($test->{data})"; |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
for my $doc_id (keys %{$test->{computed} or {}}) { |
123 |
|
|
for my $selectors (keys %{$test->{computed}->{$doc_id}}) { |
124 |
|
|
my ($window, $style) = get_computed_style |
125 |
|
|
($all_test, $doc_id, $selectors, $dom, $css_options, $ss); |
126 |
|
|
## NOTE: $window is the root object, so that we must keep it |
127 |
|
|
## referenced in this block. |
128 |
|
|
|
129 |
|
|
my $actual = serialize_style ($style, ''); |
130 |
|
|
my $expected = $DefaultComputed; |
131 |
|
|
my $diff = $test->{computed}->{$doc_id}->{$selectors}; |
132 |
|
|
($actual, $expected) = apply_diff ($actual, $expected, $diff); |
133 |
|
|
ok $actual, $expected, |
134 |
|
|
"#computed $doc_id $selectors ($test->{data})"; |
135 |
|
|
} |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
for my $doc_id (keys %{$test->{computedtext} or {}}) { |
139 |
|
|
for my $selectors (keys %{$test->{computedtext}->{$doc_id}}) { |
140 |
|
|
my ($window, $style) = get_computed_style |
141 |
|
|
($all_test, $doc_id, $selectors, $dom, $css_options, $ss); |
142 |
|
|
## NOTE: $window is the root object, so that we must keep it |
143 |
|
|
## referenced in this block. |
144 |
|
|
|
145 |
|
|
my $actual = $style->css_text; |
146 |
|
|
my $expected = $DefaultComputedText; |
147 |
|
|
my $diff = $test->{computedtext}->{$doc_id}->{$selectors}; |
148 |
|
|
($actual, $expected) = apply_diff ($actual, $expected, $diff); |
149 |
|
|
"#computedtext $doc_id $selectors ($test->{data})"; |
150 |
|
|
ok $actual, $expected, |
151 |
|
|
"#computedtext $doc_id $selectors ($test->{data})"; |
152 |
|
|
} |
153 |
|
|
} |
154 |
|
|
} |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
my @longhand; |
158 |
|
|
my @shorthand; |
159 |
|
|
BEGIN { |
160 |
|
|
@longhand = qw/ |
161 |
wakaba |
1.21 |
alignment-baseline |
162 |
wakaba |
1.1 |
background-attachment background-color background-image |
163 |
|
|
background-position-x background-position-y |
164 |
|
|
background-repeat border-bottom-color |
165 |
|
|
border-bottom-style border-bottom-width border-collapse |
166 |
|
|
border-left-color |
167 |
|
|
border-left-style border-left-width border-right-color |
168 |
|
|
border-right-style border-right-width |
169 |
|
|
-manakai-border-spacing-x -manakai-border-spacing-y |
170 |
|
|
border-top-color border-top-style border-top-width bottom |
171 |
wakaba |
1.15 |
caption-side clear clip color content counter-increment counter-reset |
172 |
wakaba |
1.21 |
cursor direction display dominant-baseline empty-cells float |
173 |
wakaba |
1.16 |
font-family font-size font-size-adjust font-stretch |
174 |
|
|
font-style font-variant font-weight height left |
175 |
wakaba |
1.1 |
letter-spacing line-height |
176 |
|
|
list-style-image list-style-position list-style-type |
177 |
wakaba |
1.16 |
margin-bottom margin-left margin-right margin-top marker-offset |
178 |
|
|
marks max-height max-width min-height min-width opacity -moz-opacity |
179 |
wakaba |
1.11 |
orphans outline-color outline-style outline-width overflow-x overflow-y |
180 |
wakaba |
1.1 |
padding-bottom padding-left padding-right padding-top |
181 |
wakaba |
1.16 |
page page-break-after page-break-before page-break-inside |
182 |
|
|
position quotes right size table-layout |
183 |
wakaba |
1.21 |
text-align text-anchor text-decoration text-indent text-transform |
184 |
wakaba |
1.1 |
top unicode-bidi vertical-align visibility white-space width widows |
185 |
wakaba |
1.21 |
word-spacing writing-mode z-index |
186 |
wakaba |
1.1 |
/; |
187 |
|
|
@shorthand = qw/ |
188 |
|
|
background background-position |
189 |
|
|
border border-color border-style border-width border-spacing |
190 |
|
|
border-top border-right border-bottom border-left |
191 |
wakaba |
1.11 |
font list-style margin outline overflow padding |
192 |
wakaba |
1.1 |
/; |
193 |
wakaba |
1.21 |
$DefaultComputedText = q[ alignment-baseline: auto; |
194 |
|
|
border-spacing: 0px; |
195 |
wakaba |
1.1 |
background: transparent none repeat scroll 0% 0%; |
196 |
|
|
border: 0px none -manakai-default; |
197 |
|
|
border-collapse: separate; |
198 |
|
|
bottom: auto; |
199 |
|
|
caption-side: top; |
200 |
|
|
clear: none; |
201 |
wakaba |
1.15 |
clip: auto; |
202 |
wakaba |
1.1 |
color: -manakai-default; |
203 |
wakaba |
1.13 |
content: normal; |
204 |
wakaba |
1.14 |
counter-increment: none; |
205 |
|
|
counter-reset: none; |
206 |
wakaba |
1.1 |
cursor: auto; |
207 |
|
|
direction: ltr; |
208 |
|
|
display: inline; |
209 |
wakaba |
1.21 |
dominant-baseline: auto; |
210 |
wakaba |
1.1 |
empty-cells: show; |
211 |
|
|
float: none; |
212 |
|
|
font-family: -manakai-default; |
213 |
|
|
font-size: 16px; |
214 |
wakaba |
1.16 |
font-size-adjust: none; |
215 |
|
|
font-stretch: normal; |
216 |
wakaba |
1.1 |
font-style: normal; |
217 |
|
|
font-variant: normal; |
218 |
|
|
font-weight: 400; |
219 |
|
|
height: auto; |
220 |
|
|
left: auto; |
221 |
|
|
letter-spacing: normal; |
222 |
|
|
line-height: normal; |
223 |
|
|
list-style-image: none; |
224 |
|
|
list-style-position: outside; |
225 |
|
|
list-style-type: disc; |
226 |
wakaba |
1.5 |
margin: 0px; |
227 |
wakaba |
1.16 |
marker-offset: auto; |
228 |
|
|
marks: none; |
229 |
wakaba |
1.1 |
max-height: none; |
230 |
|
|
max-width: none; |
231 |
|
|
min-height: 0px; |
232 |
|
|
min-width: 0px; |
233 |
|
|
opacity: 1; |
234 |
|
|
orphans: 2; |
235 |
|
|
outline: 0px none invert; |
236 |
|
|
overflow: visible; |
237 |
wakaba |
1.6 |
padding: 0px; |
238 |
wakaba |
1.16 |
page: auto; |
239 |
wakaba |
1.1 |
page-break-after: auto; |
240 |
|
|
page-break-before: auto; |
241 |
|
|
page-break-inside: auto; |
242 |
|
|
position: static; |
243 |
wakaba |
1.12 |
quotes: -manakai-default; |
244 |
wakaba |
1.1 |
right: auto; |
245 |
wakaba |
1.16 |
size: auto; |
246 |
wakaba |
1.1 |
table-layout: auto; |
247 |
|
|
text-align: begin; |
248 |
wakaba |
1.21 |
text-anchor: start; |
249 |
wakaba |
1.1 |
text-decoration: none; |
250 |
|
|
text-indent: 0px; |
251 |
|
|
text-transform: none; |
252 |
|
|
top: auto; |
253 |
|
|
unicode-bidi: normal; |
254 |
|
|
vertical-align: baseline; |
255 |
|
|
visibility: visible; |
256 |
|
|
white-space: normal; |
257 |
|
|
widows: 2; |
258 |
|
|
width: auto; |
259 |
|
|
word-spacing: normal; |
260 |
wakaba |
1.21 |
writing-mode: lr-tb; |
261 |
wakaba |
1.1 |
z-index: auto; |
262 |
|
|
]; |
263 |
|
|
$DefaultComputed = $DefaultComputedText; |
264 |
|
|
$DefaultComputed =~ s/^ /| /gm; |
265 |
|
|
$DefaultComputed =~ s/;$//gm; |
266 |
|
|
$DefaultComputed .= q[| -manakai-border-spacing-x: 0px |
267 |
|
|
| -manakai-border-spacing-y: 0px |
268 |
|
|
| -moz-opacity: 1 |
269 |
|
|
| background-attachment: scroll |
270 |
|
|
| background-color: transparent |
271 |
|
|
| background-image: none |
272 |
wakaba |
1.8 |
| background-position: 0% 0% |
273 |
wakaba |
1.1 |
| background-position-x: 0% |
274 |
|
|
| background-position-y: 0% |
275 |
|
|
| background-repeat: repeat |
276 |
|
|
| border-top: 0px none -manakai-default |
277 |
|
|
| border-right: 0px none -manakai-default |
278 |
|
|
| border-bottom: 0px none -manakai-default |
279 |
|
|
| border-left: 0px none -manakai-default |
280 |
|
|
| border-bottom-color: -manakai-default |
281 |
|
|
| border-bottom-style: none |
282 |
|
|
| border-bottom-width: 0px |
283 |
|
|
| border-left-color: -manakai-default |
284 |
|
|
| border-left-style: none |
285 |
|
|
| border-left-width: 0px |
286 |
|
|
| border-right-color: -manakai-default |
287 |
|
|
| border-right-style: none |
288 |
|
|
| border-right-width: 0px |
289 |
|
|
| border-top-color: -manakai-default |
290 |
|
|
| border-top-style: none |
291 |
|
|
| border-top-width: 0px |
292 |
|
|
| border-color: -manakai-default |
293 |
|
|
| border-style: none |
294 |
|
|
| border-width: 0px |
295 |
|
|
| float: none |
296 |
wakaba |
1.7 |
| font: 400 16px -manakai-default |
297 |
wakaba |
1.6 |
| list-style: disc none outside |
298 |
wakaba |
1.5 |
| margin-top: 0px |
299 |
|
|
| margin-right: 0px |
300 |
|
|
| margin-bottom: 0px |
301 |
|
|
| margin-left: 0px |
302 |
wakaba |
1.1 |
| outline-color: invert |
303 |
|
|
| outline-style: none |
304 |
|
|
| outline-width: 0px |
305 |
wakaba |
1.11 |
| overflow-x: visible |
306 |
|
|
| overflow-y: visible |
307 |
wakaba |
1.6 |
| padding-bottom: 0px |
308 |
|
|
| padding-left: 0px |
309 |
|
|
| padding-right: 0px |
310 |
|
|
| padding-top: 0px]; |
311 |
wakaba |
1.1 |
} |
312 |
|
|
|
313 |
wakaba |
1.4 |
sub get_parser ($) { |
314 |
|
|
my $parse_mode = shift; |
315 |
|
|
|
316 |
wakaba |
1.1 |
my $p = Whatpm::CSS::Parser->new; |
317 |
wakaba |
1.4 |
|
318 |
wakaba |
1.1 |
$p->{prop}->{$_} = 1 for (@longhand, @shorthand); |
319 |
|
|
$p->{prop_value}->{display}->{$_} = 1 for qw/ |
320 |
wakaba |
1.15 |
block clip inline inline-block inline-table list-item none |
321 |
wakaba |
1.1 |
table table-caption table-cell table-column table-column-group |
322 |
|
|
table-header-group table-footer-group table-row table-row-group |
323 |
wakaba |
1.16 |
compact marker |
324 |
wakaba |
1.1 |
/; |
325 |
|
|
$p->{prop_value}->{position}->{$_} = 1 for qw/ |
326 |
|
|
absolute fixed relative static |
327 |
|
|
/; |
328 |
|
|
$p->{prop_value}->{float}->{$_} = 1 for qw/ |
329 |
|
|
left right none |
330 |
|
|
/; |
331 |
|
|
$p->{prop_value}->{clear}->{$_} = 1 for qw/ |
332 |
|
|
left right none both |
333 |
|
|
/; |
334 |
|
|
$p->{prop_value}->{direction}->{ltr} = 1; |
335 |
|
|
$p->{prop_value}->{direction}->{rtl} = 1; |
336 |
wakaba |
1.16 |
$p->{prop_value}->{marks}->{crop} = 1; |
337 |
|
|
$p->{prop_value}->{marks}->{cross} = 1; |
338 |
wakaba |
1.1 |
$p->{prop_value}->{'unicode-bidi'}->{$_} = 1 for qw/ |
339 |
|
|
normal bidi-override embed |
340 |
|
|
/; |
341 |
wakaba |
1.11 |
for my $prop_name (qw/overflow overflow-x overflow-y/) { |
342 |
|
|
$p->{prop_value}->{$prop_name}->{$_} = 1 for qw/ |
343 |
|
|
visible hidden scroll auto -webkit-marquee -moz-hidden-unscrollable |
344 |
|
|
/; |
345 |
|
|
} |
346 |
wakaba |
1.1 |
$p->{prop_value}->{visibility}->{$_} = 1 for qw/ |
347 |
|
|
visible hidden collapse |
348 |
|
|
/; |
349 |
|
|
$p->{prop_value}->{'list-style-type'}->{$_} = 1 for qw/ |
350 |
|
|
disc circle square decimal decimal-leading-zero |
351 |
|
|
lower-roman upper-roman lower-greek lower-latin |
352 |
|
|
upper-latin armenian georgian lower-alpha upper-alpha none |
353 |
wakaba |
1.16 |
hebrew cjk-ideographic hiragana katakana hiragana-iroha |
354 |
|
|
katakana-iroha |
355 |
wakaba |
1.1 |
/; |
356 |
|
|
$p->{prop_value}->{'list-style-position'}->{outside} = 1; |
357 |
|
|
$p->{prop_value}->{'list-style-position'}->{inside} = 1; |
358 |
|
|
$p->{prop_value}->{'page-break-before'}->{$_} = 1 for qw/ |
359 |
|
|
auto always avoid left right |
360 |
|
|
/; |
361 |
|
|
$p->{prop_value}->{'page-break-after'}->{$_} = 1 for qw/ |
362 |
|
|
auto always avoid left right |
363 |
|
|
/; |
364 |
|
|
$p->{prop_value}->{'page-break-inside'}->{auto} = 1; |
365 |
|
|
$p->{prop_value}->{'page-break-inside'}->{avoid} = 1; |
366 |
|
|
$p->{prop_value}->{'background-repeat'}->{$_} = 1 for qw/ |
367 |
|
|
repeat repeat-x repeat-y no-repeat |
368 |
|
|
/; |
369 |
|
|
$p->{prop_value}->{'background-attachment'}->{scroll} = 1; |
370 |
|
|
$p->{prop_value}->{'background-attachment'}->{fixed} = 1; |
371 |
wakaba |
1.16 |
$p->{prop_value}->{'font-size'}->{$_} = 1 for qw/ |
372 |
|
|
xx-small x-small small medium large x-large xx-large |
373 |
|
|
-manakai-xxx-large -webkit-xxx-large |
374 |
|
|
larger smaller |
375 |
|
|
/; |
376 |
wakaba |
1.1 |
$p->{prop_value}->{'font-style'}->{normal} = 1; |
377 |
|
|
$p->{prop_value}->{'font-style'}->{italic} = 1; |
378 |
|
|
$p->{prop_value}->{'font-style'}->{oblique} = 1; |
379 |
|
|
$p->{prop_value}->{'font-variant'}->{normal} = 1; |
380 |
|
|
$p->{prop_value}->{'font-variant'}->{'small-caps'} = 1; |
381 |
wakaba |
1.16 |
$p->{prop_value}->{'font-stretch'}->{$_} = 1 for |
382 |
|
|
qw/normal wider narrower ultra-condensed extra-condensed |
383 |
|
|
condensed semi-condensed semi-expanded expanded |
384 |
|
|
extra-expanded ultra-expanded/; |
385 |
wakaba |
1.1 |
$p->{prop_value}->{'text-align'}->{$_} = 1 for qw/ |
386 |
|
|
left right center justify begin end |
387 |
|
|
/; |
388 |
|
|
$p->{prop_value}->{'text-transform'}->{$_} = 1 for qw/ |
389 |
|
|
capitalize uppercase lowercase none |
390 |
|
|
/; |
391 |
|
|
$p->{prop_value}->{'white-space'}->{$_} = 1 for qw/ |
392 |
wakaba |
1.18 |
normal pre nowrap pre-line pre-wrap -moz-pre-wrap |
393 |
wakaba |
1.21 |
/; |
394 |
|
|
$p->{prop_value}->{'writing-mode'}->{$_} = 1 for qw/ |
395 |
|
|
lr rl tb lr-tb rl-tb tb-rl |
396 |
|
|
/; |
397 |
|
|
$p->{prop_value}->{'text-anchor'}->{$_} = 1 for qw/ |
398 |
|
|
start middle end |
399 |
|
|
/; |
400 |
|
|
$p->{prop_value}->{'dominant-baseline'}->{$_} = 1 for qw/ |
401 |
|
|
auto use-script no-change reset-size ideographic alphabetic |
402 |
|
|
hanging mathematical central middle text-after-edge text-before-edge |
403 |
|
|
/; |
404 |
|
|
$p->{prop_value}->{'alignment-baseline'}->{$_} = 1 for qw/ |
405 |
|
|
auto baseline before-edge text-before-edge middle central |
406 |
|
|
after-edge text-after-edge ideographic alphabetic hanging |
407 |
|
|
mathematical |
408 |
wakaba |
1.1 |
/; |
409 |
|
|
$p->{prop_value}->{'text-decoration'}->{$_} = 1 for qw/ |
410 |
|
|
none blink underline overline line-through |
411 |
|
|
/; |
412 |
|
|
$p->{prop_value}->{'caption-side'}->{$_} = 1 for qw/ |
413 |
wakaba |
1.16 |
top bottom left right |
414 |
wakaba |
1.1 |
/; |
415 |
|
|
$p->{prop_value}->{'table-layout'}->{auto} = 1; |
416 |
|
|
$p->{prop_value}->{'table-layout'}->{fixed} = 1; |
417 |
wakaba |
1.18 |
$p->{prop_value}->{'border-collapse'}->{collapse} = 1; |
418 |
wakaba |
1.1 |
$p->{prop_value}->{'border-collapse'}->{separate} = 1; |
419 |
|
|
$p->{prop_value}->{'empty-cells'}->{show} = 1; |
420 |
|
|
$p->{prop_value}->{'empty-cells'}->{hide} = 1; |
421 |
|
|
$p->{prop_value}->{cursor}->{$_} = 1 for qw/ |
422 |
|
|
auto crosshair default pointer move e-resize ne-resize nw-resize n-resize |
423 |
|
|
se-resize sw-resize s-resize w-resize text wait help progress |
424 |
|
|
/; |
425 |
|
|
for my $prop (qw/border-top-style border-left-style |
426 |
|
|
border-bottom-style border-right-style outline-style/) { |
427 |
|
|
$p->{prop_value}->{$prop}->{$_} = 1 for qw/ |
428 |
|
|
none hidden dotted dashed solid double groove ridge inset outset |
429 |
|
|
/; |
430 |
|
|
} |
431 |
|
|
for my $prop (qw/color background-color |
432 |
|
|
border-bottom-color border-left-color border-right-color |
433 |
|
|
border-top-color border-color/) { |
434 |
|
|
$p->{prop_value}->{$prop}->{transparent} = 1; |
435 |
|
|
$p->{prop_value}->{$prop}->{flavor} = 1; |
436 |
|
|
$p->{prop_value}->{$prop}->{'-manakai-default'} = 1; |
437 |
|
|
} |
438 |
|
|
$p->{prop_value}->{'outline-color'}->{invert} = 1; |
439 |
|
|
$p->{prop_value}->{'outline-color'}->{'-manakai-invert-or-currentcolor'} = 1; |
440 |
|
|
$p->{pseudo_class}->{$_} = 1 for qw/ |
441 |
|
|
active checked disabled empty enabled first-child first-of-type |
442 |
|
|
focus hover indeterminate last-child last-of-type link only-child |
443 |
|
|
only-of-type root target visited |
444 |
|
|
lang nth-child nth-last-child nth-of-type nth-last-of-type not |
445 |
|
|
-manakai-contains -manakai-current |
446 |
|
|
/; |
447 |
|
|
$p->{pseudo_element}->{$_} = 1 for qw/ |
448 |
|
|
after before first-letter first-line |
449 |
|
|
/; |
450 |
|
|
|
451 |
|
|
my $css_options = { |
452 |
|
|
prop => $p->{prop}, |
453 |
|
|
prop_value => $p->{prop_value}, |
454 |
|
|
pseudo_class => $p->{pseudo_class}, |
455 |
|
|
pseudo_element => $p->{pseudo_element}, |
456 |
|
|
}; |
457 |
|
|
|
458 |
wakaba |
1.19 |
$p->init; |
459 |
|
|
if ($parse_mode eq 'q') { |
460 |
|
|
$p->{unitless_px} = 1; |
461 |
|
|
$p->{hashless_color} = 1; |
462 |
|
|
} |
463 |
wakaba |
1.1 |
$p->{href} = 'thismessage:/'; |
464 |
|
|
|
465 |
|
|
return ($p, $css_options); |
466 |
|
|
} # get_parser |
467 |
|
|
|
468 |
|
|
sub serialize_cssom ($) { |
469 |
|
|
my $ss = shift; |
470 |
|
|
|
471 |
|
|
if (defined $ss) { |
472 |
|
|
if ($ss->isa ('Message::IF::CSSStyleSheet')) { |
473 |
|
|
my $v = ''; |
474 |
|
|
for my $rule (@{$ss->css_rules}) { |
475 |
|
|
my $indent = ''; |
476 |
wakaba |
1.17 |
$v .= serialize_rule ($rule, $indent); |
477 |
wakaba |
1.1 |
} |
478 |
|
|
return $v; |
479 |
|
|
} else { |
480 |
|
|
return '(' . (ref $ss) . ')'; |
481 |
|
|
} |
482 |
|
|
} else { |
483 |
|
|
return '(undef)'; |
484 |
|
|
} |
485 |
|
|
} # serialize_cssom |
486 |
wakaba |
1.17 |
|
487 |
|
|
sub serialize_rule ($$) { |
488 |
|
|
my ($rule, $indent) = @_; |
489 |
|
|
my $v = ''; |
490 |
|
|
if ($rule->type == $rule->STYLE_RULE) { |
491 |
|
|
$v .= '| ' . $indent . '<' . $rule->selector_text . ">\n"; |
492 |
|
|
$v .= serialize_style ($rule->style, $indent . ' '); |
493 |
|
|
} elsif ($rule->type == $rule->MEDIA_RULE) { |
494 |
|
|
$v .= '| ' . $indent . '@media ' . $rule->media . "\n"; |
495 |
|
|
$v .= serialize_rule ($_, $indent . ' ') for @{$rule->css_rules}; |
496 |
wakaba |
1.18 |
} elsif ($rule->type == $rule->NAMESPACE_RULE) { |
497 |
|
|
$v .= '| ' . $indent . '@namespace '; |
498 |
|
|
my $prefix = $rule->prefix; |
499 |
|
|
$v .= $prefix . ': ' if length $prefix; |
500 |
|
|
$v .= '<' . $rule->namespace_uri . ">\n"; |
501 |
wakaba |
1.20 |
} elsif ($rule->type == $rule->IMPORT_RULE) { |
502 |
|
|
$v .= '| ' . $indent . '@import <' . $rule->href . '> ' . $rule->media; |
503 |
|
|
$v .= "\n"; |
504 |
|
|
} elsif ($rule->type == $rule->CHARSET_RULE) { |
505 |
|
|
$v .= '| ' . $indent . '@charset ' . $rule->encoding . "\n"; |
506 |
wakaba |
1.17 |
} else { |
507 |
|
|
die "Rule type @{[$rule->type]} is not supported"; |
508 |
|
|
} |
509 |
|
|
return $v; |
510 |
|
|
} # serialize_rule |
511 |
wakaba |
1.1 |
|
512 |
|
|
sub get_computed_style ($$$$$$) { |
513 |
|
|
my ($all_test, $doc_id, $selectors, $dom, $css_options, $ss) = @_; |
514 |
|
|
|
515 |
|
|
my $doc = $all_test->{document}->{$doc_id}->{document}; |
516 |
|
|
unless ($doc) { |
517 |
|
|
die "Test document $doc_id is not defined"; |
518 |
|
|
} |
519 |
|
|
|
520 |
wakaba |
1.6 |
my $element = $doc->query_selector ($selectors); |
521 |
wakaba |
1.1 |
unless ($element) { |
522 |
|
|
die "Element $selectors not found in document $doc_id"; |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
my $window = Message::DOM::Window->___new ($dom); |
526 |
|
|
$window->___set_css_options ($css_options); |
527 |
|
|
$window->___set_user_style_sheets ([$ss]); |
528 |
|
|
$window->set_document ($doc); |
529 |
|
|
|
530 |
wakaba |
1.3 |
my $style = $element->manakai_computed_style; |
531 |
wakaba |
1.1 |
return ($window, $style); |
532 |
|
|
} # get_computed_style |
533 |
|
|
|
534 |
|
|
sub serialize_style ($$) { |
535 |
|
|
my ($style, $indent) = @_; |
536 |
|
|
|
537 |
|
|
## TODO: check @$style |
538 |
|
|
|
539 |
|
|
my @v; |
540 |
|
|
for (map {get_dom_names ($_)} @shorthand, @longhand) { |
541 |
|
|
my $dom = $_->[1]; |
542 |
|
|
push @v, [$_->[0], $dom, $style->$dom, |
543 |
|
|
$style->get_property_priority ($_->[0])]; |
544 |
|
|
$v[-1]->[3] = ' !' . $v[-1]->[3] if length $v[-1]->[3]; |
545 |
|
|
} |
546 |
|
|
return join '', map {"| $indent$_->[0]: $_->[2]$_->[3]\n"} |
547 |
|
|
sort {$a->[0] cmp $b->[0]} grep {length $_->[2]} @v; |
548 |
|
|
} # serialize_style |
549 |
|
|
|
550 |
|
|
sub get_dom_names ($) { |
551 |
|
|
my $dom_name = $_[0]; |
552 |
|
|
if ($_[0] eq 'float') { |
553 |
|
|
return ([$_[0] => 'css_float'], [$_[0] => 'style_float']); |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
$dom_name =~ tr/-/_/; |
557 |
|
|
return ([$_[0] => $dom_name]); |
558 |
|
|
} # get_dom_names |
559 |
|
|
|
560 |
|
|
sub apply_diff ($$$) { |
561 |
|
|
my ($actual, $expected, $diff) = @_; |
562 |
|
|
my @actual = split /[\x0D\x0A]+/, $actual; |
563 |
|
|
my @expected = split /[\x0D\x0A]+/, $expected; |
564 |
|
|
my @diff = split /[\x0D\x0A]+/, $diff; |
565 |
|
|
for (@diff) { |
566 |
|
|
if (s/^-//) { |
567 |
|
|
push @actual, $_; |
568 |
|
|
} elsif (s/^\+//) { |
569 |
|
|
push @expected, $_; |
570 |
|
|
} else { |
571 |
|
|
die "Invalid diff line: $_"; |
572 |
|
|
} |
573 |
|
|
} |
574 |
|
|
$actual = join "\n", sort {$a cmp $b} @actual; |
575 |
|
|
$expected = join "\n", sort {$a cmp $b} @expected; |
576 |
|
|
($actual, $expected); |
577 |
|
|
} # apply_diff |