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