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