layout_api/
pseudo_element_chain.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
5use std::fmt::Debug;
6
7use malloc_size_of_derive::MallocSizeOf;
8use style::selector_parser::PseudoElement;
9
10/// A chain of pseudo-elements up to two levels deep. This is used to represent cases
11/// where a pseudo-element has its own child pseudo element (for instance
12/// `.div::after::marker`). If both [`Self::primary`] and [`Self::secondary`] are `None`,
13/// then this chain represents the element itself. Not all combinations of pseudo-elements
14/// are possible and we may not be able to calculate a style for all
15/// [`PseudoElementChain`]s.
16#[derive(Clone, Copy, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
17pub struct PseudoElementChain {
18    pub primary: Option<PseudoElement>,
19    pub secondary: Option<PseudoElement>,
20}
21
22impl PseudoElementChain {
23    pub fn unnested(pseudo_element: PseudoElement) -> Self {
24        Self {
25            primary: Some(pseudo_element),
26            secondary: None,
27        }
28    }
29
30    pub fn innermost(&self) -> Option<PseudoElement> {
31        self.secondary.or(self.primary)
32    }
33
34    /// Return a possibly nested [`PseudoElementChain`]. Currently only `::before` and
35    /// `::after` only support nesting. If the primary [`PseudoElement`] on the chain is
36    /// not `::before` or `::after` a single element chain is returned for the given
37    /// [`PseudoElement`].
38    pub fn with_pseudo(&self, pseudo_element: PseudoElement) -> Self {
39        match self.primary {
40            Some(primary) if primary.is_before_or_after() => Self {
41                primary: self.primary,
42                secondary: Some(pseudo_element),
43            },
44            _ => {
45                assert!(self.secondary.is_none());
46                Self::unnested(pseudo_element)
47            },
48        }
49    }
50
51    pub fn without_innermost(&self) -> Option<Self> {
52        let primary = self.primary?;
53        Some(
54            self.secondary
55                .map_or_else(Self::default, |_| Self::unnested(primary)),
56        )
57    }
58
59    pub fn is_empty(&self) -> bool {
60        self.primary.is_none()
61    }
62}