1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5 //! Gecko's media feature list and evaluator.
6
7 use crate::gecko_bindings::bindings;
8 use crate::gecko_bindings::structs;
9 use crate::media_queries::media_feature::{AllowsRanges, ParsingRequirements};
10 use crate::media_queries::media_feature::{Evaluator, MediaFeatureDescription};
11 use crate::media_queries::media_feature_expression::RangeOrOperator;
12 use crate::media_queries::{Device, MediaType};
13 use crate::values::computed::position::Ratio;
14 use crate::values::computed::CSSPixelLength;
15 use crate::values::computed::Resolution;
16 use crate::Atom;
17 use app_units::Au;
18 use euclid::default::Size2D;
19
viewport_size(device: &Device) -> Size2D<Au>20 fn viewport_size(device: &Device) -> Size2D<Au> {
21 if let Some(pc) = device.pres_context() {
22 if pc.mIsRootPaginatedDocument() != 0 {
23 // We want the page size, including unprintable areas and margins.
24 // FIXME(emilio, bug 1414600): Not quite!
25 let area = &pc.mPageSize;
26 return Size2D::new(Au(area.width), Au(area.height));
27 }
28 }
29 device.au_viewport_size()
30 }
31
device_size(device: &Device) -> Size2D<Au>32 fn device_size(device: &Device) -> Size2D<Au> {
33 let mut width = 0;
34 let mut height = 0;
35 unsafe {
36 bindings::Gecko_MediaFeatures_GetDeviceSize(device.document(), &mut width, &mut height);
37 }
38 Size2D::new(Au(width), Au(height))
39 }
40
41 /// https://drafts.csswg.org/mediaqueries-4/#width
eval_width( device: &Device, value: Option<CSSPixelLength>, range_or_operator: Option<RangeOrOperator>, ) -> bool42 fn eval_width(
43 device: &Device,
44 value: Option<CSSPixelLength>,
45 range_or_operator: Option<RangeOrOperator>,
46 ) -> bool {
47 RangeOrOperator::evaluate(
48 range_or_operator,
49 value.map(Au::from),
50 viewport_size(device).width,
51 )
52 }
53
54 /// https://drafts.csswg.org/mediaqueries-4/#device-width
eval_device_width( device: &Device, value: Option<CSSPixelLength>, range_or_operator: Option<RangeOrOperator>, ) -> bool55 fn eval_device_width(
56 device: &Device,
57 value: Option<CSSPixelLength>,
58 range_or_operator: Option<RangeOrOperator>,
59 ) -> bool {
60 RangeOrOperator::evaluate(
61 range_or_operator,
62 value.map(Au::from),
63 device_size(device).width,
64 )
65 }
66
67 /// https://drafts.csswg.org/mediaqueries-4/#height
eval_height( device: &Device, value: Option<CSSPixelLength>, range_or_operator: Option<RangeOrOperator>, ) -> bool68 fn eval_height(
69 device: &Device,
70 value: Option<CSSPixelLength>,
71 range_or_operator: Option<RangeOrOperator>,
72 ) -> bool {
73 RangeOrOperator::evaluate(
74 range_or_operator,
75 value.map(Au::from),
76 viewport_size(device).height,
77 )
78 }
79
80 /// https://drafts.csswg.org/mediaqueries-4/#device-height
eval_device_height( device: &Device, value: Option<CSSPixelLength>, range_or_operator: Option<RangeOrOperator>, ) -> bool81 fn eval_device_height(
82 device: &Device,
83 value: Option<CSSPixelLength>,
84 range_or_operator: Option<RangeOrOperator>,
85 ) -> bool {
86 RangeOrOperator::evaluate(
87 range_or_operator,
88 value.map(Au::from),
89 device_size(device).height,
90 )
91 }
92
eval_aspect_ratio_for<F>( device: &Device, query_value: Option<Ratio>, range_or_operator: Option<RangeOrOperator>, get_size: F, ) -> bool where F: FnOnce(&Device) -> Size2D<Au>,93 fn eval_aspect_ratio_for<F>(
94 device: &Device,
95 query_value: Option<Ratio>,
96 range_or_operator: Option<RangeOrOperator>,
97 get_size: F,
98 ) -> bool
99 where
100 F: FnOnce(&Device) -> Size2D<Au>,
101 {
102 let query_value = match query_value {
103 Some(v) => v,
104 None => return true,
105 };
106
107 let size = get_size(device);
108 let value = Ratio::new(size.width.0 as f32, size.height.0 as f32);
109 RangeOrOperator::evaluate_with_query_value(range_or_operator, query_value, value)
110 }
111
112 /// https://drafts.csswg.org/mediaqueries-4/#aspect-ratio
eval_aspect_ratio( device: &Device, query_value: Option<Ratio>, range_or_operator: Option<RangeOrOperator>, ) -> bool113 fn eval_aspect_ratio(
114 device: &Device,
115 query_value: Option<Ratio>,
116 range_or_operator: Option<RangeOrOperator>,
117 ) -> bool {
118 eval_aspect_ratio_for(device, query_value, range_or_operator, viewport_size)
119 }
120
121 /// https://drafts.csswg.org/mediaqueries-4/#device-aspect-ratio
eval_device_aspect_ratio( device: &Device, query_value: Option<Ratio>, range_or_operator: Option<RangeOrOperator>, ) -> bool122 fn eval_device_aspect_ratio(
123 device: &Device,
124 query_value: Option<Ratio>,
125 range_or_operator: Option<RangeOrOperator>,
126 ) -> bool {
127 eval_aspect_ratio_for(device, query_value, range_or_operator, device_size)
128 }
129
130 /// https://compat.spec.whatwg.org/#css-media-queries-webkit-device-pixel-ratio
eval_device_pixel_ratio( device: &Device, query_value: Option<f32>, range_or_operator: Option<RangeOrOperator>, ) -> bool131 fn eval_device_pixel_ratio(
132 device: &Device,
133 query_value: Option<f32>,
134 range_or_operator: Option<RangeOrOperator>,
135 ) -> bool {
136 eval_resolution(
137 device,
138 query_value.map(Resolution::from_dppx),
139 range_or_operator,
140 )
141 }
142
143 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
144 #[repr(u8)]
145 enum Orientation {
146 Landscape,
147 Portrait,
148 }
149
eval_orientation_for<F>(device: &Device, value: Option<Orientation>, get_size: F) -> bool where F: FnOnce(&Device) -> Size2D<Au>,150 fn eval_orientation_for<F>(device: &Device, value: Option<Orientation>, get_size: F) -> bool
151 where
152 F: FnOnce(&Device) -> Size2D<Au>,
153 {
154 let query_orientation = match value {
155 Some(v) => v,
156 None => return true,
157 };
158
159 let size = get_size(device);
160
161 // Per spec, square viewports should be 'portrait'
162 let is_landscape = size.width > size.height;
163 match query_orientation {
164 Orientation::Landscape => is_landscape,
165 Orientation::Portrait => !is_landscape,
166 }
167 }
168
169 /// https://drafts.csswg.org/mediaqueries-4/#orientation
eval_orientation(device: &Device, value: Option<Orientation>) -> bool170 fn eval_orientation(device: &Device, value: Option<Orientation>) -> bool {
171 eval_orientation_for(device, value, viewport_size)
172 }
173
174 /// FIXME: There's no spec for `-moz-device-orientation`.
eval_device_orientation(device: &Device, value: Option<Orientation>) -> bool175 fn eval_device_orientation(device: &Device, value: Option<Orientation>) -> bool {
176 eval_orientation_for(device, value, device_size)
177 }
178
179 /// Values for the display-mode media feature.
180 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
181 #[repr(u8)]
182 #[allow(missing_docs)]
183 pub enum DisplayMode {
184 Browser = 0,
185 MinimalUi,
186 Standalone,
187 Fullscreen,
188 }
189
190 /// https://w3c.github.io/manifest/#the-display-mode-media-feature
eval_display_mode(device: &Device, query_value: Option<DisplayMode>) -> bool191 fn eval_display_mode(device: &Device, query_value: Option<DisplayMode>) -> bool {
192 match query_value {
193 Some(v) => v == unsafe { bindings::Gecko_MediaFeatures_GetDisplayMode(device.document()) },
194 None => true,
195 }
196 }
197
198 /// https://drafts.csswg.org/mediaqueries-4/#grid
eval_grid(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool199 fn eval_grid(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
200 // Gecko doesn't support grid devices (e.g., ttys), so the 'grid' feature
201 // is always 0.
202 let supports_grid = false;
203 query_value.map_or(supports_grid, |v| v == supports_grid)
204 }
205
206 /// https://compat.spec.whatwg.org/#css-media-queries-webkit-transform-3d
eval_transform_3d(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool207 fn eval_transform_3d(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
208 let supports_transforms = true;
209 query_value.map_or(supports_transforms, |v| v == supports_transforms)
210 }
211
212 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
213 #[repr(u8)]
214 enum Scan {
215 Progressive,
216 Interlace,
217 }
218
219 /// https://drafts.csswg.org/mediaqueries-4/#scan
eval_scan(_: &Device, _: Option<Scan>) -> bool220 fn eval_scan(_: &Device, _: Option<Scan>) -> bool {
221 // Since Gecko doesn't support the 'tv' media type, the 'scan' feature never
222 // matches.
223 false
224 }
225
226 /// https://drafts.csswg.org/mediaqueries-4/#color
eval_color( device: &Device, query_value: Option<u32>, range_or_operator: Option<RangeOrOperator>, ) -> bool227 fn eval_color(
228 device: &Device,
229 query_value: Option<u32>,
230 range_or_operator: Option<RangeOrOperator>,
231 ) -> bool {
232 let color_bits_per_channel =
233 unsafe { bindings::Gecko_MediaFeatures_GetColorDepth(device.document()) };
234 RangeOrOperator::evaluate(range_or_operator, query_value, color_bits_per_channel)
235 }
236
237 /// https://drafts.csswg.org/mediaqueries-4/#color-index
eval_color_index( _: &Device, query_value: Option<u32>, range_or_operator: Option<RangeOrOperator>, ) -> bool238 fn eval_color_index(
239 _: &Device,
240 query_value: Option<u32>,
241 range_or_operator: Option<RangeOrOperator>,
242 ) -> bool {
243 // We should return zero if the device does not use a color lookup table.
244 let index = 0;
245 RangeOrOperator::evaluate(range_or_operator, query_value, index)
246 }
247
248 /// https://drafts.csswg.org/mediaqueries-4/#monochrome
eval_monochrome( _: &Device, query_value: Option<u32>, range_or_operator: Option<RangeOrOperator>, ) -> bool249 fn eval_monochrome(
250 _: &Device,
251 query_value: Option<u32>,
252 range_or_operator: Option<RangeOrOperator>,
253 ) -> bool {
254 // For color devices we should return 0.
255 // FIXME: On a monochrome device, return the actual color depth, not 0!
256 let depth = 0;
257 RangeOrOperator::evaluate(range_or_operator, query_value, depth)
258 }
259
260 /// https://drafts.csswg.org/mediaqueries-4/#resolution
eval_resolution( device: &Device, query_value: Option<Resolution>, range_or_operator: Option<RangeOrOperator>, ) -> bool261 fn eval_resolution(
262 device: &Device,
263 query_value: Option<Resolution>,
264 range_or_operator: Option<RangeOrOperator>,
265 ) -> bool {
266 let resolution_dppx = unsafe { bindings::Gecko_MediaFeatures_GetResolution(device.document()) };
267 RangeOrOperator::evaluate(
268 range_or_operator,
269 query_value.map(|r| r.dppx()),
270 resolution_dppx,
271 )
272 }
273
274 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
275 #[repr(u8)]
276 enum PrefersReducedMotion {
277 NoPreference,
278 Reduce,
279 }
280
281 /// Values for the prefers-color-scheme media feature.
282 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
283 #[repr(u8)]
284 #[allow(missing_docs)]
285 pub enum PrefersColorScheme {
286 Light,
287 Dark,
288 NoPreference,
289 }
290
291 /// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReducedMotion>) -> bool292 fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReducedMotion>) -> bool {
293 let prefers_reduced =
294 unsafe { bindings::Gecko_MediaFeatures_PrefersReducedMotion(device.document()) };
295 let query_value = match query_value {
296 Some(v) => v,
297 None => return prefers_reduced,
298 };
299
300 match query_value {
301 PrefersReducedMotion::NoPreference => !prefers_reduced,
302 PrefersReducedMotion::Reduce => prefers_reduced,
303 }
304 }
305
306 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
307 #[repr(u8)]
308 enum OverflowBlock {
309 None,
310 Scroll,
311 OptionalPaged,
312 Paged,
313 }
314
315 /// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-block
eval_overflow_block(device: &Device, query_value: Option<OverflowBlock>) -> bool316 fn eval_overflow_block(device: &Device, query_value: Option<OverflowBlock>) -> bool {
317 // For the time being, assume that printing (including previews)
318 // is the only time when we paginate, and we are otherwise always
319 // scrolling. This is true at the moment in Firefox, but may need
320 // updating in the future (e.g., ebook readers built with Stylo, a
321 // billboard mode that doesn't support overflow at all).
322 //
323 // If this ever changes, don't forget to change eval_overflow_inline too.
324 let scrolling = device.media_type() != MediaType::print();
325 let query_value = match query_value {
326 Some(v) => v,
327 None => return true,
328 };
329
330 match query_value {
331 OverflowBlock::None | OverflowBlock::OptionalPaged => false,
332 OverflowBlock::Scroll => scrolling,
333 OverflowBlock::Paged => !scrolling,
334 }
335 }
336
337 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
338 #[repr(u8)]
339 enum OverflowInline {
340 None,
341 Scroll,
342 }
343
344 /// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-inline
eval_overflow_inline(device: &Device, query_value: Option<OverflowInline>) -> bool345 fn eval_overflow_inline(device: &Device, query_value: Option<OverflowInline>) -> bool {
346 // See the note in eval_overflow_block.
347 let scrolling = device.media_type() != MediaType::print();
348 let query_value = match query_value {
349 Some(v) => v,
350 None => return scrolling,
351 };
352
353 match query_value {
354 OverflowInline::None => !scrolling,
355 OverflowInline::Scroll => scrolling,
356 }
357 }
358
359 /// https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme
eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorScheme>) -> bool360 fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorScheme>) -> bool {
361 let prefers_color_scheme =
362 unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
363 match query_value {
364 Some(v) => prefers_color_scheme == v,
365 None => prefers_color_scheme != PrefersColorScheme::NoPreference,
366 }
367 }
368
369 bitflags! {
370 /// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
371 struct PointerCapabilities: u8 {
372 const COARSE = structs::PointerCapabilities_Coarse;
373 const FINE = structs::PointerCapabilities_Fine;
374 const HOVER = structs::PointerCapabilities_Hover;
375 }
376 }
377
primary_pointer_capabilities(device: &Device) -> PointerCapabilities378 fn primary_pointer_capabilities(device: &Device) -> PointerCapabilities {
379 PointerCapabilities::from_bits_truncate(unsafe {
380 bindings::Gecko_MediaFeatures_PrimaryPointerCapabilities(device.document())
381 })
382 }
383
all_pointer_capabilities(device: &Device) -> PointerCapabilities384 fn all_pointer_capabilities(device: &Device) -> PointerCapabilities {
385 PointerCapabilities::from_bits_truncate(unsafe {
386 bindings::Gecko_MediaFeatures_AllPointerCapabilities(device.document())
387 })
388 }
389
390 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
391 #[repr(u8)]
392 enum Pointer {
393 None,
394 Coarse,
395 Fine,
396 }
397
eval_pointer_capabilities( query_value: Option<Pointer>, pointer_capabilities: PointerCapabilities, ) -> bool398 fn eval_pointer_capabilities(
399 query_value: Option<Pointer>,
400 pointer_capabilities: PointerCapabilities,
401 ) -> bool {
402 let query_value = match query_value {
403 Some(v) => v,
404 None => return !pointer_capabilities.is_empty(),
405 };
406
407 match query_value {
408 Pointer::None => pointer_capabilities.is_empty(),
409 Pointer::Coarse => pointer_capabilities.intersects(PointerCapabilities::COARSE),
410 Pointer::Fine => pointer_capabilities.intersects(PointerCapabilities::FINE),
411 }
412 }
413
414 /// https://drafts.csswg.org/mediaqueries-4/#pointer
eval_pointer(device: &Device, query_value: Option<Pointer>) -> bool415 fn eval_pointer(device: &Device, query_value: Option<Pointer>) -> bool {
416 eval_pointer_capabilities(query_value, primary_pointer_capabilities(device))
417 }
418
419 /// https://drafts.csswg.org/mediaqueries-4/#descdef-media-any-pointer
eval_any_pointer(device: &Device, query_value: Option<Pointer>) -> bool420 fn eval_any_pointer(device: &Device, query_value: Option<Pointer>) -> bool {
421 eval_pointer_capabilities(query_value, all_pointer_capabilities(device))
422 }
423
424 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
425 #[repr(u8)]
426 enum Hover {
427 None,
428 Hover,
429 }
430
eval_hover_capabilities( query_value: Option<Hover>, pointer_capabilities: PointerCapabilities, ) -> bool431 fn eval_hover_capabilities(
432 query_value: Option<Hover>,
433 pointer_capabilities: PointerCapabilities,
434 ) -> bool {
435 let can_hover = pointer_capabilities.intersects(PointerCapabilities::HOVER);
436 let query_value = match query_value {
437 Some(v) => v,
438 None => return can_hover,
439 };
440
441 match query_value {
442 Hover::None => !can_hover,
443 Hover::Hover => can_hover,
444 }
445 }
446
447 /// https://drafts.csswg.org/mediaqueries-4/#hover
eval_hover(device: &Device, query_value: Option<Hover>) -> bool448 fn eval_hover(device: &Device, query_value: Option<Hover>) -> bool {
449 eval_hover_capabilities(query_value, primary_pointer_capabilities(device))
450 }
451
452 /// https://drafts.csswg.org/mediaqueries-4/#descdef-media-any-hover
eval_any_hover(device: &Device, query_value: Option<Hover>) -> bool453 fn eval_any_hover(device: &Device, query_value: Option<Hover>) -> bool {
454 eval_hover_capabilities(query_value, all_pointer_capabilities(device))
455 }
456
eval_moz_is_glyph( device: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>, ) -> bool457 fn eval_moz_is_glyph(
458 device: &Device,
459 query_value: Option<bool>,
460 _: Option<RangeOrOperator>,
461 ) -> bool {
462 let is_glyph = device.document().mIsSVGGlyphsDocument();
463 query_value.map_or(is_glyph, |v| v == is_glyph)
464 }
465
eval_moz_is_resource_document( device: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>, ) -> bool466 fn eval_moz_is_resource_document(
467 device: &Device,
468 query_value: Option<bool>,
469 _: Option<RangeOrOperator>,
470 ) -> bool {
471 let is_resource_doc =
472 unsafe { bindings::Gecko_MediaFeatures_IsResourceDocument(device.document()) };
473 query_value.map_or(is_resource_doc, |v| v == is_resource_doc)
474 }
475
eval_system_metric( device: &Device, query_value: Option<bool>, metric: Atom, accessible_from_content: bool, ) -> bool476 fn eval_system_metric(
477 device: &Device,
478 query_value: Option<bool>,
479 metric: Atom,
480 accessible_from_content: bool,
481 ) -> bool {
482 let supports_metric = unsafe {
483 bindings::Gecko_MediaFeatures_HasSystemMetric(
484 device.document(),
485 metric.as_ptr(),
486 accessible_from_content,
487 )
488 };
489 query_value.map_or(supports_metric, |v| v == supports_metric)
490 }
491
eval_moz_touch_enabled( device: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>, ) -> bool492 fn eval_moz_touch_enabled(
493 device: &Device,
494 query_value: Option<bool>,
495 _: Option<RangeOrOperator>,
496 ) -> bool {
497 eval_system_metric(
498 device,
499 query_value,
500 atom!("-moz-touch-enabled"),
501 /* accessible_from_content = */ true,
502 )
503 }
504
eval_moz_os_version( device: &Device, query_value: Option<Atom>, _: Option<RangeOrOperator>, ) -> bool505 fn eval_moz_os_version(
506 device: &Device,
507 query_value: Option<Atom>,
508 _: Option<RangeOrOperator>,
509 ) -> bool {
510 let query_value = match query_value {
511 Some(v) => v,
512 None => return false,
513 };
514
515 let os_version =
516 unsafe { bindings::Gecko_MediaFeatures_GetOperatingSystemVersion(device.document()) };
517
518 query_value.as_ptr() == os_version
519 }
520
521 macro_rules! system_metric_feature {
522 ($feature_name:expr) => {{
523 fn __eval(device: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
524 eval_system_metric(
525 device,
526 query_value,
527 $feature_name,
528 /* accessible_from_content = */ false,
529 )
530 }
531
532 feature!(
533 $feature_name,
534 AllowsRanges::No,
535 Evaluator::BoolInteger(__eval),
536 ParsingRequirements::CHROME_AND_UA_ONLY,
537 )
538 }};
539 }
540
541 lazy_static! {
542 /// Adding new media features requires (1) adding the new feature to this
543 /// array, with appropriate entries (and potentially any new code needed
544 /// to support new types in these entries and (2) ensuring that either
545 /// nsPresContext::MediaFeatureValuesChanged is called when the value that
546 /// would be returned by the evaluator function could change.
547 pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 53] = [
548 feature!(
549 atom!("width"),
550 AllowsRanges::Yes,
551 Evaluator::Length(eval_width),
552 ParsingRequirements::empty(),
553 ),
554 feature!(
555 atom!("height"),
556 AllowsRanges::Yes,
557 Evaluator::Length(eval_height),
558 ParsingRequirements::empty(),
559 ),
560 feature!(
561 atom!("aspect-ratio"),
562 AllowsRanges::Yes,
563 Evaluator::NumberRatio(eval_aspect_ratio),
564 ParsingRequirements::empty(),
565 ),
566 feature!(
567 atom!("orientation"),
568 AllowsRanges::No,
569 keyword_evaluator!(eval_orientation, Orientation),
570 ParsingRequirements::empty(),
571 ),
572 feature!(
573 atom!("device-width"),
574 AllowsRanges::Yes,
575 Evaluator::Length(eval_device_width),
576 ParsingRequirements::empty(),
577 ),
578 feature!(
579 atom!("device-height"),
580 AllowsRanges::Yes,
581 Evaluator::Length(eval_device_height),
582 ParsingRequirements::empty(),
583 ),
584 feature!(
585 atom!("device-aspect-ratio"),
586 AllowsRanges::Yes,
587 Evaluator::NumberRatio(eval_device_aspect_ratio),
588 ParsingRequirements::empty(),
589 ),
590 feature!(
591 atom!("-moz-device-orientation"),
592 AllowsRanges::No,
593 keyword_evaluator!(eval_device_orientation, Orientation),
594 ParsingRequirements::empty(),
595 ),
596 // Webkit extensions that we support for de-facto web compatibility.
597 // -webkit-{min|max}-device-pixel-ratio (controlled with its own pref):
598 feature!(
599 atom!("device-pixel-ratio"),
600 AllowsRanges::Yes,
601 Evaluator::Float(eval_device_pixel_ratio),
602 ParsingRequirements::WEBKIT_PREFIX,
603 ),
604 // -webkit-transform-3d.
605 feature!(
606 atom!("transform-3d"),
607 AllowsRanges::No,
608 Evaluator::BoolInteger(eval_transform_3d),
609 ParsingRequirements::WEBKIT_PREFIX,
610 ),
611 feature!(
612 atom!("-moz-device-pixel-ratio"),
613 AllowsRanges::Yes,
614 Evaluator::Float(eval_device_pixel_ratio),
615 ParsingRequirements::empty(),
616 ),
617 feature!(
618 atom!("resolution"),
619 AllowsRanges::Yes,
620 Evaluator::Resolution(eval_resolution),
621 ParsingRequirements::empty(),
622 ),
623 feature!(
624 atom!("display-mode"),
625 AllowsRanges::No,
626 keyword_evaluator!(eval_display_mode, DisplayMode),
627 ParsingRequirements::empty(),
628 ),
629 feature!(
630 atom!("grid"),
631 AllowsRanges::No,
632 Evaluator::BoolInteger(eval_grid),
633 ParsingRequirements::empty(),
634 ),
635 feature!(
636 atom!("scan"),
637 AllowsRanges::No,
638 keyword_evaluator!(eval_scan, Scan),
639 ParsingRequirements::empty(),
640 ),
641 feature!(
642 atom!("color"),
643 AllowsRanges::Yes,
644 Evaluator::Integer(eval_color),
645 ParsingRequirements::empty(),
646 ),
647 feature!(
648 atom!("color-index"),
649 AllowsRanges::Yes,
650 Evaluator::Integer(eval_color_index),
651 ParsingRequirements::empty(),
652 ),
653 feature!(
654 atom!("monochrome"),
655 AllowsRanges::Yes,
656 Evaluator::Integer(eval_monochrome),
657 ParsingRequirements::empty(),
658 ),
659 feature!(
660 atom!("prefers-reduced-motion"),
661 AllowsRanges::No,
662 keyword_evaluator!(eval_prefers_reduced_motion, PrefersReducedMotion),
663 ParsingRequirements::empty(),
664 ),
665 feature!(
666 atom!("overflow-block"),
667 AllowsRanges::No,
668 keyword_evaluator!(eval_overflow_block, OverflowBlock),
669 ParsingRequirements::empty(),
670 ),
671 feature!(
672 atom!("overflow-inline"),
673 AllowsRanges::No,
674 keyword_evaluator!(eval_overflow_inline, OverflowInline),
675 ParsingRequirements::empty(),
676 ),
677 feature!(
678 atom!("prefers-color-scheme"),
679 AllowsRanges::No,
680 keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
681 ParsingRequirements::empty(),
682 ),
683 feature!(
684 atom!("pointer"),
685 AllowsRanges::No,
686 keyword_evaluator!(eval_pointer, Pointer),
687 ParsingRequirements::empty(),
688 ),
689 feature!(
690 atom!("any-pointer"),
691 AllowsRanges::No,
692 keyword_evaluator!(eval_any_pointer, Pointer),
693 ParsingRequirements::empty(),
694 ),
695 feature!(
696 atom!("hover"),
697 AllowsRanges::No,
698 keyword_evaluator!(eval_hover, Hover),
699 ParsingRequirements::empty(),
700 ),
701 feature!(
702 atom!("any-hover"),
703 AllowsRanges::No,
704 keyword_evaluator!(eval_any_hover, Hover),
705 ParsingRequirements::empty(),
706 ),
707
708 // Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
709 // Internal because it is really only useful in the user agent anyway
710 // and therefore not worth standardizing.
711 feature!(
712 atom!("-moz-is-glyph"),
713 AllowsRanges::No,
714 Evaluator::BoolInteger(eval_moz_is_glyph),
715 ParsingRequirements::CHROME_AND_UA_ONLY,
716 ),
717 feature!(
718 atom!("-moz-is-resource-document"),
719 AllowsRanges::No,
720 Evaluator::BoolInteger(eval_moz_is_resource_document),
721 ParsingRequirements::CHROME_AND_UA_ONLY,
722 ),
723 feature!(
724 atom!("-moz-os-version"),
725 AllowsRanges::No,
726 Evaluator::Ident(eval_moz_os_version),
727 ParsingRequirements::CHROME_AND_UA_ONLY,
728 ),
729 system_metric_feature!(atom!("-moz-scrollbar-start-backward")),
730 system_metric_feature!(atom!("-moz-scrollbar-start-forward")),
731 system_metric_feature!(atom!("-moz-scrollbar-end-backward")),
732 system_metric_feature!(atom!("-moz-scrollbar-end-forward")),
733 system_metric_feature!(atom!("-moz-scrollbar-thumb-proportional")),
734 system_metric_feature!(atom!("-moz-overlay-scrollbars")),
735 system_metric_feature!(atom!("-moz-windows-default-theme")),
736 system_metric_feature!(atom!("-moz-mac-graphite-theme")),
737 system_metric_feature!(atom!("-moz-mac-yosemite-theme")),
738 system_metric_feature!(atom!("-moz-windows-accent-color-in-titlebar")),
739 system_metric_feature!(atom!("-moz-windows-compositor")),
740 system_metric_feature!(atom!("-moz-windows-classic")),
741 system_metric_feature!(atom!("-moz-windows-glass")),
742 system_metric_feature!(atom!("-moz-menubar-drag")),
743 system_metric_feature!(atom!("-moz-swipe-animation-enabled")),
744 system_metric_feature!(atom!("-moz-gtk-csd-available")),
745 system_metric_feature!(atom!("-moz-gtk-csd-hide-titlebar-by-default")),
746 system_metric_feature!(atom!("-moz-gtk-csd-transparent-background")),
747 system_metric_feature!(atom!("-moz-gtk-csd-minimize-button")),
748 system_metric_feature!(atom!("-moz-gtk-csd-maximize-button")),
749 system_metric_feature!(atom!("-moz-gtk-csd-close-button")),
750 system_metric_feature!(atom!("-moz-gtk-csd-reversed-placement")),
751 system_metric_feature!(atom!("-moz-system-dark-theme")),
752 // This is the only system-metric media feature that's accessible to
753 // content as of today.
754 // FIXME(emilio): Restrict (or remove?) when bug 1035774 lands.
755 feature!(
756 atom!("-moz-touch-enabled"),
757 AllowsRanges::No,
758 Evaluator::BoolInteger(eval_moz_touch_enabled),
759 ParsingRequirements::empty(),
760 ),
761 ];
762 }
763