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};
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 = &[None, None, None, None];
114
115impl EagerPseudoStyles {
116 pub fn is_empty(&self) -> bool {
118 self.0.is_none()
119 }
120
121 pub fn as_optional_array(&self) -> Option<&EagerPseudoArrayInner> {
123 match self.0 {
124 None => None,
125 Some(ref x) => Some(&x.0),
126 }
127 }
128
129 pub fn as_array(&self) -> &EagerPseudoArrayInner {
132 self.as_optional_array().unwrap_or(EMPTY_PSEUDO_ARRAY)
133 }
134
135 pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
137 debug_assert!(pseudo.is_eager());
138 self.0
139 .as_ref()
140 .and_then(|p| p[pseudo.eager_index()].as_ref())
141 }
142
143 pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
145 if self.0.is_none() {
146 self.0 = Some(Arc::new(Default::default()));
147 }
148 let arr = Arc::make_mut(self.0.as_mut().unwrap());
149 arr[pseudo.eager_index()] = Some(value);
150 }
151}
152
153#[derive(Clone, Default)]
156pub struct ElementStyles {
157 pub primary: Option<Arc<ComputedValues>>,
159 pub pseudos: EagerPseudoStyles,
161}
162
163size_of_test!(ElementStyles, 16);
165
166#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
168pub enum ViewportUnitUsage {
169 None = 0,
171 FromDeclaration,
174 FromQuery,
177}
178
179impl ElementStyles {
180 pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
182 self.primary.as_ref()
183 }
184
185 pub fn primary(&self) -> &Arc<ComputedValues> {
187 self.primary.as_ref().unwrap()
188 }
189
190 pub fn is_display_none(&self) -> bool {
192 self.primary().get_box().clone_display().is_none()
193 }
194
195 pub fn viewport_unit_usage(&self) -> ViewportUnitUsage {
197 fn usage_from_flags(flags: ComputedValueFlags) -> ViewportUnitUsage {
198 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES) {
199 return ViewportUnitUsage::FromQuery;
200 }
201 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) {
202 return ViewportUnitUsage::FromDeclaration;
203 }
204 ViewportUnitUsage::None
205 }
206
207 let primary = self.primary();
208 let mut usage = usage_from_flags(primary.flags);
209
210 primary.each_cached_lazy_pseudo(|style| {
212 usage = std::cmp::max(usage, usage_from_flags(style.flags));
213 });
214
215 for pseudo_style in self.pseudos.as_array() {
216 if let Some(pseudo_style) = pseudo_style {
217 usage = std::cmp::max(usage, usage_from_flags(pseudo_style.flags));
218 pseudo_style.each_cached_lazy_pseudo(|style| {
220 usage = std::cmp::max(usage, usage_from_flags(style.flags));
221 });
222 }
223 }
224
225 usage
226 }
227
228 pub fn uses_tree_counting_function(&self, t: TreeCountingFunction) -> bool {
230 let usage_from_flags = |flags: ComputedValueFlags| -> bool {
231 if t == TreeCountingFunction::SiblingCount
232 && flags.intersects(ComputedValueFlags::USES_SIBLING_COUNT)
233 {
234 return true;
235 }
236 if t == TreeCountingFunction::SiblingIndex
237 && flags.intersects(ComputedValueFlags::USES_SIBLING_INDEX)
238 {
239 return true;
240 }
241 false
242 };
243
244 let primary = self.primary();
245 let mut usage = usage_from_flags(primary.flags);
246
247 for pseudo_style in self.pseudos.as_array().iter().flatten() {
248 usage |= usage_from_flags(pseudo_style.flags);
249 }
250
251 usage
252 }
253
254 #[cfg(feature = "gecko")]
255 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
256 0
263 }
264}
265
266impl fmt::Debug for ElementStyles {
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 write!(
272 f,
273 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
274 self.primary.as_ref().map(|x| &x.rules),
275 self.pseudos
276 )
277 }
278}
279
280#[derive(Debug, Default)]
286pub struct ElementData {
287 pub styles: ElementStyles,
289
290 pub damage: RestyleDamage,
293
294 pub hint: RestyleHint,
297
298 pub flags: ElementDataFlags,
300}
301
302#[derive(Debug, Default)]
304pub struct ElementDataWrapper {
305 inner: std::cell::UnsafeCell<ElementData>,
306 #[cfg(debug_assertions)]
308 refcell: AtomicRefCell<()>,
309}
310
311#[derive(Debug)]
313pub struct ElementDataMut<'a> {
314 v: &'a mut ElementData,
315 #[cfg(debug_assertions)]
316 _borrow: AtomicRefMut<'a, ()>,
317}
318
319#[derive(Debug)]
321pub struct ElementDataRef<'a> {
322 v: &'a ElementData,
323 #[cfg(debug_assertions)]
324 _borrow: AtomicRef<'a, ()>,
325}
326
327impl ElementDataWrapper {
328 #[inline(always)]
330 pub fn borrow(&self) -> ElementDataRef<'_> {
331 #[cfg(debug_assertions)]
332 let borrow = self.refcell.borrow();
333 ElementDataRef {
334 v: unsafe { &*self.inner.get() },
335 #[cfg(debug_assertions)]
336 _borrow: borrow,
337 }
338 }
339
340 #[inline(always)]
342 pub fn borrow_mut(&self) -> ElementDataMut<'_> {
343 #[cfg(debug_assertions)]
344 let borrow = self.refcell.borrow_mut();
345 ElementDataMut {
346 v: unsafe { &mut *self.inner.get() },
347 #[cfg(debug_assertions)]
348 _borrow: borrow,
349 }
350 }
351}
352
353impl<'a> Deref for ElementDataRef<'a> {
354 type Target = ElementData;
355 #[inline]
356 fn deref(&self) -> &Self::Target {
357 self.v
358 }
359}
360
361impl<'a> Deref for ElementDataMut<'a> {
362 type Target = ElementData;
363 #[inline]
364 fn deref(&self) -> &Self::Target {
365 &*self.v
366 }
367}
368
369impl<'a> DerefMut for ElementDataMut<'a> {
370 fn deref_mut(&mut self) -> &mut Self::Target {
371 &mut *self.v
372 }
373}
374
375size_of_test!(ElementData, 24);
377
378#[derive(Debug)]
380pub enum RestyleKind {
381 MatchAndCascade,
384 CascadeWithReplacements(RestyleHint),
387 CascadeOnly,
390}
391
392fn needs_to_match_self(hint: RestyleHint, style: &ComputedValues) -> bool {
393 if hint.intersects(RestyleHint::RESTYLE_SELF) {
394 return true;
395 }
396 if hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style() {
397 return true;
398 }
399 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_WM_OR_ANCESTOR_FONT)
400 && style
401 .flags
402 .intersects(ComputedValueFlags::USES_FONT_OR_WM_RELATIVE_UNITS_ON_CONTAINER_QUERIES)
403 {
404 return true;
405 }
406 hint.intersects(
407 RestyleHint::RESTYLE_IF_AFFECTED_BY_STYLE_QUERIES
408 | RestyleHint::RESTYLE_IF_AFFECTED_BY_NAMED_STYLE_CONTAINER,
409 ) && style
410 .flags
411 .intersects(ComputedValueFlags::DEPENDS_ON_CONTAINER_STYLE_QUERY)
412}
413
414fn needs_to_recascade_self(hint: RestyleHint, style: &ComputedValues) -> bool {
415 if hint.intersects(RestyleHint::RECASCADE_SELF) {
416 return true;
417 }
418 if hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
419 && style
420 .flags
421 .contains(ComputedValueFlags::INHERITS_RESET_STYLE)
422 {
423 return true;
424 }
425 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_WM_OR_ANCESTOR_FONT)
426 && style
427 .flags
428 .contains(ComputedValueFlags::USES_FONT_OR_WM_RELATIVE_UNITS)
429 {
430 return true;
431 }
432 false
433}
434
435impl ElementData {
436 pub fn invalidate_style_if_needed<E: TElement>(
440 &mut self,
441 element: E,
442 shared_context: &SharedStyleContext,
443 stack_limit_checker: Option<&StackLimitChecker>,
444 selector_caches: &mut SelectorCaches,
445 ) -> InvalidationResult {
446 if shared_context.traversal_flags.for_animation_only() {
448 return InvalidationResult::empty();
449 }
450
451 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
452 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
453
454 debug!(
455 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
456 handled_snapshot: {}, pseudo: {:?}",
457 element,
458 shared_context.traversal_flags,
459 element.has_snapshot(),
460 element.handled_snapshot(),
461 element.implemented_pseudo_element()
462 );
463
464 if !element.has_snapshot() || element.handled_snapshot() {
465 return InvalidationResult::empty();
466 }
467
468 let mut processor =
469 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
470
471 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
472
473 let result = invalidator.invalidate();
474
475 unsafe { element.set_handled_snapshot() }
476 debug_assert!(element.handled_snapshot());
477
478 result
479 }
480
481 #[inline]
483 pub fn has_styles(&self) -> bool {
484 self.styles.primary.is_some()
485 }
486
487 pub fn share_styles(&self) -> ResolvedElementStyles {
489 ResolvedElementStyles {
490 primary: self.share_primary_style(),
491 pseudos: self.styles.pseudos.clone(),
492 }
493 }
494
495 pub fn share_primary_style(&self) -> PrimaryStyle {
497 let reused_via_rule_node = self
498 .flags
499 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
500
501 PrimaryStyle {
502 style: ResolvedStyle(self.styles.primary().clone()),
503 reused_via_rule_node,
504 }
505 }
506
507 pub fn clone_style_with_flags(&self, flags: ComputedValueFlags) -> ResolvedStyle {
510 let primary_style = self.styles.primary();
511 let pseudo = primary_style.pseudo();
514 ResolvedStyle(
515 primary_style
516 .deref()
517 .clone_with_flags(flags, pseudo.as_ref()),
518 )
519 }
520
521 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
523 self.flags.set(
524 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
525 new_styles.primary.reused_via_rule_node,
526 );
527 mem::replace(&mut self.styles, new_styles.into())
528 }
529
530 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
533 let style = match self.styles.primary {
534 Some(ref s) => s,
535 None => return Some(RestyleKind::MatchAndCascade),
536 };
537
538 if shared_context.traversal_flags.for_animation_only() {
539 return self.restyle_kind_for_animation(shared_context);
540 }
541
542 let hint = self.hint;
543 if hint.is_empty() {
544 return None;
545 }
546
547 if needs_to_match_self(hint, style) {
548 return Some(RestyleKind::MatchAndCascade);
549 }
550
551 if hint.has_replacements() {
552 debug_assert!(
553 !hint.has_animation_hint(),
554 "Animation only restyle hint should have already processed"
555 );
556 return Some(RestyleKind::CascadeWithReplacements(
557 hint & RestyleHint::replacements(),
558 ));
559 }
560
561 if needs_to_recascade_self(hint, style) {
562 return Some(RestyleKind::CascadeOnly);
563 }
564
565 None
566 }
567
568 fn restyle_kind_for_animation(
570 &self,
571 shared_context: &SharedStyleContext,
572 ) -> Option<RestyleKind> {
573 debug_assert!(shared_context.traversal_flags.for_animation_only());
574 debug_assert!(self.has_styles());
575
576 let hint = self.hint;
585 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
586 return None;
587 }
588
589 let style = self.styles.primary();
590 if hint.has_animation_hint() {
593 return Some(RestyleKind::CascadeWithReplacements(
594 hint & RestyleHint::for_animations(),
595 ));
596 }
597
598 if needs_to_recascade_self(hint, style) {
599 return Some(RestyleKind::CascadeOnly);
600 }
601 None
602 }
603
604 #[inline]
609 pub fn clear_restyle_state(&mut self) {
610 self.hint = RestyleHint::empty();
611 self.clear_restyle_flags_and_damage();
612 }
613
614 #[inline]
616 pub fn clear_restyle_flags_and_damage(&mut self) {
617 self.damage = RestyleDamage::empty();
618 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
619 }
620
621 pub fn set_restyled(&mut self) {
624 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
625 self.flags
626 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
627 }
628
629 #[inline]
631 pub fn is_restyle(&self) -> bool {
632 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
633 }
634
635 pub fn set_traversed_without_styling(&mut self) {
637 self.flags
638 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
639 }
640
641 #[inline]
643 pub fn contains_restyle_data(&self) -> bool {
644 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
645 }
646
647 pub fn safe_for_cousin_sharing(&self) -> bool {
666 if self.flags.intersects(
667 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
668 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
669 ) {
670 return false;
671 }
672 if !self
673 .styles
674 .primary()
675 .get_box()
676 .clone_container_type()
677 .is_normal()
678 {
679 return false;
680 }
681 true
682 }
683
684 #[cfg(feature = "gecko")]
686 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
687 let n = self.styles.size_of_excluding_cvs(ops);
688
689 n
692 }
693}