1use crate::computed_value_flags::ComputedValueFlags;
8use crate::context::{SharedStyleContext, StackLimitChecker};
9use crate::dom::TElement;
10use crate::invalidation::element::invalidator::InvalidationResult;
11use crate::invalidation::element::restyle_hints::RestyleHint;
12use crate::properties::ComputedValues;
13use crate::selector_parser::{PseudoElement, RestyleDamage, EAGER_PSEUDO_COUNT};
14use crate::style_resolver::{PrimaryStyle, ResolvedElementStyles, ResolvedStyle};
15#[cfg(feature = "gecko")]
16use malloc_size_of::MallocSizeOfOps;
17use selectors::matching::SelectorCaches;
18use servo_arc::Arc;
19use std::fmt;
20use std::mem;
21use std::ops::{Deref, DerefMut};
22
23bitflags! {
24 #[derive(Debug, Default)]
26 pub struct ElementDataFlags: u8 {
27 const WAS_RESTYLED = 1 << 0;
29 const TRAVERSED_WITHOUT_STYLING = 1 << 1;
38
39 const PRIMARY_STYLE_REUSED_VIA_RULE_NODE = 1 << 2;
48
49 const MAY_HAVE_STARTING_STYLE = 1 << 3;
51 }
52}
53
54#[derive(Clone, Debug, Default)]
61pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);
62
63#[derive(Default)]
64struct EagerPseudoArray(EagerPseudoArrayInner);
65type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];
66
67impl Deref for EagerPseudoArray {
68 type Target = EagerPseudoArrayInner;
69 fn deref(&self) -> &Self::Target {
70 &self.0
71 }
72}
73
74impl DerefMut for EagerPseudoArray {
75 fn deref_mut(&mut self) -> &mut Self::Target {
76 &mut self.0
77 }
78}
79
80impl Clone for EagerPseudoArray {
83 fn clone(&self) -> Self {
84 let mut clone = Self::default();
85 for i in 0..EAGER_PSEUDO_COUNT {
86 clone[i] = self.0[i].clone();
87 }
88 clone
89 }
90}
91
92impl fmt::Debug for EagerPseudoArray {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 write!(f, "EagerPseudoArray {{ ")?;
97 for i in 0..EAGER_PSEUDO_COUNT {
98 if let Some(ref values) = self[i] {
99 write!(
100 f,
101 "{:?}: {:?}, ",
102 PseudoElement::from_eager_index(i),
103 &values.rules
104 )?;
105 }
106 }
107 write!(f, "}}")
108 }
109}
110
111#[cfg(feature = "gecko")]
114const EMPTY_PSEUDO_ARRAY: &'static EagerPseudoArrayInner = &[None, None, None, None];
115#[cfg(feature = "servo")]
116const EMPTY_PSEUDO_ARRAY: &'static EagerPseudoArrayInner = &[None, None, None];
117
118impl EagerPseudoStyles {
119 pub fn is_empty(&self) -> bool {
121 self.0.is_none()
122 }
123
124 pub fn as_optional_array(&self) -> Option<&EagerPseudoArrayInner> {
126 match self.0 {
127 None => None,
128 Some(ref x) => Some(&x.0),
129 }
130 }
131
132 pub fn as_array(&self) -> &EagerPseudoArrayInner {
135 self.as_optional_array().unwrap_or(EMPTY_PSEUDO_ARRAY)
136 }
137
138 pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
140 debug_assert!(pseudo.is_eager());
141 self.0
142 .as_ref()
143 .and_then(|p| p[pseudo.eager_index()].as_ref())
144 }
145
146 pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
148 if self.0.is_none() {
149 self.0 = Some(Arc::new(Default::default()));
150 }
151 let arr = Arc::make_mut(self.0.as_mut().unwrap());
152 arr[pseudo.eager_index()] = Some(value);
153 }
154}
155
156#[derive(Clone, Default)]
159pub struct ElementStyles {
160 pub primary: Option<Arc<ComputedValues>>,
162 pub pseudos: EagerPseudoStyles,
164}
165
166size_of_test!(ElementStyles, 16);
168
169#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
171pub enum ViewportUnitUsage {
172 None = 0,
174 FromDeclaration,
177 FromQuery,
180}
181
182impl ElementStyles {
183 pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
185 self.primary.as_ref()
186 }
187
188 pub fn primary(&self) -> &Arc<ComputedValues> {
190 self.primary.as_ref().unwrap()
191 }
192
193 pub fn is_display_none(&self) -> bool {
195 self.primary().get_box().clone_display().is_none()
196 }
197
198 pub fn viewport_unit_usage(&self) -> ViewportUnitUsage {
200 fn usage_from_flags(flags: ComputedValueFlags) -> ViewportUnitUsage {
201 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES) {
202 return ViewportUnitUsage::FromQuery;
203 }
204 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) {
205 return ViewportUnitUsage::FromDeclaration;
206 }
207 ViewportUnitUsage::None
208 }
209
210 let mut usage = usage_from_flags(self.primary().flags);
211 for pseudo_style in self.pseudos.as_array() {
212 if let Some(ref pseudo_style) = pseudo_style {
213 usage = std::cmp::max(usage, usage_from_flags(pseudo_style.flags));
214 }
215 }
216
217 usage
218 }
219
220 #[cfg(feature = "gecko")]
221 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
222 0
229 }
230}
231
232impl fmt::Debug for ElementStyles {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237 write!(
238 f,
239 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
240 self.primary.as_ref().map(|x| &x.rules),
241 self.pseudos
242 )
243 }
244}
245
246#[derive(Debug, Default)]
252pub struct ElementData {
253 pub styles: ElementStyles,
255
256 pub damage: RestyleDamage,
259
260 pub hint: RestyleHint,
263
264 pub flags: ElementDataFlags,
266}
267
268size_of_test!(ElementData, 24);
270
271#[derive(Debug)]
273pub enum RestyleKind {
274 MatchAndCascade,
277 CascadeWithReplacements(RestyleHint),
280 CascadeOnly,
283}
284
285impl ElementData {
286 pub fn invalidate_style_if_needed<'a, E: TElement>(
290 &mut self,
291 element: E,
292 shared_context: &SharedStyleContext,
293 stack_limit_checker: Option<&StackLimitChecker>,
294 selector_caches: &'a mut SelectorCaches,
295 ) -> InvalidationResult {
296 if shared_context.traversal_flags.for_animation_only() {
298 return InvalidationResult::empty();
299 }
300
301 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
302 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
303
304 debug!(
305 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
306 handled_snapshot: {}, pseudo: {:?}",
307 element,
308 shared_context.traversal_flags,
309 element.has_snapshot(),
310 element.handled_snapshot(),
311 element.implemented_pseudo_element()
312 );
313
314 if !element.has_snapshot() || element.handled_snapshot() {
315 return InvalidationResult::empty();
316 }
317
318 let mut processor =
319 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
320
321 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
322
323 let result = invalidator.invalidate();
324
325 unsafe { element.set_handled_snapshot() }
326 debug_assert!(element.handled_snapshot());
327
328 result
329 }
330
331 #[inline]
333 pub fn has_styles(&self) -> bool {
334 self.styles.primary.is_some()
335 }
336
337 pub fn share_styles(&self) -> ResolvedElementStyles {
339 ResolvedElementStyles {
340 primary: self.share_primary_style(),
341 pseudos: self.styles.pseudos.clone(),
342 }
343 }
344
345 pub fn share_primary_style(&self) -> PrimaryStyle {
347 let reused_via_rule_node = self
348 .flags
349 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
350 let may_have_starting_style = self
351 .flags
352 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE);
353
354 PrimaryStyle {
355 style: ResolvedStyle(self.styles.primary().clone()),
356 reused_via_rule_node,
357 may_have_starting_style,
358 }
359 }
360
361 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
363 self.flags.set(
364 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
365 new_styles.primary.reused_via_rule_node,
366 );
367 self.flags.set(
368 ElementDataFlags::MAY_HAVE_STARTING_STYLE,
369 new_styles.primary.may_have_starting_style,
370 );
371
372 mem::replace(&mut self.styles, new_styles.into())
373 }
374
375 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
378 let style = match self.styles.primary {
379 Some(ref s) => s,
380 None => return Some(RestyleKind::MatchAndCascade),
381 };
382
383 if shared_context.traversal_flags.for_animation_only() {
384 return self.restyle_kind_for_animation(shared_context);
385 }
386
387 let hint = self.hint;
388 if hint.is_empty() {
389 return None;
390 }
391
392 let needs_to_match_self = hint.intersects(RestyleHint::RESTYLE_SELF)
393 || (hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style());
394 if needs_to_match_self {
395 return Some(RestyleKind::MatchAndCascade);
396 }
397
398 if hint.has_replacements() {
399 debug_assert!(
400 !hint.has_animation_hint(),
401 "Animation only restyle hint should have already processed"
402 );
403 return Some(RestyleKind::CascadeWithReplacements(
404 hint & RestyleHint::replacements(),
405 ));
406 }
407
408 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
409 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
410 && style
411 .flags
412 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
413 if needs_to_recascade_self {
414 return Some(RestyleKind::CascadeOnly);
415 }
416
417 None
418 }
419
420 fn restyle_kind_for_animation(
422 &self,
423 shared_context: &SharedStyleContext,
424 ) -> Option<RestyleKind> {
425 debug_assert!(shared_context.traversal_flags.for_animation_only());
426 debug_assert!(self.has_styles());
427
428 let hint = self.hint;
437 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
438 return None;
439 }
440
441 let style = self.styles.primary();
442 if hint.has_animation_hint() {
445 return Some(RestyleKind::CascadeWithReplacements(
446 hint & RestyleHint::for_animations(),
447 ));
448 }
449
450 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
451 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
452 && style
453 .flags
454 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
455 if needs_to_recascade_self {
456 return Some(RestyleKind::CascadeOnly);
457 }
458 return None;
459 }
460
461 #[inline]
466 pub fn clear_restyle_state(&mut self) {
467 self.hint = RestyleHint::empty();
468 self.clear_restyle_flags_and_damage();
469 }
470
471 #[inline]
473 pub fn clear_restyle_flags_and_damage(&mut self) {
474 self.damage = RestyleDamage::empty();
475 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
476 }
477
478 pub fn set_restyled(&mut self) {
481 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
482 self.flags
483 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
484 }
485
486 #[inline]
488 pub fn is_restyle(&self) -> bool {
489 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
490 }
491
492 pub fn set_traversed_without_styling(&mut self) {
494 self.flags
495 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
496 }
497
498 #[inline]
500 pub fn contains_restyle_data(&self) -> bool {
501 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
502 }
503
504 pub fn safe_for_cousin_sharing(&self) -> bool {
523 if self.flags.intersects(
524 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
525 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
526 ) {
527 return false;
528 }
529 if !self
530 .styles
531 .primary()
532 .get_box()
533 .clone_container_type()
534 .is_normal()
535 {
536 return false;
537 }
538 true
539 }
540
541 #[cfg(feature = "gecko")]
543 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
544 let n = self.styles.size_of_excluding_cvs(ops);
545
546 n
549 }
550
551 #[inline]
554 pub fn may_have_starting_style(&self) -> bool {
555 self.flags
556 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE)
557 }
558}