1use crate::derives::*;
8use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription};
9use crate::queries::values::{Orientation, PrefersColorScheme};
10use crate::values::computed::{CSSPixelLength, Context, Ratio, Resolution};
11use std::fmt::Debug;
12
13fn eval_width(context: &Context) -> CSSPixelLength {
15 CSSPixelLength::new(context.device().au_viewport_size().width.to_f32_px())
16}
17
18fn eval_height(context: &Context) -> CSSPixelLength {
20 CSSPixelLength::new(context.device().au_viewport_size().height.to_f32_px())
21}
22
23fn eval_device_width(context: &Context) -> CSSPixelLength {
25 let device = context.device();
26 let scaled = device.device_size() / device.device_pixel_ratio();
27 CSSPixelLength::new(scaled.width)
28}
29
30fn eval_device_height(context: &Context) -> CSSPixelLength {
32 let device = context.device();
33 let scaled = device.device_size() / device.device_pixel_ratio();
34 CSSPixelLength::new(scaled.height)
35}
36
37fn eval_orientation(context: &Context, value: Option<Orientation>) -> bool {
39 Orientation::eval(context.device().au_viewport_size(), value)
40}
41
42#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
43#[repr(u8)]
44enum Scan {
45 Progressive,
46 Interlace,
47}
48
49fn eval_scan(_: &Context, _: Option<Scan>) -> bool {
51 false
54}
55
56fn eval_resolution(context: &Context) -> Resolution {
58 Resolution::from_dppx(context.device().device_pixel_ratio().0)
59}
60
61fn eval_device_pixel_ratio(context: &Context) -> f32 {
63 eval_resolution(context).dppx()
64}
65
66fn eval_prefers_color_scheme(context: &Context, query_value: Option<PrefersColorScheme>) -> bool {
67 match query_value {
68 Some(v) => context.device().color_scheme() == v,
69 None => true,
70 }
71}
72
73bitflags! {
74 #[derive(Debug, Clone, Copy)]
76 pub struct PointerCapabilities: u8 {
77 const COARSE = 0b001;
79 const FINE = 0b010;
81 const HOVER = 0b100;
83 }
84}
85
86impl Default for PointerCapabilities {
87 #[cfg(any(target_os = "ios", target_os = "android", target_env = "ohos"))]
88 fn default() -> Self {
89 PointerCapabilities::COARSE
90 }
91 #[cfg(not(any(target_os = "ios", target_os = "android", target_env = "ohos")))]
92 fn default() -> Self {
93 PointerCapabilities::FINE | PointerCapabilities::HOVER
94 }
95}
96
97#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
98#[repr(u8)]
99enum Pointer {
100 None,
101 Coarse,
102 Fine,
103}
104
105fn eval_pointer_capabilities(
106 query_value: Option<Pointer>,
107 pointer_capabilities: PointerCapabilities,
108) -> bool {
109 match query_value {
110 None => !pointer_capabilities.is_empty(),
111 Some(Pointer::None) => pointer_capabilities.is_empty(),
112 Some(Pointer::Coarse) => pointer_capabilities.intersects(PointerCapabilities::COARSE),
113 Some(Pointer::Fine) => pointer_capabilities.intersects(PointerCapabilities::FINE),
114 }
115}
116
117fn eval_pointer(context: &Context, query_value: Option<Pointer>) -> bool {
119 eval_pointer_capabilities(query_value, context.device().primary_pointer_capabilities())
120}
121
122fn eval_any_pointer(context: &Context, query_value: Option<Pointer>) -> bool {
124 eval_pointer_capabilities(query_value, context.device().all_pointer_capabilities())
125}
126
127#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
128#[repr(u8)]
129enum Hover {
130 None,
131 Hover,
132}
133
134fn eval_hover_capabilities(
135 query_value: Option<Hover>,
136 pointer_capabilities: PointerCapabilities,
137) -> bool {
138 let can_hover = pointer_capabilities.intersects(PointerCapabilities::HOVER);
139 match query_value {
140 Some(Hover::None) => !can_hover,
141 Some(Hover::Hover) => can_hover,
142 None => return can_hover,
143 }
144}
145
146fn eval_hover(context: &Context, query_value: Option<Hover>) -> bool {
148 eval_hover_capabilities(query_value, context.device().primary_pointer_capabilities())
149}
150
151fn eval_any_hover(context: &Context, query_value: Option<Hover>) -> bool {
153 eval_hover_capabilities(query_value, context.device().all_pointer_capabilities())
154}
155
156fn eval_aspect_ratio(context: &Context) -> Ratio {
158 let size = context.device().au_viewport_size();
159 Ratio::new(size.width.0 as f32, size.height.0 as f32)
160}
161
162pub static MEDIA_FEATURES: [QueryFeatureDescription; 15] = [
164 feature!(
165 atom!("width"),
166 AllowsRanges::Yes,
167 Evaluator::Length(eval_width),
168 FeatureFlags::VIEWPORT_DEPENDENT,
169 ),
170 feature!(
171 atom!("height"),
172 AllowsRanges::Yes,
173 Evaluator::Length(eval_height),
174 FeatureFlags::VIEWPORT_DEPENDENT,
175 ),
176 feature!(
177 atom!("orientation"),
178 AllowsRanges::No,
179 keyword_evaluator!(eval_orientation, Orientation),
180 FeatureFlags::VIEWPORT_DEPENDENT,
181 ),
182 feature!(
183 atom!("pointer"),
184 AllowsRanges::No,
185 keyword_evaluator!(eval_pointer, Pointer),
186 FeatureFlags::empty(),
187 ),
188 feature!(
189 atom!("any-pointer"),
190 AllowsRanges::No,
191 keyword_evaluator!(eval_any_pointer, Pointer),
192 FeatureFlags::empty(),
193 ),
194 feature!(
195 atom!("hover"),
196 AllowsRanges::No,
197 keyword_evaluator!(eval_hover, Hover),
198 FeatureFlags::empty(),
199 ),
200 feature!(
201 atom!("any-hover"),
202 AllowsRanges::No,
203 keyword_evaluator!(eval_any_hover, Hover),
204 FeatureFlags::empty(),
205 ),
206 feature!(
207 atom!("aspect-ratio"),
208 AllowsRanges::Yes,
209 Evaluator::NumberRatio(eval_aspect_ratio),
210 FeatureFlags::VIEWPORT_DEPENDENT,
211 ),
212 feature!(
213 atom!("device-width"),
214 AllowsRanges::Yes,
215 Evaluator::Length(eval_device_width),
216 FeatureFlags::empty(),
217 ),
218 feature!(
219 atom!("device-height"),
220 AllowsRanges::Yes,
221 Evaluator::Length(eval_device_height),
222 FeatureFlags::empty(),
223 ),
224 feature!(
225 atom!("scan"),
226 AllowsRanges::No,
227 keyword_evaluator!(eval_scan, Scan),
228 FeatureFlags::empty(),
229 ),
230 feature!(
231 atom!("resolution"),
232 AllowsRanges::Yes,
233 Evaluator::Resolution(eval_resolution),
234 FeatureFlags::empty(),
235 ),
236 feature!(
237 atom!("device-pixel-ratio"),
238 AllowsRanges::Yes,
239 Evaluator::Float(eval_device_pixel_ratio),
240 FeatureFlags::WEBKIT_PREFIX,
241 ),
242 feature!(
243 atom!("-moz-device-pixel-ratio"),
244 AllowsRanges::Yes,
245 Evaluator::Float(eval_device_pixel_ratio),
246 FeatureFlags::empty(),
247 ),
248 feature!(
249 atom!("prefers-color-scheme"),
250 AllowsRanges::No,
251 keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
252 FeatureFlags::empty(),
253 ),
254];