Backed out 5 changesets (bug 1731541) for causing multiple wpt failures. CLOSED TREE
[gecko.git] / servo / components / style / parser.rs
blob893625854fabf6b2b67fab7a5504834e235985ba
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};
12 use std::borrow::Cow;
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.
38     #[inline]
39     pub fn new(
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>,
48     ) -> Self {
49         Self {
50             stylesheet_origin,
51             url_data,
52             rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(),
53             parsing_mode,
54             quirks_mode,
55             error_reporter,
56             namespaces,
57             use_counters,
58         }
59     }
61     /// Temporarily sets the rule_type and executes the callback function, returning its result.
62     pub fn nest_for_rule<R>(
63         &mut self,
64         rule_type: CssRuleType,
65         cb: impl FnOnce(&mut Self) -> R,
66     ) -> R {
67         let old_rule_types = self.rule_types;
68         self.rule_types.insert(rule_type);
69         let r = cb(self);
70         self.rule_types = old_rule_types;
71         r
72     }
74     /// Whether we're in a @page rule.
75     #[inline]
76     pub fn in_page_rule(&self) -> bool {
77         self.rule_types.contains(CssRuleType::Page)
78     }
80     /// Get the rule type, which assumes that one is available.
81     pub fn rule_types(&self) -> CssRuleTypes {
82         self.rule_types
83     }
85     /// Returns whether CSS error reporting is enabled.
86     #[inline]
87     pub fn error_reporting_enabled(&self) -> bool {
88         self.error_reporter.is_some()
89     }
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 {
94             Some(r) => r,
95             None => return,
96         };
98         error_reporter.report_error(self.url_data, location, error)
99     }
101     /// Whether we're in a user-agent stylesheet.
102     #[inline]
103     pub fn in_ua_sheet(&self) -> bool {
104         self.stylesheet_origin == Origin::UserAgent
105     }
107     /// Returns whether chrome-only rules should be parsed.
108     #[inline]
109     pub fn chrome_rules_enabled(&self) -> bool {
110         self.url_data.chrome_rules_enabled() || self.stylesheet_origin != Origin::Author
111     }
114 /// A trait to abstract parsing of a specified value given a `ParserContext` and
115 /// CSS input.
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
122 ///    at parse-time.
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.
129     ///
130     /// Returns an error on failure.
131     fn parse<'i, 't>(
132         context: &ParserContext,
133         input: &mut Parser<'i, 't>,
134     ) -> Result<Self, ParseError<'i>>;
137 impl<T> Parse for Vec<T>
138 where
139     T: Parse + OneOrMoreSeparated,
140     <T as OneOrMoreSeparated>::S: Separator,
142     fn parse<'i, 't>(
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))
147     }
150 impl<T> Parse for Box<T>
151 where
152     T: Parse,
154     fn parse<'i, 't>(
155         context: &ParserContext,
156         input: &mut Parser<'i, 't>,
157     ) -> Result<Self, ParseError<'i>> {
158         T::parse(context, input).map(Box::new)
159     }
162 impl Parse for crate::OwnedStr {
163     fn parse<'i, 't>(
164         _: &ParserContext,
165         input: &mut Parser<'i, 't>,
166     ) -> Result<Self, ParseError<'i>> {
167         Ok(input.expect_string()?.as_ref().to_owned().into())
168     }
171 impl Parse for UnicodeRange {
172     fn parse<'i, 't>(
173         _: &ParserContext,
174         input: &mut Parser<'i, 't>,
175     ) -> Result<Self, ParseError<'i>> {
176         Ok(UnicodeRange::parse(input)?)
177     }