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, 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    /// The ::before pseudo-element of this element, if it exists.
438    fn before_pseudo_element(&self) -> Option<Self> {
439        None
440    }
441
442    /// The ::after pseudo-element of this element, if it exists.
443    fn after_pseudo_element(&self) -> Option<Self> {
444        None
445    }
446
447    /// The ::marker pseudo-element of this element, if it exists.
448    fn marker_pseudo_element(&self) -> Option<Self> {
449        None
450    }
451
452    /// Execute `f` for each anonymous content child (apart from ::before and
453    /// ::after) whose originating element is `self`.
454    fn each_anonymous_content_child<F>(&self, _f: F)
455    where
456        F: FnMut(Self),
457    {
458    }
459
460    /// Return whether this element is an element in the HTML namespace.
461    fn is_html_element(&self) -> bool;
462
463    /// Return whether this element is an element in the MathML namespace.
464    fn is_mathml_element(&self) -> bool;
465
466    /// Return whether this element is an element in the SVG namespace.
467    fn is_svg_element(&self) -> bool;
468
469    /// Return whether this element is an element in the XUL namespace.
470    fn is_xul_element(&self) -> bool {
471        false
472    }
473
474    /// Return the list of slotted nodes of this node.
475    fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
476        &[]
477    }
478
479    /// Get this element's style attribute.
480    fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>;
481
482    /// Unset the style attribute's dirty bit.
483    /// Servo doesn't need to manage ditry bit for style attribute.
484    fn unset_dirty_style_attribute(&self) {}
485
486    /// Get this element's SMIL override declarations.
487    fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
488        None
489    }
490
491    /// Get the combined animation and transition rules.
492    ///
493    /// FIXME(emilio): Is this really useful?
494    fn animation_declarations(&self, context: &SharedStyleContext) -> AnimationDeclarations {
495        if !self.may_have_animations() {
496            return Default::default();
497        }
498
499        AnimationDeclarations {
500            animations: self.animation_rule(context),
501            transitions: self.transition_rule(context),
502        }
503    }
504
505    /// Get this element's animation rule.
506    fn animation_rule(
507        &self,
508        _: &SharedStyleContext,
509    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
510
511    /// Get this element's transition rule.
512    fn transition_rule(
513        &self,
514        context: &SharedStyleContext,
515    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
516
517    /// Get this element's state, for non-tree-structural pseudos.
518    fn state(&self) -> ElementState;
519
520    /// Returns whether this element has a `part` attribute.
521    fn has_part_attr(&self) -> bool;
522
523    /// Returns whether this element exports any part from its shadow tree.
524    fn exports_any_part(&self) -> bool;
525
526    /// The ID for this element.
527    fn id(&self) -> Option<&WeakAtom>;
528
529    /// Internal iterator for the classes of this element.
530    fn each_class<F>(&self, callback: F)
531    where
532        F: FnMut(&AtomIdent);
533
534    /// Internal iterator for the classes of this element.
535    fn each_custom_state<F>(&self, callback: F)
536    where
537        F: FnMut(&AtomIdent);
538
539    /// Internal iterator for the part names of this element.
540    fn each_part<F>(&self, _callback: F)
541    where
542        F: FnMut(&AtomIdent),
543    {
544    }
545
546    /// Internal iterator for the attribute names of this element.
547    fn each_attr_name<F>(&self, callback: F)
548    where
549        F: FnMut(&LocalName);
550
551    /// Internal iterator for the part names that this element exports for a
552    /// given part name.
553    fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
554    where
555        F: FnMut(&AtomIdent),
556    {
557    }
558
559    /// Whether a given element may generate a pseudo-element.
560    ///
561    /// This is useful to avoid computing, for example, pseudo styles for
562    /// `::-first-line` or `::-first-letter`, when we know it won't affect us.
563    ///
564    /// TODO(emilio, bz): actually implement the logic for it.
565    fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
566        // ::before/::after are always supported for now, though we could try to
567        // optimize out leaf elements.
568
569        // ::first-letter and ::first-line are only supported for block-inside
570        // things, and only in Gecko, not Servo.  Unfortunately, Gecko has
571        // block-inside things that might have any computed display value due to
572        // things like fieldsets, legends, etc.  Need to figure out how this
573        // should work.
574        debug_assert!(
575            pseudo.is_eager(),
576            "Someone called may_generate_pseudo with a non-eager pseudo."
577        );
578        true
579    }
580
581    /// Returns true if this element may have a descendant needing style processing.
582    ///
583    /// Note that we cannot guarantee the existence of such an element, because
584    /// it may have been removed from the DOM between marking it for restyle and
585    /// the actual restyle traversal.
586    fn has_dirty_descendants(&self) -> bool;
587
588    /// Returns whether state or attributes that may change style have changed
589    /// on the element, and thus whether the element has been snapshotted to do
590    /// restyle hint computation.
591    fn has_snapshot(&self) -> bool;
592
593    /// Returns whether the current snapshot if present has been handled.
594    fn handled_snapshot(&self) -> bool;
595
596    /// Flags this element as having handled already its snapshot.
597    unsafe fn set_handled_snapshot(&self);
598
599    /// Returns whether the element's styles are up-to-date after traversal
600    /// (i.e. in post traversal).
601    fn has_current_styles(&self, data: &ElementData) -> bool {
602        if self.has_snapshot() && !self.handled_snapshot() {
603            return false;
604        }
605
606        data.has_styles() &&
607        // TODO(hiro): When an animating element moved into subtree of
608        // contenteditable element, there remains animation restyle hints in
609        // post traversal. It's generally harmless since the hints will be
610        // processed in a next styling but ideally it should be processed soon.
611        //
612        // Without this, we get failures in:
613        //   layout/style/crashtests/1383319.html
614        //   layout/style/crashtests/1383001.html
615        //
616        // https://bugzilla.mozilla.org/show_bug.cgi?id=1389675 tracks fixing
617        // this.
618        !data.hint.has_non_animation_invalidations()
619    }
620
621    /// Flag that this element has a descendant for style processing.
622    ///
623    /// Only safe to call with exclusive access to the element.
624    unsafe fn set_dirty_descendants(&self);
625
626    /// Flag that this element has no descendant for style processing.
627    ///
628    /// Only safe to call with exclusive access to the element.
629    unsafe fn unset_dirty_descendants(&self);
630
631    /// Similar to the dirty_descendants but for representing a descendant of
632    /// the element needs to be updated in animation-only traversal.
633    fn has_animation_only_dirty_descendants(&self) -> bool {
634        false
635    }
636
637    /// Flag that this element has a descendant for animation-only restyle
638    /// processing.
639    ///
640    /// Only safe to call with exclusive access to the element.
641    unsafe fn set_animation_only_dirty_descendants(&self) {}
642
643    /// Flag that this element has no descendant for animation-only restyle processing.
644    ///
645    /// Only safe to call with exclusive access to the element.
646    unsafe fn unset_animation_only_dirty_descendants(&self) {}
647
648    /// Clear all bits related describing the dirtiness of descendants.
649    ///
650    /// In Gecko, this corresponds to the regular dirty descendants bit, the
651    /// animation-only dirty descendants bit, and the lazy frame construction
652    /// descendants bit.
653    unsafe fn clear_descendant_bits(&self) {
654        self.unset_dirty_descendants();
655    }
656
657    /// Returns true if this element is a visited link.
658    ///
659    /// Servo doesn't support visited styles yet.
660    fn is_visited_link(&self) -> bool {
661        false
662    }
663
664    /// Returns the pseudo-element implemented by this element, if any.
665    ///
666    /// Gecko traverses pseudo-elements during the style traversal, and we need
667    /// to know this so we can properly grab the pseudo-element style from the
668    /// parent element.
669    ///
670    /// Note that we still need to compute the pseudo-elements before-hand,
671    /// given otherwise we don't know if we need to create an element or not.
672    ///
673    /// Servo doesn't have to deal with this.
674    fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
675        None
676    }
677
678    /// Atomically stores the number of children of this node that we will
679    /// need to process during bottom-up traversal.
680    fn store_children_to_process(&self, n: isize);
681
682    /// Atomically notes that a child has been processed during bottom-up
683    /// traversal. Returns the number of children left to process.
684    fn did_process_child(&self) -> isize;
685
686    /// Gets a reference to the ElementData container, or creates one.
687    ///
688    /// Unsafe because it can race to allocate and leak if not used with
689    /// exclusive access to the element.
690    unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData>;
691
692    /// Clears the element data reference, if any.
693    ///
694    /// Unsafe following the same reasoning as ensure_data.
695    unsafe fn clear_data(&self);
696
697    /// Whether there is an ElementData container.
698    fn has_data(&self) -> bool;
699
700    /// Immutably borrows the ElementData.
701    fn borrow_data(&self) -> Option<AtomicRef<ElementData>>;
702
703    /// Mutably borrows the ElementData.
704    fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>>;
705
706    /// Whether we should skip any root- or item-based display property
707    /// blockification on this element.  (This function exists so that Gecko
708    /// native anonymous content can opt out of this style fixup.)
709    fn skip_item_display_fixup(&self) -> bool;
710
711    /// In Gecko, element has a flag that represents the element may have
712    /// any type of animations or not to bail out animation stuff early.
713    /// Whereas Servo doesn't have such flag.
714    fn may_have_animations(&self) -> bool;
715
716    /// Creates a task to update various animation state on a given (pseudo-)element.
717    #[cfg(feature = "gecko")]
718    fn update_animations(
719        &self,
720        before_change_style: Option<Arc<ComputedValues>>,
721        tasks: UpdateAnimationsTasks,
722    );
723
724    /// Returns true if the element has relevant animations. Relevant
725    /// animations are those animations that are affecting the element's style
726    /// or are scheduled to do so in the future.
727    fn has_animations(&self, context: &SharedStyleContext) -> bool;
728
729    /// Returns true if the element has a CSS animation. The `context` and `pseudo_element`
730    /// arguments are only used by Servo, since it stores animations globally and pseudo-elements
731    /// are not in the DOM.
732    fn has_css_animations(
733        &self,
734        context: &SharedStyleContext,
735        pseudo_element: Option<PseudoElement>,
736    ) -> bool;
737
738    /// Returns true if the element has a CSS transition (including running transitions and
739    /// completed transitions). The `context` and `pseudo_element` arguments are only used
740    /// by Servo, since it stores animations globally and pseudo-elements are not in the DOM.
741    fn has_css_transitions(
742        &self,
743        context: &SharedStyleContext,
744        pseudo_element: Option<PseudoElement>,
745    ) -> bool;
746
747    /// Returns true if the element has animation restyle hints.
748    fn has_animation_restyle_hints(&self) -> bool {
749        let data = match self.borrow_data() {
750            Some(d) => d,
751            None => return false,
752        };
753        return data.hint.has_animation_hint();
754    }
755
756    /// The shadow root this element is a host of.
757    fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
758
759    /// The shadow root which roots the subtree this element is contained in.
760    fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
761
762    /// Return the element which we can use to look up rules in the selector
763    /// maps.
764    ///
765    /// This is always the element itself, except in the case where we are an
766    /// element-backed pseudo-element, in which case we return the originating
767    /// element.
768    fn rule_hash_target(&self) -> Self {
769        if self.is_pseudo_element() {
770            self.pseudo_element_originating_element()
771                .expect("Trying to collect rules for a detached pseudo-element")
772        } else {
773            *self
774        }
775    }
776
777    /// Executes the callback for each applicable style rule data which isn't
778    /// the main document's data (which stores UA / author rules).
779    ///
780    /// The element passed to the callback is the containing shadow host for the
781    /// data if it comes from Shadow DOM.
782    ///
783    /// Returns whether normal document author rules should apply.
784    ///
785    /// TODO(emilio): We could separate the invalidation data for elements
786    /// matching in other scopes to avoid over-invalidation.
787    fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
788    where
789        Self: 'a,
790        F: FnMut(&'a CascadeData, Self),
791    {
792        use crate::rule_collector::containing_shadow_ignoring_svg_use;
793
794        let target = self.rule_hash_target();
795        let matches_user_and_content_rules = target.matches_user_and_content_rules();
796        let mut doc_rules_apply = matches_user_and_content_rules;
797
798        // Use the same rules to look for the containing host as we do for rule
799        // collection.
800        if let Some(shadow) = containing_shadow_ignoring_svg_use(target) {
801            doc_rules_apply = false;
802            if let Some(data) = shadow.style_data() {
803                f(data, shadow.host());
804            }
805        }
806
807        if let Some(shadow) = target.shadow_root() {
808            if let Some(data) = shadow.style_data() {
809                f(data, shadow.host());
810            }
811        }
812
813        let mut current = target.assigned_slot();
814        while let Some(slot) = current {
815            // Slots can only have assigned nodes when in a shadow tree.
816            let shadow = slot.containing_shadow().unwrap();
817            if let Some(data) = shadow.style_data() {
818                if data.any_slotted_rule() {
819                    f(data, shadow.host());
820                }
821            }
822            current = slot.assigned_slot();
823        }
824
825        if target.has_part_attr() {
826            if let Some(mut inner_shadow) = target.containing_shadow() {
827                loop {
828                    let inner_shadow_host = inner_shadow.host();
829                    match inner_shadow_host.containing_shadow() {
830                        Some(shadow) => {
831                            if let Some(data) = shadow.style_data() {
832                                if data.any_part_rule() {
833                                    f(data, shadow.host())
834                                }
835                            }
836                            // TODO: Could be more granular.
837                            if !inner_shadow_host.exports_any_part() {
838                                break;
839                            }
840                            inner_shadow = shadow;
841                        },
842                        None => {
843                            // TODO(emilio): Should probably distinguish with
844                            // MatchesDocumentRules::{No,Yes,IfPart} or something so that we could
845                            // skip some work.
846                            doc_rules_apply = matches_user_and_content_rules;
847                            break;
848                        },
849                    }
850                }
851            }
852        }
853
854        doc_rules_apply
855    }
856
857    /// Returns true if one of the transitions needs to be updated on this element. We check all
858    /// the transition properties to make sure that updating transitions is necessary.
859    /// This method should only be called if might_needs_transitions_update returns true when
860    /// passed the same parameters.
861    #[cfg(feature = "gecko")]
862    fn needs_transitions_update(
863        &self,
864        before_change_style: &ComputedValues,
865        after_change_style: &ComputedValues,
866    ) -> bool;
867
868    /// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
869    /// the `lang=""` attribute) on this element.
870    fn lang_attr(&self) -> Option<AttrValue>;
871
872    /// Returns whether this element's language matches the language tag
873    /// `value`.  If `override_lang` is not `None`, it specifies the value
874    /// of the `xml:lang=""` or `lang=""` attribute to use in place of
875    /// looking at the element and its ancestors.  (This argument is used
876    /// to implement matching of `:lang()` against snapshots.)
877    fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool;
878
879    /// Returns whether this element is the main body element of the HTML
880    /// document it is on.
881    fn is_html_document_body_element(&self) -> bool;
882
883    /// Generate the proper applicable declarations due to presentational hints,
884    /// and insert them into `hints`.
885    fn synthesize_presentational_hints_for_legacy_attributes<V>(
886        &self,
887        visited_handling: VisitedHandlingMode,
888        hints: &mut V,
889    ) where
890        V: Push<ApplicableDeclarationBlock>;
891
892    /// Generate the proper applicable declarations due to view transition dynamic rules, and
893    /// insert them into `rules`.
894    /// https://drafts.csswg.org/css-view-transitions-1/#document-dynamic-view-transition-style-sheet
895    fn synthesize_view_transition_dynamic_rules<V>(&self, _rules: &mut V)
896    where
897        V: Push<ApplicableDeclarationBlock>
898    {}
899
900    /// Returns element's local name.
901    fn local_name(&self) -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedLocalName;
902
903    /// Returns element's namespace.
904    fn namespace(&self)
905        -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedNamespaceUrl;
906
907    /// Returns the size of the element to be used in container size queries.
908    /// This will usually be the size of the content area of the primary box,
909    /// but can be None if there is no box or if some axis lacks size containment.
910    fn query_container_size(
911        &self,
912        display: &Display,
913    ) -> euclid::default::Size2D<Option<app_units::Au>>;
914
915    /// Returns true if the element has all of specified selector flags.
916    fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
917
918    /// Returns the search direction for relative selector invalidation, if it is on the search path.
919    fn relative_selector_search_direction(&self) -> ElementSelectorFlags;
920
921    /// Returns the implicit scope root for given sheet index and host.
922    fn implicit_scope_for_sheet_in_shadow_root(
923        _opaque_host: OpaqueElement,
924        _sheet_index: usize,
925    ) -> Option<ImplicitScopeRoot> {
926        None
927    }
928}
929
930/// TNode and TElement aren't Send because we want to be careful and explicit
931/// about our parallel traversal. However, there are certain situations
932/// (including but not limited to the traversal) where we need to send DOM
933/// objects to other threads.
934///
935/// That's the reason why `SendNode` exists.
936#[derive(Clone, Debug, PartialEq)]
937pub struct SendNode<N: TNode>(N);
938unsafe impl<N: TNode> Send for SendNode<N> {}
939impl<N: TNode> SendNode<N> {
940    /// Unsafely construct a SendNode.
941    pub unsafe fn new(node: N) -> Self {
942        SendNode(node)
943    }
944}
945impl<N: TNode> Deref for SendNode<N> {
946    type Target = N;
947    fn deref(&self) -> &N {
948        &self.0
949    }
950}
951
952/// Same reason as for the existence of SendNode, SendElement does the proper
953/// things for a given `TElement`.
954#[derive(Debug, Eq, Hash, PartialEq)]
955pub struct SendElement<E: TElement>(E);
956unsafe impl<E: TElement> Send for SendElement<E> {}
957impl<E: TElement> SendElement<E> {
958    /// Unsafely construct a SendElement.
959    pub unsafe fn new(el: E) -> Self {
960        SendElement(el)
961    }
962}
963impl<E: TElement> Deref for SendElement<E> {
964    type Target = E;
965    fn deref(&self) -> &E {
966        &self.0
967    }
968}