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
113const EMPTY_PSEUDO_ARRAY: &'static EagerPseudoArrayInner = &[None, None, None, None];
116
117impl EagerPseudoStyles {
118 pub fn is_empty(&self) -> bool {
120 self.0.is_none()
121 }
122
123 pub fn as_optional_array(&self) -> Option<&EagerPseudoArrayInner> {
125 match self.0 {
126 None => None,
127 Some(ref x) => Some(&x.0),
128 }
129 }
130
131 pub fn as_array(&self) -> &EagerPseudoArrayInner {
134 self.as_optional_array().unwrap_or(EMPTY_PSEUDO_ARRAY)
135 }
136
137 pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
139 debug_assert!(pseudo.is_eager());
140 self.0
141 .as_ref()
142 .and_then(|p| p[pseudo.eager_index()].as_ref())
143 }
144
145 pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
147 if self.0.is_none() {
148 self.0 = Some(Arc::new(Default::default()));
149 }
150 let arr = Arc::make_mut(self.0.as_mut().unwrap());
151 arr[pseudo.eager_index()] = Some(value);
152 }
153}
154
155#[derive(Clone, Default)]
158pub struct ElementStyles {
159 pub primary: Option<Arc<ComputedValues>>,
161 pub pseudos: EagerPseudoStyles,
163}
164
165size_of_test!(ElementStyles, 16);
167
168#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
170pub enum ViewportUnitUsage {
171 None = 0,
173 FromDeclaration,
176 FromQuery,
179}
180
181impl ElementStyles {
182 pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
184 self.primary.as_ref()
185 }
186
187 pub fn primary(&self) -> &Arc<ComputedValues> {
189 self.primary.as_ref().unwrap()
190 }
191
192 pub fn is_display_none(&self) -> bool {
194 self.primary().get_box().clone_display().is_none()
195 }
196
197 pub fn viewport_unit_usage(&self) -> ViewportUnitUsage {
199 fn usage_from_flags(flags: ComputedValueFlags) -> ViewportUnitUsage {
200 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES) {
201 return ViewportUnitUsage::FromQuery;
202 }
203 if flags.intersects(ComputedValueFlags::USES_VIEWPORT_UNITS) {
204 return ViewportUnitUsage::FromDeclaration;
205 }
206 ViewportUnitUsage::None
207 }
208
209 let primary = self.primary();
210 let mut usage = usage_from_flags(primary.flags);
211
212 primary.each_cached_lazy_pseudo(|style| {
214 usage = std::cmp::max(usage, usage_from_flags(style.flags));
215 });
216
217 for pseudo_style in self.pseudos.as_array() {
218 if let Some(ref pseudo_style) = pseudo_style {
219 usage = std::cmp::max(usage, usage_from_flags(pseudo_style.flags));
220 pseudo_style.each_cached_lazy_pseudo(|style| {
222 usage = std::cmp::max(usage, usage_from_flags(style.flags));
223 });
224 }
225 }
226
227 usage
228 }
229
230 #[cfg(feature = "gecko")]
231 fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize {
232 0
239 }
240}
241
242impl fmt::Debug for ElementStyles {
246 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247 write!(
248 f,
249 "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
250 self.primary.as_ref().map(|x| &x.rules),
251 self.pseudos
252 )
253 }
254}
255
256#[derive(Debug, Default)]
262pub struct ElementData {
263 pub styles: ElementStyles,
265
266 pub damage: RestyleDamage,
269
270 pub hint: RestyleHint,
273
274 pub flags: ElementDataFlags,
276}
277
278#[derive(Debug, Default)]
280pub struct ElementDataWrapper {
281 inner: std::cell::UnsafeCell<ElementData>,
282 #[cfg(debug_assertions)]
284 refcell: AtomicRefCell<()>,
285}
286
287#[derive(Debug)]
289pub struct ElementDataMut<'a> {
290 v: &'a mut ElementData,
291 #[cfg(debug_assertions)]
292 _borrow: AtomicRefMut<'a, ()>,
293}
294
295#[derive(Debug)]
297pub struct ElementDataRef<'a> {
298 v: &'a ElementData,
299 #[cfg(debug_assertions)]
300 _borrow: AtomicRef<'a, ()>,
301}
302
303impl ElementDataWrapper {
304 #[inline(always)]
306 pub fn borrow(&self) -> ElementDataRef<'_> {
307 #[cfg(debug_assertions)]
308 let borrow = self.refcell.borrow();
309 ElementDataRef {
310 v: unsafe { &*self.inner.get() },
311 #[cfg(debug_assertions)]
312 _borrow: borrow,
313 }
314 }
315
316 #[inline(always)]
318 pub fn borrow_mut(&self) -> ElementDataMut<'_> {
319 #[cfg(debug_assertions)]
320 let borrow = self.refcell.borrow_mut();
321 ElementDataMut {
322 v: unsafe { &mut *self.inner.get() },
323 #[cfg(debug_assertions)]
324 _borrow: borrow,
325 }
326 }
327}
328
329impl<'a> Deref for ElementDataRef<'a> {
330 type Target = ElementData;
331 #[inline]
332 fn deref(&self) -> &Self::Target {
333 &*self.v
334 }
335}
336
337impl<'a> Deref for ElementDataMut<'a> {
338 type Target = ElementData;
339 #[inline]
340 fn deref(&self) -> &Self::Target {
341 &*self.v
342 }
343}
344
345impl<'a> DerefMut for ElementDataMut<'a> {
346 fn deref_mut(&mut self) -> &mut Self::Target {
347 &mut *self.v
348 }
349}
350
351size_of_test!(ElementData, 24);
353
354#[derive(Debug)]
356pub enum RestyleKind {
357 MatchAndCascade,
360 CascadeWithReplacements(RestyleHint),
363 CascadeOnly,
366}
367
368impl ElementData {
369 pub fn invalidate_style_if_needed<'a, E: TElement>(
373 &mut self,
374 element: E,
375 shared_context: &SharedStyleContext,
376 stack_limit_checker: Option<&StackLimitChecker>,
377 selector_caches: &'a mut SelectorCaches,
378 ) -> InvalidationResult {
379 if shared_context.traversal_flags.for_animation_only() {
381 return InvalidationResult::empty();
382 }
383
384 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
385 use crate::invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
386
387 debug!(
388 "invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
389 handled_snapshot: {}, pseudo: {:?}",
390 element,
391 shared_context.traversal_flags,
392 element.has_snapshot(),
393 element.handled_snapshot(),
394 element.implemented_pseudo_element()
395 );
396
397 if !element.has_snapshot() || element.handled_snapshot() {
398 return InvalidationResult::empty();
399 }
400
401 let mut processor =
402 StateAndAttrInvalidationProcessor::new(shared_context, element, self, selector_caches);
403
404 let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
405
406 let result = invalidator.invalidate();
407
408 unsafe { element.set_handled_snapshot() }
409 debug_assert!(element.handled_snapshot());
410
411 result
412 }
413
414 #[inline]
416 pub fn has_styles(&self) -> bool {
417 self.styles.primary.is_some()
418 }
419
420 pub fn share_styles(&self) -> ResolvedElementStyles {
422 ResolvedElementStyles {
423 primary: self.share_primary_style(),
424 pseudos: self.styles.pseudos.clone(),
425 }
426 }
427
428 pub fn share_primary_style(&self) -> PrimaryStyle {
430 let reused_via_rule_node = self
431 .flags
432 .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
433 let may_have_starting_style = self
434 .flags
435 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE);
436
437 PrimaryStyle {
438 style: ResolvedStyle(self.styles.primary().clone()),
439 reused_via_rule_node,
440 may_have_starting_style,
441 }
442 }
443
444 pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
446 self.flags.set(
447 ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
448 new_styles.primary.reused_via_rule_node,
449 );
450 self.flags.set(
451 ElementDataFlags::MAY_HAVE_STARTING_STYLE,
452 new_styles.primary.may_have_starting_style,
453 );
454
455 mem::replace(&mut self.styles, new_styles.into())
456 }
457
458 pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> Option<RestyleKind> {
461 let style = match self.styles.primary {
462 Some(ref s) => s,
463 None => return Some(RestyleKind::MatchAndCascade),
464 };
465
466 if shared_context.traversal_flags.for_animation_only() {
467 return self.restyle_kind_for_animation(shared_context);
468 }
469
470 let hint = self.hint;
471 if hint.is_empty() {
472 return None;
473 }
474
475 let needs_to_match_self = hint.intersects(RestyleHint::RESTYLE_SELF)
476 || (hint.intersects(RestyleHint::RESTYLE_SELF_IF_PSEUDO) && style.is_pseudo_style());
477 if needs_to_match_self {
478 return Some(RestyleKind::MatchAndCascade);
479 }
480
481 if hint.has_replacements() {
482 debug_assert!(
483 !hint.has_animation_hint(),
484 "Animation only restyle hint should have already processed"
485 );
486 return Some(RestyleKind::CascadeWithReplacements(
487 hint & RestyleHint::replacements(),
488 ));
489 }
490
491 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
492 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
493 && style
494 .flags
495 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
496 if needs_to_recascade_self {
497 return Some(RestyleKind::CascadeOnly);
498 }
499
500 None
501 }
502
503 fn restyle_kind_for_animation(
505 &self,
506 shared_context: &SharedStyleContext,
507 ) -> Option<RestyleKind> {
508 debug_assert!(shared_context.traversal_flags.for_animation_only());
509 debug_assert!(self.has_styles());
510
511 let hint = self.hint;
520 if self.styles.is_display_none() && hint.intersects(RestyleHint::RESTYLE_SELF) {
521 return None;
522 }
523
524 let style = self.styles.primary();
525 if hint.has_animation_hint() {
528 return Some(RestyleKind::CascadeWithReplacements(
529 hint & RestyleHint::for_animations(),
530 ));
531 }
532
533 let needs_to_recascade_self = hint.intersects(RestyleHint::RECASCADE_SELF)
534 || (hint.intersects(RestyleHint::RECASCADE_SELF_IF_INHERIT_RESET_STYLE)
535 && style
536 .flags
537 .contains(ComputedValueFlags::INHERITS_RESET_STYLE));
538 if needs_to_recascade_self {
539 return Some(RestyleKind::CascadeOnly);
540 }
541 return None;
542 }
543
544 #[inline]
549 pub fn clear_restyle_state(&mut self) {
550 self.hint = RestyleHint::empty();
551 self.clear_restyle_flags_and_damage();
552 }
553
554 #[inline]
556 pub fn clear_restyle_flags_and_damage(&mut self) {
557 self.damage = RestyleDamage::empty();
558 self.flags.remove(ElementDataFlags::WAS_RESTYLED);
559 }
560
561 pub fn set_restyled(&mut self) {
564 self.flags.insert(ElementDataFlags::WAS_RESTYLED);
565 self.flags
566 .remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
567 }
568
569 #[inline]
571 pub fn is_restyle(&self) -> bool {
572 self.flags.contains(ElementDataFlags::WAS_RESTYLED)
573 }
574
575 pub fn set_traversed_without_styling(&mut self) {
577 self.flags
578 .insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
579 }
580
581 #[inline]
583 pub fn contains_restyle_data(&self) -> bool {
584 self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
585 }
586
587 pub fn safe_for_cousin_sharing(&self) -> bool {
606 if self.flags.intersects(
607 ElementDataFlags::TRAVERSED_WITHOUT_STYLING
608 | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
609 ) {
610 return false;
611 }
612 if !self
613 .styles
614 .primary()
615 .get_box()
616 .clone_container_type()
617 .is_normal()
618 {
619 return false;
620 }
621 true
622 }
623
624 #[cfg(feature = "gecko")]
626 pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
627 let n = self.styles.size_of_excluding_cvs(ops);
628
629 n
632 }
633
634 #[inline]
637 pub fn may_have_starting_style(&self) -> bool {
638 self.flags
639 .contains(ElementDataFlags::MAY_HAVE_STARTING_STYLE)
640 }
641}