1use crate::context::QuirksMode;
8use crate::custom_properties::{AttrTaint, AttrTaintedRange};
9use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
10use crate::properties::PropertyIdRef;
11use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData};
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 fn set(&mut self, property_id: PropertyIdRef<'a>) {
86 debug_assert!(
87 self.property_id.is_none(),
88 "Previous declaration should be empty"
89 );
90 self.property_id = Some(property_id);
91 self.random_count.set(0);
92 }
93
94 fn clear(&mut self) {
95 self.property_id = None;
96 self.random_count.set(0);
97 }
98
99 pub fn property_id(&self) -> Option<PropertyIdRef<'a>> {
101 self.property_id
102 }
103
104 pub fn current_random_index(&self) -> i32 {
106 self.random_count.get()
107 }
108
109 pub fn increment_random_count(&self) -> i32 {
113 let index = self.random_count.get() + 1;
114 self.random_count.set(index);
115 index
116 }
117}
118
119pub struct ParserContext<'a> {
121 pub stylesheet_origin: Origin,
124 pub url_data: &'a UrlExtraData,
126 pub parsing_mode: ParsingMode,
128 pub quirks_mode: QuirksMode,
130 error_reporter: Option<&'a dyn ParseErrorReporter>,
132 pub namespaces: Cow<'a, Namespaces>,
134 pub use_counters: Option<&'a UseCounters>,
136 pub nesting_context: NestingContext,
138 pub attr_tainted_regions: AttrTaint,
140 pub property_declaration_context: PropertyDeclarationContext<'a>,
142}
143
144impl<'a> ParserContext<'a> {
145 #[inline]
147 pub fn new(
148 stylesheet_origin: Origin,
149 url_data: &'a UrlExtraData,
150 rule_type: Option<CssRuleType>,
151 parsing_mode: ParsingMode,
152 quirks_mode: QuirksMode,
153 namespaces: Cow<'a, Namespaces>,
154 error_reporter: Option<&'a dyn ParseErrorReporter>,
155 use_counters: Option<&'a UseCounters>,
156 attr_tainted_regions: AttrTaint,
157 ) -> Self {
158 Self {
159 stylesheet_origin,
160 url_data,
161 parsing_mode,
162 quirks_mode,
163 error_reporter,
164 namespaces,
165 use_counters,
166 nesting_context: NestingContext::new_from_rule(rule_type),
167 attr_tainted_regions,
168 property_declaration_context: Default::default(),
169 }
170 }
171
172 pub fn with_property_declaration<R>(
175 &mut self,
176 property_id: PropertyIdRef<'a>,
177 cb: impl FnOnce(&Self) -> R,
178 ) -> R {
179 self.property_declaration_context.set(property_id);
180 let r = cb(self);
181 self.property_declaration_context.clear();
182 r
183 }
184
185 pub fn nest_for_rule<R>(
187 &mut self,
188 rule_type: CssRuleType,
189 cb: impl FnOnce(&mut Self) -> R,
190 ) -> R {
191 let old = self.nesting_context.save(rule_type);
192 let r = cb(self);
193 self.nesting_context.restore(old);
194 r
195 }
196
197 pub fn with_parsing_mode<R>(&mut self, mode: ParsingMode, cb: impl FnOnce(&Self) -> R) -> R {
199 let old = self.parsing_mode;
200 self.parsing_mode |= mode;
201 let r = cb(self);
202 self.parsing_mode = old;
203 r
204 }
205
206 #[inline]
208 pub fn in_page_rule(&self) -> bool {
209 self.nesting_context.rule_types.contains(CssRuleType::Page)
210 }
211
212 #[inline]
214 pub fn allows_important_declarations(&self) -> bool {
215 !self
216 .nesting_context
217 .rule_types
218 .intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
219 }
220
221 #[inline]
223 pub fn has_element_context(&self) -> bool {
224 if self
225 .nesting_context
226 .rule_types
227 .intersects(CssRuleTypes::WITHOUT_ELEMENT_CONTEXT)
228 {
229 return false;
230 }
231
232 if self
233 .parsing_mode
234 .intersects(ParsingMode::MEDIA_QUERY_CONDITION)
235 {
236 return false;
237 }
238
239 if !self.allows_computational_dependence() {
240 return false;
241 }
242
243 true
244 }
245
246 pub fn rule_types(&self) -> CssRuleTypes {
248 self.nesting_context.rule_types
249 }
250
251 #[inline]
253 pub fn error_reporting_enabled(&self) -> bool {
254 self.error_reporter.is_some()
255 }
256
257 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
259 let error_reporter = match self.error_reporter {
260 Some(r) => r,
261 None => return,
262 };
263
264 error_reporter.report_error(self.url_data, location, error)
265 }
266
267 #[inline]
269 pub fn in_ua_sheet(&self) -> bool {
270 self.stylesheet_origin == Origin::UserAgent
271 }
272
273 #[inline]
275 pub fn chrome_rules_enabled(&self) -> bool {
276 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
277 }
278
279 #[inline]
281 pub fn allows_computational_dependence(&self) -> bool {
282 self.parsing_mode.allows_computational_dependence()
283 }
284
285 pub fn disallow_urls_in_range(&self, range: &AttrTaintedRange) -> bool {
287 self.attr_tainted_regions
288 .should_disallow_urls_in_range(range)
289 }
290}
291
292pub trait Parse: Sized {
309 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError>;
313}
314
315impl<T> Parse for Vec<T>
316where
317 T: Parse + OneOrMoreSeparated,
318 <T as OneOrMoreSeparated>::S: Separator,
319{
320 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
321 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
322 }
323}
324
325impl<T> Parse for Box<T>
326where
327 T: Parse,
328{
329 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
330 T::parse(context, input).map(Box::new)
331 }
332}
333
334impl Parse for crate::OwnedStr {
335 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
336 Ok(input.expect_string()?.as_ref().to_owned().into())
337 }
338}
339
340impl Parse for UnicodeRange {
341 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
342 Ok(UnicodeRange::parse(input)?)
343 }
344}