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: AtomicU32,
89
90 extra: ExtraDeviceData,
92}
93
94impl Device {
95 #[inline]
97 pub fn environment(&self) -> &CssEnvironment {
98 &self.environment
99 }
100
101 pub fn default_computed_values(&self) -> &ComputedValues {
104 &self.default_values
105 }
106
107 pub fn default_computed_values_arc(&self) -> &Arc<ComputedValues> {
109 &self.default_values
110 }
111
112 pub fn set_root_style(&self, style: &Arc<ComputedValues>) {
115 *self.root_style.write() = style.clone();
116 }
117
118 pub fn root_font_size(&self) -> Length {
120 self.used_root_font_size.store(true, Ordering::Relaxed);
121 Length::new(f32::from_bits(self.root_font_size.load(Ordering::Relaxed)))
122 }
123
124 pub fn set_root_font_size(&self, size: f32) {
126 self.root_font_size.store(size.to_bits(), Ordering::Relaxed)
127 }
128
129 pub fn root_line_height(&self) -> Length {
131 self.used_root_line_height.store(true, Ordering::Relaxed);
132 Length::new(f32::from_bits(
133 self.root_line_height.load(Ordering::Relaxed),
134 ))
135 }
136
137 pub fn set_root_line_height(&self, size: f32) {
139 self.root_line_height
140 .store(size.to_bits(), Ordering::Relaxed);
141 }
142
143 pub fn root_font_metrics_ex(&self) -> Length {
145 self.ensure_root_font_metrics_updated();
146 Length::new(f32::from_bits(
147 self.root_font_metrics_ex.load(Ordering::Relaxed),
148 ))
149 }
150
151 pub fn set_root_font_metrics_ex(&self, size: f32) -> bool {
153 let size = size.to_bits();
154 let previous = self.root_font_metrics_ex.swap(size, Ordering::Relaxed);
155 previous != size
156 }
157
158 pub fn root_font_metrics_cap(&self) -> Length {
160 self.ensure_root_font_metrics_updated();
161 Length::new(f32::from_bits(
162 self.root_font_metrics_cap.load(Ordering::Relaxed),
163 ))
164 }
165
166 pub fn set_root_font_metrics_cap(&self, size: f32) -> bool {
168 let size = size.to_bits();
169 let previous = self.root_font_metrics_cap.swap(size, Ordering::Relaxed);
170 previous != size
171 }
172
173 pub fn root_font_metrics_ch(&self) -> Length {
175 self.ensure_root_font_metrics_updated();
176 Length::new(f32::from_bits(
177 self.root_font_metrics_ch.load(Ordering::Relaxed),
178 ))
179 }
180
181 pub fn set_root_font_metrics_ch(&self, size: f32) -> bool {
183 let size = size.to_bits();
184 let previous = self.root_font_metrics_ch.swap(size, Ordering::Relaxed);
185 previous != size
186 }
187
188 pub fn root_font_metrics_ic(&self) -> Length {
190 self.ensure_root_font_metrics_updated();
191 Length::new(f32::from_bits(
192 self.root_font_metrics_ic.load(Ordering::Relaxed),
193 ))
194 }
195
196 pub fn set_root_font_metrics_ic(&self, size: f32) -> bool {
198 let size = size.to_bits();
199 let previous = self.root_font_metrics_ic.swap(size, Ordering::Relaxed);
200 previous != size
201 }
202
203 fn ensure_root_font_metrics_updated(&self) {
204 let mut guard = self.used_root_font_metrics.write();
205 let previously_computed = mem::replace(&mut *guard, true);
206 if !previously_computed {
207 self.update_root_font_metrics();
208 }
209 }
210
211 pub fn update_root_font_metrics(&self) -> bool {
214 let root_style = self.root_style.read();
215 let root_effective_zoom = (*root_style).effective_zoom;
216 let root_font_size = (*root_style).get_font().clone_font_size().computed_size();
217
218 let root_font_metrics = self.query_font_metrics(
219 (*root_style).writing_mode.is_upright(),
220 &(*root_style).get_font(),
221 root_font_size,
222 QueryFontMetricsFlags::USE_USER_FONT_SET
223 | QueryFontMetricsFlags::NEEDS_CH
224 | QueryFontMetricsFlags::NEEDS_IC,
225 false,
226 );
227
228 let mut root_font_metrics_changed = false;
229 root_font_metrics_changed |= self.set_root_font_metrics_ex(
230 root_effective_zoom.unzoom(root_font_metrics.x_height_or_default(root_font_size).px()),
231 );
232 root_font_metrics_changed |= self.set_root_font_metrics_ch(
233 root_effective_zoom.unzoom(
234 root_font_metrics
235 .zero_advance_measure_or_default(
236 root_font_size,
237 (*root_style).writing_mode.is_upright(),
238 )
239 .px(),
240 ),
241 );
242 root_font_metrics_changed |= self.set_root_font_metrics_cap(
243 root_effective_zoom.unzoom(root_font_metrics.cap_height_or_default().px()),
244 );
245 root_font_metrics_changed |= self.set_root_font_metrics_ic(
246 root_effective_zoom.unzoom(root_font_metrics.ic_width_or_default(root_font_size).px()),
247 );
248
249 root_font_metrics_changed
250 }
251
252 pub fn used_root_font_size(&self) -> bool {
254 self.used_root_font_size.load(Ordering::Relaxed)
255 }
256
257 pub fn used_root_line_height(&self) -> bool {
259 self.used_root_line_height.load(Ordering::Relaxed)
260 }
261
262 pub fn used_root_font_metrics(&self) -> bool {
264 *self.used_root_font_metrics.read()
265 }
266
267 pub fn used_viewport_size(&self) -> bool {
269 self.used_viewport_size.load(Ordering::Relaxed)
270 }
271
272 pub fn used_dynamic_viewport_size(&self) -> bool {
274 self.used_dynamic_viewport_size.load(Ordering::Relaxed)
275 }
276
277 pub fn used_font_metrics(&self) -> bool {
279 self.used_font_metrics.load(Ordering::Relaxed)
280 }
281
282 pub fn body_text_color(&self) -> AbsoluteColor {
284 AbsoluteColor::from_nscolor(self.body_text_color.load(Ordering::Relaxed))
285 }
286
287 pub fn set_body_text_color(&self, color: AbsoluteColor) {
291 self.body_text_color
292 .store(color.to_nscolor(), Ordering::Relaxed)
293 }
294}