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: &'static 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(ref 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() {
248 if let Some(ref pseudo_style) = pseudo_style {
249 usage |= usage_from_flags(pseudo_style.flags);
250 }
251 }
252
253 usage
254 }
255
256 #[cfg(feature = "gecko")]
257 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
258 0
265 }
266}
267
268impl fmt::Debug for ElementStyles {
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 write!(
274 f,
275 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
276 self.primary.as_ref().map(|x| &x.rules),
277 self.pseudos
278 )
279 }
280}
281
282#[derive(Debug, Default)]
288pub struct ElementData {
289 pub styles: ElementStyles,
291
292 pub damage: RestyleDamage,
295
296 pub hint: RestyleHint,
299
300 pub flags: ElementDataFlags,
302}
303
304#[derive(Debug, Default)]
306pub struct ElementDataWrapper {
307 inner: std::cell::UnsafeCell<ElementData>,
308 #[cfg(debug_assertions)]
310 refcell: AtomicRefCell<()>,
311}
312
313#[derive(Debug)]
315pub struct ElementDataMut<'a> {
316 v: &'a mut ElementData,
317 #[cfg(debug_assertions)]
318 _borrow: AtomicRefMut<'a, ()>,
319}
320
321#[derive(Debug)]
323pub struct ElementDataRef<'a> {
324 v: &'a ElementData,
325 #[cfg(debug_assertions)]
326 _borrow: AtomicRef<'a, ()>,
327}
328
329impl ElementDataWrapper {
330 #[inline(always)]
332 pub fn borrow(&self) -> ElementDataRef<'_> {
333 #[cfg(debug_assertions)]
334 let borrow = self.refcell.borrow();
335 ElementDataRef {
336 v: unsafe { &*self.inner.get() },
337 #[cfg(debug_assertions)]
338 _borrow: borrow,
339 }
340 }
341
342 #[inline(always)]
344 pub fn borrow_mut(&self) -> ElementDataMut<'_> {
345 #[cfg(debug_assertions)]
346 let borrow = self.refcell.borrow_mut();
347 ElementDataMut {
348 v: unsafe { &mut *self.inner.get() },
349 #[cfg(debug_assertions)]
350 _borrow: borrow,
351 }
352 }
353}
354
355impl<'a> Deref for ElementDataRef<'a> {
356 type Target = ElementData;
357 #[inline]
358 fn deref(&self) -> &Self::Target {
359 &*self.v
360 }
361}
362
363impl<'a> Deref for ElementDataMut<'a> {
364 type Target = ElementData;
365 #[inline]
366 fn deref(&self) -> &Self::Target {
367 &*self.v
368 }
369}
370
371impl<'a> DerefMut for ElementDataMut<'a> {
372 fn deref_mut(&mut self) -> &mut Self::Target {
373 &mut *self.v
374 }
375}
376
377size_of_test!(ElementData, 24);
379
380#[derive(Debug)]
382pub enum RestyleKind {
383 MatchAndCascade,
386 CascadeWithReplacements(RestyleHint),
389 CascadeOnly,
392}
393
394fn needs_to_match_self(hint: RestyleHint, style: &ComputedValues) -> bool {
395 if hint.intersects(RestyleHint::RESTYLE_SELF) {
396 return true;
397 }
398 if hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style() {
399 return true;
400 }
401 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_ANCESTOR_FONT)
402 && style
403 .flags
404 .intersects(ComputedValueFlags::USES_FONT_RELATIVE_UNITS_ON_CONTAINER_QUERIES)
405 {
406 return true;
407 }
408 hint.intersects(
409 RestyleHint::RESTYLE_IF_AFFECTED_BY_STYLE_QUERIES
410 | RestyleHint::RESTYLE_IF_AFFECTED_BY_NAMED_STYLE_CONTAINER,
411 ) && style
412 .flags
413 .intersects(ComputedValueFlags::DEPENDS_ON_CONTAINER_STYLE_QUERY)
414}
415
416fn needs_to_recascade_self(hint: RestyleHint, style: &ComputedValues) -> bool {
417 if hint.intersects(RestyleHint::RECASCADE_SELF) {
418 return true;
419 }
420 if hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
421 && style
422 .flags
423 .contains(ComputedValueFlags::INHERITS_RESET_STYLE)
424 {
425 return true;
426 }
427 if hint.intersects(RestyleHint::RESTYLE_IF_AFFECTED_BY_ANCESTOR_FONT)
428 && style
429 .flags
430 .contains(ComputedValueFlags::USES_FONT_RELATIVE_UNITS)
431 {
432 return true;
433 }
434 return false;
435}
436
437impl ElementData {
438 pub fn invalidate_style_if_needed<'a, E: TElement>(
442 &mut self,
443 element: E,
444 shared_context: &SharedStyleContext,
445 stack_limit_checker: Option<&StackLimitChecker>,
446 selector_caches: &'a mut SelectorCaches,
447 ) -> InvalidationResult {
448 if shared_context.traversal_flags.for_animation_only() {
450 return InvalidationResult::empty();
451 }
452
453 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
454 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
455
456 debug!(
457 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
458 handled_snapshot: {}, pseudo: {:?}",
459 element,
460 shared_context.traversal_flags,
461 element.has_snapshot(),
462 element.handled_snapshot(),
463 element.implemented_pseudo_element()
464 );
465
466 if !element.has_snapshot() || element.handled_snapshot() {
467 return InvalidationResult::empty();
468 }
469
470 let mut processor =
471 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
472
473 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
474
475 let result = invalidator.invalidate();
476
477 unsafe { element.set_handled_snapshot() }
478 debug_assert!(element.handled_snapshot());
479
480 result
481 }
482
483 #[inline]
485 pub fn has_styles(&self) -> bool {
486 self.styles.primary.is_some()
487 }
488
489 pub fn share_styles(&self) -> ResolvedElementStyles {
491 ResolvedElementStyles {
492 primary: self.share_primary_style(),
493 pseudos: self.styles.pseudos.clone(),
494 }
495 }
496
497 pub fn share_primary_style(&self) -> PrimaryStyle {
499 let reused_via_rule_node = self
500 .flags
501 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
502
503 PrimaryStyle {
504 style: ResolvedStyle(self.styles.primary().clone()),
505 reused_via_rule_node,
506 }
507 }
508
509 pub fn clone_style_with_flags(&self, flags: ComputedValueFlags) -> ResolvedStyle {
512 let primary_style = self.styles.primary();
513 let pseudo = primary_style.pseudo();
516 ResolvedStyle(
517 primary_style
518 .deref()
519 .clone_with_flags(flags, pseudo.as_ref()),
520 )
521 }
522
523 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
525 self.flags.set(
526 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
527 new_styles.primary.reused_via_rule_node,
528 );
529 mem::replace(&mut self.styles, new_styles.into())
530 }
531
532 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
535 let style = match self.styles.primary {
536 Some(ref s) => s,
537 None => return Some(RestyleKind::MatchAndCascade),
538 };
539
540 if shared_context.traversal_flags.for_animation_only() {
541 return self.restyle_kind_for_animation(shared_context);
542 }
543
544 let hint = self.hint;
545 if hint.is_empty() {
546 return None;
547 }
548
549 if needs_to_match_self(hint, style) {
550 return Some(RestyleKind::MatchAndCascade);
551 }
552
553 if hint.has_replacements() {
554 debug_assert!(
555 !hint.has_animation_hint(),
556 "Animation only restyle hint should have already processed"
557 );
558 return Some(RestyleKind::CascadeWithReplacements(
559 hint & RestyleHint::replacements(),
560 ));
561 }
562
563 if needs_to_recascade_self(hint, style) {
564 return Some(RestyleKind::CascadeOnly);
565 }
566
567 None
568 }
569
570 fn restyle_kind_for_animation(
572 &self,
573 shared_context: &SharedStyleContext,
574 ) -> Option<RestyleKind> {
575 debug_assert!(shared_context.traversal_flags.for_animation_only());
576 debug_assert!(self.has_styles());
577
578 let hint = self.hint;
587 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
588 return None;
589 }
590
591 let style = self.styles.primary();
592 if hint.has_animation_hint() {
595 return Some(RestyleKind::CascadeWithReplacements(
596 hint & RestyleHint::for_animations(),
597 ));
598 }
599
600 if needs_to_recascade_self(hint, style) {
601 return Some(RestyleKind::CascadeOnly);
602 }
603 return None;
604 }
605
606 #[inline]
611 pub fn clear_restyle_state(&mut self) {
612 self.hint = RestyleHint::empty();
613 self.clear_restyle_flags_and_damage();
614 }
615
616 #[inline]
618 pub fn clear_restyle_flags_and_damage(&mut self) {
619 self.damage = RestyleDamage::empty();
620 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
621 }
622
623 pub fn set_restyled(&mut self) {
626 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
627 self.flags
628 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
629 }
630
631 #[inline]
633 pub fn is_restyle(&self) -> bool {
634 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
635 }
636
637 pub fn set_traversed_without_styling(&mut self) {
639 self.flags
640 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
641 }
642
643 #[inline]
645 pub fn contains_restyle_data(&self) -> bool {
646 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
647 }
648
649 pub fn safe_for_cousin_sharing(&self) -> bool {
668 if self.flags.intersects(
669 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
670 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
671 ) {
672 return false;
673 }
674 if !self
675 .styles
676 .primary()
677 .get_box()
678 .clone_container_type()
679 .is_normal()
680 {
681 return false;
682 }
683 true
684 }
685
686 #[cfg(feature = "gecko")]
688 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
689 let n = self.styles.size_of_excluding_cvs(ops);
690
691 n
694 }
695}