|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <!-- |
|
4 https://bugzilla.mozilla.org/show_bug.cgi?id=156716 |
|
5 --> |
|
6 <head> |
|
7 <title>Test for Bug 156716</title> |
|
8 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
|
10 </head> |
|
11 <body onload="run()"> |
|
12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=156716">Mozilla Bug 156716</a> |
|
13 <iframe id="subdoc" src="media_queries_iframe.html"></iframe> |
|
14 <div id="content" style="display: none"> |
|
15 |
|
16 </div> |
|
17 <pre id="test"> |
|
18 <script class="testbody" type="application/javascript"> |
|
19 |
|
20 /** Test for Bug 156716 **/ |
|
21 |
|
22 // Note that many other tests are in test_acid3_test46.html . |
|
23 |
|
24 SimpleTest.waitForExplicitFinish(); |
|
25 |
|
26 var iframe; |
|
27 |
|
28 function getScreenPixelsPerCSSPixel() { |
|
29 return SpecialPowers.DOMWindowUtils.screenPixelsPerCSSPixel; |
|
30 } |
|
31 |
|
32 function run() { |
|
33 iframe = document.getElementById("subdoc"); |
|
34 var subdoc = iframe.contentDocument; |
|
35 var subwin = iframe.contentWindow; |
|
36 var style = subdoc.getElementById("style"); |
|
37 var iframe_style = iframe.style; |
|
38 var body_cs = subdoc.defaultView.getComputedStyle(subdoc.body, ""); |
|
39 |
|
40 function query_applies(q) { |
|
41 style.setAttribute("media", q); |
|
42 return body_cs.getPropertyValue("text-decoration") == "underline"; |
|
43 } |
|
44 |
|
45 function should_apply(q) { |
|
46 ok(query_applies(q), q + " should apply"); |
|
47 test_serialization(q, true, true); |
|
48 } |
|
49 |
|
50 function should_not_apply(q) { |
|
51 ok(!query_applies(q), q + " should not apply"); |
|
52 test_serialization(q, true, false); |
|
53 } |
|
54 |
|
55 /* for queries that are parseable standalone but not within CSS */ |
|
56 function should_apply_unbalanced(q) { |
|
57 ok(query_applies(q), q + " should apply"); |
|
58 } |
|
59 |
|
60 /* for queries that are parseable standalone but not within CSS */ |
|
61 function should_not_apply_unbalanced(q) { |
|
62 ok(!query_applies(q), q + " should not apply"); |
|
63 } |
|
64 |
|
65 /* |
|
66 * Functions to test whether a query is parseable at all. (Should not |
|
67 * be used for parse errors within expressions.) |
|
68 */ |
|
69 var parse_test_style_element = document.createElement("style"); |
|
70 parse_test_style_element.type = "text/css"; |
|
71 parse_test_style_element.disabled = true; // for performance, hopefully |
|
72 var parse_test_style_text = document.createTextNode(""); |
|
73 parse_test_style_element.appendChild(parse_test_style_text); |
|
74 document.getElementsByTagName("head")[0] |
|
75 .appendChild(parse_test_style_element); |
|
76 |
|
77 function query_is_parseable(q) { |
|
78 parse_test_style_text.data = "@media screen, " + q + " {}"; |
|
79 var sheet = parse_test_style_element.sheet; // XXX yikes, not live! |
|
80 if (sheet.cssRules.length == 1 && |
|
81 sheet.cssRules[0].type == CSSRule.MEDIA_RULE) |
|
82 return sheet.cssRules[0].media.mediaText != "screen, not all"; |
|
83 ok(false, "unexpected result testing whether query " + q + |
|
84 " is parseable"); |
|
85 return true; // doesn't matter, we already failed |
|
86 } |
|
87 |
|
88 function query_should_be_parseable(q) { |
|
89 ok(query_is_parseable(q), "query " + q + " should be parseable"); |
|
90 test_serialization(q, false, false); |
|
91 } |
|
92 |
|
93 function query_should_not_be_parseable(q) { |
|
94 ok(!query_is_parseable(q), "query " + q + " should not be parseable"); |
|
95 } |
|
96 |
|
97 /* |
|
98 * Functions to test whether a single media expression is parseable. |
|
99 */ |
|
100 function expression_is_parseable(e) { |
|
101 style.setAttribute("media", "all and (" + e + ")"); |
|
102 return style.sheet.media.mediaText != "not all"; |
|
103 } |
|
104 |
|
105 function expression_should_be_parseable(e) { |
|
106 ok(expression_is_parseable(e), |
|
107 "expression " + e + " should be parseable"); |
|
108 test_serialization("all and (" + e + ")", false, false); |
|
109 } |
|
110 |
|
111 function expression_should_not_be_parseable(e) { |
|
112 ok(!expression_is_parseable(e), |
|
113 "expression " + e + " should not be parseable"); |
|
114 } |
|
115 |
|
116 function test_serialization(q, test_application, should_apply) { |
|
117 style.setAttribute("media", q); |
|
118 var ser1 = style.sheet.media.mediaText; |
|
119 isnot(ser1, "", "serialization of '" + q + "' should not be empty"); |
|
120 style.setAttribute("media", ser1); |
|
121 var ser2 = style.sheet.media.mediaText; |
|
122 is(ser2, ser1, "parse+serialize of '" + q + "' should be idempotent"); |
|
123 if (test_application) { |
|
124 var applies = body_cs.getPropertyValue("text-decoration") == "underline"; |
|
125 is(applies, should_apply, |
|
126 "Media query '" + q + "' should " + (should_apply ? "" : "NOT ") + |
|
127 "apply after serialize + reparse"); |
|
128 } |
|
129 |
|
130 // Test cloning |
|
131 var sheet = "@media " + q + " { body { text-decoration: underline } }" |
|
132 var sheeturl = "data:text/css," + escape(sheet); |
|
133 var link = "<link rel='stylesheet' href='" + sheeturl + "'>"; |
|
134 var htmldoc = "<!DOCTYPE HTML>" + link + link + "<body>"; |
|
135 var docurl = "data:text/html," + escape(htmldoc); |
|
136 post_clone_test(docurl, function() { |
|
137 var clonedoc = iframe.contentDocument; |
|
138 var clonewin = iframe.contentWindow; |
|
139 var links = clonedoc.getElementsByTagName("link"); |
|
140 // cause a clone |
|
141 var clonedsheet = links[1].sheet; |
|
142 clonedsheet.insertRule("#nonexistent { color: purple}", 1); |
|
143 // remove the uncloned sheet |
|
144 links[0].parentNode.removeChild(links[0]); |
|
145 |
|
146 var ser3 = clonedsheet.cssRules[0].media.mediaText; |
|
147 is(ser3, ser1, "cloning query '" + q + "' should not change " + |
|
148 "serialization"); |
|
149 if (test_application) { |
|
150 var applies = clonewin.getComputedStyle(clonedoc.body, ""). |
|
151 textDecoration == "underline"; |
|
152 is(applies, should_apply, |
|
153 "Media query '" + q + "' should " + (should_apply ? "" : "NOT ") + |
|
154 "apply after cloning"); |
|
155 } |
|
156 }); |
|
157 } |
|
158 |
|
159 // The no-type syntax doesn't mix with the not and only keywords. |
|
160 query_should_be_parseable("(orientation)"); |
|
161 query_should_not_be_parseable("not (orientation)"); |
|
162 query_should_not_be_parseable("only (orientation)"); |
|
163 query_should_be_parseable("all and (orientation)"); |
|
164 query_should_be_parseable("not all and (orientation)"); |
|
165 query_should_be_parseable("only all and (orientation)"); |
|
166 |
|
167 query_should_be_parseable("(-moz-device-orientation)"); |
|
168 query_should_not_be_parseable("not (-moz-device-orientation)"); |
|
169 query_should_not_be_parseable("only (-moz-device-orientation)"); |
|
170 query_should_be_parseable("all and (-moz-device-orientation)"); |
|
171 query_should_be_parseable("not all and (-moz-device-orientation)"); |
|
172 query_should_be_parseable("only all and (-moz-device-orientation)"); |
|
173 |
|
174 // Test that the 'not', 'only', 'and', and 'or' keywords are not |
|
175 // allowed as media types. |
|
176 query_should_not_be_parseable("not"); |
|
177 query_should_not_be_parseable("and"); |
|
178 query_should_not_be_parseable("or"); |
|
179 query_should_not_be_parseable("only"); |
|
180 query_should_be_parseable("unknowntype"); |
|
181 query_should_not_be_parseable("not not"); |
|
182 query_should_not_be_parseable("not and"); |
|
183 query_should_not_be_parseable("not or"); |
|
184 query_should_not_be_parseable("not only"); |
|
185 query_should_be_parseable("not unknowntype"); |
|
186 query_should_not_be_parseable("only not"); |
|
187 query_should_not_be_parseable("only and"); |
|
188 query_should_not_be_parseable("only or"); |
|
189 query_should_not_be_parseable("only only"); |
|
190 query_should_be_parseable("only unknowntype"); |
|
191 query_should_not_be_parseable("not and (width)"); |
|
192 query_should_not_be_parseable("and and (width)"); |
|
193 query_should_not_be_parseable("or and (width)"); |
|
194 query_should_not_be_parseable("only and (width)"); |
|
195 query_should_be_parseable("unknowntype and (width)"); |
|
196 query_should_not_be_parseable("not not and (width)"); |
|
197 query_should_not_be_parseable("not and and (width)"); |
|
198 query_should_not_be_parseable("not or and (width)"); |
|
199 query_should_not_be_parseable("not only and (width)"); |
|
200 query_should_be_parseable("not unknowntype and (width)"); |
|
201 query_should_not_be_parseable("only not and (width)"); |
|
202 query_should_not_be_parseable("only and and (width)"); |
|
203 query_should_not_be_parseable("only or and (width)"); |
|
204 query_should_not_be_parseable("only only and (width)"); |
|
205 query_should_be_parseable("only unknowntype and (width)"); |
|
206 |
|
207 var features = [ "width", "height", "device-width", "device-height" ]; |
|
208 var feature; |
|
209 var i; |
|
210 for (i in features) { |
|
211 feature = features[i]; |
|
212 expression_should_be_parseable(feature); |
|
213 expression_should_be_parseable(feature + ": 0"); |
|
214 expression_should_be_parseable(feature + ": 0px"); |
|
215 expression_should_be_parseable(feature + ": 0em"); |
|
216 expression_should_be_parseable(feature + ": -0"); |
|
217 expression_should_be_parseable("min-" + feature + ": -0"); |
|
218 expression_should_be_parseable("max-" + feature + ": -0"); |
|
219 expression_should_be_parseable(feature + ": -0cm"); |
|
220 expression_should_be_parseable(feature + ": 1px"); |
|
221 expression_should_be_parseable(feature + ": 0.001mm"); |
|
222 expression_should_be_parseable(feature + ": 100000px"); |
|
223 expression_should_not_be_parseable(feature + ": -1px"); |
|
224 expression_should_not_be_parseable("min-" + feature + ": -1px"); |
|
225 expression_should_not_be_parseable("max-" + feature + ": -1px"); |
|
226 expression_should_not_be_parseable(feature + ": -0.00001mm"); |
|
227 expression_should_not_be_parseable(feature + ": -100000em"); |
|
228 expression_should_not_be_parseable("min-" + feature); |
|
229 expression_should_not_be_parseable("max-" + feature); |
|
230 } |
|
231 |
|
232 var content_div = document.getElementById("content"); |
|
233 content_div.style.font = "initial"; |
|
234 var em_size = |
|
235 getComputedStyle(content_div, "").fontSize.match(/^(\d+)px$/)[1]; |
|
236 |
|
237 // in this test, assume the common underlying implementation is correct |
|
238 var width_val = 117; // pick two not-too-round numbers |
|
239 var height_val = 76; |
|
240 change_state(function() { |
|
241 iframe_style.width = width_val + "px"; |
|
242 iframe_style.height = height_val + "px"; |
|
243 }); |
|
244 var device_width = window.screen.width; |
|
245 var device_height = window.screen.height; |
|
246 features = { "width": width_val, |
|
247 "height": height_val, |
|
248 "device-width": device_width, |
|
249 "device-height": device_height }; |
|
250 for (feature in features) { |
|
251 var value = features[feature]; |
|
252 should_apply("all and (" + feature + ": " + value + "px)"); |
|
253 should_not_apply("all and (" + feature + ": " + (value + 1) + "px)"); |
|
254 should_not_apply("all and (" + feature + ": " + (value - 1) + "px)"); |
|
255 should_apply("all and (min-" + feature + ": " + value + "px)"); |
|
256 should_not_apply("all and (min-" + feature + ": " + (value + 1) + "px)"); |
|
257 should_apply("all and (min-" + feature + ": " + (value - 1) + "px)"); |
|
258 should_apply("all and (max-" + feature + ": " + value + "px)"); |
|
259 should_apply("all and (max-" + feature + ": " + (value + 1) + "px)"); |
|
260 should_not_apply("all and (max-" + feature + ": " + (value - 1) + "px)"); |
|
261 should_not_apply("all and (min-" + feature + ": " + |
|
262 (Math.ceil(value/em_size) + 1) + "em)"); |
|
263 should_apply("all and (min-" + feature + ": " + |
|
264 (Math.floor(value/em_size) - 1) + "em)"); |
|
265 should_apply("all and (max-" + feature + ": " + |
|
266 (Math.ceil(value/em_size) + 1) + "em)"); |
|
267 should_not_apply("all and (max-" + feature + ": " + |
|
268 (Math.floor(value/em_size) - 1) + "em)"); |
|
269 should_not_apply("all and (min-" + feature + ": " + |
|
270 (Math.ceil(value/em_size) + 1) + "rem)"); |
|
271 should_apply("all and (min-" + feature + ": " + |
|
272 (Math.floor(value/em_size) - 1) + "rem)"); |
|
273 should_apply("all and (max-" + feature + ": " + |
|
274 (Math.ceil(value/em_size) + 1) + "rem)"); |
|
275 should_not_apply("all and (max-" + feature + ": " + |
|
276 (Math.floor(value/em_size) - 1) + "rem)"); |
|
277 } |
|
278 |
|
279 change_state(function() { |
|
280 iframe_style.width = "0"; |
|
281 }); |
|
282 should_apply("all and (height)"); |
|
283 should_not_apply("all and (width)"); |
|
284 change_state(function() { |
|
285 iframe_style.height = "0"; |
|
286 }); |
|
287 should_not_apply("all and (height)"); |
|
288 should_not_apply("all and (width)"); |
|
289 should_apply("all and (device-height)"); |
|
290 should_apply("all and (device-width)"); |
|
291 change_state(function() { |
|
292 iframe_style.width = width_val + "px"; |
|
293 }); |
|
294 should_not_apply("all and (height)"); |
|
295 should_apply("all and (width)"); |
|
296 change_state(function() { |
|
297 iframe_style.height = height_val + "px"; |
|
298 }); |
|
299 should_apply("all and (height)"); |
|
300 should_apply("all and (width)"); |
|
301 |
|
302 // ratio that reduces to 59/40 |
|
303 change_state(function() { |
|
304 iframe_style.width = "236px"; |
|
305 iframe_style.height = "160px"; |
|
306 }); |
|
307 expression_should_be_parseable("orientation"); |
|
308 expression_should_be_parseable("orientation: portrait"); |
|
309 expression_should_be_parseable("orientation: landscape"); |
|
310 expression_should_not_be_parseable("min-orientation"); |
|
311 expression_should_not_be_parseable("min-orientation: portrait"); |
|
312 expression_should_not_be_parseable("min-orientation: landscape"); |
|
313 expression_should_not_be_parseable("max-orientation"); |
|
314 expression_should_not_be_parseable("max-orientation: portrait"); |
|
315 expression_should_not_be_parseable("max-orientation: landscape"); |
|
316 should_apply("(orientation)"); |
|
317 should_apply("(orientation: landscape)"); |
|
318 should_not_apply("(orientation: portrait)"); |
|
319 should_apply("not all and (orientation: portrait)"); |
|
320 // ratio that reduces to 59/80 |
|
321 change_state(function() { |
|
322 iframe_style.height = "320px"; |
|
323 }); |
|
324 should_apply("(orientation)"); |
|
325 should_not_apply("(orientation: landscape)"); |
|
326 should_apply("not all and (orientation: landscape)"); |
|
327 should_apply("(orientation: portrait)"); |
|
328 |
|
329 expression_should_be_parseable("-moz-device-orientation"); |
|
330 expression_should_be_parseable("-moz-device-orientation: portrait"); |
|
331 expression_should_be_parseable("-moz-device-orientation: landscape"); |
|
332 expression_should_not_be_parseable("min--moz-device-orientation"); |
|
333 expression_should_not_be_parseable("min--moz-device-orientation: portrait"); |
|
334 expression_should_not_be_parseable("min--moz-device-orientation: landscape"); |
|
335 expression_should_not_be_parseable("max--moz-device-orientation"); |
|
336 expression_should_not_be_parseable("max--moz-device-orientation: portrait"); |
|
337 expression_should_not_be_parseable("max--moz-device-orientation: landscape"); |
|
338 |
|
339 // determine the actual configuration of the screen and test against it |
|
340 var device_orientation = (device_width > device_height) ? "landscape" : "portrait"; |
|
341 var not_device_orientation = (device_orientation == "landscape") ? "portrait" : "landscape"; |
|
342 should_apply("(-moz-device-orientation)"); |
|
343 should_apply("(-moz-device-orientation: " + device_orientation + ")"); |
|
344 should_not_apply("(-moz-device-orientation: " + not_device_orientation + ")"); |
|
345 should_apply("not all and (-moz-device-orientation: " + not_device_orientation + ")"); |
|
346 |
|
347 should_apply("(aspect-ratio: 59/80)"); |
|
348 should_not_apply("(aspect-ratio: 58/80)"); |
|
349 should_not_apply("(aspect-ratio: 59/81)"); |
|
350 should_not_apply("(aspect-ratio: 60/80)"); |
|
351 should_not_apply("(aspect-ratio: 59/79)"); |
|
352 should_apply("(aspect-ratio: 177/240)"); |
|
353 should_apply("(aspect-ratio: 413/560)"); |
|
354 should_apply("(aspect-ratio: 5900/8000)"); |
|
355 should_not_apply("(aspect-ratio: 5901/8000)"); |
|
356 should_not_apply("(aspect-ratio: 5899/8000)"); |
|
357 should_not_apply("(aspect-ratio: 5900/8001)"); |
|
358 should_not_apply("(aspect-ratio: 5900/7999)"); |
|
359 should_apply("(aspect-ratio)"); |
|
360 |
|
361 should_apply("(min-aspect-ratio: 59/80)"); |
|
362 should_apply("(min-aspect-ratio: 58/80)"); |
|
363 should_apply("(min-aspect-ratio: 59/81)"); |
|
364 should_not_apply("(min-aspect-ratio: 60/80)"); |
|
365 should_not_apply("(min-aspect-ratio: 59/79)"); |
|
366 expression_should_not_be_parseable("min-aspect-ratio"); |
|
367 |
|
368 should_apply("(max-aspect-ratio: 59/80)"); |
|
369 should_not_apply("(max-aspect-ratio: 58/80)"); |
|
370 should_not_apply("(max-aspect-ratio: 59/81)"); |
|
371 should_apply("(max-aspect-ratio: 60/80)"); |
|
372 should_apply("(max-aspect-ratio: 59/79)"); |
|
373 expression_should_not_be_parseable("max-aspect-ratio"); |
|
374 |
|
375 var real_dar = device_width + "/" + device_height; |
|
376 var high_dar_1 = (device_width + 1) + "/" + device_height; |
|
377 var high_dar_2 = device_width + "/" + (device_height - 1); |
|
378 var low_dar_1 = (device_width - 1) + "/" + device_height; |
|
379 var low_dar_2 = device_width + "/" + (device_height + 1); |
|
380 should_apply("(device-aspect-ratio: " + real_dar + ")"); |
|
381 should_apply("not all and (device-aspect-ratio: " + high_dar_1 + ")"); |
|
382 should_not_apply("all and (device-aspect-ratio: " + high_dar_2 + ")"); |
|
383 should_not_apply("all and (device-aspect-ratio: " + low_dar_1 + ")"); |
|
384 should_apply("not all and (device-aspect-ratio: " + low_dar_2 + ")"); |
|
385 should_apply("(device-aspect-ratio)"); |
|
386 |
|
387 should_apply("(min-device-aspect-ratio: " + real_dar + ")"); |
|
388 should_not_apply("all and (min-device-aspect-ratio: " + high_dar_1 + ")"); |
|
389 should_apply("not all and (min-device-aspect-ratio: " + high_dar_2 + ")"); |
|
390 should_not_apply("not all and (min-device-aspect-ratio: " + low_dar_1 + ")"); |
|
391 should_apply("all and (min-device-aspect-ratio: " + low_dar_2 + ")"); |
|
392 expression_should_not_be_parseable("min-device-aspect-ratio"); |
|
393 |
|
394 should_apply("all and (max-device-aspect-ratio: " + real_dar + ")"); |
|
395 should_apply("(max-device-aspect-ratio: " + high_dar_1 + ")"); |
|
396 should_apply("(max-device-aspect-ratio: " + high_dar_2 + ")"); |
|
397 should_not_apply("all and (max-device-aspect-ratio: " + low_dar_1 + ")"); |
|
398 should_apply("not all and (max-device-aspect-ratio: " + low_dar_2 + ")"); |
|
399 expression_should_not_be_parseable("max-device-aspect-ratio"); |
|
400 |
|
401 var real_dpr = 1.0 * getScreenPixelsPerCSSPixel(); |
|
402 var high_dpr = 1.1 * getScreenPixelsPerCSSPixel(); |
|
403 var low_dpr = 0.9 * getScreenPixelsPerCSSPixel(); |
|
404 should_apply("all and (max--moz-device-pixel-ratio: " + real_dpr + ")"); |
|
405 should_apply("all and (min--moz-device-pixel-ratio: " + real_dpr + ")"); |
|
406 should_not_apply("not all and (max--moz-device-pixel-ratio: " + real_dpr + ")"); |
|
407 should_not_apply("not all and (min--moz-device-pixel-ratio: " + real_dpr + ")"); |
|
408 should_apply("all and (min--moz-device-pixel-ratio: " + low_dpr + ")"); |
|
409 should_apply("all and (max--moz-device-pixel-ratio: " + high_dpr + ")"); |
|
410 should_not_apply("all and (max--moz-device-pixel-ratio: " + low_dpr + ")"); |
|
411 should_not_apply("all and (min--moz-device-pixel-ratio: " + high_dpr + ")"); |
|
412 should_apply("not all and (max--moz-device-pixel-ratio: " + low_dpr + ")"); |
|
413 should_apply("not all and (min--moz-device-pixel-ratio: " + high_dpr + ")"); |
|
414 should_apply("(-moz-device-pixel-ratio: " + real_dpr + ")"); |
|
415 should_not_apply("(-moz-device-pixel-ratio: " + high_dpr + ")"); |
|
416 should_not_apply("(-moz-device-pixel-ratio: " + low_dpr + ")"); |
|
417 should_apply("(-moz-device-pixel-ratio)"); |
|
418 expression_should_not_be_parseable("min--moz-device-pixel-ratio"); |
|
419 expression_should_not_be_parseable("max--moz-device-pixel-ratio"); |
|
420 |
|
421 features = [ "max-aspect-ratio", "device-aspect-ratio" ]; |
|
422 for (i in features) { |
|
423 feature = features[i]; |
|
424 expression_should_be_parseable(feature + ": 1/1"); |
|
425 expression_should_be_parseable(feature + ": 1 /1"); |
|
426 expression_should_be_parseable(feature + ": 1 / \t\n1"); |
|
427 expression_should_be_parseable(feature + ": 1/\r1"); |
|
428 expression_should_not_be_parseable(feature + ": 1"); |
|
429 expression_should_not_be_parseable(feature + ": 0.5"); |
|
430 expression_should_not_be_parseable(feature + ": 1.0/1"); |
|
431 expression_should_not_be_parseable(feature + ": 1/1.0"); |
|
432 expression_should_not_be_parseable(feature + ": 1.0/1.0"); |
|
433 expression_should_not_be_parseable(feature + ": 0/1"); |
|
434 expression_should_not_be_parseable(feature + ": 1/0"); |
|
435 expression_should_not_be_parseable(feature + ": 0/0"); |
|
436 expression_should_not_be_parseable(feature + ": -1/1"); |
|
437 expression_should_not_be_parseable(feature + ": 1/-1"); |
|
438 expression_should_not_be_parseable(feature + ": -1/-1"); |
|
439 } |
|
440 |
|
441 var is_monochrome = query_applies("all and (min-monochrome: 1)"); |
|
442 test_serialization("all and (min-monochrome: 1)", true, is_monochrome); |
|
443 var is_color = query_applies("all and (min-color: 1)"); |
|
444 test_serialization("all and (min-color: 1)", true, is_color); |
|
445 isnot(is_monochrome, is_color, "should be either monochrome or color"); |
|
446 |
|
447 function depth_query(prefix, depth) { |
|
448 return "all and (" + prefix + (is_color ? "color" : "monochrome") + |
|
449 ":" + depth + ")"; |
|
450 } |
|
451 |
|
452 var depth = 0; |
|
453 do { |
|
454 if (depth > 50) { |
|
455 ok(false, "breaking from loop, depth > 50"); |
|
456 break; |
|
457 } |
|
458 } while (query_applies(depth_query("min-", ++depth))); |
|
459 --depth; |
|
460 |
|
461 should_apply(depth_query("", depth)); |
|
462 should_not_apply(depth_query("", depth - 1)); |
|
463 should_not_apply(depth_query("", depth + 1)); |
|
464 should_apply(depth_query("max-", depth)); |
|
465 should_not_apply(depth_query("max-", depth - 1)); |
|
466 should_apply(depth_query("max-", depth + 1)); |
|
467 |
|
468 (is_color ? should_apply : should_not_apply)("all and (color)"); |
|
469 expression_should_not_be_parseable("max-color"); |
|
470 expression_should_not_be_parseable("min-color"); |
|
471 (is_color ? should_not_apply : should_apply)("all and (monochrome)"); |
|
472 expression_should_not_be_parseable("max-monochrome"); |
|
473 expression_should_not_be_parseable("min-monochrome"); |
|
474 (is_color ? should_apply : should_not_apply)("not all and (monochrome)"); |
|
475 (is_color ? should_not_apply : should_apply)("not all and (color)"); |
|
476 (is_color ? should_apply : should_not_apply)("only all and (color)"); |
|
477 (is_color ? should_not_apply : should_apply)("only all and (monochrome)"); |
|
478 |
|
479 features = [ "color", "min-monochrome", "max-color-index" ]; |
|
480 for (i in features) { |
|
481 feature = features[i]; |
|
482 expression_should_be_parseable(feature + ": 1"); |
|
483 expression_should_be_parseable(feature + ": 327"); |
|
484 expression_should_be_parseable(feature + ": 0"); |
|
485 expression_should_not_be_parseable(feature + ": 1.0"); |
|
486 expression_should_not_be_parseable(feature + ": -1"); |
|
487 expression_should_not_be_parseable(feature + ": 1/1"); |
|
488 } |
|
489 |
|
490 // Presume that we never support indexed color (at least not usefully |
|
491 // enough to call it indexed color). |
|
492 should_apply("(color-index: 0)"); |
|
493 should_not_apply("(color-index: 1)"); |
|
494 should_apply("(min-color-index: 0)"); |
|
495 should_not_apply("(min-color-index: 1)"); |
|
496 should_apply("(max-color-index: 0)"); |
|
497 should_apply("(max-color-index: 1)"); |
|
498 should_apply("(max-color-index: 157)"); |
|
499 |
|
500 features = [ "resolution", "min-resolution", "max-resolution" ]; |
|
501 for (i in features) { |
|
502 feature = features[i]; |
|
503 expression_should_be_parseable(feature + ": 3dpi"); |
|
504 expression_should_be_parseable(feature + ":3dpi"); |
|
505 expression_should_be_parseable(feature + ": 3.0dpi"); |
|
506 expression_should_be_parseable(feature + ": 3.4dpi"); |
|
507 expression_should_be_parseable(feature + "\t: 120dpcm"); |
|
508 expression_should_be_parseable(feature + ": 1dppx"); |
|
509 expression_should_be_parseable(feature + ": 1.5dppx"); |
|
510 expression_should_be_parseable(feature + ": 2.0dppx"); |
|
511 expression_should_not_be_parseable(feature + ": 0dpi"); |
|
512 expression_should_not_be_parseable(feature + ": -3dpi"); |
|
513 expression_should_not_be_parseable(feature + ": 0dppx"); |
|
514 } |
|
515 |
|
516 // Find the resolution using max-resolution |
|
517 var resolution = 0; |
|
518 do { |
|
519 ++resolution; |
|
520 if (resolution > 10000) { |
|
521 ok(false, "resolution greater than 10000dpi???"); |
|
522 break; |
|
523 } |
|
524 } while (!query_applies("(max-resolution: " + resolution + "dpi)")); |
|
525 |
|
526 // resolution should now be Math.ceil() of the actual resolution. |
|
527 var dpi_high; |
|
528 var dpi_low = resolution - 1; |
|
529 if (query_applies("(min-resolution: " + resolution + "dpi)")) { |
|
530 // It's exact! |
|
531 should_apply("(resolution: " + resolution + "dpi)"); |
|
532 should_apply("(resolution: " + Math.floor(resolution/96) + "dppx)"); |
|
533 should_not_apply("(resolution: " + (resolution + 1) + "dpi)"); |
|
534 should_not_apply("(resolution: " + (resolution - 1) + "dpi)"); |
|
535 dpi_high = resolution + 1; |
|
536 } else { |
|
537 // We have no way to test resolution applying since it need not be |
|
538 // an integer. |
|
539 should_not_apply("(resolution: " + resolution + "dpi)"); |
|
540 should_not_apply("(resolution: " + (resolution - 1) + "dpi)"); |
|
541 dpi_high = resolution; |
|
542 } |
|
543 |
|
544 should_apply("(min-resolution: " + dpi_low + "dpi)"); |
|
545 should_not_apply("not all and (min-resolution: " + dpi_low + "dpi)"); |
|
546 should_apply("not all and (min-resolution: " + dpi_high + "dpi)"); |
|
547 should_not_apply("all and (min-resolution: " + dpi_high + "dpi)"); |
|
548 |
|
549 // Test dpcm units based on what we computed in dpi. |
|
550 var dpcm_high = Math.ceil(dpi_high / 2.54); |
|
551 var dpcm_low = Math.floor(dpi_low / 2.54); |
|
552 should_apply("(min-resolution: " + dpcm_low + "dpcm)"); |
|
553 should_apply("(max-resolution: " + dpcm_high + "dpcm)"); |
|
554 should_not_apply("(max-resolution: " + dpcm_low + "dpcm)"); |
|
555 should_apply("not all and (min-resolution: " + dpcm_high + "dpcm)"); |
|
556 |
|
557 expression_should_be_parseable("scan"); |
|
558 expression_should_be_parseable("scan: progressive"); |
|
559 expression_should_be_parseable("scan:interlace"); |
|
560 expression_should_not_be_parseable("min-scan:interlace"); |
|
561 expression_should_not_be_parseable("scan: 1"); |
|
562 expression_should_not_be_parseable("max-scan"); |
|
563 expression_should_not_be_parseable("max-scan: progressive"); |
|
564 // Assume we don't support tv devices. |
|
565 should_not_apply("(scan)"); |
|
566 should_not_apply("(scan: progressive)"); |
|
567 should_not_apply("(scan: interlace)"); |
|
568 should_apply("not all and (scan)"); |
|
569 should_apply("not all and (scan: progressive)"); |
|
570 should_apply("not all and (scan: interlace)"); |
|
571 |
|
572 expression_should_be_parseable("grid"); |
|
573 expression_should_be_parseable("grid: 0"); |
|
574 expression_should_be_parseable("grid: 1"); |
|
575 expression_should_be_parseable("grid: 1"); |
|
576 expression_should_not_be_parseable("min-grid"); |
|
577 expression_should_not_be_parseable("min-grid:0"); |
|
578 expression_should_not_be_parseable("max-grid: 1"); |
|
579 expression_should_not_be_parseable("grid: 2"); |
|
580 expression_should_not_be_parseable("grid: -1"); |
|
581 |
|
582 // Assume we don't support grid devices |
|
583 should_not_apply("(grid)"); |
|
584 should_apply("(grid: 0)"); |
|
585 should_not_apply("(grid: 1)"); |
|
586 should_not_apply("(grid: 2)"); |
|
587 should_not_apply("(grid: -1)"); |
|
588 |
|
589 // System metrics |
|
590 expression_should_be_parseable("-moz-scrollbar-start-backward"); |
|
591 expression_should_be_parseable("-moz-scrollbar-start-forward"); |
|
592 expression_should_be_parseable("-moz-scrollbar-end-backward"); |
|
593 expression_should_be_parseable("-moz-scrollbar-end-forward"); |
|
594 expression_should_be_parseable("-moz-scrollbar-thumb-proportional"); |
|
595 expression_should_be_parseable("-moz-images-in-menus"); |
|
596 expression_should_be_parseable("-moz-images-in-buttons"); |
|
597 expression_should_be_parseable("-moz-overlay-scrollbars"); |
|
598 expression_should_be_parseable("-moz-windows-default-theme"); |
|
599 expression_should_be_parseable("-moz-mac-graphite-theme"); |
|
600 expression_should_be_parseable("-moz-mac-lion-theme"); |
|
601 expression_should_be_parseable("-moz-windows-compositor"); |
|
602 expression_should_be_parseable("-moz-windows-classic"); |
|
603 expression_should_be_parseable("-moz-windows-glass"); |
|
604 expression_should_be_parseable("-moz-touch-enabled"); |
|
605 expression_should_be_parseable("-moz-swipe-animation-enabled"); |
|
606 |
|
607 expression_should_be_parseable("-moz-scrollbar-start-backward: 0"); |
|
608 expression_should_be_parseable("-moz-scrollbar-start-forward: 0"); |
|
609 expression_should_be_parseable("-moz-scrollbar-end-backward: 0"); |
|
610 expression_should_be_parseable("-moz-scrollbar-end-forward: 0"); |
|
611 expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 0"); |
|
612 expression_should_be_parseable("-moz-images-in-menus: 0"); |
|
613 expression_should_be_parseable("-moz-images-in-buttons: 0"); |
|
614 expression_should_be_parseable("-moz-overlay-scrollbars: 0"); |
|
615 expression_should_be_parseable("-moz-windows-default-theme: 0"); |
|
616 expression_should_be_parseable("-moz-mac-graphite-theme: 0"); |
|
617 expression_should_be_parseable("-moz-mac-lion-theme: 0"); |
|
618 expression_should_be_parseable("-moz-windows-compositor: 0"); |
|
619 expression_should_be_parseable("-moz-windows-classic: 0"); |
|
620 expression_should_be_parseable("-moz-windows-glass: 0"); |
|
621 expression_should_be_parseable("-moz-touch-enabled: 0"); |
|
622 expression_should_be_parseable("-moz-swipe-animation-enabled: 0"); |
|
623 |
|
624 expression_should_be_parseable("-moz-scrollbar-start-backward: 1"); |
|
625 expression_should_be_parseable("-moz-scrollbar-start-forward: 1"); |
|
626 expression_should_be_parseable("-moz-scrollbar-end-backward: 1"); |
|
627 expression_should_be_parseable("-moz-scrollbar-end-forward: 1"); |
|
628 expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 1"); |
|
629 expression_should_be_parseable("-moz-images-in-menus: 1"); |
|
630 expression_should_be_parseable("-moz-images-in-buttons: 1"); |
|
631 expression_should_be_parseable("-moz-overlay-scrollbars: 1"); |
|
632 expression_should_be_parseable("-moz-windows-default-theme: 1"); |
|
633 expression_should_be_parseable("-moz-mac-graphite-theme: 1"); |
|
634 expression_should_be_parseable("-moz-mac-lion-theme: 1"); |
|
635 expression_should_be_parseable("-moz-windows-compositor: 1"); |
|
636 expression_should_be_parseable("-moz-windows-classic: 1"); |
|
637 expression_should_be_parseable("-moz-windows-glass: 1"); |
|
638 expression_should_be_parseable("-moz-touch-enabled: 1"); |
|
639 expression_should_be_parseable("-moz-swipe-animation-enabled: 1"); |
|
640 |
|
641 expression_should_not_be_parseable("-moz-scrollbar-start-backward: -1"); |
|
642 expression_should_not_be_parseable("-moz-scrollbar-start-forward: -1"); |
|
643 expression_should_not_be_parseable("-moz-scrollbar-end-backward: -1"); |
|
644 expression_should_not_be_parseable("-moz-scrollbar-end-forward: -1"); |
|
645 expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: -1"); |
|
646 expression_should_not_be_parseable("-moz-images-in-menus: -1"); |
|
647 expression_should_not_be_parseable("-moz-images-in-buttons: -1"); |
|
648 expression_should_not_be_parseable("-moz-overlay-scrollbars: -1"); |
|
649 expression_should_not_be_parseable("-moz-windows-default-theme: -1"); |
|
650 expression_should_not_be_parseable("-moz-mac-graphite-theme: -1"); |
|
651 expression_should_not_be_parseable("-moz-mac-lion-theme: -1"); |
|
652 expression_should_not_be_parseable("-moz-windows-compositor: -1"); |
|
653 expression_should_not_be_parseable("-moz-windows-classic: -1"); |
|
654 expression_should_not_be_parseable("-moz-windows-glass: -1"); |
|
655 expression_should_not_be_parseable("-moz-touch-enabled: -1"); |
|
656 expression_should_not_be_parseable("-moz-swipe-animation-enabled: -1"); |
|
657 |
|
658 expression_should_not_be_parseable("-moz-scrollbar-start-backward: true"); |
|
659 expression_should_not_be_parseable("-moz-scrollbar-start-forward: true"); |
|
660 expression_should_not_be_parseable("-moz-scrollbar-end-backward: true"); |
|
661 expression_should_not_be_parseable("-moz-scrollbar-end-forward: true"); |
|
662 expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: true"); |
|
663 expression_should_not_be_parseable("-moz-images-in-menus: true"); |
|
664 expression_should_not_be_parseable("-moz-images-in-buttons: true"); |
|
665 expression_should_not_be_parseable("-moz-overlay-scrollbars: true"); |
|
666 expression_should_not_be_parseable("-moz-windows-default-theme: true"); |
|
667 expression_should_not_be_parseable("-moz-mac-graphite-theme: true"); |
|
668 expression_should_not_be_parseable("-moz-mac-lion-theme: true"); |
|
669 expression_should_not_be_parseable("-moz-windows-compositor: true"); |
|
670 expression_should_not_be_parseable("-moz-windows-classic: true"); |
|
671 expression_should_not_be_parseable("-moz-windows-glass: true"); |
|
672 expression_should_not_be_parseable("-moz-touch-enabled: true"); |
|
673 expression_should_not_be_parseable("-moz-swipe-animation-enabled: true"); |
|
674 |
|
675 // windows theme media queries |
|
676 expression_should_be_parseable("-moz-windows-theme: aero"); |
|
677 expression_should_be_parseable("-moz-windows-theme: aero-lite"); |
|
678 expression_should_be_parseable("-moz-windows-theme: luna-blue"); |
|
679 expression_should_be_parseable("-moz-windows-theme: luna-olive"); |
|
680 expression_should_be_parseable("-moz-windows-theme: luna-silver"); |
|
681 expression_should_be_parseable("-moz-windows-theme: royale"); |
|
682 expression_should_be_parseable("-moz-windows-theme: generic"); |
|
683 expression_should_be_parseable("-moz-windows-theme: zune"); |
|
684 expression_should_be_parseable("-moz-windows-theme: garbage"); |
|
685 expression_should_not_be_parseable("-moz-windows-theme: ''"); |
|
686 expression_should_not_be_parseable("-moz-windows-theme: "); |
|
687 |
|
688 // os version media queries (currently windows only) |
|
689 expression_should_be_parseable("-moz-os-version: windows-xp"); |
|
690 expression_should_be_parseable("-moz-os-version: windows-vista"); |
|
691 expression_should_be_parseable("-moz-os-version: windows-win7"); |
|
692 expression_should_be_parseable("-moz-os-version: windows-win8"); |
|
693 expression_should_not_be_parseable("-moz-os-version: "); |
|
694 |
|
695 // OpenType SVG media features |
|
696 query_should_be_parseable("(-moz-is-glyph)"); |
|
697 query_should_not_be_parseable("not (-moz-is-glyph)"); |
|
698 query_should_not_be_parseable("only (-moz-is-glyph)"); |
|
699 query_should_be_parseable("all and (-moz-is-glyph)"); |
|
700 query_should_be_parseable("not all and (-moz-is-glyph)"); |
|
701 query_should_be_parseable("only all and (-moz-is-glyph)"); |
|
702 |
|
703 query_should_be_parseable("(-moz-is-glyph:0)"); |
|
704 query_should_not_be_parseable("not (-moz-is-glyph:0)"); |
|
705 query_should_not_be_parseable("only (-moz-is-glyph:0)"); |
|
706 query_should_be_parseable("all and (-moz-is-glyph:0)"); |
|
707 query_should_be_parseable("not all and (-moz-is-glyph:0)"); |
|
708 query_should_be_parseable("only all and (-moz-is-glyph:0)"); |
|
709 |
|
710 query_should_be_parseable("(-moz-is-glyph:1)"); |
|
711 query_should_not_be_parseable("not (-moz-is-glyph:1)"); |
|
712 query_should_not_be_parseable("only (-moz-is-glyph:1)"); |
|
713 query_should_be_parseable("all and (-moz-is-glyph:1)"); |
|
714 query_should_be_parseable("not all and (-moz-is-glyph:1)"); |
|
715 query_should_be_parseable("only all and (-moz-is-glyph:1)"); |
|
716 |
|
717 query_should_not_be_parseable("(min--moz-is-glyph:0)"); |
|
718 query_should_not_be_parseable("(max--moz-is-glyph:0)"); |
|
719 query_should_not_be_parseable("(min--moz-is-glyph:1)"); |
|
720 query_should_not_be_parseable("(max--moz-is-glyph:1)"); |
|
721 |
|
722 should_apply("not all and (-moz-is-glyph)"); |
|
723 should_apply("(-moz-is-glyph:0)"); |
|
724 should_apply("not all and (-moz-is-glyph:1)"); |
|
725 should_apply("only all and (-moz-is-glyph:0)"); |
|
726 should_not_apply("(-moz-is-glyph)"); |
|
727 should_not_apply("(-moz-is-glyph:1)"); |
|
728 should_not_apply("not all and (-moz-is-glyph:0)"); |
|
729 should_not_apply("only all and (-moz-is-glyph:1)"); |
|
730 |
|
731 // Parsing tests |
|
732 // bug 454227 |
|
733 should_apply_unbalanced("(orientation"); |
|
734 should_not_apply_unbalanced("not all and (orientation"); |
|
735 should_not_apply_unbalanced("(orientation:"); |
|
736 should_apply_unbalanced("all,(orientation:"); |
|
737 should_not_apply_unbalanced("(orientation:,all"); |
|
738 should_apply_unbalanced("not all and (grid"); |
|
739 should_not_apply_unbalanced("only all and (grid"); |
|
740 should_not_apply_unbalanced("(grid"); |
|
741 should_apply_unbalanced("all,(grid"); |
|
742 should_not_apply_unbalanced("(grid,all"); |
|
743 // bug 454226 |
|
744 should_apply(",all"); |
|
745 should_apply("all,"); |
|
746 should_apply(",all,"); |
|
747 should_apply("all,badmedium"); |
|
748 should_apply("badmedium,all"); |
|
749 should_not_apply(",badmedium,"); |
|
750 should_apply("all,(badexpression)"); |
|
751 should_apply("(badexpression),all"); |
|
752 should_not_apply("(badexpression),badmedium"); |
|
753 should_not_apply("badmedium,(badexpression)"); |
|
754 should_apply("all,[badsyntax]"); |
|
755 should_apply("[badsyntax],all"); |
|
756 should_not_apply("badmedium,[badsyntax]"); |
|
757 should_not_apply("[badsyntax],badmedium"); |
|
758 // bug 528096 |
|
759 should_not_apply_unbalanced("((resolution),all"); |
|
760 should_not_apply_unbalanced("(resolution(),all"); |
|
761 should_not_apply_unbalanced("(resolution (),all"); |
|
762 should_not_apply_unbalanced("(resolution:(),all"); |
|
763 |
|
764 handle_posted_items(); |
|
765 } |
|
766 |
|
767 /* |
|
768 * The cloning tests have to post tests that wait for onload. However, |
|
769 * we also make a bunch of state changes during the tests above. So we |
|
770 * always change state using the change_state call, with both makes the |
|
771 * change immediately and posts an item in the same queue so that we |
|
772 * make the same state change again later. |
|
773 */ |
|
774 |
|
775 var posted_items = []; |
|
776 |
|
777 function change_state(func) |
|
778 { |
|
779 func(); |
|
780 posted_items.push({state: func}); |
|
781 } |
|
782 |
|
783 function post_clone_test(docurl, testfunc) |
|
784 { |
|
785 posted_items.push({docurl: docurl, testfunc: testfunc}); |
|
786 } |
|
787 |
|
788 function handle_posted_items() |
|
789 { |
|
790 if (posted_items.length == 0) { |
|
791 SimpleTest.finish(); |
|
792 return; |
|
793 } |
|
794 |
|
795 if ("state" in posted_items[0]) { |
|
796 var item = posted_items.shift(); |
|
797 item.state(); |
|
798 handle_posted_items(); |
|
799 return; |
|
800 } |
|
801 |
|
802 var docurl = posted_items[0].docurl; |
|
803 iframe.onload = handle_iframe_onload; |
|
804 iframe.src = docurl; |
|
805 } |
|
806 |
|
807 function handle_iframe_onload(event) |
|
808 { |
|
809 if (event.target != iframe) |
|
810 return; |
|
811 |
|
812 var item = posted_items.shift(); |
|
813 item.testfunc(); |
|
814 handle_posted_items(); |
|
815 } |
|
816 |
|
817 </script> |
|
818 </pre> |
|
819 </body> |
|
820 </html> |
|
821 |
|
822 |