1use crate::color::AbsoluteColor;
8use crate::custom_properties::CssEnvironment;
9#[cfg(feature = "servo")]
10use crate::derives::*;
11use crate::properties::ComputedValues;
12use crate::values::computed::font::QueryFontMetricsFlags;
13use crate::values::computed::Length;
14use parking_lot::RwLock;
15use servo_arc::Arc;
16use std::mem;
17use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
18
19#[cfg(feature = "gecko")]
20use crate::device::gecko::ExtraDeviceData;
21#[cfg(feature = "servo")]
22use crate::device::servo::ExtraDeviceData;
23
24#[cfg(feature = "gecko")]
25pub mod gecko;
26#[cfg(feature = "servo")]
27pub mod servo;
28
29#[cfg_attr(feature = "servo", derive(Debug, MallocSizeOf))]
42pub struct Device {
43 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc is shared")]
45 default_values: Arc<ComputedValues>,
46 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
49 root_style: RwLock<Arc<ComputedValues>>,
50 root_font_size: AtomicU32,
52 root_line_height: AtomicU32,
54 root_font_metrics_ex: AtomicU32,
56 root_font_metrics_cap: AtomicU32,
58 root_font_metrics_ch: AtomicU32,
60 root_font_metrics_ic: AtomicU32,
62 used_root_font_size: AtomicBool,
65 used_root_line_height: AtomicBool,
68 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Pure stack type")]
72 used_root_font_metrics: RwLock<bool>,
73 used_font_metrics: AtomicBool,
75 used_viewport_size: AtomicBool,
78 used_dynamic_viewport_size: AtomicBool,
81 environment: CssEnvironment,
84 body_text_color: RwLock<AbsoluteColor>,
88
89 extra: ExtraDeviceData,
91}
92
93impl Device {
94 #[inline]
96 pub fn environment(&self) -> &CssEnvironment {
97 &self.environment
98 }
99
100 pub fn default_computed_values(&self) -> &ComputedValues {
103 &self.default_values
104 }
105
106 pub fn default_computed_values_arc(&self) -> &Arc<ComputedValues> {
108 &self.default_values
109 }
110
111 pub fn set_root_style(&self, style: &Arc<ComputedValues>) {
114 *self.root_style.write() = style.clone();
115 }
116
117 pub fn root_font_size(&self) -> Length {
119 self.used_root_font_size.store(true, Ordering::Relaxed);
120 Length::new(f32::from_bits(self.root_font_size.load(Ordering::Relaxed)))
121 }
122
123 pub fn set_root_font_size(&self, size: f32) {
125 self.root_font_size.store(size.to_bits(), Ordering::Relaxed)
126 }
127
128 pub fn root_line_height(&self) -> Length {
130 self.used_root_line_height.store(true, Ordering::Relaxed);
131 Length::new(f32::from_bits(
132 self.root_line_height.load(Ordering::Relaxed),
133 ))
134 }
135
136 pub fn set_root_line_height(&self, size: f32) {
138 self.root_line_height
139 .store(size.to_bits(), Ordering::Relaxed);
140 }
141
142 pub fn root_font_metrics_ex(&self) -> Length {
144 self.ensure_root_font_metrics_updated();
145 Length::new(f32::from_bits(
146 self.root_font_metrics_ex.load(Ordering::Relaxed),
147 ))
148 }
149
150 pub fn set_root_font_metrics_ex(&self, size: f32) -> bool {
152 let size = size.to_bits();
153 let previous = self.root_font_metrics_ex.swap(size, Ordering::Relaxed);
154 previous != size
155 }
156
157 pub fn root_font_metrics_cap(&self) -> Length {
159 self.ensure_root_font_metrics_updated();
160 Length::new(f32::from_bits(
161 self.root_font_metrics_cap.load(Ordering::Relaxed),
162 ))
163 }
164
165 pub fn set_root_font_metrics_cap(&self, size: f32) -> bool {
167 let size = size.to_bits();
168 let previous = self.root_font_metrics_cap.swap(size, Ordering::Relaxed);
169 previous != size
170 }
171
172 pub fn root_font_metrics_ch(&self) -> Length {
174 self.ensure_root_font_metrics_updated();
175 Length::new(f32::from_bits(
176 self.root_font_metrics_ch.load(Ordering::Relaxed),
177 ))
178 }
179
180 pub fn set_root_font_metrics_ch(&self, size: f32) -> bool {
182 let size = size.to_bits();
183 let previous = self.root_font_metrics_ch.swap(size, Ordering::Relaxed);
184 previous != size
185 }
186
187 pub fn root_font_metrics_ic(&self) -> Length {
189 self.ensure_root_font_metrics_updated();
190 Length::new(f32::from_bits(
191 self.root_font_metrics_ic.load(Ordering::Relaxed),
192 ))
193 }
194
195 pub fn set_root_font_metrics_ic(&self, size: f32) -> bool {
197 let size = size.to_bits();
198 let previous = self.root_font_metrics_ic.swap(size, Ordering::Relaxed);
199 previous != size
200 }
201
202 fn ensure_root_font_metrics_updated(&self) {
203 let mut guard = self.used_root_font_metrics.write();
204 let previously_computed = mem::replace(&mut *guard, true);
205 if !previously_computed {
206 self.update_root_font_metrics();
207 }
208 }
209
210 pub fn update_root_font_metrics(&self) -> bool {
213 let root_style = self.root_style.read();
214 let root_effective_zoom = root_style.effective_zoom;
215 let root_font_size = (*root_style).get_font().clone_font_size().computed_size();
216
217 let root_font_metrics = self.query_font_metrics(
218 root_style.writing_mode.is_upright(),
219 (*root_style).get_font(),
220 root_font_size,
221 QueryFontMetricsFlags::USE_USER_FONT_SET
222 | QueryFontMetricsFlags::NEEDS_CH
223 | QueryFontMetricsFlags::NEEDS_IC,
224 false,
225 );
226
227 let mut root_font_metrics_changed = false;
228 root_font_metrics_changed |= self.set_root_font_metrics_ex(
229 root_effective_zoom.unzoom(root_font_metrics.x_height_or_default(root_font_size).px()),
230 );
231 root_font_metrics_changed |= self.set_root_font_metrics_ch(
232 root_effective_zoom.unzoom(
233 root_font_metrics
234 .zero_advance_measure_or_default(
235 root_font_size,
236 root_style.writing_mode.is_upright(),
237 )
238 .px(),
239 ),
240 );
241 root_font_metrics_changed |= self.set_root_font_metrics_cap(
242 root_effective_zoom.unzoom(root_font_metrics.cap_height_or_default().px()),
243 );
244 root_font_metrics_changed |= self.set_root_font_metrics_ic(
245 root_effective_zoom.unzoom(root_font_metrics.ic_width_or_default(root_font_size).px()),
246 );
247
248 root_font_metrics_changed
249 }
250
251 pub fn used_root_font_size(&self) -> bool {
253 self.used_root_font_size.load(Ordering::Relaxed)
254 }
255
256 pub fn used_root_line_height(&self) -> bool {
258 self.used_root_line_height.load(Ordering::Relaxed)
259 }
260
261 pub fn used_root_font_metrics(&self) -> bool {
263 *self.used_root_font_metrics.read()
264 }
265
266 pub fn used_viewport_size(&self) -> bool {
268 self.used_viewport_size.load(Ordering::Relaxed)
269 }
270
271 pub fn used_dynamic_viewport_size(&self) -> bool {
273 self.used_dynamic_viewport_size.load(Ordering::Relaxed)
274 }
275
276 pub fn used_font_metrics(&self) -> bool {
278 self.used_font_metrics.load(Ordering::Relaxed)
279 }
280
281 pub fn body_text_color(&self) -> AbsoluteColor {
283 *self.body_text_color.read()
284 }
285
286 pub fn set_body_text_color(&self, color: AbsoluteColor) {
290 *self.body_text_color.write() = color;
291 }
292
293 #[inline]
295 pub fn zoom_text(&self, size: Length) -> Length {
296 size.scale_by(self.text_zoom())
297 }
298
299 #[inline]
301 pub fn unzoom_text(&self, size: Length) -> Length {
302 size.scale_by(1. / self.text_zoom())
303 }
304}