1use crate::context::QuirksMode;
8use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
9use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData};
10use crate::use_counters::UseCounters;
11use cssparser::{Parser, SourceLocation, UnicodeRange};
12use selectors::parser::ParseRelative;
13use std::borrow::Cow;
14use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
15
16#[derive(Clone, Copy)]
18pub struct NestingContext {
19 pub rule_types: CssRuleTypes,
21 pub parse_relative: ParseRelative,
23}
24
25impl NestingContext {
26 fn parse_relative_for(rule_type: CssRuleType) -> ParseRelative {
27 match rule_type {
28 CssRuleType::Scope => ParseRelative::ForScope,
29 CssRuleType::Style => ParseRelative::ForNesting,
30 _ => ParseRelative::No,
31 }
32 }
33
34 pub fn new(rule_types: CssRuleTypes, parse_nested_rule_type: Option<CssRuleType>) -> Self {
36 Self {
37 rule_types,
38 parse_relative: parse_nested_rule_type
39 .map_or(ParseRelative::No, Self::parse_relative_for),
40 }
41 }
42
43 pub fn new_from_rule(rule_type: Option<CssRuleType>) -> Self {
45 Self {
46 rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(),
47 parse_relative: rule_type
48 .map(Self::parse_relative_for)
49 .unwrap_or(ParseRelative::No),
50 }
51 }
52
53 pub fn save(&mut self, rule_type: CssRuleType) -> Self {
55 let old = *self;
56 self.rule_types.insert(rule_type);
57 let new_parse_relative = Self::parse_relative_for(rule_type);
58 if new_parse_relative != ParseRelative::No {
59 self.parse_relative = new_parse_relative;
60 }
61 old
62 }
63
64 pub fn restore(&mut self, saved: Self) {
66 *self = saved;
67 }
68}
69
70pub struct ParserContext<'a> {
72 pub stylesheet_origin: Origin,
75 pub url_data: &'a UrlExtraData,
77 pub parsing_mode: ParsingMode,
79 pub quirks_mode: QuirksMode,
81 error_reporter: Option<&'a dyn ParseErrorReporter>,
83 pub namespaces: Cow<'a, Namespaces>,
85 pub use_counters: Option<&'a UseCounters>,
87 pub nesting_context: NestingContext,
89}
90
91impl<'a> ParserContext<'a> {
92 #[inline]
94 pub fn new(
95 stylesheet_origin: Origin,
96 url_data: &'a UrlExtraData,
97 rule_type: Option<CssRuleType>,
98 parsing_mode: ParsingMode,
99 quirks_mode: QuirksMode,
100 namespaces: Cow<'a, Namespaces>,
101 error_reporter: Option<&'a dyn ParseErrorReporter>,
102 use_counters: Option<&'a UseCounters>,
103 ) -> Self {
104 Self {
105 stylesheet_origin,
106 url_data,
107 parsing_mode,
108 quirks_mode,
109 error_reporter,
110 namespaces,
111 use_counters,
112 nesting_context: NestingContext::new_from_rule(rule_type),
113 }
114 }
115
116 pub fn nest_for_rule<R>(
118 &mut self,
119 rule_type: CssRuleType,
120 cb: impl FnOnce(&mut Self) -> R,
121 ) -> R {
122 let old = self.nesting_context.save(rule_type);
123 let r = cb(self);
124 self.nesting_context.restore(old);
125 r
126 }
127
128 #[inline]
130 pub fn in_page_rule(&self) -> bool {
131 self.nesting_context.rule_types.contains(CssRuleType::Page)
132 }
133
134 #[inline]
136 pub fn allows_important_declarations(&self) -> bool {
137 !self.nesting_context.rule_types.intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
138 }
139
140 pub fn rule_types(&self) -> CssRuleTypes {
142 self.nesting_context.rule_types
143 }
144
145 #[inline]
147 pub fn error_reporting_enabled(&self) -> bool {
148 self.error_reporter.is_some()
149 }
150
151 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
153 let error_reporter = match self.error_reporter {
154 Some(r) => r,
155 None => return,
156 };
157
158 error_reporter.report_error(self.url_data, location, error)
159 }
160
161 #[inline]
163 pub fn in_ua_sheet(&self) -> bool {
164 self.stylesheet_origin == Origin::UserAgent
165 }
166
167 #[inline]
169 pub fn chrome_rules_enabled(&self) -> bool {
170 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
171 }
172
173 #[inline]
175 pub fn allows_computational_dependence(&self) -> bool {
176 self.parsing_mode.allows_computational_dependence()
177 }
178}
179
180pub trait Parse: Sized {
197 fn parse<'i, 't>(
201 context: &ParserContext,
202 input: &mut Parser<'i, 't>,
203 ) -> Result<Self, ParseError<'i>>;
204}
205
206impl<T> Parse for Vec<T>
207where
208 T: Parse + OneOrMoreSeparated,
209 <T as OneOrMoreSeparated>::S: Separator,
210{
211 fn parse<'i, 't>(
212 context: &ParserContext,
213 input: &mut Parser<'i, 't>,
214 ) -> Result<Self, ParseError<'i>> {
215 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
216 }
217}
218
219impl<T> Parse for Box<T>
220where
221 T: Parse,
222{
223 fn parse<'i, 't>(
224 context: &ParserContext,
225 input: &mut Parser<'i, 't>,
226 ) -> Result<Self, ParseError<'i>> {
227 T::parse(context, input).map(Box::new)
228 }
229}
230
231impl Parse for crate::OwnedStr {
232 fn parse<'i, 't>(
233 _: &ParserContext,
234 input: &mut Parser<'i, 't>,
235 ) -> Result<Self, ParseError<'i>> {
236 Ok(input.expect_string()?.as_ref().to_owned().into())
237 }
238}
239
240impl Parse for UnicodeRange {
241 fn parse<'i, 't>(
242 _: &ParserContext,
243 input: &mut Parser<'i, 't>,
244 ) -> Result<Self, ParseError<'i>> {
245 Ok(UnicodeRange::parse(input)?)
246 }
247}