Skip to main content

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