style/properties_and_values/syntax/
mod.rs1use std::fmt::{self, Debug};
10use std::{borrow::Cow, fmt::Write};
11
12use crate::derives::*;
13use crate::parser::{Parse, ParserContext};
14use crate::values::CustomIdent;
15use cssparser::{Parser as CSSParser, ParserInput as CSSParserInput, Token};
16use style_traits::{
17 CssWriter, ParseError as StyleParseError, PropertySyntaxParseError as ParseError,
18 StyleParseErrorKind, ToCss,
19};
20
21use self::data_type::{DataType, DependentDataTypes};
22
23mod ascii;
24pub mod data_type;
25
26#[derive(Debug, Clone, Default, MallocSizeOf, PartialEq, ToShmem)]
28pub struct Descriptor {
29 pub components: Vec<Component>,
32 specified: Option<Box<str>>,
34}
35
36impl Descriptor {
37 pub const fn universal() -> Self {
39 Self {
40 components: Vec::new(),
41 specified: None,
42 }
43 }
44
45 #[inline]
47 pub fn is_universal(&self) -> bool {
48 self.components.is_empty()
49 }
50
51 #[inline]
53 pub fn specified_string(&self) -> Option<&str> {
54 self.specified.as_deref()
55 }
56
57 #[inline]
60 pub fn from_css_parser<'i>(input: &mut CSSParser<'i, '_>) -> Result<Self, StyleParseError<'i>> {
61 let mut components = vec![];
62
63 if input.try_parse(|i| i.expect_delim('*')).is_ok() {
64 return Ok(Self::universal());
65 }
66
67 if let Ok(syntax_string) = input.try_parse(|i| i.expect_string_cloned()) {
69 return Self::from_str(syntax_string.as_ref(), true).or_else(
70 |err| Err(input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err))),
71 );
72 }
73
74 loop {
75 let name = Self::try_parse_component_name(input).map_err(|err| {
76 input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err))
77 })?;
78
79 let multiplier = if name.is_pre_multiplied() {
80 None
81 } else {
82 Self::try_parse_multiplier(input)
83 };
84
85 let component = Component { multiplier, name };
86 components.push(component);
87 let Ok(delim) = input.next() else { break };
88
89 if delim != &Token::Delim('|') {
90 return Err(
91 input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(
92 ParseError::ExpectedPipeBetweenComponents,
93 )),
94 );
95 }
96 }
97
98 Ok(Self {
99 components,
100 specified: None,
101 })
102 }
103
104 fn try_parse_multiplier<'i>(input: &mut CSSParser<'i, '_>) -> Option<Multiplier> {
105 input
106 .try_parse(|input| {
107 let next = input.next().map_err(|_| ())?;
108 match next {
109 Token::Delim('+') => Ok(Multiplier::Space),
110 Token::Delim('#') => Ok(Multiplier::Comma),
111 _ => Err(()),
112 }
113 })
114 .ok()
115 }
116
117 fn try_parse_component_name<'i>(
118 input: &mut CSSParser<'i, '_>,
119 ) -> Result<ComponentName, ParseError> {
120 if input.try_parse(|input| input.expect_delim('<')).is_ok() {
121 let name = Self::parse_component_data_type_name(input)?;
122 input
123 .expect_delim('>')
124 .map_err(|_| ParseError::UnclosedDataTypeName)?;
125 Ok(ComponentName::DataType(name))
126 } else {
127 input.try_parse(|input| {
128 let name = CustomIdent::parse(input, &[]).map_err(|_| ParseError::InvalidName)?;
129 Ok(ComponentName::Ident(name))
130 })
131 }
132 }
133
134 fn parse_component_data_type_name<'i>(
135 input: &mut CSSParser<'i, '_>,
136 ) -> Result<DataType, ParseError> {
137 input
138 .expect_ident()
139 .ok()
140 .and_then(|n| DataType::from_str(n))
141 .ok_or(ParseError::UnknownDataTypeName)
142 }
143
144 pub fn from_str(css: &str, save_specified: bool) -> Result<Self, ParseError> {
147 let input = ascii::trim_ascii_whitespace(css);
149
150 if input.is_empty() {
152 return Err(ParseError::EmptyInput);
153 }
154
155 let specified = if save_specified {
156 Some(Box::from(css))
157 } else {
158 None
159 };
160
161 if input.len() == 1 && input.as_bytes()[0] == b'*' {
164 return Ok(Self {
165 components: Default::default(),
166 specified,
167 });
168 }
169
170 let mut components = vec![];
177 {
178 let mut input = Parser::new(input, &mut components);
179 input.parse()?;
181 }
182 Ok(Self {
183 components,
184 specified,
185 })
186 }
187
188 pub fn dependent_types(&self) -> DependentDataTypes {
190 let mut types = DependentDataTypes::empty();
191 for component in self.components.iter() {
192 let t = match &component.name {
193 ComponentName::DataType(ref t) => t,
194 ComponentName::Ident(_) => continue,
195 };
196 types.insert(t.dependent_types());
197 }
198 types
199 }
200}
201
202impl ToCss for Descriptor {
203 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
204 where
205 W: Write,
206 {
207 if let Some(ref specified) = self.specified {
208 return specified.to_css(dest);
209 }
210
211 if self.is_universal() {
212 return dest.write_char('*');
213 }
214
215 let mut first = true;
216 for component in &*self.components {
217 if !first {
218 dest.write_str(" | ")?;
219 }
220 component.to_css(dest)?;
221 first = false;
222 }
223
224 Ok(())
225 }
226}
227
228impl Parse for Descriptor {
229 fn parse<'i>(
231 _: &ParserContext,
232 parser: &mut CSSParser<'i, '_>,
233 ) -> Result<Self, StyleParseError<'i>> {
234 let input = parser.expect_string()?;
235 Descriptor::from_str(input.as_ref(), true)
236 .map_err(|err| parser.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err)))
237 }
238}
239
240#[derive(
242 Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
243)]
244pub enum Multiplier {
245 Space,
247 Comma,
249}
250
251impl ToCss for Multiplier {
252 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
253 where
254 W: Write,
255 {
256 dest.write_char(match *self {
257 Multiplier::Space => '+',
258 Multiplier::Comma => '#',
259 })
260 }
261}
262
263#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
265pub struct Component {
266 name: ComponentName,
267 multiplier: Option<Multiplier>,
268}
269
270impl Component {
271 #[inline]
273 pub fn name(&self) -> &ComponentName {
274 &self.name
275 }
276
277 #[inline]
279 pub fn multiplier(&self) -> Option<Multiplier> {
280 self.multiplier
281 }
282
283 #[inline]
285 pub fn unpremultiplied(&self) -> Cow<'_, Self> {
286 match self.name.unpremultiply() {
287 Some(component) => {
288 debug_assert!(
289 self.multiplier.is_none(),
290 "Shouldn't have parsed a multiplier for a pre-multiplied data type name",
291 );
292 Cow::Owned(component)
293 },
294 None => Cow::Borrowed(self),
295 }
296 }
297}
298
299impl ToCss for Component {
300 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
301 where
302 W: Write,
303 {
304 self.name().to_css(dest)?;
305 self.multiplier().to_css(dest)
306 }
307}
308
309#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
311pub enum ComponentName {
312 DataType(DataType),
314 Ident(CustomIdent),
316}
317
318impl ComponentName {
319 fn unpremultiply(&self) -> Option<Component> {
320 match *self {
321 ComponentName::DataType(ref t) => t.unpremultiply(),
322 ComponentName::Ident(..) => None,
323 }
324 }
325
326 fn is_pre_multiplied(&self) -> bool {
328 self.unpremultiply().is_some()
329 }
330}
331
332struct Parser<'a> {
333 input: &'a str,
334 position: usize,
335 output: &'a mut Vec<Component>,
336}
337
338fn is_letter(byte: u8) -> bool {
340 match byte {
341 b'A'..=b'Z' | b'a'..=b'z' => true,
342 _ => false,
343 }
344}
345
346fn is_non_ascii(byte: u8) -> bool {
348 byte >= 0x80
349}
350
351fn is_name_start(byte: u8) -> bool {
353 is_letter(byte) || is_non_ascii(byte) || byte == b'_'
354}
355
356impl<'a> Parser<'a> {
357 fn new(input: &'a str, output: &'a mut Vec<Component>) -> Self {
358 Self {
359 input,
360 position: 0,
361 output,
362 }
363 }
364
365 fn peek(&self) -> Option<u8> {
366 self.input.as_bytes().get(self.position).cloned()
367 }
368
369 fn parse(&mut self) -> Result<(), ParseError> {
370 loop {
372 let component = self.parse_component()?;
373 self.output.push(component);
374 self.skip_whitespace();
375
376 let byte = match self.peek() {
377 None => return Ok(()),
378 Some(b) => b,
379 };
380
381 if byte != b'|' {
382 return Err(ParseError::ExpectedPipeBetweenComponents);
383 }
384
385 self.position += 1;
386 }
387 }
388
389 fn skip_whitespace(&mut self) {
390 loop {
391 match self.peek() {
392 Some(c) if c.is_ascii_whitespace() => self.position += 1,
393 _ => return,
394 }
395 }
396 }
397
398 fn parse_data_type_name(&mut self) -> Result<DataType, ParseError> {
400 let start = self.position;
401 loop {
402 let byte = match self.peek() {
403 Some(b) => b,
404 None => return Err(ParseError::UnclosedDataTypeName),
405 };
406 if byte != b'>' {
407 self.position += 1;
408 continue;
409 }
410 let ty = match DataType::from_str(&self.input[start..self.position]) {
411 Some(ty) => ty,
412 None => return Err(ParseError::UnknownDataTypeName),
413 };
414 self.position += 1;
415 return Ok(ty);
416 }
417 }
418
419 fn parse_name(&mut self) -> Result<ComponentName, ParseError> {
420 let b = match self.peek() {
421 Some(b) => b,
422 None => return Err(ParseError::UnexpectedEOF),
423 };
424
425 if b == b'<' {
426 self.position += 1;
427 return Ok(ComponentName::DataType(self.parse_data_type_name()?));
428 }
429
430 if b != b'\\' && !is_name_start(b) {
431 return Err(ParseError::InvalidNameStart);
432 }
433
434 let input = &self.input[self.position..];
435 let mut input = CSSParserInput::new(input);
436 let mut input = CSSParser::new(&mut input);
437 let name = match CustomIdent::parse(&mut input, &[]) {
438 Ok(name) => name,
439 Err(_) => return Err(ParseError::InvalidName),
440 };
441 self.position += input.position().byte_index();
442 return Ok(ComponentName::Ident(name));
443 }
444
445 fn parse_multiplier(&mut self) -> Option<Multiplier> {
446 let multiplier = match self.peek()? {
447 b'+' => Multiplier::Space,
448 b'#' => Multiplier::Comma,
449 _ => return None,
450 };
451 self.position += 1;
452 Some(multiplier)
453 }
454
455 fn parse_component(&mut self) -> Result<Component, ParseError> {
457 self.skip_whitespace();
459 let name = self.parse_name()?;
460 let multiplier = if name.is_pre_multiplied() {
461 None
462 } else {
463 self.parse_multiplier()
464 };
465 Ok(Component { name, multiplier })
466 }
467}