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::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
14use crate::style_resolver::{PrimaryStyle, ResolvedElementStyles, ResolvedStyle};
15use crate::values::specified::TreeCountingFunction;
16#[cfg(feature = "gecko")]
17use malloc_size_of::MallocSizeOfOps;
18use selectors::matching::SelectorCaches;
19use servo_arc::Arc;
20use std::ops::{Deref, DerefMut};
21use std::{fmt, mem};
22
23#[cfg(debug_assertions)]
24use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
25
26bitflags! {
27 #[derive(Debug, Default)]
29 pub struct ElementDataFlags: u8 {
30 const WAS_RESTYLED = 1 << 0;
32 const TRAVERSED_WITHOUT_STYLING = 1 << 1;
41
42 const PRIMARY_STYLE_REUSED_VIA_RULE_NODE = 1 << 2;
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
111const EMPTY_PSEUDO_ARRAY: &EagerPseudoArrayInner = &[const { None }; EAGER_PSEUDO_COUNT];
112
113impl EagerPseudoStyles {
114 pub fn is_empty(&self) -> bool {
116 self.0.is_none()
117 }
118
119 pub fn as_optional_array(&self) -> Option<&EagerPseudoArrayInner> {
121 match self.0 {
122 None => None,
123 Some(ref x) => Some(&x.0),
124 }
125 }
126
127 pub fn as_array(&self) -> &EagerPseudoArrayInner {
130 self.as_optional_array().unwrap_or(EMPTY_PSEUDO_ARRAY)
131 }
132
133 pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
135 debug_assert!(pseudo.is_eager());
136 self.0
137 .as_ref()
138 .and_then(|p| p[pseudo.eager_index()].as_ref())
139 }
140
141 pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
143 if self.0.is_none() {
144 self.0 = Some(Arc::new(Default::default()));
145 }
146 let arr = Arc::make_mut(self.0.as_mut().unwrap());
147 arr[pseudo.eager_index()] = Some(value);
148 }
149}
150
151#[derive(Clone, Default)]
154pub struct ElementStyles {
155 pub primary: Option<Arc<ComputedValues>>,
157 pub pseudos: EagerPseudoStyles,
159}
160
161size_of_test!(ElementStyles, 16);
163
164#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
166pub enum ViewportUnitUsage {
167 None = 0,
169 FromDeclaration,
172 FromQuery,
175}
176
177impl ElementStyles {
178 pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
180 self.primary.as_ref()
181 }
182
183 pub fn primary(&self) -> &Arc<ComputedValues> {
185 self.primary.as_ref().unwrap()
186 }
187
188 pub fn is_display_none(&self) -> bool {
190 self.primary().get_box().get_display().is_none()
191 }
192
193 pub fn viewport_unit_usage(&self) -> ViewportUnitUsage {
195 fn usage_from_flags(flags: ComputedValueFlags) -> ViewportUnitUsage {
196 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES) {
197 return ViewportUnitUsage::FromQuery;
198 }
199 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) {
200 return ViewportUnitUsage::FromDeclaration;
201 }
202 ViewportUnitUsage::None
203 }
204
205 let primary = self.primary();
206 let mut usage = usage_from_flags(primary.flags);
207
208 primary.each_cached_lazy_pseudo(|style| {
210 usage = std::cmp::max(usage, usage_from_flags(style.flags));
211 });
212
213 for pseudo_style in self.pseudos.as_array() {
214 if let Some(pseudo_style) = pseudo_style {
215 usage = std::cmp::max(usage, usage_from_flags(pseudo_style.flags));
216 pseudo_style.each_cached_lazy_pseudo(|style| {
218 usage = std::cmp::max(usage, usage_from_flags(style.flags));
219 });
220 }
221 }
222
223 usage
224 }
225
226 pub fn uses_tree_counting_function(&self, t: TreeCountingFunction) -> bool {
228 let usage_from_flags = |flags: ComputedValueFlags| {
229 if t == TreeCountingFunction::SiblingCount
230 && flags.intersects(ComputedValueFlags::USES_SIBLING_COUNT)
231 {
232 return true;
233 }
234 if t == TreeCountingFunction::SiblingIndex
235 && flags.intersects(ComputedValueFlags::USES_SIBLING_INDEX)
236 {
237 return true;
238 }
239 false
240 };
241
242 if usage_from_flags(self.primary().flags) {
243 return true;
244 }
245
246 for pseudo_style in self.pseudos.as_array().iter().flatten() {
247 if usage_from_flags(pseudo_style.flags) {
248 return true;
249 }
250 }
251
252 false
253 }
254
255 pub fn uses_element_scoped_random(&self) -> bool {
257 let usage_from_flags = |flags: ComputedValueFlags| {
258 flags.intersects(ComputedValueFlags::USES_ELEMENT_SCOPED_RANDOM)
259 };
260
261 if usage_from_flags(self.primary().flags) {
262 return true;
263 }
264
265 for pseudo_style in self.pseudos.as_array().iter().flatten() {
266 if usage_from_flags(pseudo_style.flags) {
267 return true;
268 }
269 }
270
271 false
272 }
273
274 #[cfg(feature = "gecko")]
275 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
276 0
283 }
284}
285
286impl fmt::Debug for ElementStyles {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291 write!(
292 f,
293 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
294 self.primary.as_ref().map(|x| &x.rules),
295 self.pseudos
296 )
297 }
298}
299
300#[derive(Debug, Default)]
306pub struct ElementData {
307 pub styles: ElementStyles,
309
310 pub damage: RestyleDamage,
313
314 pub hint: RestyleHint,
317
318 pub flags: ElementDataFlags,
320}
321
322#[derive(Debug, Default)]
324pub struct ElementDataWrapper {
325 inner: std::cell::UnsafeCell<ElementData>,
326 #[cfg(debug_assertions)]
328 refcell: AtomicRefCell<()>,
329}
330
331#[derive(Debug)]
333pub struct ElementDataMut<'a> {
334 v: &'a mut ElementData,
335 #[cfg(debug_assertions)]
336 _borrow: AtomicRefMut<'a, ()>,
337}
338
339#[derive(Debug)]
341pub struct ElementDataRef<'a> {
342 v: &'a ElementData,
343 #[cfg(debug_assertions)]
344 _borrow: AtomicRef<'a, ()>,
345}
346
347impl ElementDataWrapper {
348 #[inline(always)]
350 pub fn borrow(&self) -> ElementDataRef<'_> {
351 #[cfg(debug_assertions)]
352 let borrow = self.refcell.borrow();
353 ElementDataRef {
354 v: unsafe { &*self.inner.get() },
355 #[cfg(debug_assertions)]
356 _borrow: borrow,
357 }
358 }
359
360 #[inline(always)]
362 pub fn borrow_mut(&self) -> ElementDataMut<'_> {
363 #[cfg(debug_assertions)]
364 let borrow = self.refcell.borrow_mut();
365 ElementDataMut {
366 v: unsafe { &mut *self.inner.get() },
367 #[cfg(debug_assertions)]
368 _borrow: borrow,
369 }
370 }
371}
372
373impl<'a> Deref for ElementDataRef<'a> {
374 type Target = ElementData;
375 #[inline]
376 fn deref(&self) -> &Self::Target {
377 self.v
378 }
379}
380
381impl<'a> Deref for ElementDataMut<'a> {
382 type Target = ElementData;
383 #[inline]
384 fn deref(&self) -> &Self::Target {
385 &*self.v
386 }
387}
388
389impl<'a> DerefMut for ElementDataMut<'a> {
390 fn deref_mut(&mut self) -> &mut Self::Target {
391 &mut *self.v
392 }
393}
394
395size_of_test!(ElementData, 24);
397
398#[derive(Debug)]
400pub enum RestyleKind {
401 MatchAndCascade,
404 CascadeWithReplacements(RestyleHint),
407 CascadeOnly,
410}
411
412fn needs_to_match_self(hint: RestyleHint, style: &ComputedValues) -> bool {
413 if hint.intersects(RestyleHint::RESTYLE_SELF) {
414 return true;
415 }
416 if hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style() {
417 return true;
418 }
419 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_WM_OR_ANCESTOR_FONT)
420 && style
421 .flags
422 .intersects(ComputedValueFlags::USES_FONT_OR_WM_RELATIVE_UNITS_ON_CONTAINER_QUERIES)
423 {
424 return true;
425 }
426 hint.intersects(
427 RestyleHint::RESTYLE_IF_AFFECTED_BY_STYLE_QUERIES
428 | RestyleHint::RESTYLE_IF_AFFECTED_BY_NAMED_STYLE_CONTAINER,
429 ) && style
430 .flags
431 .intersects(ComputedValueFlags::DEPENDS_ON_CONTAINER_STYLE_QUERY)
432}
433
434fn needs_to_recascade_self(hint: RestyleHint, style: &ComputedValues) -> bool {
435 if hint.intersects(RestyleHint::RECASCADE_SELF) {
436 return true;
437 }
438 if hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
439 && style
440 .flags
441 .contains(ComputedValueFlags::INHERITS_RESET_STYLE)
442 {
443 return true;
444 }
445 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_WM_OR_ANCESTOR_FONT)
446 && style
447 .flags
448 .contains(ComputedValueFlags::USES_FONT_OR_WM_RELATIVE_UNITS)
449 {
450 return true;
451 }
452 false
453}
454
455impl ElementData {
456 pub fn invalidate_style_if_needed<E: TElement>(
460 &mut self,
461 element: E,
462 shared_context: &SharedStyleContext,
463 stack_limit_checker: Option<&StackLimitChecker>,
464 selector_caches: &mut SelectorCaches,
465 ) -> InvalidationResult {
466 if shared_context.traversal_flags.for_animation_only() {
468 return InvalidationResult::empty();
469 }
470
471 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
472 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
473
474 debug!(
475 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
476 handled_snapshot: {}, pseudo: {:?}",
477 element,
478 shared_context.traversal_flags,
479 element.has_snapshot(),
480 element.handled_snapshot(),
481 element.implemented_pseudo_element()
482 );
483
484 if !element.has_snapshot() || element.handled_snapshot() {
485 return InvalidationResult::empty();
486 }
487
488 let mut processor =
489 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
490
491 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
492
493 let result = invalidator.invalidate();
494
495 unsafe { element.set_handled_snapshot() }
496 debug_assert!(element.handled_snapshot());
497
498 result
499 }
500
501 #[inline]
503 pub fn has_styles(&self) -> bool {
504 self.styles.primary.is_some()
505 }
506
507 pub fn share_styles(&self) -> ResolvedElementStyles {
509 ResolvedElementStyles {
510 primary: self.share_primary_style(),
511 pseudos: self.styles.pseudos.clone(),
512 }
513 }
514
515 pub fn share_primary_style(&self) -> PrimaryStyle {
517 let reused_via_rule_node = self
518 .flags
519 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
520
521 PrimaryStyle {
522 style: ResolvedStyle(self.styles.primary().clone()),
523 reused_via_rule_node,
524 }
525 }
526
527 pub fn clone_style_with_flags(&self, flags: ComputedValueFlags) -> ResolvedStyle {
530 let primary_style = self.styles.primary();
531 let pseudo = primary_style.pseudo();
534 ResolvedStyle(
535 primary_style
536 .deref()
537 .clone_with_flags(flags, pseudo.as_ref()),
538 )
539 }
540
541 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
543 self.flags.set(
544 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
545 new_styles.primary.reused_via_rule_node,
546 );
547 mem::replace(&mut self.styles, new_styles.into())
548 }
549
550 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
553 let style = match self.styles.primary {
554 Some(ref s) => s,
555 None => return Some(RestyleKind::MatchAndCascade),
556 };
557
558 if shared_context.traversal_flags.for_animation_only() {
559 return self.restyle_kind_for_animation(shared_context);
560 }
561
562 let hint = self.hint;
563 if hint.is_empty() {
564 return None;
565 }
566
567 if needs_to_match_self(hint, style) {
568 return Some(RestyleKind::MatchAndCascade);
569 }
570
571 if hint.has_replacements() {
572 debug_assert!(
573 !hint.has_animation_hint(),
574 "Animation only restyle hint should have already processed"
575 );
576 return Some(RestyleKind::CascadeWithReplacements(
577 hint & RestyleHint::replacements(),
578 ));
579 }
580
581 if needs_to_recascade_self(hint, style) {
582 return Some(RestyleKind::CascadeOnly);
583 }
584
585 None
586 }
587
588 fn restyle_kind_for_animation(
590 &self,
591 shared_context: &SharedStyleContext,
592 ) -> Option<RestyleKind> {
593 debug_assert!(shared_context.traversal_flags.for_animation_only());
594 debug_assert!(self.has_styles());
595
596 let hint = self.hint;
605 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
606 return None;
607 }
608
609 let style = self.styles.primary();
610 if hint.has_animation_hint() {
613 return Some(RestyleKind::CascadeWithReplacements(
614 hint & RestyleHint::for_animations(),
615 ));
616 }
617
618 if needs_to_recascade_self(hint, style) {
619 return Some(RestyleKind::CascadeOnly);
620 }
621 None
622 }
623
624 #[inline]
629 pub fn clear_restyle_state(&mut self) {
630 self.hint = RestyleHint::empty();
631 self.clear_restyle_flags_and_damage();
632 }
633
634 #[inline]
636 pub fn clear_restyle_flags_and_damage(&mut self) {
637 self.damage = RestyleDamage::empty();
638 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
639 }
640
641 pub fn set_restyled(&mut self) {
644 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
645 self.flags
646 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
647 }
648
649 #[inline]
651 pub fn is_restyle(&self) -> bool {
652 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
653 }
654
655 pub fn set_traversed_without_styling(&mut self) {
657 self.flags
658 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
659 }
660
661 #[inline]
663 pub fn contains_restyle_data(&self) -> bool {
664 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
665 }
666
667 pub fn safe_for_cousin_sharing(&self) -> bool {
686 if self.flags.intersects(
687 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
688 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
689 ) {
690 return false;
691 }
692 if !self
693 .styles
694 .primary()
695 .get_box()
696 .get_container_type()
697 .is_normal()
698 {
699 return false;
700 }
701 true
702 }
703
704 #[cfg(feature = "gecko")]
706 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
707 let n = self.styles.size_of_excluding_cvs(ops);
708
709 n
712 }
713}