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
138 .nesting_context
139 .rule_types
140 .intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
141 }
142
143 pub fn rule_types(&self) -> CssRuleTypes {
145 self.nesting_context.rule_types
146 }
147
148 #[inline]
150 pub fn error_reporting_enabled(&self) -> bool {
151 self.error_reporter.is_some()
152 }
153
154 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
156 let error_reporter = match self.error_reporter {
157 Some(r) => r,
158 None => return,
159 };
160
161 error_reporter.report_error(self.url_data, location, error)
162 }
163
164 #[inline]
166 pub fn in_ua_sheet(&self) -> bool {
167 self.stylesheet_origin == Origin::UserAgent
168 }
169
170 #[inline]
172 pub fn chrome_rules_enabled(&self) -> bool {
173 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
174 }
175
176 #[inline]
178 pub fn allows_computational_dependence(&self) -> bool {
179 self.parsing_mode.allows_computational_dependence()
180 }
181}
182
183pub trait Parse: Sized {
200 fn parse<'i, 't>(
204 context: &ParserContext,
205 input: &mut Parser<'i, 't>,
206 ) -> Result<Self, ParseError<'i>>;
207}
208
209impl<T> Parse for Vec<T>
210where
211 T: Parse + OneOrMoreSeparated,
212 <T as OneOrMoreSeparated>::S: Separator,
213{
214 fn parse<'i, 't>(
215 context: &ParserContext,
216 input: &mut Parser<'i, 't>,
217 ) -> Result<Self, ParseError<'i>> {
218 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
219 }
220}
221
222impl<T> Parse for Box<T>
223where
224 T: Parse,
225{
226 fn parse<'i, 't>(
227 context: &ParserContext,
228 input: &mut Parser<'i, 't>,
229 ) -> Result<Self, ParseError<'i>> {
230 T::parse(context, input).map(Box::new)
231 }
232}
233
234impl Parse for crate::OwnedStr {
235 fn parse<'i, 't>(
236 _: &ParserContext,
237 input: &mut Parser<'i, 't>,
238 ) -> Result<Self, ParseError<'i>> {
239 Ok(input.expect_string()?.as_ref().to_owned().into())
240 }
241}
242
243impl Parse for UnicodeRange {
244 fn parse<'i, 't>(
245 _: &ParserContext,
246 input: &mut Parser<'i, 't>,
247 ) -> Result<Self, ParseError<'i>> {
248 Ok(UnicodeRange::parse(input)?)
249 }
250}