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 #[inline]
135 pub fn in_page_rule(&self) -> bool {
136 self.nesting_context.rule_types.contains(CssRuleType::Page)
137 }
138
139 #[inline]
141 pub fn allows_important_declarations(&self) -> bool {
142 !self
143 .nesting_context
144 .rule_types
145 .intersects(CssRuleTypes::IMPORTANT_FORBIDDEN)
146 }
147
148 pub fn rule_types(&self) -> CssRuleTypes {
150 self.nesting_context.rule_types
151 }
152
153 #[inline]
155 pub fn error_reporting_enabled(&self) -> bool {
156 self.error_reporter.is_some()
157 }
158
159 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
161 let error_reporter = match self.error_reporter {
162 Some(r) => r,
163 None => return,
164 };
165
166 error_reporter.report_error(self.url_data, location, error)
167 }
168
169 #[inline]
171 pub fn in_ua_sheet(&self) -> bool {
172 self.stylesheet_origin == Origin::UserAgent
173 }
174
175 #[inline]
177 pub fn chrome_rules_enabled(&self) -> bool {
178 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
179 }
180
181 #[inline]
183 pub fn allows_computational_dependence(&self) -> bool {
184 self.parsing_mode.allows_computational_dependence()
185 }
186
187 pub fn disallow_urls_in_range(&self, range: &AttrTaintedRange) -> bool {
189 self.attr_tainted_regions
190 .should_disallow_urls_in_range(range)
191 }
192}
193
194pub trait Parse: Sized {
211 fn parse<'i, 't>(
215 context: &ParserContext,
216 input: &mut Parser<'i, 't>,
217 ) -> Result<Self, ParseError<'i>>;
218}
219
220impl<T> Parse for Vec<T>
221where
222 T: Parse + OneOrMoreSeparated,
223 <T as OneOrMoreSeparated>::S: Separator,
224{
225 fn parse<'i, 't>(
226 context: &ParserContext,
227 input: &mut Parser<'i, 't>,
228 ) -> Result<Self, ParseError<'i>> {
229 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
230 }
231}
232
233impl<T> Parse for Box<T>
234where
235 T: Parse,
236{
237 fn parse<'i, 't>(
238 context: &ParserContext,
239 input: &mut Parser<'i, 't>,
240 ) -> Result<Self, ParseError<'i>> {
241 T::parse(context, input).map(Box::new)
242 }
243}
244
245impl Parse for crate::OwnedStr {
246 fn parse<'i, 't>(
247 _: &ParserContext,
248 input: &mut Parser<'i, 't>,
249 ) -> Result<Self, ParseError<'i>> {
250 Ok(input.expect_string()?.as_ref().to_owned().into())
251 }
252}
253
254impl Parse for UnicodeRange {
255 fn parse<'i, 't>(
256 _: &ParserContext,
257 input: &mut Parser<'i, 't>,
258 ) -> Result<Self, ParseError<'i>> {
259 Ok(UnicodeRange::parse(input)?)
260 }
261}