style/values/specified/
list.rs

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/. */
4
5//! `list` specified values.
6
7use crate::counter_style::{CounterStyle, CounterStyleParsingFlags};
8use crate::derives::*;
9use crate::parser::{Parse, ParserContext};
10use cssparser::{Parser, Token};
11use style_traits::{ParseError, StyleParseErrorKind};
12
13/// Specified and computed `list-style-type` property.
14#[derive(
15    Clone,
16    Debug,
17    Eq,
18    MallocSizeOf,
19    PartialEq,
20    SpecifiedValueInfo,
21    ToComputedValue,
22    ToCss,
23    ToResolvedValue,
24    ToShmem,
25    ToTyped,
26)]
27#[repr(transparent)]
28pub struct ListStyleType(pub CounterStyle);
29
30impl ListStyleType {
31    /// Initial specified value for `list-style-type`.
32    #[inline]
33    pub fn disc() -> Self {
34        Self(CounterStyle::disc())
35    }
36
37    /// none value.
38    #[inline]
39    pub fn none() -> Self {
40        Self(CounterStyle::None)
41    }
42
43    /// Convert from gecko keyword to list-style-type.
44    ///
45    /// This should only be used for mapping type attribute to list-style-type, and thus only
46    /// values possible in that attribute is considered here.
47    #[cfg(feature = "gecko")]
48    pub fn from_gecko_keyword(value: u32) -> Self {
49        use crate::gecko_bindings::structs;
50        use crate::values::CustomIdent;
51        let v8 = value as u8;
52        if v8 == structs::ListStyle_None {
53            return Self::none();
54        }
55
56        Self(CounterStyle::Name(CustomIdent(match v8 {
57            structs::ListStyle_Disc => atom!("disc"),
58            structs::ListStyle_Circle => atom!("circle"),
59            structs::ListStyle_Square => atom!("square"),
60            structs::ListStyle_Decimal => atom!("decimal"),
61            structs::ListStyle_LowerRoman => atom!("lower-roman"),
62            structs::ListStyle_UpperRoman => atom!("upper-roman"),
63            structs::ListStyle_LowerAlpha => atom!("lower-alpha"),
64            structs::ListStyle_UpperAlpha => atom!("upper-alpha"),
65            _ => unreachable!("Unknown counter style keyword value"),
66        })))
67    }
68
69    /// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`)
70    #[inline]
71    pub fn is_bullet(&self) -> bool {
72        self.0.is_bullet()
73    }
74}
75
76impl Parse for ListStyleType {
77    fn parse<'i, 't>(
78        context: &ParserContext,
79        input: &mut Parser<'i, 't>,
80    ) -> Result<Self, ParseError<'i>> {
81        let flags = CounterStyleParsingFlags::ALLOW_NONE | CounterStyleParsingFlags::ALLOW_STRING;
82        Ok(Self(CounterStyle::parse(context, input, flags)?))
83    }
84}
85
86/// A quote pair.
87#[derive(
88    Clone,
89    Debug,
90    MallocSizeOf,
91    PartialEq,
92    SpecifiedValueInfo,
93    ToComputedValue,
94    ToCss,
95    ToResolvedValue,
96    ToShmem,
97)]
98#[repr(C)]
99pub struct QuotePair {
100    /// The opening quote.
101    pub opening: crate::OwnedStr,
102
103    /// The closing quote.
104    pub closing: crate::OwnedStr,
105}
106
107/// List of quote pairs for the specified/computed value of `quotes` property.
108#[derive(
109    Clone,
110    Debug,
111    Default,
112    MallocSizeOf,
113    PartialEq,
114    SpecifiedValueInfo,
115    ToComputedValue,
116    ToCss,
117    ToResolvedValue,
118    ToShmem,
119)]
120#[repr(transparent)]
121pub struct QuoteList(
122    #[css(iterable, if_empty = "none")]
123    #[ignore_malloc_size_of = "Arc"]
124    pub crate::ArcSlice<QuotePair>,
125);
126
127/// Specified and computed `quotes` property: `auto`, `none`, or a list
128/// of characters.
129#[derive(
130    Clone,
131    Debug,
132    MallocSizeOf,
133    PartialEq,
134    SpecifiedValueInfo,
135    ToComputedValue,
136    ToCss,
137    ToResolvedValue,
138    ToShmem,
139    ToTyped,
140)]
141#[repr(C)]
142pub enum Quotes {
143    /// list of quote pairs
144    QuoteList(QuoteList),
145    /// auto (use lang-dependent quote marks)
146    Auto,
147}
148
149impl Parse for Quotes {
150    fn parse<'i, 't>(
151        _: &ParserContext,
152        input: &mut Parser<'i, 't>,
153    ) -> Result<Quotes, ParseError<'i>> {
154        if input
155            .try_parse(|input| input.expect_ident_matching("auto"))
156            .is_ok()
157        {
158            return Ok(Quotes::Auto);
159        }
160
161        if input
162            .try_parse(|input| input.expect_ident_matching("none"))
163            .is_ok()
164        {
165            return Ok(Quotes::QuoteList(QuoteList::default()));
166        }
167
168        let mut quotes = Vec::new();
169        loop {
170            let location = input.current_source_location();
171            let opening = match input.next() {
172                Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into(),
173                Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
174                Err(_) => break,
175            };
176
177            let closing = input.expect_string()?.as_ref().to_owned().into();
178            quotes.push(QuotePair { opening, closing });
179        }
180
181        if !quotes.is_empty() {
182            Ok(Quotes::QuoteList(QuoteList(crate::ArcSlice::from_iter(
183                quotes.into_iter(),
184            ))))
185        } else {
186            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
187        }
188    }
189}