Skip to main content

style/servo/
media_features.rs

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//! Servo's media feature list and evaluator.
6
7use crate::derives::*;
8use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription};
9use crate::queries::values::PrefersColorScheme;
10use crate::values::computed::{CSSPixelLength, Context, Resolution};
11use std::fmt::Debug;
12
13/// https://drafts.csswg.org/mediaqueries-4/#width
14fn eval_width(context: &Context) -> CSSPixelLength {
15    CSSPixelLength::new(context.device().au_viewport_size().width.to_f32_px())
16}
17
18#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
19#[repr(u8)]
20enum Scan {
21    Progressive,
22    Interlace,
23}
24
25/// https://drafts.csswg.org/mediaqueries-4/#scan
26fn eval_scan(_: &Context, _: Option<Scan>) -> bool {
27    // Since we doesn't support the 'tv' media type, the 'scan' feature never
28    // matches.
29    false
30}
31
32/// https://drafts.csswg.org/mediaqueries-4/#resolution
33fn eval_resolution(context: &Context) -> Resolution {
34    Resolution::from_dppx(context.device().device_pixel_ratio().0)
35}
36
37/// https://compat.spec.whatwg.org/#css-media-queries-webkit-device-pixel-ratio
38fn eval_device_pixel_ratio(context: &Context) -> f32 {
39    eval_resolution(context).dppx()
40}
41
42fn eval_prefers_color_scheme(context: &Context, query_value: Option<PrefersColorScheme>) -> bool {
43    match query_value {
44        Some(v) => context.device().color_scheme() == v,
45        None => true,
46    }
47}
48
49bitflags! {
50    /// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
51    #[derive(Debug, Clone, Copy)]
52    pub struct PointerCapabilities: u8 {
53        /// The input mechanism includes a pointing device of limited accuracy, such as a finger on a touchscreen.
54        const COARSE = 0b001;
55        /// The input mechanism includes an accurate pointing device, such as a mouse.
56        const FINE = 0b010;
57        /// The input mechanism can conveniently hover over elements.
58        const HOVER = 0b100;
59    }
60}
61
62impl Default for PointerCapabilities {
63    #[cfg(any(target_os = "ios", target_os = "android", target_env = "ohos"))]
64    fn default() -> Self {
65        PointerCapabilities::COARSE
66    }
67    #[cfg(not(any(target_os = "ios", target_os = "android", target_env = "ohos")))]
68    fn default() -> Self {
69        PointerCapabilities::FINE | PointerCapabilities::HOVER
70    }
71}
72
73#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
74#[repr(u8)]
75enum Pointer {
76    None,
77    Coarse,
78    Fine,
79}
80
81fn eval_pointer_capabilities(
82    query_value: Option<Pointer>,
83    pointer_capabilities: PointerCapabilities,
84) -> bool {
85    match query_value {
86        None => !pointer_capabilities.is_empty(),
87        Some(Pointer::None) => pointer_capabilities.is_empty(),
88        Some(Pointer::Coarse) => pointer_capabilities.intersects(PointerCapabilities::COARSE),
89        Some(Pointer::Fine) => pointer_capabilities.intersects(PointerCapabilities::FINE),
90    }
91}
92
93/// https://drafts.csswg.org/mediaqueries-4/#pointer
94fn eval_pointer(context: &Context, query_value: Option<Pointer>) -> bool {
95    eval_pointer_capabilities(query_value, context.device().primary_pointer_capabilities())
96}
97
98/// https://drafts.csswg.org/mediaqueries-4/#descdef-media-any-pointer
99fn eval_any_pointer(context: &Context, query_value: Option<Pointer>) -> bool {
100    eval_pointer_capabilities(query_value, context.device().all_pointer_capabilities())
101}
102
103#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
104#[repr(u8)]
105enum Hover {
106    None,
107    Hover,
108}
109
110fn eval_hover_capabilities(
111    query_value: Option<Hover>,
112    pointer_capabilities: PointerCapabilities,
113) -> bool {
114    let can_hover = pointer_capabilities.intersects(PointerCapabilities::HOVER);
115    match query_value {
116        Some(Hover::None) => !can_hover,
117        Some(Hover::Hover) => can_hover,
118        None => return can_hover,
119    }
120}
121
122/// https://drafts.csswg.org/mediaqueries-4/#hover
123fn eval_hover(context: &Context, query_value: Option<Hover>) -> bool {
124    eval_hover_capabilities(query_value, context.device().primary_pointer_capabilities())
125}
126
127/// https://drafts.csswg.org/mediaqueries-4/#descdef-media-any-hover
128fn eval_any_hover(context: &Context, query_value: Option<Hover>) -> bool {
129    eval_hover_capabilities(query_value, context.device().all_pointer_capabilities())
130}
131
132/// A list with all the media features that Servo supports.
133pub static MEDIA_FEATURES: [QueryFeatureDescription; 10] = [
134    feature!(
135        atom!("width"),
136        AllowsRanges::Yes,
137        Evaluator::Length(eval_width),
138        FeatureFlags::empty(),
139    ),
140    feature!(
141        atom!("pointer"),
142        AllowsRanges::No,
143        keyword_evaluator!(eval_pointer, Pointer),
144        FeatureFlags::empty(),
145    ),
146    feature!(
147        atom!("any-pointer"),
148        AllowsRanges::No,
149        keyword_evaluator!(eval_any_pointer, Pointer),
150        FeatureFlags::empty(),
151    ),
152    feature!(
153        atom!("hover"),
154        AllowsRanges::No,
155        keyword_evaluator!(eval_hover, Hover),
156        FeatureFlags::empty(),
157    ),
158    feature!(
159        atom!("any-hover"),
160        AllowsRanges::No,
161        keyword_evaluator!(eval_any_hover, Hover),
162        FeatureFlags::empty(),
163    ),
164    feature!(
165        atom!("scan"),
166        AllowsRanges::No,
167        keyword_evaluator!(eval_scan, Scan),
168        FeatureFlags::empty(),
169    ),
170    feature!(
171        atom!("resolution"),
172        AllowsRanges::Yes,
173        Evaluator::Resolution(eval_resolution),
174        FeatureFlags::empty(),
175    ),
176    feature!(
177        atom!("device-pixel-ratio"),
178        AllowsRanges::Yes,
179        Evaluator::Float(eval_device_pixel_ratio),
180        FeatureFlags::WEBKIT_PREFIX,
181    ),
182    feature!(
183        atom!("-moz-device-pixel-ratio"),
184        AllowsRanges::Yes,
185        Evaluator::Float(eval_device_pixel_ratio),
186        FeatureFlags::empty(),
187    ),
188    feature!(
189        atom!("prefers-color-scheme"),
190        AllowsRanges::No,
191        keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
192        FeatureFlags::empty(),
193    ),
194];