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