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::ComputedValues;
14use crate::properties::style_structs::Font;
15use crate::queries::values::PrefersColorScheme;
16use crate::servo::media_features::PointerCapabilities;
17use crate::values::KeyframesName;
18use crate::values::computed::font::GenericFontFamily;
19use crate::values::computed::{
20 CSSPixelLength, Length, LineHeight, LinkParameters, NonNegativeLength,
21};
22use crate::values::specified::ViewportVariant;
23use crate::values::specified::color::{ColorSchemeFlags, ForcedColors, SystemColor};
24use crate::values::specified::font::{
25 FONT_MEDIUM_CAP_PX, FONT_MEDIUM_CH_PX, FONT_MEDIUM_EX_PX, FONT_MEDIUM_IC_PX,
26 FONT_MEDIUM_LINE_HEIGHT_PX, FONT_MEDIUM_PX, QueryFontMetricsFlags,
27};
28use app_units::{AU_PER_PX, Au};
29use euclid::default::Size2D as UntypedSize2D;
30use euclid::{Scale, SideOffsets2D, Size2D};
31use malloc_size_of_derive::MallocSizeOf;
32use mime::Mime;
33use parking_lot::RwLock;
34use servo_arc::Arc;
35use std::fmt::Debug;
36use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
37use style_traits::{CSSPixel, DevicePixel};
38
39use crate::device::Device;
40
41pub trait FontMetricsProvider: Debug + Sync {
44 fn query_font_metrics(
46 &self,
47 vertical: bool,
48 font: &Font,
49 base_size: CSSPixelLength,
50 flags: QueryFontMetricsFlags,
51 ) -> FontMetrics;
52 fn base_size_for_generic(&self, generic: GenericFontFamily) -> Length;
54}
55
56#[derive(Debug, MallocSizeOf)]
57pub(super) struct ExtraDeviceData {
58 media_type: MediaType,
60 viewport_size: Size2D<f32, CSSPixel>,
62 device_size: Size2D<f32, DevicePixel>,
64 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
66 #[ignore_malloc_size_of = "Pure stack type"]
68 quirks_mode: QuirksMode,
69 #[ignore_malloc_size_of = "Pure stack type"]
71 prefers_color_scheme: PrefersColorScheme,
72 #[ignore_malloc_size_of = "Pure stack type"]
74 primary_pointer_capabilities: PointerCapabilities,
75 #[ignore_malloc_size_of = "Pure stack type"]
77 all_pointer_capabilities: PointerCapabilities,
78 #[ignore_malloc_size_of = "Owned by embedder"]
80 font_metrics_provider: Box<dyn FontMetricsProvider>,
81}
82
83impl Device {
84 pub fn new(
86 media_type: MediaType,
87 quirks_mode: QuirksMode,
88 viewport_size: Size2D<f32, CSSPixel>,
89 device_size: Size2D<f32, DevicePixel>,
90 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
91 font_metrics_provider: Box<dyn FontMetricsProvider>,
92 default_values: Arc<ComputedValues>,
93 prefers_color_scheme: PrefersColorScheme,
94 primary_pointer_capabilities: PointerCapabilities,
95 all_pointer_capabilities: PointerCapabilities,
96 ) -> Device {
97 let root_style = RwLock::new(Arc::clone(&default_values));
98 Device {
99 root_style,
100 root_font_size: AtomicU32::new(FONT_MEDIUM_PX.to_bits()),
101 root_line_height: AtomicU32::new(FONT_MEDIUM_LINE_HEIGHT_PX.to_bits()),
102 root_font_metrics_ex: AtomicU32::new(FONT_MEDIUM_EX_PX.to_bits()),
103 root_font_metrics_cap: AtomicU32::new(FONT_MEDIUM_CAP_PX.to_bits()),
104 root_font_metrics_ch: AtomicU32::new(FONT_MEDIUM_CH_PX.to_bits()),
105 root_font_metrics_ic: AtomicU32::new(FONT_MEDIUM_IC_PX.to_bits()),
106 used_root_font_size: AtomicBool::new(false),
107 used_root_line_height: AtomicBool::new(false),
108 used_root_font_metrics: RwLock::new(false),
109 used_font_metrics: AtomicBool::new(false),
110 used_viewport_size: AtomicBool::new(false),
111 used_dynamic_viewport_size: AtomicBool::new(false),
112 environment: CssEnvironment,
113 default_values,
114 body_text_color: RwLock::new(AbsoluteColor::BLACK),
115 extra: ExtraDeviceData {
116 media_type,
117 viewport_size,
118 device_size,
119 device_pixel_ratio,
120 quirks_mode,
121 prefers_color_scheme,
122 primary_pointer_capabilities,
123 all_pointer_capabilities,
124 font_metrics_provider,
125 },
126 }
127 }
128
129 pub fn calc_line_height(
133 &self,
134 font: &crate::properties::style_structs::Font,
135 _writing_mode: WritingMode,
136 _element: Option<()>,
137 ) -> NonNegativeLength {
138 (match font.line_height {
139 LineHeight::Normal => CSSPixelLength::new(0.),
141 LineHeight::Number(number) => font.font_size.computed_size() * number.0,
142 LineHeight::Length(length) => length.0,
143 })
144 .into()
145 }
146
147 pub fn quirks_mode(&self) -> QuirksMode {
149 self.extra.quirks_mode
150 }
151
152 #[inline]
155 pub fn document_random_seed(&self) -> u64 {
156 0
158 }
159
160 pub fn base_size_for_generic(&self, generic: GenericFontFamily) -> Length {
162 self.extra
163 .font_metrics_provider
164 .base_size_for_generic(generic)
165 }
166
167 pub fn animation_name_may_be_referenced(&self, _: &KeyframesName) -> bool {
169 true
171 }
172
173 pub fn viewport_size(&self) -> Size2D<f32, CSSPixel> {
175 self.extra.viewport_size
176 }
177
178 pub fn set_viewport_size(&mut self, viewport_size: Size2D<f32, CSSPixel>) {
184 self.extra.viewport_size = viewport_size;
185 }
186
187 #[inline]
190 pub fn au_viewport_size(&self) -> UntypedSize2D<Au> {
191 Size2D::new(
192 Au::from_f32_px(self.extra.viewport_size.width),
193 Au::from_f32_px(self.extra.viewport_size.height),
194 )
195 }
196
197 pub fn au_viewport_size_for_viewport_unit_resolution(
199 &self,
200 _: ViewportVariant,
201 ) -> UntypedSize2D<Au> {
202 self.used_viewport_size.store(true, Ordering::Relaxed);
203 self.au_viewport_size()
206 }
207
208 pub fn app_units_per_device_pixel(&self) -> i32 {
210 (AU_PER_PX as f32 / self.extra.device_pixel_ratio.0) as i32
211 }
212
213 pub fn device_pixel_ratio_ignoring_full_zoom(&self) -> Scale<f32, CSSPixel, DevicePixel> {
215 self.extra.device_pixel_ratio
216 }
217
218 pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
220 self.extra.device_pixel_ratio
221 }
222
223 pub fn set_device_pixel_ratio(
229 &mut self,
230 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
231 ) {
232 self.extra.device_pixel_ratio = device_pixel_ratio;
233 }
234
235 pub fn set_device_size(&mut self, device_size: Size2D<f32, DevicePixel>) {
241 self.extra.device_size = device_size;
242 }
243
244 #[inline]
246 pub fn device_size(&self) -> Size2D<f32, DevicePixel> {
247 self.extra.device_size
248 }
249
250 pub fn scrollbar_inline_size(&self) -> CSSPixelLength {
252 CSSPixelLength::new(0.0)
254 }
255
256 pub fn query_font_metrics(
258 &self,
259 vertical: bool,
260 font: &Font,
261 base_size: CSSPixelLength,
262 flags: QueryFontMetricsFlags,
263 track_usage: bool,
264 ) -> FontMetrics {
265 if track_usage {
266 self.used_font_metrics.store(true, Ordering::Relaxed);
267 }
268 self.extra
269 .font_metrics_provider
270 .query_font_metrics(vertical, font, base_size, flags)
271 }
272
273 pub fn set_media_type(&mut self, media_type: MediaType) {
279 self.extra.media_type = media_type;
280 }
281
282 pub fn media_type(&self) -> MediaType {
284 self.extra.media_type.clone()
285 }
286
287 pub fn forced_colors(&self) -> ForcedColors {
289 ForcedColors::None
290 }
291
292 pub fn default_background_color(&self) -> AbsoluteColor {
294 AbsoluteColor::WHITE
295 }
296
297 pub fn default_color(&self) -> AbsoluteColor {
299 AbsoluteColor::BLACK
300 }
301
302 pub fn set_color_scheme(&mut self, new_color_scheme: PrefersColorScheme) {
308 self.extra.prefers_color_scheme = new_color_scheme;
309 }
310
311 pub fn color_scheme(&self) -> PrefersColorScheme {
313 self.extra.prefers_color_scheme
314 }
315
316 pub fn set_primary_pointer_capabilities(&mut self, capabilities: PointerCapabilities) {
322 self.extra.primary_pointer_capabilities = capabilities;
323 }
324
325 pub fn primary_pointer_capabilities(&self) -> PointerCapabilities {
327 self.extra.primary_pointer_capabilities
328 }
329
330 pub fn set_all_pointer_capabilities(&mut self, capabilities: PointerCapabilities) {
336 self.extra.all_pointer_capabilities = capabilities;
337 }
338
339 pub fn all_pointer_capabilities(&self) -> PointerCapabilities {
341 self.extra.all_pointer_capabilities
342 }
343
344 pub(crate) fn is_dark_color_scheme(&self, color_scheme_flags: ColorSchemeFlags) -> bool {
345 let supports_dark_mode = color_scheme_flags.contains(ColorSchemeFlags::DARK);
348 let supports_light_mode = color_scheme_flags.contains(ColorSchemeFlags::LIGHT);
349
350 if supports_dark_mode != supports_light_mode {
352 return supports_dark_mode;
353 }
354
355 return self.color_scheme() == PrefersColorScheme::Dark;
358 }
359
360 pub(crate) fn system_color(
361 &self,
362 system_color: SystemColor,
363 color_scheme_flags: ColorSchemeFlags,
364 ) -> AbsoluteColor {
365 fn srgb(r: u8, g: u8, b: u8) -> AbsoluteColor {
366 AbsoluteColor::srgb_legacy(r, g, b, 1f32)
367 }
368
369 if self.is_dark_color_scheme(color_scheme_flags) {
372 match system_color {
373 SystemColor::Accentcolor => srgb(10, 132, 255),
374 SystemColor::Accentcolortext => srgb(255, 255, 255),
375 SystemColor::Activetext => srgb(255, 0, 0),
376 SystemColor::Linktext => srgb(158, 158, 255),
377 SystemColor::Visitedtext => srgb(208, 173, 240),
378 SystemColor::Buttonborder
379 | SystemColor::Activeborder
381 | SystemColor::Inactiveborder
382 | SystemColor::Threeddarkshadow
383 | SystemColor::Threedshadow
384 | SystemColor::Windowframe => srgb(255, 255, 255),
385 SystemColor::Buttonface
386 | SystemColor::Buttonhighlight
388 | SystemColor::Buttonshadow
389 | SystemColor::Threedface
390 | SystemColor::Threedhighlight
391 | SystemColor::Threedlightshadow => srgb(107, 107, 107),
392 SystemColor::Buttontext => srgb(245, 245, 245),
393 SystemColor::Canvas
394 | SystemColor::Activecaption
396 | SystemColor::Appworkspace
397 | SystemColor::Background
398 | SystemColor::Inactivecaption
399 | SystemColor::Infobackground
400 | SystemColor::Menu
401 | SystemColor::Scrollbar
402 | SystemColor::Window => srgb(30, 30, 30),
403 SystemColor::Canvastext
404 | SystemColor::Captiontext
406 | SystemColor::Infotext
407 | SystemColor::Menutext
408 | SystemColor::Windowtext => srgb(232, 232, 232),
409 SystemColor::Field => srgb(45, 45, 45),
410 SystemColor::Fieldtext => srgb(240, 240, 240),
411 SystemColor::Graytext
412 | SystemColor::Inactivecaptiontext => srgb(155, 155, 155),
414 SystemColor::Highlight => srgb(38, 79, 120),
415 SystemColor::Highlighttext => srgb(255, 255, 255),
416 SystemColor::Mark => srgb(102, 92, 0),
417 SystemColor::Marktext => srgb(255, 255, 255),
418 SystemColor::Selecteditem => srgb(153, 200, 255),
419 SystemColor::Selecteditemtext => srgb(59, 59, 59),
420 }
421 } else {
422 match system_color {
423 SystemColor::Accentcolor => srgb(0, 102, 204),
424 SystemColor::Accentcolortext => srgb(255, 255, 255),
425 SystemColor::Activetext => srgb(238, 0, 0),
426 SystemColor::Linktext => srgb(0, 0, 238),
427 SystemColor::Visitedtext => srgb(85, 26, 139),
428 SystemColor::Buttonborder
429 | SystemColor::Activeborder
431 | SystemColor::Inactiveborder
432 | SystemColor::Threeddarkshadow
433 | SystemColor::Threedshadow
434 | SystemColor::Windowframe => srgb(169, 169, 169),
435 SystemColor::Buttonface
436 | SystemColor::Buttonhighlight
438 | SystemColor::Buttonshadow
439 | SystemColor::Threedface
440 | SystemColor::Threedhighlight
441 | SystemColor::Threedlightshadow => srgb(220, 220, 220),
442 SystemColor::Buttontext => srgb(0, 0, 0),
443 SystemColor::Canvas
444 | SystemColor::Activecaption
446 | SystemColor::Appworkspace
447 | SystemColor::Background
448 | SystemColor::Inactivecaption
449 | SystemColor::Infobackground
450 | SystemColor::Menu
451 | SystemColor::Scrollbar
452 | SystemColor::Window => srgb(255, 255, 255),
453 SystemColor::Canvastext
454 | SystemColor::Captiontext
456 | SystemColor::Infotext
457 | SystemColor::Menutext
458 | SystemColor::Windowtext => srgb(0, 0, 0),
459 SystemColor::Field => srgb(255, 255, 255),
460 SystemColor::Fieldtext => srgb(0, 0, 0),
461 SystemColor::Graytext
462 | SystemColor::Inactivecaptiontext => srgb(109, 109, 109),
464 SystemColor::Highlight => srgb(0, 65, 198),
465 SystemColor::Highlighttext => srgb(0, 0, 0),
466 SystemColor::Mark => srgb(255, 235, 59),
467 SystemColor::Marktext => srgb(0, 0, 0),
468 SystemColor::Selecteditem => srgb(0, 102, 204),
469 SystemColor::Selecteditemtext => srgb(255, 255, 255),
470 }
471 }
472 }
473
474 #[inline]
476 pub(super) fn text_zoom(&self) -> f32 {
477 1.
479 }
480
481 pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> {
483 SideOffsets2D::zero()
484 }
485
486 pub fn is_supported_mime_type(&self, mime_type: &str) -> bool {
488 match mime_type.parse::<Mime>() {
489 Ok(m) => {
490 m == mime::IMAGE_BMP
493 || m == mime::IMAGE_GIF
494 || m == mime::IMAGE_PNG
495 || m == mime::IMAGE_JPEG
496 || m == "image/x-icon"
497 || m == "image/webp"
498 },
499 _ => false,
500 }
501 }
502
503 #[inline]
505 pub fn chrome_rules_enabled_for_document(&self) -> bool {
506 false
507 }
508
509 #[inline]
512 pub fn link_parameters(&self) -> Option<&LinkParameters> {
513 None
514 }
515}