/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Types and traits used to access the DOM from style calculation.

#![allow(unsafe_code)]
#![deny(missing_docs)]

use crate::applicable_declarations::ApplicableDeclarationBlock;
use crate::context::SharedStyleContext;
#[cfg(feature = "gecko")]
use crate::context::UpdateAnimationsTasks;
use crate::data::ElementData;
use crate::media_queries::Device;
use crate::properties::{AnimationDeclarations, ComputedValues, PropertyDeclarationBlock};
use crate::selector_parser::{AttrValue, Lang, PseudoElement, RestyleDamage, SelectorImpl};
use crate::shared_lock::{Locked, SharedRwLock};
use crate::stylesheets::scope_rule::ImplicitScopeRoot;
use crate::stylist::CascadeData;
use crate::values::computed::Display;
use crate::values::AtomIdent;
use crate::{LocalName, WeakAtom};
use atomic_refcell::{AtomicRef, AtomicRefMut};
use dom::ElementState;
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
use selectors::sink::Push;
use selectors::{Element as SelectorsElement, OpaqueElement};
use servo_arc::{Arc, ArcBorrow};
use std::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;

pub use style_traits::dom::OpaqueNode;

/// Simple trait to provide basic information about the type of an element.
///
/// We avoid exposing the full type id, since computing it in the general case
/// would be difficult for Gecko nodes.
pub trait NodeInfo {
    /// Whether this node is an element.
    fn is_element(&self) -> bool;
    /// Whether this node is a text node.
    fn is_text_node(&self) -> bool;
}

/// A node iterator that only returns node that don't need layout.
pub struct LayoutIterator<T>(pub T);

impl<T, N> Iterator for LayoutIterator<T>
where
    T: Iterator<Item = N>,
    N: NodeInfo,
{
    type Item = N;

    fn next(&mut self) -> Option<N> {
        loop {
            let n = self.0.next()?;
            // Filter out nodes that layout should ignore.
            if n.is_text_node() || n.is_element() {
                return Some(n);
            }
        }
    }
}

/// An iterator over the DOM children of a node.
pub struct DomChildren<N>(Option<N>);
impl<N> Iterator for DomChildren<N>
where
    N: TNode,
{
    type Item = N;

    fn next(&mut self) -> Option<N> {
        let n = self.0.take()?;
        self.0 = n.next_sibling();
        Some(n)
    }
}

/// An iterator over the DOM descendants of a node in pre-order.
pub struct DomDescendants<N> {
    previous: Option<N>,
    scope: N,
}

impl<N> Iterator for DomDescendants<N>
where
    N: TNode,
{
    type Item = N;

    #[inline]
    fn next(&mut self) -> Option<N> {
        let prev = self.previous.take()?;
        self.previous = prev.next_in_preorder(self.scope);
        self.previous
    }
}

/// The `TDocument` trait, to represent a document node.
pub trait TDocument: Sized + Copy + Clone {
    /// The concrete `TNode` type.
    type ConcreteNode: TNode<ConcreteDocument = Self>;

    /// Get this document as a `TNode`.
    fn as_node(&self) -> Self::ConcreteNode;

    /// Returns whether this document is an HTML document.
    fn is_html_document(&self) -> bool;

    /// Returns the quirks mode of this document.
    fn quirks_mode(&self) -> QuirksMode;

    /// Get a list of elements with a given ID in this document, sorted by
    /// tree position.
    ///
    /// Can return an error to signal that this list is not available, or also
    /// return an empty slice.
    fn elements_with_id<'a>(
        &self,
        _id: &AtomIdent,
    ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
    where
        Self: 'a,
    {
        Err(())
    }

    /// This document's shared lock.
    fn shared_lock(&self) -> &SharedRwLock;
}

/// The `TNode` trait. This is the main generic trait over which the style
/// system can be implemented.
pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
    /// The concrete `TElement` type.
    type ConcreteElement: TElement<ConcreteNode = Self>;

    /// The concrete `TDocument` type.
    type ConcreteDocument: TDocument<ConcreteNode = Self>;

    /// The concrete `TShadowRoot` type.
    type ConcreteShadowRoot: TShadowRoot<ConcreteNode = Self>;

    /// Get this node's parent node.
    fn parent_node(&self) -> Option<Self>;

    /// Get this node's first child.
    fn first_child(&self) -> Option<Self>;

    /// Get this node's last child.
    fn last_child(&self) -> Option<Self>;

    /// Get this node's previous sibling.
    fn prev_sibling(&self) -> Option<Self>;

    /// Get this node's next sibling.
    fn next_sibling(&self) -> Option<Self>;

    /// Get the owner document of this node.
    fn owner_doc(&self) -> Self::ConcreteDocument;

    /// Iterate over the DOM children of a node.
    #[inline(always)]
    fn dom_children(&self) -> DomChildren<Self> {
        DomChildren(self.first_child())
    }

    /// Returns whether the node is attached to a document.
    fn is_in_document(&self) -> bool;

    /// Iterate over the DOM children of a node, in preorder.
    #[inline(always)]
    fn dom_descendants(&self) -> DomDescendants<Self> {
        DomDescendants {
            previous: Some(*self),
            scope: *self,
        }
    }

    /// Returns the next node after this one, in a pre-order tree-traversal of
    /// the subtree rooted at scoped_to.
    #[inline]
    fn next_in_preorder(&self, scoped_to: Self) -> Option<Self> {
        if let Some(c) = self.first_child() {
            return Some(c);
        }

        let mut current = *self;
        loop {
            if current == scoped_to {
                return None;
            }

            if let Some(s) = current.next_sibling() {
                return Some(s);
            }

            debug_assert!(
                current.parent_node().is_some(),
                "Not a descendant of the scope?"
            );
            current = current.parent_node()?;
        }
    }

    /// Returns the depth of this node in the DOM.
    fn depth(&self) -> usize {
        let mut depth = 0;
        let mut curr = *self;
        while let Some(parent) = curr.traversal_parent() {
            depth += 1;
            curr = parent.as_node();
        }
        depth
    }

    /// Get this node's parent element from the perspective of a restyle
    /// traversal.
    fn traversal_parent(&self) -> Option<Self::ConcreteElement>;

    /// Get this node's parent element if present.
    fn parent_element(&self) -> Option<Self::ConcreteElement> {
        self.parent_node().and_then(|n| n.as_element())
    }

    /// Get this node's parent element, or shadow host if it's a shadow root.
    fn parent_element_or_host(&self) -> Option<Self::ConcreteElement> {
        let parent = self.parent_node()?;
        if let Some(e) = parent.as_element() {
            return Some(e);
        }
        if let Some(root) = parent.as_shadow_root() {
            return Some(root.host());
        }
        None
    }

    /// Converts self into an `OpaqueNode`.
    fn opaque(&self) -> OpaqueNode;

    /// A debug id, only useful, mm... for debugging.
    fn debug_id(self) -> usize;

    /// Get this node as an element, if it's one.
    fn as_element(&self) -> Option<Self::ConcreteElement>;

    /// Get this node as a document, if it's one.
    fn as_document(&self) -> Option<Self::ConcreteDocument>;

    /// Get this node as a ShadowRoot, if it's one.
    fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot>;
}

/// Wrapper to output the subtree rather than the single node when formatting
/// for Debug.
pub struct ShowSubtree<N: TNode>(pub N);
impl<N: TNode> Debug for ShowSubtree<N> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "DOM Subtree:")?;
        fmt_subtree(f, &|f, n| write!(f, "{:?}", n), self.0, 1)
    }
}

/// Wrapper to output the subtree along with the ElementData when formatting
/// for Debug.
pub struct ShowSubtreeData<N: TNode>(pub N);
impl<N: TNode> Debug for ShowSubtreeData<N> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "DOM Subtree:")?;
        fmt_subtree(f, &|f, n| fmt_with_data(f, n), self.0, 1)
    }
}

/// Wrapper to output the subtree along with the ElementData and primary
/// ComputedValues when formatting for Debug. This is extremely verbose.
#[cfg(feature = "servo")]
pub struct ShowSubtreeDataAndPrimaryValues<N: TNode>(pub N);
#[cfg(feature = "servo")]
impl<N: TNode> Debug for ShowSubtreeDataAndPrimaryValues<N> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "DOM Subtree:")?;
        fmt_subtree(f, &|f, n| fmt_with_data_and_primary_values(f, n), self.0, 1)
    }
}

fn fmt_with_data<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
    if let Some(el) = n.as_element() {
        write!(
            f,
            "{:?} dd={} aodd={} data={:?}",
            el,
            el.has_dirty_descendants(),
            el.has_animation_only_dirty_descendants(),
            el.borrow_data(),
        )
    } else {
        write!(f, "{:?}", n)
    }
}

#[cfg(feature = "servo")]
fn fmt_with_data_and_primary_values<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
    if let Some(el) = n.as_element() {
        let dd = el.has_dirty_descendants();
        let aodd = el.has_animation_only_dirty_descendants();
        let data = el.borrow_data();
        let values = data.as_ref().and_then(|d| d.styles.get_primary());
        write!(
            f,
            "{:?} dd={} aodd={} data={:?} values={:?}",
            el, dd, aodd, &data, values
        )
    } else {
        write!(f, "{:?}", n)
    }
}

fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) -> fmt::Result
where
    F: Fn(&mut fmt::Formatter, N) -> fmt::Result,
{
    for _ in 0..indent {
        write!(f, "  ")?;
    }
    stringify(f, n)?;
    if let Some(e) = n.as_element() {
        for kid in e.traversal_children() {
            writeln!(f, "")?;
            fmt_subtree(f, stringify, kid, indent + 1)?;
        }
    }

    Ok(())
}

/// The ShadowRoot trait.
pub trait TShadowRoot: Sized + Copy + Clone + Debug + PartialEq {
    /// The concrete node type.
    type ConcreteNode: TNode<ConcreteShadowRoot = Self>;

    /// Get this ShadowRoot as a node.
    fn as_node(&self) -> Self::ConcreteNode;

    /// Get the shadow host that hosts this ShadowRoot.
    fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;

    /// Get the style data for this ShadowRoot.
    fn style_data<'a>(&self) -> Option<&'a CascadeData>
    where
        Self: 'a;

    /// Get the list of shadow parts for this shadow root.
    fn parts<'a>(&self) -> &[<Self::ConcreteNode as TNode>::ConcreteElement]
    where
        Self: 'a,
    {
        &[]
    }

    /// Get a list of elements with a given ID in this shadow root, sorted by
    /// tree position.
    ///
    /// Can return an error to signal that this list is not available, or also
    /// return an empty slice.
    fn elements_with_id<'a>(
        &self,
        _id: &AtomIdent,
    ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
    where
        Self: 'a,
    {
        Err(())
    }

    /// Get the implicit scope for a stylesheet in given index.
    fn implicit_scope_for_sheet(&self, _sheet_index: usize) -> Option<ImplicitScopeRoot> {
        None
    }
}

/// The element trait, the main abstraction the style crate acts over.
pub trait TElement:
    Eq
    + PartialEq
    + Debug
    + Hash
    + Sized
    + Copy
    + Clone
    + SelectorsElement<Impl = SelectorImpl>
    + AttributeProvider
{
    /// The concrete node type.
    type ConcreteNode: TNode<ConcreteElement = Self>;

    /// A concrete children iterator type in order to iterate over the `Node`s.
    ///
    /// TODO(emilio): We should eventually replace this with the `impl Trait`
    /// syntax.
    type TraversalChildrenIterator: Iterator<Item = Self::ConcreteNode>;

    /// Get this element as a node.
    fn as_node(&self) -> Self::ConcreteNode;

    /// A debug-only check that the device's owner doc matches the actual doc
    /// we're the root of.
    ///
    /// Otherwise we may set document-level state incorrectly, like the root
    /// font-size used for rem units.
    fn owner_doc_matches_for_testing(&self, _: &Device) -> bool {
        true
    }

    /// Whether this element should match user and content rules.
    ///
    /// We use this for Native Anonymous Content in Gecko.
    fn matches_user_and_content_rules(&self) -> bool {
        true
    }

    /// Get this node's parent element from the perspective of a restyle
    /// traversal.
    fn traversal_parent(&self) -> Option<Self> {
        self.as_node().traversal_parent()
    }

    /// Get this node's children from the perspective of a restyle traversal.
    fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator>;

    /// Returns the parent element we should inherit from.
    ///
    /// This is pretty much always the parent element itself, except in the case
    /// of Gecko's Native Anonymous Content, which uses the traversal parent
    /// (i.e. the flattened tree parent) and which also may need to find the
    /// closest non-NAC ancestor.
    fn inheritance_parent(&self) -> Option<Self> {
        self.parent_element()
    }

    /// Execute `f` for each anonymous content child (apart from ::before and
    /// ::after) whose originating element is `self`.
    fn each_anonymous_content_child<F>(&self, _f: F)
    where
        F: FnMut(Self),
    {
    }

    /// Return whether this element is an element in the HTML namespace.
    fn is_html_element(&self) -> bool;

    /// Return whether this element is an element in the MathML namespace.
    fn is_mathml_element(&self) -> bool;

    /// Return whether this element is an element in the SVG namespace.
    fn is_svg_element(&self) -> bool;

    /// Return whether this element is an element in the XUL namespace.
    fn is_xul_element(&self) -> bool {
        false
    }

    /// Return the list of slotted nodes of this node.
    fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
        &[]
    }

    /// Get this element's style attribute.
    fn style_attribute(&self) -> Option<ArcBorrow<'_, Locked<PropertyDeclarationBlock>>>;

    /// Unset the style attribute's dirty bit.
    /// Servo doesn't need to manage ditry bit for style attribute.
    fn unset_dirty_style_attribute(&self) {}

    /// Get this element's SMIL override declarations.
    fn smil_override(&self) -> Option<ArcBorrow<'_, Locked<PropertyDeclarationBlock>>> {
        None
    }

    /// Get the combined animation and transition rules.
    ///
    /// FIXME(emilio): Is this really useful?
    fn animation_declarations(&self, context: &SharedStyleContext) -> AnimationDeclarations {
        if !self.may_have_animations() {
            return Default::default();
        }

        AnimationDeclarations {
            animations: self.animation_rule(context),
            transitions: self.transition_rule(context),
        }
    }

    /// Get this element's animation rule.
    fn animation_rule(
        &self,
        _: &SharedStyleContext,
    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;

    /// Get this element's transition rule.
    fn transition_rule(
        &self,
        context: &SharedStyleContext,
    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;

    /// Get this element's state, for non-tree-structural pseudos.
    fn state(&self) -> ElementState;

    /// Returns whether this element has a `part` attribute.
    fn has_part_attr(&self) -> bool;

    /// Returns whether this element exports any part from its shadow tree.
    fn exports_any_part(&self) -> bool;

    /// The ID for this element.
    fn id(&self) -> Option<&WeakAtom>;

    /// Internal iterator for the classes of this element.
    fn each_class<F>(&self, callback: F)
    where
        F: FnMut(&AtomIdent);

    /// Internal iterator for the classes of this element.
    fn each_custom_state<F>(&self, callback: F)
    where
        F: FnMut(&AtomIdent);

    /// Internal iterator for the part names of this element.
    fn each_part<F>(&self, _callback: F)
    where
        F: FnMut(&AtomIdent),
    {
    }

    /// Internal iterator for the attribute names of this element.
    fn each_attr_name<F>(&self, callback: F)
    where
        F: FnMut(&LocalName);

    /// Internal iterator for the part names that this element exports for a
    /// given part name.
    fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
    where
        F: FnMut(&AtomIdent),
    {
    }

    /// Whether a given element may generate a pseudo-element.
    ///
    /// This is useful to avoid computing, for example, pseudo styles for
    /// `::-first-line` or `::-first-letter`, when we know it won't affect us.
    ///
    /// TODO(emilio, bz): actually implement the logic for it.
    fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
        // ::before/::after are always supported for now, though we could try to
        // optimize out leaf elements.

        // ::first-letter and ::first-line are only supported for block-inside
        // things, and only in Gecko, not Servo.  Unfortunately, Gecko has
        // block-inside things that might have any computed display value due to
        // things like fieldsets, legends, etc.  Need to figure out how this
        // should work.
        debug_assert!(
            pseudo.is_eager(),
            "Someone called may_generate_pseudo with a non-eager pseudo."
        );
        true
    }

    /// Returns true if this element may have a descendant needing style processing.
    ///
    /// Note that we cannot guarantee the existence of such an element, because
    /// it may have been removed from the DOM between marking it for restyle and
    /// the actual restyle traversal.
    fn has_dirty_descendants(&self) -> bool;

    /// Returns whether state or attributes that may change style have changed
    /// on the element, and thus whether the element has been snapshotted to do
    /// restyle hint computation.
    fn has_snapshot(&self) -> bool;

    /// Returns whether the current snapshot if present has been handled.
    fn handled_snapshot(&self) -> bool;

    /// Flags this element as having handled already its snapshot.
    unsafe fn set_handled_snapshot(&self);

    /// Returns whether the element's styles are up-to-date after traversal
    /// (i.e. in post traversal).
    fn has_current_styles(&self, data: &ElementData) -> bool {
        if self.has_snapshot() && !self.handled_snapshot() {
            return false;
        }

        data.has_styles() &&
        // TODO(hiro): When an animating element moved into subtree of
        // contenteditable element, there remains animation restyle hints in
        // post traversal. It's generally harmless since the hints will be
        // processed in a next styling but ideally it should be processed soon.
        //
        // Without this, we get failures in:
        //   layout/style/crashtests/1383319.html
        //   layout/style/crashtests/1383001.html
        //
        // https://bugzilla.mozilla.org/show_bug.cgi?id=1389675 tracks fixing
        // this.
        !data.hint.has_non_animation_invalidations()
    }

    /// Flag that this element has a descendant for style processing.
    ///
    /// Only safe to call with exclusive access to the element.
    unsafe fn set_dirty_descendants(&self);

    /// Flag that this element has no descendant for style processing.
    ///
    /// Only safe to call with exclusive access to the element.
    unsafe fn unset_dirty_descendants(&self);

    /// Similar to the dirty_descendants but for representing a descendant of
    /// the element needs to be updated in animation-only traversal.
    fn has_animation_only_dirty_descendants(&self) -> bool {
        false
    }

    /// Flag that this element has a descendant for animation-only restyle
    /// processing.
    ///
    /// Only safe to call with exclusive access to the element.
    unsafe fn set_animation_only_dirty_descendants(&self) {}

    /// Flag that this element has no descendant for animation-only restyle processing.
    ///
    /// Only safe to call with exclusive access to the element.
    unsafe fn unset_animation_only_dirty_descendants(&self) {}

    /// Clear all bits related describing the dirtiness of descendants.
    ///
    /// In Gecko, this corresponds to the regular dirty descendants bit, the
    /// animation-only dirty descendants bit, and the lazy frame construction
    /// descendants bit.
    unsafe fn clear_descendant_bits(&self) {
        self.unset_dirty_descendants();
    }

    /// Returns true if this element is a visited link.
    ///
    /// Servo doesn't support visited styles yet.
    fn is_visited_link(&self) -> bool {
        false
    }

    /// Returns the pseudo-element implemented by this element, if any.
    ///
    /// Gecko traverses pseudo-elements during the style traversal, and we need
    /// to know this so we can properly grab the pseudo-element style from the
    /// parent element.
    ///
    /// Note that we still need to compute the pseudo-elements before-hand,
    /// given otherwise we don't know if we need to create an element or not.
    fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
        None
    }

    /// Atomically stores the number of children of this node that we will
    /// need to process during bottom-up traversal.
    fn store_children_to_process(&self, n: isize);

    /// Atomically notes that a child has been processed during bottom-up
    /// traversal. Returns the number of children left to process.
    fn did_process_child(&self) -> isize;

    /// Gets a reference to the ElementData container, or creates one.
    ///
    /// Unsafe because it can race to allocate and leak if not used with
    /// exclusive access to the element.
    unsafe fn ensure_data(&self) -> AtomicRefMut<'_, ElementData>;

    /// Clears the element data reference, if any.
    ///
    /// Unsafe following the same reasoning as ensure_data.
    unsafe fn clear_data(&self);

    /// Whether there is an ElementData container.
    fn has_data(&self) -> bool;

    /// Immutably borrows the ElementData.
    fn borrow_data(&self) -> Option<AtomicRef<'_, ElementData>>;

    /// Mutably borrows the ElementData.
    fn mutate_data(&self) -> Option<AtomicRefMut<'_, ElementData>>;

    /// Whether we should skip any root- or item-based display property
    /// blockification on this element.  (This function exists so that Gecko
    /// native anonymous content can opt out of this style fixup.)
    fn skip_item_display_fixup(&self) -> bool;

    /// In Gecko, element has a flag that represents the element may have
    /// any type of animations or not to bail out animation stuff early.
    /// Whereas Servo doesn't have such flag.
    fn may_have_animations(&self) -> bool;

    /// Creates a task to update various animation state on a given (pseudo-)element.
    #[cfg(feature = "gecko")]
    fn update_animations(
        &self,
        before_change_style: Option<Arc<ComputedValues>>,
        tasks: UpdateAnimationsTasks,
    );

    /// Returns true if the element has relevant animations. Relevant
    /// animations are those animations that are affecting the element's style
    /// or are scheduled to do so in the future.
    fn has_animations(&self, context: &SharedStyleContext) -> bool;

    /// Returns true if the element has a CSS animation. The `context` and `pseudo_element`
    /// arguments are only used by Servo, since it stores animations globally and pseudo-elements
    /// are not in the DOM.
    fn has_css_animations(
        &self,
        context: &SharedStyleContext,
        pseudo_element: Option<PseudoElement>,
    ) -> bool;

    /// Returns true if the element has a CSS transition (including running transitions and
    /// completed transitions). The `context` and `pseudo_element` arguments are only used
    /// by Servo, since it stores animations globally and pseudo-elements are not in the DOM.
    fn has_css_transitions(
        &self,
        context: &SharedStyleContext,
        pseudo_element: Option<PseudoElement>,
    ) -> bool;

    /// Returns true if the element has animation restyle hints.
    fn has_animation_restyle_hints(&self) -> bool {
        let data = match self.borrow_data() {
            Some(d) => d,
            None => return false,
        };
        return data.hint.has_animation_hint();
    }

    /// The shadow root this element is a host of.
    fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;

    /// The shadow root which roots the subtree this element is contained in.
    fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;

    /// Return the element which we can use to look up rules in the selector
    /// maps.
    ///
    /// This is always the element itself, except in the case where we are an
    /// element-backed pseudo-element, in which case we return the originating
    /// element.
    fn rule_hash_target(&self) -> Self {
        let mut cur = *self;
        while cur.is_pseudo_element() {
            cur = cur
                .pseudo_element_originating_element()
                .expect("Trying to collect rules for a detached pseudo-element")
        }
        cur
    }

    /// Executes the callback for each applicable style rule data which isn't
    /// the main document's data (which stores UA / author rules).
    ///
    /// The element passed to the callback is the containing shadow host for the
    /// data if it comes from Shadow DOM.
    ///
    /// Returns whether normal document author rules should apply.
    ///
    /// TODO(emilio): We could separate the invalidation data for elements
    /// matching in other scopes to avoid over-invalidation.
    fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
    where
        Self: 'a,
        F: FnMut(&'a CascadeData, Self),
    {
        use crate::rule_collector::containing_shadow_ignoring_svg_use;

        let target = self.rule_hash_target();
        let matches_user_and_content_rules = target.matches_user_and_content_rules();
        let mut doc_rules_apply = matches_user_and_content_rules;

        // Use the same rules to look for the containing host as we do for rule
        // collection.
        if let Some(shadow) = containing_shadow_ignoring_svg_use(target) {
            doc_rules_apply = false;
            if let Some(data) = shadow.style_data() {
                f(data, shadow.host());
            }
        }

        if let Some(shadow) = target.shadow_root() {
            if let Some(data) = shadow.style_data() {
                f(data, shadow.host());
            }
        }

        let mut current = target.assigned_slot();
        while let Some(slot) = current {
            // Slots can only have assigned nodes when in a shadow tree.
            let shadow = slot.containing_shadow().unwrap();
            if let Some(data) = shadow.style_data() {
                if data.any_slotted_rule() {
                    f(data, shadow.host());
                }
            }
            current = slot.assigned_slot();
        }

        if target.has_part_attr() {
            if let Some(mut inner_shadow) = target.containing_shadow() {
                loop {
                    let inner_shadow_host = inner_shadow.host();
                    match inner_shadow_host.containing_shadow() {
                        Some(shadow) => {
                            if let Some(data) = shadow.style_data() {
                                if data.any_part_rule() {
                                    f(data, shadow.host())
                                }
                            }
                            // TODO: Could be more granular.
                            if !inner_shadow_host.exports_any_part() {
                                break;
                            }
                            inner_shadow = shadow;
                        },
                        None => {
                            // TODO(emilio): Should probably distinguish with
                            // MatchesDocumentRules::{No,Yes,IfPart} or something so that we could
                            // skip some work.
                            doc_rules_apply = matches_user_and_content_rules;
                            break;
                        },
                    }
                }
            }
        }

        doc_rules_apply
    }

    /// Returns true if one of the transitions needs to be updated on this element. We check all
    /// the transition properties to make sure that updating transitions is necessary.
    /// This method should only be called if might_needs_transitions_update returns true when
    /// passed the same parameters.
    #[cfg(feature = "gecko")]
    fn needs_transitions_update(
        &self,
        before_change_style: &ComputedValues,
        after_change_style: &ComputedValues,
    ) -> bool;

    /// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
    /// the `lang=""` attribute) on this element.
    fn lang_attr(&self) -> Option<AttrValue>;

    /// Returns whether this element's language matches the language tag
    /// `value`.  If `override_lang` is not `None`, it specifies the value
    /// of the `xml:lang=""` or `lang=""` attribute to use in place of
    /// looking at the element and its ancestors.  (This argument is used
    /// to implement matching of `:lang()` against snapshots.)
    fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool;

    /// Returns whether this element is the main body element of the HTML
    /// document it is on.
    fn is_html_document_body_element(&self) -> bool;

    /// Generate the proper applicable declarations due to presentational hints,
    /// and insert them into `hints`.
    fn synthesize_presentational_hints_for_legacy_attributes<V>(
        &self,
        visited_handling: VisitedHandlingMode,
        hints: &mut V,
    ) where
        V: Push<ApplicableDeclarationBlock>;

    /// Generate the proper applicable declarations due to view transition dynamic rules, and
    /// insert them into `rules`.
    /// https://drafts.csswg.org/css-view-transitions-1/#document-dynamic-view-transition-style-sheet
    fn synthesize_view_transition_dynamic_rules<V>(&self, _rules: &mut V)
    where
        V: Push<ApplicableDeclarationBlock>,
    {
    }

    /// Returns element's local name.
    fn local_name(&self) -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedLocalName;

    /// Returns element's namespace.
    fn namespace(&self)
        -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedNamespaceUrl;

    /// Returns the size of the element to be used in container size queries.
    /// This will usually be the size of the content area of the primary box,
    /// but can be None if there is no box or if some axis lacks size containment.
    fn query_container_size(
        &self,
        display: &Display,
    ) -> euclid::default::Size2D<Option<app_units::Au>>;

    /// Returns true if the element has all of specified selector flags.
    fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;

    /// Returns the search direction for relative selector invalidation, if it is on the search path.
    fn relative_selector_search_direction(&self) -> ElementSelectorFlags;

    /// Returns the implicit scope root for given sheet index and host.
    fn implicit_scope_for_sheet_in_shadow_root(
        _opaque_host: OpaqueElement,
        _sheet_index: usize,
    ) -> Option<ImplicitScopeRoot> {
        None
    }

    /// Compute the damage incurred by the change from the `_old` to `_new`.
    fn compute_layout_damage(_old: &ComputedValues, _new: &ComputedValues) -> RestyleDamage {
        Default::default()
    }
}

/// The attribute provider trait
pub trait AttributeProvider {
    /// Return the value of the given custom attibute if it exists.
    fn get_attr(&self, attr: &LocalName) -> Option<String>;
}

/// A dummy AttributeProvider that returns none to any attribute query.
#[derive(Clone, Debug, PartialEq)]
pub struct DummyAttributeProvider;

impl AttributeProvider for DummyAttributeProvider {
    fn get_attr(&self, _attr: &LocalName) -> Option<String> {
        None
    }
}

/// TNode and TElement aren't Send because we want to be careful and explicit
/// about our parallel traversal. However, there are certain situations
/// (including but not limited to the traversal) where we need to send DOM
/// objects to other threads.
///
/// That's the reason why `SendNode` exists.
#[derive(Clone, Debug, PartialEq)]
pub struct SendNode<N: TNode>(N);
unsafe impl<N: TNode> Send for SendNode<N> {}
impl<N: TNode> SendNode<N> {
    /// Unsafely construct a SendNode.
    pub unsafe fn new(node: N) -> Self {
        SendNode(node)
    }
}
impl<N: TNode> Deref for SendNode<N> {
    type Target = N;
    fn deref(&self) -> &N {
        &self.0
    }
}

/// Same reason as for the existence of SendNode, SendElement does the proper
/// things for a given `TElement`.
#[derive(Debug, Eq, Hash, PartialEq)]
pub struct SendElement<E: TElement>(E);
unsafe impl<E: TElement> Send for SendElement<E> {}
impl<E: TElement> SendElement<E> {
    /// Unsafely construct a SendElement.
    pub unsafe fn new(el: E) -> Self {
        SendElement(el)
    }
}
impl<E: TElement> Deref for SendElement<E> {
    type Target = E;
    fn deref(&self) -> &E {
        &self.0
    }
}
