1use crate::context::QuirksMode;
8use crate::custom_properties::{AttrTaint, AttrTaintedRange};
9use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
10use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData};
11use crate::use_counters::UseCounters;
12use cssparser::{Parser, SourceLocation, UnicodeRange};
13use selectors::parser::ParseRelative;
14use std::borrow::Cow;
15use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
16
17#[derive(Clone, Copy)]
19pub struct NestingContext {
20 pub rule_types: CssRuleTypes,
22 pub parse_relative: ParseRelative,
24}
25
26impl NestingContext {
27 fn parse_relative_for(rule_type: CssRuleType) -> ParseRelative {
28 match rule_type {
29 CssRuleType::Scope => ParseRelative::ForScope,
30 CssRuleType::Style => ParseRelative::ForNesting,
31 _ => ParseRelative::No,
32 }
33 }
34
35 pub fn new(rule_types: CssRuleTypes, parse_nested_rule_type: Option<CssRuleType>) -> Self {
37 Self {
38 rule_types,
39 parse_relative: parse_nested_rule_type
40 .map_or(ParseRelative::No, Self::parse_relative_for),
41 }
42 }
43
44 pub fn new_from_rule(rule_type: Option<CssRuleType>) -> Self {
46 Self {
47 rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(),
48 parse_relative: rule_type
49 .map(Self::parse_relative_for)
50 .unwrap_or(ParseRelative::No),
51 }
52 }
53
54 pub fn save(&mut self, rule_type: CssRuleType) -> Self {
56 let old = *self;
57 self.rule_types.insert(rule_type);
58 let new_parse_relative = Self::parse_relative_for(rule_type);
59 if new_parse_relative != ParseRelative::No {
60 self.parse_relative = new_parse_relative;
61 }
62 old
63 }
64
65 pub fn restore(&mut self, saved: Self) {
67 *self = saved;
68 }
69}
70
71pub struct ParserContext<'a> {
73 pub stylesheet_origin: Origin,
76 pub url_data: &'a UrlExtraData,
78 pub parsing_mode: ParsingMode,
80 pub quirks_mode: QuirksMode,
82 error_reporter: Option<&'a dyn ParseErrorReporter>,
84 pub namespaces: Cow<'a, Namespaces>,
86 pub use_counters: Option<&'a UseCounters>,
88 pub nesting_context: NestingContext,
90 pub attr_tainted_regions: AttrTaint,
92}
93
94impl<'a> ParserContext<'a> {
95 #[inline]
97 pub fn new(
98 stylesheet_origin: Origin,
99 url_data: &'a UrlExtraData,
100 rule_type: Option<CssRuleType>,
101 parsing_mode: ParsingMode,
102 quirks_mode: QuirksMode,
103 namespaces: Cow<'a, Namespaces>,
104 error_reporter: Option<&'a dyn ParseErrorReporter>,
105 use_counters: Option<&'a UseCounters>,
106 attr_tainted_regions: AttrTaint,
107 ) -> Self {
108 Self {
109 stylesheet_origin,
110 url_data,
111 parsing_mode,
112 quirks_mode,
113 error_reporter,
114 namespaces,
115 use_counters,
116 nesting_context: NestingContext::new_from_rule(rule_type),
117 attr_tainted_regions,
118 }
119 }
120
121 pub fn nest_for_rule<R>(
123 &mut self,
124 rule_type: CssRuleType,
125 cb: impl FnOnce(&mut Self) -> R,
126 ) -> R {
127 let old = self.nesting_context.save(rule_type);
128 let r = cb(self);
129 self.nesting_context.restore(old);
130 r
131 }
132
133 pub fn with_parsing_mode<R>(&mut self, mode: ParsingMode, cb: impl FnOnce(&Self) -> R) -> R {
135 let old = self.parsing_mode;
136 self.parsing_mode |= mode;
137 let r = cb(self);
138 self.parsing_mode = old;
139 r
140 }
141
142 #[inline]
144 pub fn in_page_rule(&self) -> bool {
145 self.nesting_context.rule_types.contains(CssRuleType::Page)
146 }
147
148 #[inline]
150 pub fn allows_important_declarations(&self) -> bool {
151 !self
152 .nesting_context
153 .rule_types
154 .intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
155 }
156
157 #[inline]
159 pub fn has_element_context(&self) -> bool {
160 if self
161 .nesting_context
162 .rule_types
163 .intersects(CssRuleTypes::WITHOUT_ELEMENT_CONTEXT)
164 {
165 return false;
166 }
167
168 if self
169 .parsing_mode
170 .intersects(ParsingMode::MEDIA_QUERY_CONDITION)
171 {
172 return false;
173 }
174
175 true
176 }
177
178 pub fn rule_types(&self) -> CssRuleTypes {
180 self.nesting_context.rule_types
181 }
182
183 #[inline]
185 pub fn error_reporting_enabled(&self) -> bool {
186 self.error_reporter.is_some()
187 }
188
189 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
191 let error_reporter = match self.error_reporter {
192 Some(r) => r,
193 None => return,
194 };
195
196 error_reporter.report_error(self.url_data, location, error)
197 }
198
199 #[inline]
201 pub fn in_ua_sheet(&self) -> bool {
202 self.stylesheet_origin == Origin::UserAgent
203 }
204
205 #[inline]
207 pub fn chrome_rules_enabled(&self) -> bool {
208 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
209 }
210
211 #[inline]
213 pub fn allows_computational_dependence(&self) -> bool {
214 self.parsing_mode.allows_computational_dependence()
215 }
216
217 pub fn disallow_urls_in_range(&self, range: &AttrTaintedRange) -> bool {
219 self.attr_tainted_regions
220 .should_disallow_urls_in_range(range)
221 }
222}
223
224pub trait Parse: Sized {
241 fn parse<'i, 't>(
245 context: &ParserContext,
246 input: &mut Parser<'i, 't>,
247 ) -> Result<Self, ParseError<'i>>;
248}
249
250impl<T> Parse for Vec<T>
251where
252 T: Parse + OneOrMoreSeparated,
253 <T as OneOrMoreSeparated>::S: Separator,
254{
255 fn parse<'i, 't>(
256 context: &ParserContext,
257 input: &mut Parser<'i, 't>,
258 ) -> Result<Self, ParseError<'i>> {
259 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
260 }
261}
262
263impl<T> Parse for Box<T>
264where
265 T: Parse,
266{
267 fn parse<'i, 't>(
268 context: &ParserContext,
269 input: &mut Parser<'i, 't>,
270 ) -> Result<Self, ParseError<'i>> {
271 T::parse(context, input).map(Box::new)
272 }
273}
274
275impl Parse for crate::OwnedStr {
276 fn parse<'i, 't>(
277 _: &ParserContext,
278 input: &mut Parser<'i, 't>,
279 ) -> Result<Self, ParseError<'i>> {
280 Ok(input.expect_string()?.as_ref().to_owned().into())
281 }
282}
283
284impl Parse for UnicodeRange {
285 fn parse<'i, 't>(
286 _: &ParserContext,
287 input: &mut Parser<'i, 't>,
288 ) -> Result<Self, ParseError<'i>> {
289 Ok(UnicodeRange::parse(input)?)
290 }
291}