style/dom.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Types and traits used to access the DOM from style calculation.
6
7#![allow(unsafe_code)]
8#![deny(missing_docs)]
9
10use crate::applicable_declarations::ApplicableDeclarationBlock;
11use crate::context::SharedStyleContext;
12#[cfg(feature = "gecko")]
13use crate::context::UpdateAnimationsTasks;
14use crate::data::ElementData;
15use crate::media_queries::Device;
16use crate::properties::{AnimationDeclarations, ComputedValues, PropertyDeclarationBlock};
17use crate::selector_parser::{AttrValue, Lang, PseudoElement, RestyleDamage, SelectorImpl};
18use crate::shared_lock::{Locked, SharedRwLock};
19use crate::stylesheets::scope_rule::ImplicitScopeRoot;
20use crate::stylist::CascadeData;
21use crate::values::computed::Display;
22use crate::values::AtomIdent;
23use crate::{LocalName, WeakAtom};
24use atomic_refcell::{AtomicRef, AtomicRefMut};
25use dom::ElementState;
26use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
27use selectors::sink::Push;
28use selectors::{Element as SelectorsElement, OpaqueElement};
29use servo_arc::{Arc, ArcBorrow};
30use std::fmt;
31use std::fmt::Debug;
32use std::hash::Hash;
33use std::ops::Deref;
34
35pub use style_traits::dom::OpaqueNode;
36
37/// Simple trait to provide basic information about the type of an element.
38///
39/// We avoid exposing the full type id, since computing it in the general case
40/// would be difficult for Gecko nodes.
41pub trait NodeInfo {
42 /// Whether this node is an element.
43 fn is_element(&self) -> bool;
44 /// Whether this node is a text node.
45 fn is_text_node(&self) -> bool;
46}
47
48/// A node iterator that only returns node that don't need layout.
49pub struct LayoutIterator<T>(pub T);
50
51impl<T, N> Iterator for LayoutIterator<T>
52where
53 T: Iterator<Item = N>,
54 N: NodeInfo,
55{
56 type Item = N;
57
58 fn next(&mut self) -> Option<N> {
59 loop {
60 let n = self.0.next()?;
61 // Filter out nodes that layout should ignore.
62 if n.is_text_node() || n.is_element() {
63 return Some(n);
64 }
65 }
66 }
67}
68
69/// An iterator over the DOM children of a node.
70pub struct DomChildren<N>(Option<N>);
71impl<N> Iterator for DomChildren<N>
72where
73 N: TNode,
74{
75 type Item = N;
76
77 fn next(&mut self) -> Option<N> {
78 let n = self.0.take()?;
79 self.0 = n.next_sibling();
80 Some(n)
81 }
82}
83
84/// An iterator over the DOM descendants of a node in pre-order.
85pub struct DomDescendants<N> {
86 previous: Option<N>,
87 scope: N,
88}
89
90impl<N> Iterator for DomDescendants<N>
91where
92 N: TNode,
93{
94 type Item = N;
95
96 #[inline]
97 fn next(&mut self) -> Option<N> {
98 let prev = self.previous.take()?;
99 self.previous = prev.next_in_preorder(self.scope);
100 self.previous
101 }
102}
103
104/// The `TDocument` trait, to represent a document node.
105pub trait TDocument: Sized + Copy + Clone {
106 /// The concrete `TNode` type.
107 type ConcreteNode: TNode<ConcreteDocument = Self>;
108
109 /// Get this document as a `TNode`.
110 fn as_node(&self) -> Self::ConcreteNode;
111
112 /// Returns whether this document is an HTML document.
113 fn is_html_document(&self) -> bool;
114
115 /// Returns the quirks mode of this document.
116 fn quirks_mode(&self) -> QuirksMode;
117
118 /// Get a list of elements with a given ID in this document, sorted by
119 /// tree position.
120 ///
121 /// Can return an error to signal that this list is not available, or also
122 /// return an empty slice.
123 fn elements_with_id<'a>(
124 &self,
125 _id: &AtomIdent,
126 ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
127 where
128 Self: 'a,
129 {
130 Err(())
131 }
132
133 /// This document's shared lock.
134 fn shared_lock(&self) -> &SharedRwLock;
135}
136
137/// The `TNode` trait. This is the main generic trait over which the style
138/// system can be implemented.
139pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
140 /// The concrete `TElement` type.
141 type ConcreteElement: TElement<ConcreteNode = Self>;
142
143 /// The concrete `TDocument` type.
144 type ConcreteDocument: TDocument<ConcreteNode = Self>;
145
146 /// The concrete `TShadowRoot` type.
147 type ConcreteShadowRoot: TShadowRoot<ConcreteNode = Self>;
148
149 /// Get this node's parent node.
150 fn parent_node(&self) -> Option<Self>;
151
152 /// Get this node's first child.
153 fn first_child(&self) -> Option<Self>;
154
155 /// Get this node's last child.
156 fn last_child(&self) -> Option<Self>;
157
158 /// Get this node's previous sibling.
159 fn prev_sibling(&self) -> Option<Self>;
160
161 /// Get this node's next sibling.
162 fn next_sibling(&self) -> Option<Self>;
163
164 /// Get the owner document of this node.
165 fn owner_doc(&self) -> Self::ConcreteDocument;
166
167 /// Iterate over the DOM children of a node.
168 #[inline(always)]
169 fn dom_children(&self) -> DomChildren<Self> {
170 DomChildren(self.first_child())
171 }
172
173 /// Returns whether the node is attached to a document.
174 fn is_in_document(&self) -> bool;
175
176 /// Iterate over the DOM children of a node, in preorder.
177 #[inline(always)]
178 fn dom_descendants(&self) -> DomDescendants<Self> {
179 DomDescendants {
180 previous: Some(*self),
181 scope: *self,
182 }
183 }
184
185 /// Returns the next node after this one, in a pre-order tree-traversal of
186 /// the subtree rooted at scoped_to.
187 #[inline]
188 fn next_in_preorder(&self, scoped_to: Self) -> Option<Self> {
189 if let Some(c) = self.first_child() {
190 return Some(c);
191 }
192
193 let mut current = *self;
194 loop {
195 if current == scoped_to {
196 return None;
197 }
198
199 if let Some(s) = current.next_sibling() {
200 return Some(s);
201 }
202
203 debug_assert!(
204 current.parent_node().is_some(),
205 "Not a descendant of the scope?"
206 );
207 current = current.parent_node()?;
208 }
209 }
210
211 /// Returns the depth of this node in the DOM.
212 fn depth(&self) -> usize {
213 let mut depth = 0;
214 let mut curr = *self;
215 while let Some(parent) = curr.traversal_parent() {
216 depth += 1;
217 curr = parent.as_node();
218 }
219 depth
220 }
221
222 /// Get this node's parent element from the perspective of a restyle
223 /// traversal.
224 fn traversal_parent(&self) -> Option<Self::ConcreteElement>;
225
226 /// Get this node's parent element if present.
227 fn parent_element(&self) -> Option<Self::ConcreteElement> {
228 self.parent_node().and_then(|n| n.as_element())
229 }
230
231 /// Get this node's parent element, or shadow host if it's a shadow root.
232 fn parent_element_or_host(&self) -> Option<Self::ConcreteElement> {
233 let parent = self.parent_node()?;
234 if let Some(e) = parent.as_element() {
235 return Some(e);
236 }
237 if let Some(root) = parent.as_shadow_root() {
238 return Some(root.host());
239 }
240 None
241 }
242
243 /// Converts self into an `OpaqueNode`.
244 fn opaque(&self) -> OpaqueNode;
245
246 /// A debug id, only useful, mm... for debugging.
247 fn debug_id(self) -> usize;
248
249 /// Get this node as an element, if it's one.
250 fn as_element(&self) -> Option<Self::ConcreteElement>;
251
252 /// Get this node as a document, if it's one.
253 fn as_document(&self) -> Option<Self::ConcreteDocument>;
254
255 /// Get this node as a ShadowRoot, if it's one.
256 fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot>;
257}
258
259/// Wrapper to output the subtree rather than the single node when formatting
260/// for Debug.
261pub struct ShowSubtree<N: TNode>(pub N);
262impl<N: TNode> Debug for ShowSubtree<N> {
263 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264 writeln!(f, "DOM Subtree:")?;
265 fmt_subtree(f, &|f, n| write!(f, "{:?}", n), self.0, 1)
266 }
267}
268
269/// Wrapper to output the subtree along with the ElementData when formatting
270/// for Debug.
271pub struct ShowSubtreeData<N: TNode>(pub N);
272impl<N: TNode> Debug for ShowSubtreeData<N> {
273 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 writeln!(f, "DOM Subtree:")?;
275 fmt_subtree(f, &|f, n| fmt_with_data(f, n), self.0, 1)
276 }
277}
278
279/// Wrapper to output the subtree along with the ElementData and primary
280/// ComputedValues when formatting for Debug. This is extremely verbose.
281#[cfg(feature = "servo")]
282pub struct ShowSubtreeDataAndPrimaryValues<N: TNode>(pub N);
283#[cfg(feature = "servo")]
284impl<N: TNode> Debug for ShowSubtreeDataAndPrimaryValues<N> {
285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 writeln!(f, "DOM Subtree:")?;
287 fmt_subtree(f, &|f, n| fmt_with_data_and_primary_values(f, n), self.0, 1)
288 }
289}
290
291fn fmt_with_data<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
292 if let Some(el) = n.as_element() {
293 write!(
294 f,
295 "{:?} dd={} aodd={} data={:?}",
296 el,
297 el.has_dirty_descendants(),
298 el.has_animation_only_dirty_descendants(),
299 el.borrow_data(),
300 )
301 } else {
302 write!(f, "{:?}", n)
303 }
304}
305
306#[cfg(feature = "servo")]
307fn fmt_with_data_and_primary_values<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
308 if let Some(el) = n.as_element() {
309 let dd = el.has_dirty_descendants();
310 let aodd = el.has_animation_only_dirty_descendants();
311 let data = el.borrow_data();
312 let values = data.as_ref().and_then(|d| d.styles.get_primary());
313 write!(
314 f,
315 "{:?} dd={} aodd={} data={:?} values={:?}",
316 el, dd, aodd, &data, values
317 )
318 } else {
319 write!(f, "{:?}", n)
320 }
321}
322
323fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) -> fmt::Result
324where
325 F: Fn(&mut fmt::Formatter, N) -> fmt::Result,
326{
327 for _ in 0..indent {
328 write!(f, " ")?;
329 }
330 stringify(f, n)?;
331 if let Some(e) = n.as_element() {
332 for kid in e.traversal_children() {
333 writeln!(f, "")?;
334 fmt_subtree(f, stringify, kid, indent + 1)?;
335 }
336 }
337
338 Ok(())
339}
340
341/// The ShadowRoot trait.
342pub trait TShadowRoot: Sized + Copy + Clone + Debug + PartialEq {
343 /// The concrete node type.
344 type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
345
346 /// Get this ShadowRoot as a node.
347 fn as_node(&self) -> Self::ConcreteNode;
348
349 /// Get the shadow host that hosts this ShadowRoot.
350 fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
351
352 /// Get the style data for this ShadowRoot.
353 fn style_data<'a>(&self) -> Option<&'a CascadeData>
354 where
355 Self: 'a;
356
357 /// Get the list of shadow parts for this shadow root.
358 fn parts<'a>(&self) -> &[<Self::ConcreteNode as TNode>::ConcreteElement]
359 where
360 Self: 'a,
361 {
362 &[]
363 }
364
365 /// Get a list of elements with a given ID in this shadow root, sorted by
366 /// tree position.
367 ///
368 /// Can return an error to signal that this list is not available, or also
369 /// return an empty slice.
370 fn elements_with_id<'a>(
371 &self,
372 _id: &AtomIdent,
373 ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
374 where
375 Self: 'a,
376 {
377 Err(())
378 }
379
380 /// Get the implicit scope for a stylesheet in given index.
381 fn implicit_scope_for_sheet(&self, _sheet_index: usize) -> Option<ImplicitScopeRoot> {
382 None
383 }
384}
385
386/// The element trait, the main abstraction the style crate acts over.
387pub trait TElement:
388 Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + SelectorsElement<Impl = SelectorImpl>
389{
390 /// The concrete node type.
391 type ConcreteNode: TNode<ConcreteElement = Self>;
392
393 /// A concrete children iterator type in order to iterate over the `Node`s.
394 ///
395 /// TODO(emilio): We should eventually replace this with the `impl Trait`
396 /// syntax.
397 type TraversalChildrenIterator: Iterator<Item = Self::ConcreteNode>;
398
399 /// Get this element as a node.
400 fn as_node(&self) -> Self::ConcreteNode;
401
402 /// A debug-only check that the device's owner doc matches the actual doc
403 /// we're the root of.
404 ///
405 /// Otherwise we may set document-level state incorrectly, like the root
406 /// font-size used for rem units.
407 fn owner_doc_matches_for_testing(&self, _: &Device) -> bool {
408 true
409 }
410
411 /// Whether this element should match user and content rules.
412 ///
413 /// We use this for Native Anonymous Content in Gecko.
414 fn matches_user_and_content_rules(&self) -> bool {
415 true
416 }
417
418 /// Get this node's parent element from the perspective of a restyle
419 /// traversal.
420 fn traversal_parent(&self) -> Option<Self> {
421 self.as_node().traversal_parent()
422 }
423
424 /// Get this node's children from the perspective of a restyle traversal.
425 fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator>;
426
427 /// Returns the parent element we should inherit from.
428 ///
429 /// This is pretty much always the parent element itself, except in the case
430 /// of Gecko's Native Anonymous Content, which uses the traversal parent
431 /// (i.e. the flattened tree parent) and which also may need to find the
432 /// closest non-NAC ancestor.
433 fn inheritance_parent(&self) -> Option<Self> {
434 self.parent_element()
435 }
436
437 /// Execute `f` for each anonymous content child (apart from ::before and
438 /// ::after) whose originating element is `self`.
439 fn each_anonymous_content_child<F>(&self, _f: F)
440 where
441 F: FnMut(Self),
442 {
443 }
444
445 /// Return whether this element is an element in the HTML namespace.
446 fn is_html_element(&self) -> bool;
447
448 /// Return whether this element is an element in the MathML namespace.
449 fn is_mathml_element(&self) -> bool;
450
451 /// Return whether this element is an element in the SVG namespace.
452 fn is_svg_element(&self) -> bool;
453
454 /// Return whether this element is an element in the XUL namespace.
455 fn is_xul_element(&self) -> bool {
456 false
457 }
458
459 /// Return the list of slotted nodes of this node.
460 fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
461 &[]
462 }
463
464 /// Get this element's style attribute.
465 fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>;
466
467 /// Unset the style attribute's dirty bit.
468 /// Servo doesn't need to manage ditry bit for style attribute.
469 fn unset_dirty_style_attribute(&self) {}
470
471 /// Get this element's SMIL override declarations.
472 fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
473 None
474 }
475
476 /// Get the combined animation and transition rules.
477 ///
478 /// FIXME(emilio): Is this really useful?
479 fn animation_declarations(&self, context: &SharedStyleContext) -> AnimationDeclarations {
480 if !self.may_have_animations() {
481 return Default::default();
482 }
483
484 AnimationDeclarations {
485 animations: self.animation_rule(context),
486 transitions: self.transition_rule(context),
487 }
488 }
489
490 /// Get this element's animation rule.
491 fn animation_rule(
492 &self,
493 _: &SharedStyleContext,
494 ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
495
496 /// Get this element's transition rule.
497 fn transition_rule(
498 &self,
499 context: &SharedStyleContext,
500 ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
501
502 /// Get this element's state, for non-tree-structural pseudos.
503 fn state(&self) -> ElementState;
504
505 /// Returns whether this element has a `part` attribute.
506 fn has_part_attr(&self) -> bool;
507
508 /// Returns whether this element exports any part from its shadow tree.
509 fn exports_any_part(&self) -> bool;
510
511 /// The ID for this element.
512 fn id(&self) -> Option<&WeakAtom>;
513
514 /// Internal iterator for the classes of this element.
515 fn each_class<F>(&self, callback: F)
516 where
517 F: FnMut(&AtomIdent);
518
519 /// Internal iterator for the classes of this element.
520 fn each_custom_state<F>(&self, callback: F)
521 where
522 F: FnMut(&AtomIdent);
523
524 /// Internal iterator for the part names of this element.
525 fn each_part<F>(&self, _callback: F)
526 where
527 F: FnMut(&AtomIdent),
528 {
529 }
530
531 /// Internal iterator for the attribute names of this element.
532 fn each_attr_name<F>(&self, callback: F)
533 where
534 F: FnMut(&LocalName);
535
536 /// Internal iterator for the part names that this element exports for a
537 /// given part name.
538 fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
539 where
540 F: FnMut(&AtomIdent),
541 {
542 }
543
544 /// Whether a given element may generate a pseudo-element.
545 ///
546 /// This is useful to avoid computing, for example, pseudo styles for
547 /// `::-first-line` or `::-first-letter`, when we know it won't affect us.
548 ///
549 /// TODO(emilio, bz): actually implement the logic for it.
550 fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
551 // ::before/::after are always supported for now, though we could try to
552 // optimize out leaf elements.
553
554 // ::first-letter and ::first-line are only supported for block-inside
555 // things, and only in Gecko, not Servo. Unfortunately, Gecko has
556 // block-inside things that might have any computed display value due to
557 // things like fieldsets, legends, etc. Need to figure out how this
558 // should work.
559 debug_assert!(
560 pseudo.is_eager(),
561 "Someone called may_generate_pseudo with a non-eager pseudo."
562 );
563 true
564 }
565
566 /// Returns true if this element may have a descendant needing style processing.
567 ///
568 /// Note that we cannot guarantee the existence of such an element, because
569 /// it may have been removed from the DOM between marking it for restyle and
570 /// the actual restyle traversal.
571 fn has_dirty_descendants(&self) -> bool;
572
573 /// Returns whether state or attributes that may change style have changed
574 /// on the element, and thus whether the element has been snapshotted to do
575 /// restyle hint computation.
576 fn has_snapshot(&self) -> bool;
577
578 /// Returns whether the current snapshot if present has been handled.
579 fn handled_snapshot(&self) -> bool;
580
581 /// Flags this element as having handled already its snapshot.
582 unsafe fn set_handled_snapshot(&self);
583
584 /// Returns whether the element's styles are up-to-date after traversal
585 /// (i.e. in post traversal).
586 fn has_current_styles(&self, data: &ElementData) -> bool {
587 if self.has_snapshot() && !self.handled_snapshot() {
588 return false;
589 }
590
591 data.has_styles() &&
592 // TODO(hiro): When an animating element moved into subtree of
593 // contenteditable element, there remains animation restyle hints in
594 // post traversal. It's generally harmless since the hints will be
595 // processed in a next styling but ideally it should be processed soon.
596 //
597 // Without this, we get failures in:
598 // layout/style/crashtests/1383319.html
599 // layout/style/crashtests/1383001.html
600 //
601 // https://bugzilla.mozilla.org/show_bug.cgi?id=1389675 tracks fixing
602 // this.
603 !data.hint.has_non_animation_invalidations()
604 }
605
606 /// Flag that this element has a descendant for style processing.
607 ///
608 /// Only safe to call with exclusive access to the element.
609 unsafe fn set_dirty_descendants(&self);
610
611 /// Flag that this element has no descendant for style processing.
612 ///
613 /// Only safe to call with exclusive access to the element.
614 unsafe fn unset_dirty_descendants(&self);
615
616 /// Similar to the dirty_descendants but for representing a descendant of
617 /// the element needs to be updated in animation-only traversal.
618 fn has_animation_only_dirty_descendants(&self) -> bool {
619 false
620 }
621
622 /// Flag that this element has a descendant for animation-only restyle
623 /// processing.
624 ///
625 /// Only safe to call with exclusive access to the element.
626 unsafe fn set_animation_only_dirty_descendants(&self) {}
627
628 /// Flag that this element has no descendant for animation-only restyle processing.
629 ///
630 /// Only safe to call with exclusive access to the element.
631 unsafe fn unset_animation_only_dirty_descendants(&self) {}
632
633 /// Clear all bits related describing the dirtiness of descendants.
634 ///
635 /// In Gecko, this corresponds to the regular dirty descendants bit, the
636 /// animation-only dirty descendants bit, and the lazy frame construction
637 /// descendants bit.
638 unsafe fn clear_descendant_bits(&self) {
639 self.unset_dirty_descendants();
640 }
641
642 /// Returns true if this element is a visited link.
643 ///
644 /// Servo doesn't support visited styles yet.
645 fn is_visited_link(&self) -> bool {
646 false
647 }
648
649 /// Returns the pseudo-element implemented by this element, if any.
650 ///
651 /// Gecko traverses pseudo-elements during the style traversal, and we need
652 /// to know this so we can properly grab the pseudo-element style from the
653 /// parent element.
654 ///
655 /// Note that we still need to compute the pseudo-elements before-hand,
656 /// given otherwise we don't know if we need to create an element or not.
657 fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
658 None
659 }
660
661 /// Atomically stores the number of children of this node that we will
662 /// need to process during bottom-up traversal.
663 fn store_children_to_process(&self, n: isize);
664
665 /// Atomically notes that a child has been processed during bottom-up
666 /// traversal. Returns the number of children left to process.
667 fn did_process_child(&self) -> isize;
668
669 /// Gets a reference to the ElementData container, or creates one.
670 ///
671 /// Unsafe because it can race to allocate and leak if not used with
672 /// exclusive access to the element.
673 unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData>;
674
675 /// Clears the element data reference, if any.
676 ///
677 /// Unsafe following the same reasoning as ensure_data.
678 unsafe fn clear_data(&self);
679
680 /// Whether there is an ElementData container.
681 fn has_data(&self) -> bool;
682
683 /// Immutably borrows the ElementData.
684 fn borrow_data(&self) -> Option<AtomicRef<ElementData>>;
685
686 /// Mutably borrows the ElementData.
687 fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>>;
688
689 /// Whether we should skip any root- or item-based display property
690 /// blockification on this element. (This function exists so that Gecko
691 /// native anonymous content can opt out of this style fixup.)
692 fn skip_item_display_fixup(&self) -> bool;
693
694 /// In Gecko, element has a flag that represents the element may have
695 /// any type of animations or not to bail out animation stuff early.
696 /// Whereas Servo doesn't have such flag.
697 fn may_have_animations(&self) -> bool;
698
699 /// Creates a task to update various animation state on a given (pseudo-)element.
700 #[cfg(feature = "gecko")]
701 fn update_animations(
702 &self,
703 before_change_style: Option<Arc<ComputedValues>>,
704 tasks: UpdateAnimationsTasks,
705 );
706
707 /// Returns true if the element has relevant animations. Relevant
708 /// animations are those animations that are affecting the element's style
709 /// or are scheduled to do so in the future.
710 fn has_animations(&self, context: &SharedStyleContext) -> bool;
711
712 /// Returns true if the element has a CSS animation. The `context` and `pseudo_element`
713 /// arguments are only used by Servo, since it stores animations globally and pseudo-elements
714 /// are not in the DOM.
715 fn has_css_animations(
716 &self,
717 context: &SharedStyleContext,
718 pseudo_element: Option<PseudoElement>,
719 ) -> bool;
720
721 /// Returns true if the element has a CSS transition (including running transitions and
722 /// completed transitions). The `context` and `pseudo_element` arguments are only used
723 /// by Servo, since it stores animations globally and pseudo-elements are not in the DOM.
724 fn has_css_transitions(
725 &self,
726 context: &SharedStyleContext,
727 pseudo_element: Option<PseudoElement>,
728 ) -> bool;
729
730 /// Returns true if the element has animation restyle hints.
731 fn has_animation_restyle_hints(&self) -> bool {
732 let data = match self.borrow_data() {
733 Some(d) => d,
734 None => return false,
735 };
736 return data.hint.has_animation_hint();
737 }
738
739 /// The shadow root this element is a host of.
740 fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
741
742 /// The shadow root which roots the subtree this element is contained in.
743 fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
744
745 /// Return the element which we can use to look up rules in the selector
746 /// maps.
747 ///
748 /// This is always the element itself, except in the case where we are an
749 /// element-backed pseudo-element, in which case we return the originating
750 /// element.
751 fn rule_hash_target(&self) -> Self {
752 let mut cur = *self;
753 while cur.is_pseudo_element() {
754 cur = cur
755 .pseudo_element_originating_element()
756 .expect("Trying to collect rules for a detached pseudo-element")
757 }
758 cur
759 }
760
761 /// Executes the callback for each applicable style rule data which isn't
762 /// the main document's data (which stores UA / author rules).
763 ///
764 /// The element passed to the callback is the containing shadow host for the
765 /// data if it comes from Shadow DOM.
766 ///
767 /// Returns whether normal document author rules should apply.
768 ///
769 /// TODO(emilio): We could separate the invalidation data for elements
770 /// matching in other scopes to avoid over-invalidation.
771 fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
772 where
773 Self: 'a,
774 F: FnMut(&'a CascadeData, Self),
775 {
776 use crate::rule_collector::containing_shadow_ignoring_svg_use;
777
778 let target = self.rule_hash_target();
779 let matches_user_and_content_rules = target.matches_user_and_content_rules();
780 let mut doc_rules_apply = matches_user_and_content_rules;
781
782 // Use the same rules to look for the containing host as we do for rule
783 // collection.
784 if let Some(shadow) = containing_shadow_ignoring_svg_use(target) {
785 doc_rules_apply = false;
786 if let Some(data) = shadow.style_data() {
787 f(data, shadow.host());
788 }
789 }
790
791 if let Some(shadow) = target.shadow_root() {
792 if let Some(data) = shadow.style_data() {
793 f(data, shadow.host());
794 }
795 }
796
797 let mut current = target.assigned_slot();
798 while let Some(slot) = current {
799 // Slots can only have assigned nodes when in a shadow tree.
800 let shadow = slot.containing_shadow().unwrap();
801 if let Some(data) = shadow.style_data() {
802 if data.any_slotted_rule() {
803 f(data, shadow.host());
804 }
805 }
806 current = slot.assigned_slot();
807 }
808
809 if target.has_part_attr() {
810 if let Some(mut inner_shadow) = target.containing_shadow() {
811 loop {
812 let inner_shadow_host = inner_shadow.host();
813 match inner_shadow_host.containing_shadow() {
814 Some(shadow) => {
815 if let Some(data) = shadow.style_data() {
816 if data.any_part_rule() {
817 f(data, shadow.host())
818 }
819 }
820 // TODO: Could be more granular.
821 if !inner_shadow_host.exports_any_part() {
822 break;
823 }
824 inner_shadow = shadow;
825 },
826 None => {
827 // TODO(emilio): Should probably distinguish with
828 // MatchesDocumentRules::{No,Yes,IfPart} or something so that we could
829 // skip some work.
830 doc_rules_apply = matches_user_and_content_rules;
831 break;
832 },
833 }
834 }
835 }
836 }
837
838 doc_rules_apply
839 }
840
841 /// Returns true if one of the transitions needs to be updated on this element. We check all
842 /// the transition properties to make sure that updating transitions is necessary.
843 /// This method should only be called if might_needs_transitions_update returns true when
844 /// passed the same parameters.
845 #[cfg(feature = "gecko")]
846 fn needs_transitions_update(
847 &self,
848 before_change_style: &ComputedValues,
849 after_change_style: &ComputedValues,
850 ) -> bool;
851
852 /// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
853 /// the `lang=""` attribute) on this element.
854 fn lang_attr(&self) -> Option<AttrValue>;
855
856 /// Returns whether this element's language matches the language tag
857 /// `value`. If `override_lang` is not `None`, it specifies the value
858 /// of the `xml:lang=""` or `lang=""` attribute to use in place of
859 /// looking at the element and its ancestors. (This argument is used
860 /// to implement matching of `:lang()` against snapshots.)
861 fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool;
862
863 /// Returns whether this element is the main body element of the HTML
864 /// document it is on.
865 fn is_html_document_body_element(&self) -> bool;
866
867 /// Generate the proper applicable declarations due to presentational hints,
868 /// and insert them into `hints`.
869 fn synthesize_presentational_hints_for_legacy_attributes<V>(
870 &self,
871 visited_handling: VisitedHandlingMode,
872 hints: &mut V,
873 ) where
874 V: Push<ApplicableDeclarationBlock>;
875
876 /// Generate the proper applicable declarations due to view transition dynamic rules, and
877 /// insert them into `rules`.
878 /// https://drafts.csswg.org/css-view-transitions-1/#document-dynamic-view-transition-style-sheet
879 fn synthesize_view_transition_dynamic_rules<V>(&self, _rules: &mut V)
880 where
881 V: Push<ApplicableDeclarationBlock>,
882 {
883 }
884
885 /// Returns element's local name.
886 fn local_name(&self) -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedLocalName;
887
888 /// Returns element's namespace.
889 fn namespace(&self)
890 -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedNamespaceUrl;
891
892 /// Returns the size of the element to be used in container size queries.
893 /// This will usually be the size of the content area of the primary box,
894 /// but can be None if there is no box or if some axis lacks size containment.
895 fn query_container_size(
896 &self,
897 display: &Display,
898 ) -> euclid::default::Size2D<Option<app_units::Au>>;
899
900 /// Returns true if the element has all of specified selector flags.
901 fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
902
903 /// Returns the search direction for relative selector invalidation, if it is on the search path.
904 fn relative_selector_search_direction(&self) -> ElementSelectorFlags;
905
906 /// Returns the implicit scope root for given sheet index and host.
907 fn implicit_scope_for_sheet_in_shadow_root(
908 _opaque_host: OpaqueElement,
909 _sheet_index: usize,
910 ) -> Option<ImplicitScopeRoot> {
911 None
912 }
913
914 /// Compute the damage incurred by the change from the `_old` to `_new`.
915 fn compute_layout_damage(_old: &ComputedValues, _new: &ComputedValues) -> RestyleDamage {
916 Default::default()
917 }
918}
919
920/// TNode and TElement aren't Send because we want to be careful and explicit
921/// about our parallel traversal. However, there are certain situations
922/// (including but not limited to the traversal) where we need to send DOM
923/// objects to other threads.
924///
925/// That's the reason why `SendNode` exists.
926#[derive(Clone, Debug, PartialEq)]
927pub struct SendNode<N: TNode>(N);
928unsafe impl<N: TNode> Send for SendNode<N> {}
929impl<N: TNode> SendNode<N> {
930 /// Unsafely construct a SendNode.
931 pub unsafe fn new(node: N) -> Self {
932 SendNode(node)
933 }
934}
935impl<N: TNode> Deref for SendNode<N> {
936 type Target = N;
937 fn deref(&self) -> &N {
938 &self.0
939 }
940}
941
942/// Same reason as for the existence of SendNode, SendElement does the proper
943/// things for a given `TElement`.
944#[derive(Debug, Eq, Hash, PartialEq)]
945pub struct SendElement<E: TElement>(E);
946unsafe impl<E: TElement> Send for SendElement<E> {}
947impl<E: TElement> SendElement<E> {
948 /// Unsafely construct a SendElement.
949 pub unsafe fn new(el: E) -> Self {
950 SendElement(el)
951 }
952}
953impl<E: TElement> Deref for SendElement<E> {
954 type Target = E;
955 fn deref(&self) -> &E {
956 &self.0
957 }
958}