1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
5 //! The context within which CSS code is parsed.
7 use crate::context::QuirksMode;
8 use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
9 use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData};
10 use crate::use_counters::UseCounters;
11 use cssparser::{Parser, SourceLocation, UnicodeRange};
13 use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
15 /// The data that the parser needs from outside in order to parse a stylesheet.
16 pub struct ParserContext<'a> {
17 /// The `Origin` of the stylesheet, whether it's a user, author or
18 /// user-agent stylesheet.
19 pub stylesheet_origin: Origin,
20 /// The extra data we need for resolving url values.
21 pub url_data: &'a UrlExtraData,
22 /// The current rule types, if any.
23 pub rule_types: CssRuleTypes,
24 /// The mode to use when parsing.
25 pub parsing_mode: ParsingMode,
26 /// The quirks mode of this stylesheet.
27 pub quirks_mode: QuirksMode,
28 /// The active error reporter, or none if error reporting is disabled.
29 error_reporter: Option<&'a dyn ParseErrorReporter>,
30 /// The currently active namespaces.
31 pub namespaces: Cow<'a, Namespaces>,
32 /// The use counters we want to record while parsing style rules, if any.
33 pub use_counters: Option<&'a UseCounters>,
36 impl<'a> ParserContext<'a> {
37 /// Create a parser context.
40 stylesheet_origin: Origin,
41 url_data: &'a UrlExtraData,
42 rule_type: Option<CssRuleType>,
43 parsing_mode: ParsingMode,
44 quirks_mode: QuirksMode,
45 namespaces: Cow<'a, Namespaces>,
46 error_reporter: Option<&'a dyn ParseErrorReporter>,
47 use_counters: Option<&'a UseCounters>,
52 rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(),
61 /// Temporarily sets the rule_type and executes the callback function, returning its result.
62 pub fn nest_for_rule<R>(
64 rule_type: CssRuleType,
65 cb: impl FnOnce(&mut Self) -> R,
67 let old_rule_types = self.rule_types;
68 self.rule_types.insert(rule_type);
70 self.rule_types = old_rule_types;
74 /// Whether we're in a @page rule.
76 pub fn in_page_rule(&self) -> bool {
77 self.rule_types.contains(CssRuleType::Page)
80 /// Get the rule type, which assumes that one is available.
81 pub fn rule_types(&self) -> CssRuleTypes {
85 /// Returns whether CSS error reporting is enabled.
87 pub fn error_reporting_enabled(&self) -> bool {
88 self.error_reporter.is_some()
91 /// Record a CSS parse error with this context’s error reporting.
92 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
93 let error_reporter = match self.error_reporter {
98 error_reporter.report_error(self.url_data, location, error)
101 /// Whether we're in a user-agent stylesheet.
103 pub fn in_ua_sheet(&self) -> bool {
104 self.stylesheet_origin == Origin::UserAgent
107 /// Returns whether chrome-only rules should be parsed.
109 pub fn chrome_rules_enabled(&self) -> bool {
110 self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
114 /// A trait to abstract parsing of a specified value given a `ParserContext` and
117 /// This can be derived on keywords with `#[derive(Parse)]`.
119 /// The derive code understands the following attributes on each of the variants:
121 /// * `#[parse(aliases = "foo,bar")]` can be used to alias a value with another
124 /// * `#[parse(condition = "function")]` can be used to make the parsing of the
125 /// value conditional on `function`, which needs to fulfill
126 /// `fn(&ParserContext) -> bool`.
127 pub trait Parse: Sized {
128 /// Parse a value of this type.
130 /// Returns an error on failure.
132 context: &ParserContext,
133 input: &mut Parser<'i, 't>,
134 ) -> Result<Self, ParseError<'i>>;
137 impl<T> Parse for Vec<T>
139 T: Parse + OneOrMoreSeparated,
140 <T as OneOrMoreSeparated>::S: Separator,
143 context: &ParserContext,
144 input: &mut Parser<'i, 't>,
145 ) -> Result<Self, ParseError<'i>> {
146 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
150 impl<T> Parse for Box<T>
155 context: &ParserContext,
156 input: &mut Parser<'i, 't>,
157 ) -> Result<Self, ParseError<'i>> {
158 T::parse(context, input).map(Box::new)
162 impl Parse for crate::OwnedStr {
165 input: &mut Parser<'i, 't>,
166 ) -> Result<Self, ParseError<'i>> {
167 Ok(input.expect_string()?.as_ref().to_owned().into())
171 impl Parse for UnicodeRange {
174 input: &mut Parser<'i, 't>,
175 ) -> Result<Self, ParseError<'i>> {
176 Ok(UnicodeRange::parse(input)?)