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-query device and expression representation.
6
7 use crate::context::QuirksMode;
8 use crate::custom_properties::CssEnvironment;
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::MediaType;
13 use crate::properties::ComputedValues;
14 use crate::values::computed::CSSPixelLength;
15 use crate::values::specified::font::FONT_MEDIUM_PX;
16 use crate::values::KeyframesName;
17 use app_units::Au;
18 use cssparser::RGBA;
19 use euclid::default::Size2D as UntypedSize2D;
20 use euclid::{Scale, SideOffsets2D, Size2D};
21 use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
22 use style_traits::viewport::ViewportConstraints;
23 use style_traits::{CSSPixel, DevicePixel};
24
25 /// A device is a structure that represents the current media a given document
26 /// is displayed in.
27 ///
28 /// This is the struct against which media queries are evaluated.
29 #[derive(Debug, MallocSizeOf)]
30 pub struct Device {
31 /// The current media type used by de device.
32 media_type: MediaType,
33 /// The current viewport size, in CSS pixels.
34 viewport_size: Size2D<f32, CSSPixel>,
35 /// The current device pixel ratio, from CSS pixels to device pixels.
36 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
37 /// The current quirks mode.
38 #[ignore_malloc_size_of = "Pure stack type"]
39 quirks_mode: QuirksMode,
40
41 /// The font size of the root element
42 /// This is set when computing the style of the root
43 /// element, and used for rem units in other elements
44 ///
45 /// When computing the style of the root element, there can't be any
46 /// other style being computed at the same time, given we need the style of
47 /// the parent to compute everything else. So it is correct to just use
48 /// a relaxed atomic here.
49 #[ignore_malloc_size_of = "Pure stack type"]
50 root_font_size: AtomicU32,
51 /// Whether any styles computed in the document relied on the root font-size
52 /// by using rem units.
53 #[ignore_malloc_size_of = "Pure stack type"]
54 used_root_font_size: AtomicBool,
55 /// Whether any styles computed in the document relied on the viewport size.
56 #[ignore_malloc_size_of = "Pure stack type"]
57 used_viewport_units: AtomicBool,
58 /// The CssEnvironment object responsible of getting CSS environment
59 /// variables.
60 environment: CssEnvironment,
61 }
62
63 impl Device {
64 /// Trivially construct a new `Device`.
new( media_type: MediaType, quirks_mode: QuirksMode, viewport_size: Size2D<f32, CSSPixel>, device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>, ) -> Device65 pub fn new(
66 media_type: MediaType,
67 quirks_mode: QuirksMode,
68 viewport_size: Size2D<f32, CSSPixel>,
69 device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
70 ) -> Device {
71 Device {
72 media_type,
73 viewport_size,
74 device_pixel_ratio,
75 quirks_mode,
76 // FIXME(bz): Seems dubious?
77 root_font_size: AtomicU32::new(FONT_MEDIUM_PX.to_bits()),
78 used_root_font_size: AtomicBool::new(false),
79 used_viewport_units: AtomicBool::new(false),
80 environment: CssEnvironment,
81 }
82 }
83
84 /// Get the relevant environment to resolve `env()` functions.
85 #[inline]
environment(&self) -> &CssEnvironment86 pub fn environment(&self) -> &CssEnvironment {
87 &self.environment
88 }
89
90 /// Return the default computed values for this device.
default_computed_values(&self) -> &ComputedValues91 pub fn default_computed_values(&self) -> &ComputedValues {
92 // FIXME(bz): This isn't really right, but it's no more wrong
93 // than what we used to do. See
94 // https://github.com/servo/servo/issues/14773 for fixing it properly.
95 ComputedValues::initial_values()
96 }
97
98 /// Get the font size of the root element (for rem)
root_font_size(&self) -> CSSPixelLength99 pub fn root_font_size(&self) -> CSSPixelLength {
100 self.used_root_font_size.store(true, Ordering::Relaxed);
101 CSSPixelLength::new(f32::from_bits(self.root_font_size.load(Ordering::Relaxed)))
102 }
103
104 /// Set the font size of the root element (for rem)
set_root_font_size(&self, size: CSSPixelLength)105 pub fn set_root_font_size(&self, size: CSSPixelLength) {
106 self.root_font_size
107 .store(size.px().to_bits(), Ordering::Relaxed)
108 }
109
110 /// Get the quirks mode of the current device.
quirks_mode(&self) -> QuirksMode111 pub fn quirks_mode(&self) -> QuirksMode {
112 self.quirks_mode
113 }
114
115 /// Sets the body text color for the "inherit color from body" quirk.
116 ///
117 /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
set_body_text_color(&self, _color: RGBA)118 pub fn set_body_text_color(&self, _color: RGBA) {
119 // Servo doesn't implement this quirk (yet)
120 }
121
122 /// Whether a given animation name may be referenced from style.
animation_name_may_be_referenced(&self, _: &KeyframesName) -> bool123 pub fn animation_name_may_be_referenced(&self, _: &KeyframesName) -> bool {
124 // Assume it is, since we don't have any good way to prove it's not.
125 true
126 }
127
128 /// Returns whether we ever looked up the root font size of the Device.
used_root_font_size(&self) -> bool129 pub fn used_root_font_size(&self) -> bool {
130 self.used_root_font_size.load(Ordering::Relaxed)
131 }
132
133 /// Returns the viewport size of the current device in app units, needed,
134 /// among other things, to resolve viewport units.
135 #[inline]
au_viewport_size(&self) -> UntypedSize2D<Au>136 pub fn au_viewport_size(&self) -> UntypedSize2D<Au> {
137 Size2D::new(
138 Au::from_f32_px(self.viewport_size.width),
139 Au::from_f32_px(self.viewport_size.height),
140 )
141 }
142
143 /// Like the above, but records that we've used viewport units.
au_viewport_size_for_viewport_unit_resolution(&self) -> UntypedSize2D<Au>144 pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> UntypedSize2D<Au> {
145 self.used_viewport_units.store(true, Ordering::Relaxed);
146 self.au_viewport_size()
147 }
148
149 /// Whether viewport units were used since the last device change.
used_viewport_units(&self) -> bool150 pub fn used_viewport_units(&self) -> bool {
151 self.used_viewport_units.load(Ordering::Relaxed)
152 }
153
154 /// Returns the device pixel ratio.
device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel>155 pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
156 self.device_pixel_ratio
157 }
158
159 /// Take into account a viewport rule taken from the stylesheets.
account_for_viewport_rule(&mut self, constraints: &ViewportConstraints)160 pub fn account_for_viewport_rule(&mut self, constraints: &ViewportConstraints) {
161 self.viewport_size = constraints.size;
162 }
163
164 /// Return the media type of the current device.
media_type(&self) -> MediaType165 pub fn media_type(&self) -> MediaType {
166 self.media_type.clone()
167 }
168
169 /// Returns whether document colors are enabled.
use_document_colors(&self) -> bool170 pub fn use_document_colors(&self) -> bool {
171 true
172 }
173
174 /// Returns the default background color.
default_background_color(&self) -> RGBA175 pub fn default_background_color(&self) -> RGBA {
176 RGBA::new(255, 255, 255, 255)
177 }
178
179 /// Returns the default color color.
default_color(&self) -> RGBA180 pub fn default_color(&self) -> RGBA {
181 RGBA::new(0, 0, 0, 255)
182 }
183
184 /// Returns safe area insets
safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel>185 pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> {
186 SideOffsets2D::zero()
187 }
188 }
189
190 /// https://drafts.csswg.org/mediaqueries-4/#width
eval_width( device: &Device, value: Option<CSSPixelLength>, range_or_operator: Option<RangeOrOperator>, ) -> bool191 fn eval_width(
192 device: &Device,
193 value: Option<CSSPixelLength>,
194 range_or_operator: Option<RangeOrOperator>,
195 ) -> bool {
196 RangeOrOperator::evaluate(
197 range_or_operator,
198 value.map(Au::from),
199 device.au_viewport_size().width,
200 )
201 }
202
203 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
204 #[repr(u8)]
205 enum Scan {
206 Progressive,
207 Interlace,
208 }
209
210 /// https://drafts.csswg.org/mediaqueries-4/#scan
eval_scan(_: &Device, _: Option<Scan>) -> bool211 fn eval_scan(_: &Device, _: Option<Scan>) -> bool {
212 // Since we doesn't support the 'tv' media type, the 'scan' feature never
213 // matches.
214 false
215 }
216
217 lazy_static! {
218 /// A list with all the media features that Servo supports.
219 pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 2] = [
220 feature!(
221 atom!("width"),
222 AllowsRanges::Yes,
223 Evaluator::Length(eval_width),
224 ParsingRequirements::empty(),
225 ),
226 feature!(
227 atom!("scan"),
228 AllowsRanges::No,
229 keyword_evaluator!(eval_scan, Scan),
230 ParsingRequirements::empty(),
231 ),
232 ];
233 }
234