1use crate::context::QuirksMode;
8use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
9use crate::properties::PropertyIdRef;
10use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData};
11use crate::substitution::{AttrTaint, AttrTaintedRange};
12use crate::use_counters::UseCounters;
13use cssparser::{Parser, SourceLocation, UnicodeRange};
14use selectors::parser::ParseRelative;
15use std::borrow::Cow;
16use std::cell::Cell;
17use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
18
19#[derive(Clone, Copy)]
21pub struct NestingContext {
22 pub rule_types: CssRuleTypes,
24 pub parse_relative: ParseRelative,
26}
27
28impl NestingContext {
29 fn parse_relative_for(rule_type: CssRuleType) -> ParseRelative {
30 match rule_type {
31 CssRuleType::Scope => ParseRelative::ForScope,
32 CssRuleType::Style => ParseRelative::ForNesting,
33 _ => ParseRelative::No,
34 }
35 }
36
37 pub fn new(rule_types: CssRuleTypes, parse_nested_rule_type: Option<CssRuleType>) -> Self {
39 Self {
40 rule_types,
41 parse_relative: parse_nested_rule_type
42 .map_or(ParseRelative::No, Self::parse_relative_for),
43 }
44 }
45
46 pub fn new_from_rule(rule_type: Option<CssRuleType>) -> Self {
48 Self {
49 rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(),
50 parse_relative: rule_type
51 .map(Self::parse_relative_for)
52 .unwrap_or(ParseRelative::No),
53 }
54 }
55
56 pub fn save(&mut self, rule_type: CssRuleType) -> Self {
58 let old = *self;
59 self.rule_types.insert(rule_type);
60 let new_parse_relative = Self::parse_relative_for(rule_type);
61 if new_parse_relative != ParseRelative::No {
62 self.parse_relative = new_parse_relative;
63 }
64 old
65 }
66
67 pub fn restore(&mut self, saved: Self) {
69 *self = saved;
70 }
71}
72
73#[derive(Debug, Default)]
75pub struct PropertyDeclarationContext<'a> {
76 property_id: Option<PropertyIdRef<'a>>,
78 random_count: Cell<i32>,
82}
83
84impl<'a> PropertyDeclarationContext<'a> {
85 pub fn property_id(&self) -> Option<PropertyIdRef<'a>> {
87 self.property_id
88 }
89
90 pub fn current_random_index(&self) -> i32 {
92 self.random_count.get()
93 }
94
95 pub fn increment_random_count(&self) -> i32 {
99 let index = self.random_count.get() + 1;
100 self.random_count.set(index);
101 index
102 }
103}
104
105pub struct ParserContext<'a> {
107 pub stylesheet_origin: Origin,
110 pub url_data: &'a UrlExtraData,
112 pub parsing_mode: ParsingMode,
114 pub quirks_mode: QuirksMode,
116 error_reporter: Option<&'a dyn ParseErrorReporter>,
118 pub namespaces: Cow<'a, Namespaces>,
120 pub use_counters: Option<&'a UseCounters>,
122 pub nesting_context: NestingContext,
124 pub attr_tainted_regions: Cow<'a, AttrTaint>,
126 pub property_declaration_context: PropertyDeclarationContext<'a>,
128}
129
130impl<'a> ParserContext<'a> {
131 #[inline]
133 pub fn new(
134 stylesheet_origin: Origin,
135 url_data: &'a UrlExtraData,
136 rule_type: Option<CssRuleType>,
137 parsing_mode: ParsingMode,
138 quirks_mode: QuirksMode,
139 namespaces: Cow<'a, Namespaces>,
140 error_reporter: Option<&'a dyn ParseErrorReporter>,
141 use_counters: Option<&'a UseCounters>,
142 attr_tainted_regions: AttrTaint,
143 ) -> Self {
144 Self {
145 stylesheet_origin,
146 url_data,
147 parsing_mode,
148 quirks_mode,
149 error_reporter,
150 namespaces,
151 use_counters,
152 nesting_context: NestingContext::new_from_rule(rule_type),
153 attr_tainted_regions: Cow::Owned(attr_tainted_regions),
154 property_declaration_context: Default::default(),
155 }
156 }
157
158 #[inline]
160 pub fn new_with_property_id(
161 stylesheet_origin: Origin,
162 url_data: &'a UrlExtraData,
163 rule_type: Option<CssRuleType>,
164 parsing_mode: ParsingMode,
165 quirks_mode: QuirksMode,
166 namespaces: Cow<'a, Namespaces>,
167 error_reporter: Option<&'a dyn ParseErrorReporter>,
168 use_counters: Option<&'a UseCounters>,
169 attr_tainted_regions: AttrTaint,
170 property_id: Option<PropertyIdRef<'a>>,
171 ) -> Self {
172 Self {
173 stylesheet_origin,
174 url_data,
175 parsing_mode,
176 quirks_mode,
177 error_reporter,
178 namespaces,
179 use_counters,
180 nesting_context: NestingContext::new_from_rule(rule_type),
181 attr_tainted_regions: Cow::Owned(attr_tainted_regions),
182 property_declaration_context: PropertyDeclarationContext {
183 property_id,
184 ..Default::default()
185 },
186 }
187 }
188
189 pub fn with_property_id<'b, R>(
192 &'b self,
193 property_id: Option<PropertyIdRef<'b>>,
194 cb: impl FnOnce(&ParserContext<'b>) -> R,
195 ) -> R {
196 cb(&ParserContext {
197 stylesheet_origin: self.stylesheet_origin,
198 url_data: self.url_data,
199 parsing_mode: self.parsing_mode,
200 quirks_mode: self.quirks_mode,
201 error_reporter: self.error_reporter,
202 namespaces: Cow::Borrowed(&*self.namespaces),
203 use_counters: self.use_counters,
204 nesting_context: self.nesting_context,
205 attr_tainted_regions: Cow::Borrowed(&*self.attr_tainted_regions),
206 property_declaration_context: PropertyDeclarationContext {
207 property_id,
208 ..Default::default()
209 },
210 })
211 }
212
213 pub fn nest_for_rule<R>(
215 &mut self,
216 rule_type: CssRuleType,
217 cb: impl FnOnce(&mut Self) -> R,
218 ) -> R {
219 let old = self.nesting_context.save(rule_type);
220 let r = cb(self);
221 self.nesting_context.restore(old);
222 r
223 }
224
225 pub fn with_parsing_mode<R>(&mut self, mode: ParsingMode, cb: impl FnOnce(&Self) -> R) -> R {
227 let old = self.parsing_mode;
228 self.parsing_mode |= mode;
229 let r = cb(self);
230 self.parsing_mode = old;
231 r
232 }
233
234 #[inline]
236 pub fn in_page_rule(&self) -> bool {
237 self.nesting_context.rule_types.contains(CssRuleType::Page)
238 }
239
240 #[inline]
242 pub fn allows_important_declarations(&self) -> bool {
243 !self
244 .nesting_context
245 .rule_types
246 .intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
247 }
248
249 #[inline]
251 pub fn has_element_context(&self) -> bool {
252 if self
253 .nesting_context
254 .rule_types
255 .intersects(CssRuleTypes::WITHOUT_ELEMENT_CONTEXT)
256 {
257 return false;
258 }
259
260 if self
261 .parsing_mode
262 .intersects(ParsingMode::MEDIA_QUERY_CONDITION)
263 {
264 return false;
265 }
266
267 if !self.allows_computational_dependence() {
268 return false;
269 }
270
271 true
272 }
273
274 #[inline]
276 pub fn rule_types(&self) -> CssRuleTypes {
277 self.nesting_context.rule_types
278 }
279
280 #[inline]
282 pub fn error_reporting_enabled(&self) -> bool {
283 self.error_reporter.is_some()
284 }
285
286 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
288 let error_reporter = match self.error_reporter {
289 Some(r) => r,
290 None => return,
291 };
292
293 error_reporter.report_error(self.url_data, location, error)
294 }
295
296 #[inline]
298 pub fn in_ua_sheet(&self) -> bool {
299 self.stylesheet_origin == Origin::UserAgent
300 }
301
302 #[inline]
304 pub fn chrome_rules_enabled(&self) -> bool {
305 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
306 }
307
308 #[inline]
310 pub fn allows_computational_dependence(&self) -> bool {
311 self.parsing_mode.allows_computational_dependence()
312 }
313
314 pub fn disallow_urls_in_range(&self, range: &AttrTaintedRange) -> bool {
316 self.attr_tainted_regions
317 .should_disallow_urls_in_range(range)
318 }
319}
320
321pub trait Parse: Sized {
338 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError>;
342}
343
344impl<T> Parse for Vec<T>
345where
346 T: Parse + OneOrMoreSeparated,
347 <T as OneOrMoreSeparated>::S: Separator,
348{
349 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
350 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
351 }
352}
353
354impl<T> Parse for Box<T>
355where
356 T: Parse,
357{
358 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
359 T::parse(context, input).map(Box::new)
360 }
361}
362
363impl Parse for crate::OwnedStr {
364 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
365 Ok(input.expect_string()?.as_ref().to_owned().into())
366 }
367}
368
369impl Parse for UnicodeRange {
370 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
371 Ok(UnicodeRange::parse(input)?)
372 }
373}