1use crate::color::AbsoluteColor;
8use crate::context::QuirksMode;
9use crate::custom_properties::CssEnvironment;
10use crate::font_metrics::FontMetrics;
11use crate::logical_geometry::WritingMode;
12use crate::media_queries::MediaType;
13use crate::properties::style_structs::Font;
14use crate::properties::ComputedValues;
15use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription};
16use crate::queries::values::PrefersColorScheme;
17use crate::values::computed::font::GenericFontFamily;
18use crate::values::computed::{
19 CSSPixelLength, Context, Length, LineHeight, NonNegativeLength, Resolution,
20};
21use crate::values::specified::color::{ColorSchemeFlags, ForcedColors};
22use crate::values::specified::font::{
23 QueryFontMetricsFlags, FONT_MEDIUM_LINE_HEIGHT_PX, FONT_MEDIUM_PX,
24};
25use crate::values::specified::ViewportVariant;
26use crate::values::KeyframesName;
27use app_units::{Au, AU_PER_PX};
28use euclid::default::Size2D as UntypedSize2D;
29use euclid::{Scale, SideOffsets2D, Size2D};
30use mime::Mime;
31use servo_arc::Arc;
32use std::fmt::Debug;
33use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
34use style_traits::{CSSPixel, DevicePixel};
35
36pub trait FontMetricsProvider: Debug + Sync {
39 fn query_font_metrics(
41 &self,
42 vertical: bool,
43 font: &Font,
44 base_size: CSSPixelLength,
45 flags: QueryFontMetricsFlags,
46 ) -> FontMetrics;
47 fn base_size_for_generic(&self, generic: GenericFontFamily) -> Length;
49}
50
51#[derive(Debug, MallocSizeOf)]
56pub struct Device {
57 media_type: MediaType,
59 viewport_size: Size2D<f32, CSSPixel>,
61 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
63 #[ignore_malloc_size_of = "Pure stack type"]
65 quirks_mode: QuirksMode,
66
67 #[ignore_malloc_size_of = "Pure stack type"]
76 root_font_size: AtomicU32,
77 #[ignore_malloc_size_of = "Pure stack type"]
79 root_line_height: AtomicU32,
80 #[ignore_malloc_size_of = "Pure stack type"]
83 used_root_font_size: AtomicBool,
84 #[ignore_malloc_size_of = "Pure stack type"]
87 used_root_line_height: AtomicBool,
88 used_font_metrics: AtomicBool,
90 #[ignore_malloc_size_of = "Pure stack type"]
92 used_viewport_units: AtomicBool,
93 #[ignore_malloc_size_of = "Pure stack type"]
95 prefers_color_scheme: PrefersColorScheme,
96 environment: CssEnvironment,
99 #[ignore_malloc_size_of = "Owned by embedder"]
101 font_metrics_provider: Box<dyn FontMetricsProvider>,
102 #[ignore_malloc_size_of = "Arc is shared"]
104 default_computed_values: Arc<ComputedValues>,
105}
106
107impl Device {
108 pub fn new(
110 media_type: MediaType,
111 quirks_mode: QuirksMode,
112 viewport_size: Size2D<f32, CSSPixel>,
113 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
114 font_metrics_provider: Box<dyn FontMetricsProvider>,
115 default_computed_values: Arc<ComputedValues>,
116 prefers_color_scheme: PrefersColorScheme,
117 ) -> Device {
118 Device {
119 media_type,
120 viewport_size,
121 device_pixel_ratio,
122 quirks_mode,
123 root_font_size: AtomicU32::new(FONT_MEDIUM_PX.to_bits()),
124 root_line_height: AtomicU32::new(FONT_MEDIUM_LINE_HEIGHT_PX.to_bits()),
125 used_root_font_size: AtomicBool::new(false),
126 used_root_line_height: AtomicBool::new(false),
127 used_font_metrics: AtomicBool::new(false),
128 used_viewport_units: AtomicBool::new(false),
129 prefers_color_scheme,
130 environment: CssEnvironment,
131 font_metrics_provider,
132 default_computed_values,
133 }
134 }
135
136 #[inline]
138 pub fn environment(&self) -> &CssEnvironment {
139 &self.environment
140 }
141
142 pub fn default_computed_values(&self) -> &ComputedValues {
144 &self.default_computed_values
145 }
146
147 pub fn root_font_size(&self) -> CSSPixelLength {
149 self.used_root_font_size.store(true, Ordering::Relaxed);
150 CSSPixelLength::new(f32::from_bits(self.root_font_size.load(Ordering::Relaxed)))
151 }
152
153 pub fn set_root_font_size(&self, size: f32) {
155 self.root_font_size.store(size.to_bits(), Ordering::Relaxed)
156 }
157
158 pub fn root_line_height(&self) -> CSSPixelLength {
160 self.used_root_line_height.store(true, Ordering::Relaxed);
161 CSSPixelLength::new(f32::from_bits(
162 self.root_line_height.load(Ordering::Relaxed),
163 ))
164 }
165
166 pub fn set_root_line_height(&self, size: f32) {
168 self.root_line_height
169 .store(size.to_bits(), Ordering::Relaxed);
170 }
171
172 pub fn calc_line_height(
176 &self,
177 font: &crate::properties::style_structs::Font,
178 _writing_mode: WritingMode,
179 _element: Option<()>,
180 ) -> NonNegativeLength {
181 (match font.line_height {
182 LineHeight::Normal => CSSPixelLength::new(0.),
184 LineHeight::Number(number) => font.font_size.computed_size() * number.0,
185 LineHeight::Length(length) => length.0,
186 })
187 .into()
188 }
189
190 pub fn quirks_mode(&self) -> QuirksMode {
192 self.quirks_mode
193 }
194
195 pub fn set_body_text_color(&self, _color: AbsoluteColor) {
199 }
201
202 pub fn base_size_for_generic(&self, generic: GenericFontFamily) -> Length {
204 self.font_metrics_provider.base_size_for_generic(generic)
205 }
206
207 pub fn animation_name_may_be_referenced(&self, _: &KeyframesName) -> bool {
209 true
211 }
212
213 pub fn used_root_font_size(&self) -> bool {
215 self.used_root_font_size.load(Ordering::Relaxed)
216 }
217
218 pub fn used_root_line_height(&self) -> bool {
220 self.used_root_line_height.load(Ordering::Relaxed)
221 }
222
223 pub fn used_font_metrics(&self) -> bool {
225 self.used_font_metrics.load(Ordering::Relaxed)
226 }
227
228 pub fn viewport_size(&self) -> Size2D<f32, CSSPixel> {
230 self.viewport_size
231 }
232
233 pub fn set_viewport_size(&mut self, viewport_size: Size2D<f32, CSSPixel>) {
239 self.viewport_size = viewport_size;
240 }
241
242 #[inline]
245 pub fn au_viewport_size(&self) -> UntypedSize2D<Au> {
246 Size2D::new(
247 Au::from_f32_px(self.viewport_size.width),
248 Au::from_f32_px(self.viewport_size.height),
249 )
250 }
251
252 pub fn au_viewport_size_for_viewport_unit_resolution(
254 &self,
255 _: ViewportVariant,
256 ) -> UntypedSize2D<Au> {
257 self.used_viewport_units.store(true, Ordering::Relaxed);
258 self.au_viewport_size()
261 }
262
263 pub fn used_viewport_units(&self) -> bool {
265 self.used_viewport_units.load(Ordering::Relaxed)
266 }
267
268 pub fn app_units_per_device_pixel(&self) -> i32 {
270 (AU_PER_PX as f32 / self.device_pixel_ratio.0) as i32
271 }
272
273 pub fn device_pixel_ratio_ignoring_full_zoom(&self) -> Scale<f32, CSSPixel, DevicePixel> {
275 self.device_pixel_ratio
276 }
277
278 pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
280 self.device_pixel_ratio
281 }
282
283 pub fn set_device_pixel_ratio(
289 &mut self,
290 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
291 ) {
292 self.device_pixel_ratio = device_pixel_ratio;
293 }
294
295 pub fn scrollbar_inline_size(&self) -> CSSPixelLength {
297 CSSPixelLength::new(0.0)
299 }
300
301 pub fn query_font_metrics(
303 &self,
304 vertical: bool,
305 font: &Font,
306 base_size: CSSPixelLength,
307 flags: QueryFontMetricsFlags,
308 ) -> FontMetrics {
309 self.used_font_metrics.store(true, Ordering::Relaxed);
310 self.font_metrics_provider
311 .query_font_metrics(vertical, font, base_size, flags)
312 }
313
314 pub fn media_type(&self) -> MediaType {
316 self.media_type.clone()
317 }
318
319 pub fn forced_colors(&self) -> ForcedColors {
321 ForcedColors::None
322 }
323
324 pub fn default_background_color(&self) -> AbsoluteColor {
326 AbsoluteColor::WHITE
327 }
328
329 pub fn default_color(&self) -> AbsoluteColor {
331 AbsoluteColor::BLACK
332 }
333
334 pub fn set_color_scheme(&mut self, new_color_scheme: PrefersColorScheme) {
340 self.prefers_color_scheme = new_color_scheme;
341 }
342
343 pub fn color_scheme(&self) -> PrefersColorScheme {
345 self.prefers_color_scheme
346 }
347
348 pub(crate) fn is_dark_color_scheme(&self, _: ColorSchemeFlags) -> bool {
349 false
350 }
351
352 pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> {
354 SideOffsets2D::zero()
355 }
356
357 pub fn is_supported_mime_type(&self, mime_type: &str) -> bool {
359 match mime_type.parse::<Mime>() {
360 Ok(m) => {
361 m == mime::IMAGE_BMP
364 || m == mime::IMAGE_GIF
365 || m == mime::IMAGE_PNG
366 || m == mime::IMAGE_JPEG
367 || m == "image/x-icon"
368 || m == "image/webp"
369 },
370 _ => false,
371 }
372 }
373
374 #[inline]
376 pub fn chrome_rules_enabled_for_document(&self) -> bool {
377 false
378 }
379}
380
381fn eval_width(context: &Context) -> CSSPixelLength {
383 CSSPixelLength::new(context.device().au_viewport_size().width.to_f32_px())
384}
385
386#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
387#[repr(u8)]
388enum Scan {
389 Progressive,
390 Interlace,
391}
392
393fn eval_scan(_: &Context, _: Option<Scan>) -> bool {
395 false
398}
399
400fn eval_resolution(context: &Context) -> Resolution {
402 Resolution::from_dppx(context.device().device_pixel_ratio.0)
403}
404
405fn eval_device_pixel_ratio(context: &Context) -> f32 {
407 eval_resolution(context).dppx()
408}
409
410fn eval_prefers_color_scheme(context: &Context, query_value: Option<PrefersColorScheme>) -> bool {
411 match query_value {
412 Some(v) => context.device().prefers_color_scheme == v,
413 None => true,
414 }
415}
416
417pub static MEDIA_FEATURES: [QueryFeatureDescription; 6] = [
419 feature!(
420 atom!("width"),
421 AllowsRanges::Yes,
422 Evaluator::Length(eval_width),
423 FeatureFlags::empty(),
424 ),
425 feature!(
426 atom!("scan"),
427 AllowsRanges::No,
428 keyword_evaluator!(eval_scan, Scan),
429 FeatureFlags::empty(),
430 ),
431 feature!(
432 atom!("resolution"),
433 AllowsRanges::Yes,
434 Evaluator::Resolution(eval_resolution),
435 FeatureFlags::empty(),
436 ),
437 feature!(
438 atom!("device-pixel-ratio"),
439 AllowsRanges::Yes,
440 Evaluator::Float(eval_device_pixel_ratio),
441 FeatureFlags::WEBKIT_PREFIX,
442 ),
443 feature!(
444 atom!("-moz-device-pixel-ratio"),
445 AllowsRanges::Yes,
446 Evaluator::Float(eval_device_pixel_ratio),
447 FeatureFlags::empty(),
448 ),
449 feature!(
450 atom!("prefers-color-scheme"),
451 AllowsRanges::No,
452 keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
453 FeatureFlags::empty(),
454 ),
455];