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::ops::{Deref, DerefMut};
20use std::{fmt, mem};
21
22#[cfg(debug_assertions)]
23use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
24
25bitflags! {
26 #[derive(Debug, Default)]
28 pub struct ElementDataFlags: u8 {
29 const WAS_RESTYLED = 1 << 0;
31 const TRAVERSED_WITHOUT_STYLING = 1 << 1;
40
41 const PRIMARY_STYLE_REUSED_VIA_RULE_NODE = 1 << 2;
50
51 const MAY_HAVE_STARTING_STYLE = 1 << 3;
53 }
54}
55
56#[derive(Clone, Debug, Default)]
63pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);
64
65#[derive(Default)]
66struct EagerPseudoArray(EagerPseudoArrayInner);
67type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];
68
69impl Deref for EagerPseudoArray {
70 type Target = EagerPseudoArrayInner;
71 fn deref(&self) -> &Self::Target {
72 &self.0
73 }
74}
75
76impl DerefMut for EagerPseudoArray {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.0
79 }
80}
81
82impl Clone for EagerPseudoArray {
85 fn clone(&self) -> Self {
86 let mut clone = Self::default();
87 for i in 0..EAGER_PSEUDO_COUNT {
88 clone[i] = self.0[i].clone();
89 }
90 clone
91 }
92}
93
94impl fmt::Debug for EagerPseudoArray {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 write!(f, "EagerPseudoArray {{ ")?;
99 for i in 0..EAGER_PSEUDO_COUNT {
100 if let Some(ref values) = self[i] {
101 write!(
102 f,
103 "{:?}: {:?}, ",
104 PseudoElement::from_eager_index(i),
105 &values.rules
106 )?;
107 }
108 }
109 write!(f, "}}")
110 }
111}
112
113#[cfg(feature = "gecko")]
116const EMPTY_PSEUDO_ARRAY: &'static EagerPseudoArrayInner = &[None, None, None, None];
117#[cfg(feature = "servo")]
118const EMPTY_PSEUDO_ARRAY: &'static EagerPseudoArrayInner = &[None, None, None];
119
120impl EagerPseudoStyles {
121 pub fn is_empty(&self) -> bool {
123 self.0.is_none()
124 }
125
126 pub fn as_optional_array(&self) -> Option<&EagerPseudoArrayInner> {
128 match self.0 {
129 None => None,
130 Some(ref x) => Some(&x.0),
131 }
132 }
133
134 pub fn as_array(&self) -> &EagerPseudoArrayInner {
137 self.as_optional_array().unwrap_or(EMPTY_PSEUDO_ARRAY)
138 }
139
140 pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
142 debug_assert!(pseudo.is_eager());
143 self.0
144 .as_ref()
145 .and_then(|p| p[pseudo.eager_index()].as_ref())
146 }
147
148 pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
150 if self.0.is_none() {
151 self.0 = Some(Arc::new(Default::default()));
152 }
153 let arr = Arc::make_mut(self.0.as_mut().unwrap());
154 arr[pseudo.eager_index()] = Some(value);
155 }
156}
157
158#[derive(Clone, Default)]
161pub struct ElementStyles {
162 pub primary: Option<Arc<ComputedValues>>,
164 pub pseudos: EagerPseudoStyles,
166}
167
168size_of_test!(ElementStyles, 16);
170
171#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
173pub enum ViewportUnitUsage {
174 None = 0,
176 FromDeclaration,
179 FromQuery,
182}
183
184impl ElementStyles {
185 pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
187 self.primary.as_ref()
188 }
189
190 pub fn primary(&self) -> &Arc<ComputedValues> {
192 self.primary.as_ref().unwrap()
193 }
194
195 pub fn is_display_none(&self) -> bool {
197 self.primary().get_box().clone_display().is_none()
198 }
199
200 pub fn viewport_unit_usage(&self) -> ViewportUnitUsage {
202 fn usage_from_flags(flags: ComputedValueFlags) -> ViewportUnitUsage {
203 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES) {
204 return ViewportUnitUsage::FromQuery;
205 }
206 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) {
207 return ViewportUnitUsage::FromDeclaration;
208 }
209 ViewportUnitUsage::None
210 }
211
212 let primary = self.primary();
213 let mut usage = usage_from_flags(primary.flags);
214
215 primary.each_cached_lazy_pseudo(|style| {
217 usage = std::cmp::max(usage, usage_from_flags(style.flags));
218 });
219
220 for pseudo_style in self.pseudos.as_array() {
221 if let Some(ref pseudo_style) = pseudo_style {
222 usage = std::cmp::max(usage, usage_from_flags(pseudo_style.flags));
223 pseudo_style.each_cached_lazy_pseudo(|style| {
225 usage = std::cmp::max(usage, usage_from_flags(style.flags));
226 });
227 }
228 }
229
230 usage
231 }
232
233 #[cfg(feature = "gecko")]
234 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
235 0
242 }
243}
244
245impl fmt::Debug for ElementStyles {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 write!(
251 f,
252 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
253 self.primary.as_ref().map(|x| &x.rules),
254 self.pseudos
255 )
256 }
257}
258
259#[derive(Debug, Default)]
265pub struct ElementData {
266 pub styles: ElementStyles,
268
269 pub damage: RestyleDamage,
272
273 pub hint: RestyleHint,
276
277 pub flags: ElementDataFlags,
279}
280
281#[derive(Debug, Default)]
283pub struct ElementDataWrapper {
284 inner: std::cell::UnsafeCell<ElementData>,
285 #[cfg(debug_assertions)]
287 refcell: AtomicRefCell<()>,
288}
289
290#[derive(Debug)]
292pub struct ElementDataMut<'a> {
293 v: &'a mut ElementData,
294 #[cfg(debug_assertions)]
295 _borrow: AtomicRefMut<'a, ()>,
296}
297
298#[derive(Debug)]
300pub struct ElementDataRef<'a> {
301 v: &'a ElementData,
302 #[cfg(debug_assertions)]
303 _borrow: AtomicRef<'a, ()>,
304}
305
306impl ElementDataWrapper {
307 #[inline(always)]
309 pub fn borrow(&self) -> ElementDataRef<'_> {
310 #[cfg(debug_assertions)]
311 let borrow = self.refcell.borrow();
312 ElementDataRef {
313 v: unsafe { &*self.inner.get() },
314 #[cfg(debug_assertions)]
315 _borrow: borrow,
316 }
317 }
318
319 #[inline(always)]
321 pub fn borrow_mut(&self) -> ElementDataMut<'_> {
322 #[cfg(debug_assertions)]
323 let borrow = self.refcell.borrow_mut();
324 ElementDataMut {
325 v: unsafe { &mut *self.inner.get() },
326 #[cfg(debug_assertions)]
327 _borrow: borrow,
328 }
329 }
330}
331
332impl<'a> Deref for ElementDataRef<'a> {
333 type Target = ElementData;
334 #[inline]
335 fn deref(&self) -> &Self::Target {
336 &*self.v
337 }
338}
339
340impl<'a> Deref for ElementDataMut<'a> {
341 type Target = ElementData;
342 #[inline]
343 fn deref(&self) -> &Self::Target {
344 &*self.v
345 }
346}
347
348impl<'a> DerefMut for ElementDataMut<'a> {
349 fn deref_mut(&mut self) -> &mut Self::Target {
350 &mut *self.v
351 }
352}
353
354size_of_test!(ElementData, 24);
356
357#[derive(Debug)]
359pub enum RestyleKind {
360 MatchAndCascade,
363 CascadeWithReplacements(RestyleHint),
366 CascadeOnly,
369}
370
371impl ElementData {
372 pub fn invalidate_style_if_needed<'a, E: TElement>(
376 &mut self,
377 element: E,
378 shared_context: &SharedStyleContext,
379 stack_limit_checker: Option<&StackLimitChecker>,
380 selector_caches: &'a mut SelectorCaches,
381 ) -> InvalidationResult {
382 if shared_context.traversal_flags.for_animation_only() {
384 return InvalidationResult::empty();
385 }
386
387 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
388 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
389
390 debug!(
391 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
392 handled_snapshot: {}, pseudo: {:?}",
393 element,
394 shared_context.traversal_flags,
395 element.has_snapshot(),
396 element.handled_snapshot(),
397 element.implemented_pseudo_element()
398 );
399
400 if !element.has_snapshot() || element.handled_snapshot() {
401 return InvalidationResult::empty();
402 }
403
404 let mut processor =
405 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
406
407 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
408
409 let result = invalidator.invalidate();
410
411 unsafe { element.set_handled_snapshot() }
412 debug_assert!(element.handled_snapshot());
413
414 result
415 }
416
417 #[inline]
419 pub fn has_styles(&self) -> bool {
420 self.styles.primary.is_some()
421 }
422
423 pub fn share_styles(&self) -> ResolvedElementStyles {
425 ResolvedElementStyles {
426 primary: self.share_primary_style(),
427 pseudos: self.styles.pseudos.clone(),
428 }
429 }
430
431 pub fn share_primary_style(&self) -> PrimaryStyle {
433 let reused_via_rule_node = self
434 .flags
435 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
436 let may_have_starting_style = self
437 .flags
438 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE);
439
440 PrimaryStyle {
441 style: ResolvedStyle(self.styles.primary().clone()),
442 reused_via_rule_node,
443 may_have_starting_style,
444 }
445 }
446
447 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
449 self.flags.set(
450 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
451 new_styles.primary.reused_via_rule_node,
452 );
453 self.flags.set(
454 ElementDataFlags::MAY_HAVE_STARTING_STYLE,
455 new_styles.primary.may_have_starting_style,
456 );
457
458 mem::replace(&mut self.styles, new_styles.into())
459 }
460
461 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
464 let style = match self.styles.primary {
465 Some(ref s) => s,
466 None => return Some(RestyleKind::MatchAndCascade),
467 };
468
469 if shared_context.traversal_flags.for_animation_only() {
470 return self.restyle_kind_for_animation(shared_context);
471 }
472
473 let hint = self.hint;
474 if hint.is_empty() {
475 return None;
476 }
477
478 let needs_to_match_self = hint.intersects(RestyleHint::RESTYLE_SELF)
479 || (hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style());
480 if needs_to_match_self {
481 return Some(RestyleKind::MatchAndCascade);
482 }
483
484 if hint.has_replacements() {
485 debug_assert!(
486 !hint.has_animation_hint(),
487 "Animation only restyle hint should have already processed"
488 );
489 return Some(RestyleKind::CascadeWithReplacements(
490 hint & RestyleHint::replacements(),
491 ));
492 }
493
494 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
495 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
496 && style
497 .flags
498 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
499 if needs_to_recascade_self {
500 return Some(RestyleKind::CascadeOnly);
501 }
502
503 None
504 }
505
506 fn restyle_kind_for_animation(
508 &self,
509 shared_context: &SharedStyleContext,
510 ) -> Option<RestyleKind> {
511 debug_assert!(shared_context.traversal_flags.for_animation_only());
512 debug_assert!(self.has_styles());
513
514 let hint = self.hint;
523 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
524 return None;
525 }
526
527 let style = self.styles.primary();
528 if hint.has_animation_hint() {
531 return Some(RestyleKind::CascadeWithReplacements(
532 hint & RestyleHint::for_animations(),
533 ));
534 }
535
536 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
537 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
538 && style
539 .flags
540 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
541 if needs_to_recascade_self {
542 return Some(RestyleKind::CascadeOnly);
543 }
544 return None;
545 }
546
547 #[inline]
552 pub fn clear_restyle_state(&mut self) {
553 self.hint = RestyleHint::empty();
554 self.clear_restyle_flags_and_damage();
555 }
556
557 #[inline]
559 pub fn clear_restyle_flags_and_damage(&mut self) {
560 self.damage = RestyleDamage::empty();
561 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
562 }
563
564 pub fn set_restyled(&mut self) {
567 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
568 self.flags
569 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
570 }
571
572 #[inline]
574 pub fn is_restyle(&self) -> bool {
575 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
576 }
577
578 pub fn set_traversed_without_styling(&mut self) {
580 self.flags
581 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
582 }
583
584 #[inline]
586 pub fn contains_restyle_data(&self) -> bool {
587 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
588 }
589
590 pub fn safe_for_cousin_sharing(&self) -> bool {
609 if self.flags.intersects(
610 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
611 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
612 ) {
613 return false;
614 }
615 if !self
616 .styles
617 .primary()
618 .get_box()
619 .clone_container_type()
620 .is_normal()
621 {
622 return false;
623 }
624 true
625 }
626
627 #[cfg(feature = "gecko")]
629 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
630 let n = self.styles.size_of_excluding_cvs(ops);
631
632 n
635 }
636
637 #[inline]
640 pub fn may_have_starting_style(&self) -> bool {
641 self.flags
642 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE)
643 }
644}