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, Namespaces, Origin, UrlExtraData};
10 use crate::use_counters::UseCounters;
11 use cssparser::{Parser, SourceLocation, UnicodeRange};
12 use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
14 /// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
15 #[cfg(feature = "gecko")]
17 pub fn assert_parsing_mode_match() {
18 use crate::gecko_bindings::structs;
20 macro_rules! check_parsing_modes {
21 ( $( $a:ident => $b:path ),*, ) => {
22 if cfg!(debug_assertions) {
23 let mut modes = ParsingMode::all();
25 assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b));
28 assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion");
33 check_parsing_modes! {
34 ParsingMode_Default => ParsingMode::DEFAULT,
35 ParsingMode_AllowUnitlessLength => ParsingMode::ALLOW_UNITLESS_LENGTH,
36 ParsingMode_AllowAllNumericValues => ParsingMode::ALLOW_ALL_NUMERIC_VALUES,
40 /// The data that the parser needs from outside in order to parse a stylesheet.
41 pub struct ParserContext<'a> {
42 /// The `Origin` of the stylesheet, whether it's a user, author or
43 /// user-agent stylesheet.
44 pub stylesheet_origin: Origin,
45 /// The extra data we need for resolving url values.
46 pub url_data: &'a UrlExtraData,
47 /// The current rule type, if any.
48 pub rule_type: Option<CssRuleType>,
49 /// The mode to use when parsing.
50 pub parsing_mode: ParsingMode,
51 /// The quirks mode of this stylesheet.
52 pub quirks_mode: QuirksMode,
53 /// The active error reporter, or none if error reporting is disabled.
54 error_reporter: Option<&'a dyn ParseErrorReporter>,
55 /// The currently active namespaces.
56 pub namespaces: Option<&'a Namespaces>,
57 /// The use counters we want to record while parsing style rules, if any.
58 pub use_counters: Option<&'a UseCounters>,
61 impl<'a> ParserContext<'a> {
62 /// Create a parser context.
65 stylesheet_origin: Origin,
66 url_data: &'a UrlExtraData,
67 rule_type: Option<CssRuleType>,
68 parsing_mode: ParsingMode,
69 quirks_mode: QuirksMode,
70 error_reporter: Option<&'a dyn ParseErrorReporter>,
71 use_counters: Option<&'a UseCounters>,
85 /// Create a parser context based on a previous context, but with a modified
88 pub fn new_with_rule_type(
89 context: &'a ParserContext,
90 rule_type: CssRuleType,
91 namespaces: &'a Namespaces,
92 ) -> ParserContext<'a> {
94 stylesheet_origin: context.stylesheet_origin,
95 url_data: context.url_data,
96 rule_type: Some(rule_type),
97 parsing_mode: context.parsing_mode,
98 quirks_mode: context.quirks_mode,
99 namespaces: Some(namespaces),
100 error_reporter: context.error_reporter,
101 use_counters: context.use_counters,
105 /// Whether we're in a @page rule.
107 pub fn in_page_rule(&self) -> bool {
109 .map_or(false, |rule_type| rule_type == CssRuleType::Page)
112 /// Get the rule type, which assumes that one is available.
113 pub fn rule_type(&self) -> CssRuleType {
115 .expect("Rule type expected, but none was found.")
118 /// Returns whether CSS error reporting is enabled.
120 pub fn error_reporting_enabled(&self) -> bool {
121 self.error_reporter.is_some()
124 /// Record a CSS parse error with this context’s error reporting.
125 pub fn log_css_error(&self, location: SourceLocation, error: ContextualParseError) {
126 let error_reporter = match self.error_reporter {
131 error_reporter.report_error(self.url_data, location, error)
134 /// Whether we're in a user-agent stylesheet.
136 pub fn in_ua_sheet(&self) -> bool {
137 self.stylesheet_origin == Origin::UserAgent
140 /// Returns whether chrome-only rules should be parsed.
142 pub fn chrome_rules_enabled(&self) -> bool {
143 self.url_data.chrome_rules_enabled() || self.stylesheet_origin == Origin::User
146 /// Whether we're in a user-agent stylesheet or chrome rules are enabled.
148 pub fn in_ua_or_chrome_sheet(&self) -> bool {
149 self.in_ua_sheet() || self.chrome_rules_enabled()
153 /// A trait to abstract parsing of a specified value given a `ParserContext` and
156 /// This can be derived on keywords with `#[derive(Parse)]`.
158 /// The derive code understands the following attributes on each of the variants:
160 /// * `#[parse(aliases = "foo,bar")]` can be used to alias a value with another
163 /// * `#[parse(condition = "function")]` can be used to make the parsing of the
164 /// value conditional on `function`, which needs to fulfill
165 /// `fn(&ParserContext) -> bool`.
166 pub trait Parse: Sized {
167 /// Parse a value of this type.
169 /// Returns an error on failure.
171 context: &ParserContext,
172 input: &mut Parser<'i, 't>,
173 ) -> Result<Self, ParseError<'i>>;
176 impl<T> Parse for Vec<T>
178 T: Parse + OneOrMoreSeparated,
179 <T as OneOrMoreSeparated>::S: Separator,
182 context: &ParserContext,
183 input: &mut Parser<'i, 't>,
184 ) -> Result<Self, ParseError<'i>> {
185 <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
189 impl<T> Parse for Box<T>
194 context: &ParserContext,
195 input: &mut Parser<'i, 't>,
196 ) -> Result<Self, ParseError<'i>> {
197 T::parse(context, input).map(Box::new)
201 impl Parse for crate::OwnedStr {
204 input: &mut Parser<'i, 't>,
205 ) -> Result<Self, ParseError<'i>> {
206 Ok(input.expect_string()?.as_ref().to_owned().into())
210 impl Parse for UnicodeRange {
213 input: &mut Parser<'i, 't>,
214 ) -> Result<Self, ParseError<'i>> {
215 Ok(UnicodeRange::parse(input)?)