1#![deny(missing_docs)]
8
9use crate::stylesheets::{Namespaces, Origin, UrlExtraData};
10use crate::values::serialize_atom_identifier;
11use crate::Atom;
12use cssparser::{Parser as CssParser, ParserInput};
13use dom::ElementState;
14use selectors::parser::{ParseRelative, SelectorList};
15use std::fmt::{self, Debug, Write};
16use style_traits::{CssWriter, ParseError, ToCss};
17
18pub type AttrValue = <SelectorImpl as ::selectors::SelectorImpl>::AttrValue;
21
22#[cfg(feature = "servo")]
23pub use crate::servo::selector_parser::*;
24
25#[cfg(feature = "gecko")]
26pub use crate::gecko::selector_parser::*;
27
28#[cfg(feature = "servo")]
29pub use crate::servo::selector_parser::ServoElementSnapshot as Snapshot;
30
31#[cfg(feature = "gecko")]
32pub use crate::gecko::snapshot::GeckoElementSnapshot as Snapshot;
33
34#[cfg(feature = "servo")]
35pub use crate::servo::restyle_damage::ServoRestyleDamage as RestyleDamage;
36
37#[cfg(feature = "gecko")]
38pub use crate::gecko::restyle_damage::GeckoRestyleDamage as RestyleDamage;
39
40#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
42pub struct SelectorParser<'a> {
43 pub stylesheet_origin: Origin,
45 pub namespaces: &'a Namespaces,
47 pub url_data: &'a UrlExtraData,
50 pub for_supports_rule: bool,
52}
53
54impl<'a> SelectorParser<'a> {
55 pub fn parse_author_origin_no_namespace<'i>(
60 input: &'i str,
61 url_data: &UrlExtraData,
62 ) -> Result<SelectorList<SelectorImpl>, ParseError<'i>> {
63 let namespaces = Namespaces::default();
64 let parser = SelectorParser {
65 stylesheet_origin: Origin::Author,
66 namespaces: &namespaces,
67 url_data,
68 for_supports_rule: false,
69 };
70 let mut input = ParserInput::new(input);
71 SelectorList::parse(&parser, &mut CssParser::new(&mut input), ParseRelative::No)
72 }
73
74 pub fn in_user_agent_stylesheet(&self) -> bool {
76 matches!(self.stylesheet_origin, Origin::UserAgent)
77 }
78
79 pub fn chrome_rules_enabled(&self) -> bool {
82 self.url_data.chrome_rules_enabled() || self.stylesheet_origin == Origin::User
83 }
84}
85
86#[derive(Clone, Debug, Eq, PartialEq)]
88pub enum PseudoElementCascadeType {
89 Eager,
97 Lazy,
103 Precomputed,
111}
112
113#[derive(Clone, MallocSizeOf)]
115pub struct PerPseudoElementMap<T> {
116 entries: [Option<T>; PSEUDO_COUNT],
117}
118
119impl<T> Default for PerPseudoElementMap<T> {
120 fn default() -> Self {
121 Self {
122 entries: PseudoElement::pseudo_none_array(),
123 }
124 }
125}
126
127impl<T> Debug for PerPseudoElementMap<T>
128where
129 T: Debug,
130{
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 f.write_char('[')?;
133 let mut first = true;
134 for entry in self.entries.iter() {
135 if !first {
136 f.write_str(", ")?;
137 }
138 first = false;
139 entry.fmt(f)?;
140 }
141 f.write_char(']')
142 }
143}
144
145impl<T> PerPseudoElementMap<T> {
146 pub fn get(&self, pseudo: &PseudoElement) -> Option<&T> {
148 self.entries[pseudo.index()].as_ref()
149 }
150
151 pub fn clear(&mut self) {
153 *self = Self::default();
154 }
155
156 pub fn set(&mut self, pseudo: &PseudoElement, value: T) {
160 self.entries[pseudo.index()] = Some(value);
161 }
162
163 pub fn get_or_insert_with<F>(&mut self, pseudo: &PseudoElement, f: F) -> &mut T
165 where
166 F: FnOnce() -> T,
167 {
168 let index = pseudo.index();
169 if self.entries[index].is_none() {
170 self.entries[index] = Some(f());
171 }
172 self.entries[index].as_mut().unwrap()
173 }
174
175 pub fn iter(&self) -> std::slice::Iter<Option<T>> {
177 self.entries.iter()
178 }
179
180 pub fn iter_mut(&mut self) -> std::slice::IterMut<Option<T>> {
182 self.entries.iter_mut()
183 }
184}
185
186#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
190pub struct Direction(pub Atom);
191
192#[derive(Clone, Debug, Eq, PartialEq)]
194pub enum HorizontalDirection {
195 Ltr,
197 Rtl,
199}
200
201impl Direction {
202 pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> {
204 let ident = parser.expect_ident()?;
205 Ok(Direction(match_ignore_ascii_case! { &ident,
206 "rtl" => atom!("rtl"),
207 "ltr" => atom!("ltr"),
208 _ => Atom::from(ident.as_ref()),
209 }))
210 }
211
212 pub fn as_horizontal_direction(&self) -> Option<HorizontalDirection> {
214 if self.0 == atom!("ltr") {
215 Some(HorizontalDirection::Ltr)
216 } else if self.0 == atom!("rtl") {
217 Some(HorizontalDirection::Rtl)
218 } else {
219 None
220 }
221 }
222
223 pub fn element_state(&self) -> ElementState {
225 match self.as_horizontal_direction() {
226 Some(HorizontalDirection::Ltr) => ElementState::LTR,
227 Some(HorizontalDirection::Rtl) => ElementState::RTL,
228 None => ElementState::empty(),
229 }
230 }
231}
232
233impl ToCss for Direction {
234 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
235 where
236 W: Write,
237 {
238 serialize_atom_identifier(&self.0, dest)
239 }
240}