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
7#[cfg(feature = "gecko")]
8use crate::counter_style::{CounterStyle, CounterStyleParsingFlags};
9use crate::derives::*;
10use crate::parser::{Parse, ParserContext};
11use cssparser::{Parser, Token};
12use style_traits::{ParseError, StyleParseErrorKind};
13
14/// Specified and computed `list-style-type` property.
15#[cfg(feature = "gecko")]
16#[derive(
17    Clone,
18    Debug,
19    Eq,
20    MallocSizeOf,
21    PartialEq,
22    SpecifiedValueInfo,
23    ToComputedValue,
24    ToCss,
25    ToResolvedValue,
26    ToShmem,
27    ToTyped,
28)]
29#[repr(transparent)]
30pub struct ListStyleType(pub CounterStyle);
31
32#[cfg(feature = "gecko")]
33impl ListStyleType {
34    /// Initial specified value for `list-style-type`.
35    #[inline]
36    pub fn disc() -> Self {
37        Self(CounterStyle::disc())
38    }
39
40    /// none value.
41    #[inline]
42    pub fn none() -> Self {
43        Self(CounterStyle::None)
44    }
45
46    /// Convert from gecko keyword to list-style-type.
47    ///
48    /// This should only be used for mapping type attribute to list-style-type, and thus only
49    /// values possible in that attribute is considered here.
50    pub fn from_gecko_keyword(value: u32) -> Self {
51        use crate::gecko_bindings::structs;
52        use crate::values::CustomIdent;
53        let v8 = value as u8;
54        if v8 == structs::ListStyle_None {
55            return Self::none();
56        }
57
58        Self(CounterStyle::Name(CustomIdent(match v8 {
59            structs::ListStyle_Disc => atom!("disc"),
60            structs::ListStyle_Circle => atom!("circle"),
61            structs::ListStyle_Square => atom!("square"),
62            structs::ListStyle_Decimal => atom!("decimal"),
63            structs::ListStyle_LowerRoman => atom!("lower-roman"),
64            structs::ListStyle_UpperRoman => atom!("upper-roman"),
65            structs::ListStyle_LowerAlpha => atom!("lower-alpha"),
66            structs::ListStyle_UpperAlpha => atom!("upper-alpha"),
67            _ => unreachable!("Unknown counter style keyword value"),
68        })))
69    }
70
71    /// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`)
72    #[inline]
73    pub fn is_bullet(&self) -> bool {
74        self.0.is_bullet()
75    }
76}
77
78#[cfg(feature = "gecko")]
79impl Parse for ListStyleType {
80    fn parse<'i, 't>(
81        context: &ParserContext,
82        input: &mut Parser<'i, 't>,
83    ) -> Result<Self, ParseError<'i>> {
84        let flags = CounterStyleParsingFlags::ALLOW_NONE | CounterStyleParsingFlags::ALLOW_STRING;
85        Ok(Self(CounterStyle::parse(context, input, flags)?))
86    }
87}
88
89/// Specified and computed `list-style-type` property.
90#[cfg(feature = "servo")]
91#[derive(
92    Clone,
93    Debug,
94    Eq,
95    MallocSizeOf,
96    Parse,
97    PartialEq,
98    SpecifiedValueInfo,
99    ToCss,
100    ToComputedValue,
101    ToResolvedValue,
102    ToShmem,
103    ToTyped,
104)]
105pub enum ListStyleType {
106    /// A filled circle, similar to • U+2022 BULLET.
107    /// <https://www.w3.org/TR/css-counter-styles-3/#disc>
108    Disc,
109    /// The element has no marker string.
110    /// <https://www.w3.org/TR/css-lists-3/#valdef-list-style-type-none>
111    None,
112    /// A hollow circle, similar to ◦ U+25E6 WHITE BULLET.
113    /// <https://www.w3.org/TR/css-counter-styles-3/#circle>
114    Circle,
115    /// A filled square, similar to ▪ U+25AA BLACK SMALL SQUARE.
116    /// <https://www.w3.org/TR/css-counter-styles-3/#square>
117    Square,
118    /// Symbol for indicating an open disclosure widget, such as the HTML `<details>` element.
119    /// <https://www.w3.org/TR/css-counter-styles-3/#disclosure-open>
120    DisclosureOpen,
121    /// Symbol for indicating a closed disclosure widget, such as the HTML `<details>` element.
122    /// <https://www.w3.org/TR/css-counter-styles-3/#disclosure-closed>
123    DisclosureClosed,
124    /// Western decimal numbers (e.g., 1, 2, 3, ..., 98, 99, 100).
125    /// <https://www.w3.org/TR/css-counter-styles-3/#decimal>
126    Decimal,
127    /// Lowercase ASCII letters (e.g., a, b, c, ..., z, aa, ab).
128    /// <https://www.w3.org/TR/css-counter-styles-3/#lower-alpha>
129    LowerAlpha,
130    /// Uppercase ASCII letters (e.g., A, B, C, ..., Z, AA, AB).
131    /// <https://www.w3.org/TR/css-counter-styles-3/#upper-alpha>
132    UpperAlpha,
133    /// Arabic-indic numbering (e.g.، ١، ٢، ٣، ٤، ...، ٩٨، ٩٩، ١٠٠).
134    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-arabic-indic>
135    ArabicIndic,
136    /// Bengali numbering (e.g., ১, ২, ৩, ..., ৯৮, ৯৯, ১০০).
137    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-bengali>
138    Bengali,
139    /// Cambodian/Khmer numbering (e.g., ១, ២, ៣, ..., ៩៨, ៩៩, ១០០).
140    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-cambodian>
141    Cambodian,
142    /// Han decimal numbers (e.g., 一, 二, 三, ..., 九八, 九九, 一〇〇).
143    /// <https://www.w3.org/TR/css-counter-styles-3/#cjk-decimal>
144    CjkDecimal,
145    /// devanagari numbering (e.g., १, २, ३, ..., ९८, ९९, १००).
146    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-devanagari>
147    Devanagari,
148    /// Gujarati numbering (e.g., ૧, ૨, ૩, ..., ૯૮, ૯૯, ૧૦૦).
149    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-gujarati>
150    Gujarati,
151    /// Gurmukhi numbering (e.g., ੧, ੨, ੩, ..., ੯੮, ੯੯, ੧੦੦).
152    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-gurmukhi>
153    Gurmukhi,
154    /// Kannada numbering (e.g., ೧, ೨, ೩, ..., ೯೮, ೯೯, ೧೦೦).
155    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-kannada>
156    Kannada,
157    /// Cambodian/Khmer numbering (e.g., ១, ២, ៣, ..., ៩៨, ៩៩, ១០០).
158    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-khmer>
159    Khmer,
160    /// Laotian numbering (e.g., ໑, ໒, ໓, ..., ໙໘, ໙໙, ໑໐໐).
161    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-lao<
162    Lao,
163    /// Malayalam numbering (e.g., ൧, ൨, ൩, ..., ൯൮, ൯൯, ൧൦൦).
164    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-malayalam>
165    Malayalam,
166    /// Mongolian numbering (e.g., ᠑, ᠒, ᠓, ..., ᠙᠘, ᠙᠙, ᠑᠐᠐).
167    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-mongolian>
168    Mongolian,
169    /// Myanmar (Burmese) numbering (e.g., ၁, ၂, ၃, ..., ၉၈, ၉၉, ၁၀၀).
170    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-myanmar>
171    Myanmar,
172    /// Oriya numbering (e.g., ୧, ୨, ୩, ..., ୯୮, ୯୯, ୧୦୦).
173    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-oriya>
174    Oriya,
175    /// Persian numbering (e.g., ۱, ۲, ۳, ۴, ..., ۹۸, ۹۹, ۱۰۰).
176    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-persian>
177    Persian,
178    /// Telugu numbering (e.g., ౧, ౨, ౩, ..., ౯౮, ౯౯, ౧౦౦).
179    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-telugu>
180    Telugu,
181    /// Thai (Siamese) numbering (e.g., ๑, ๒, ๓, ..., ๙๘, ๙๙, ๑๐๐).
182    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-thai>
183    Thai,
184    /// Tibetan numbering (e.g., ༡, ༢, ༣, ..., ༩༨, ༩༩, ༡༠༠).
185    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-tibetan>
186    Tibetan,
187    /// Han "Earthly Branch" ordinals (e.g., 子, 丑, 寅, ..., 亥).
188    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-cjk-earthly-branch>
189    CjkEarthlyBranch,
190    /// Han "Heavenly Stem" ordinals (e.g., 甲, 乙, 丙, ..., 癸)
191    /// <https://www.w3.org/TR/css-counter-styles-3/#valdef-counter-style-name-cjk-heavenly-stem>
192    CjkHeavenlyStem,
193    /// Lowercase classical Greek (e.g., α, β, γ, ..., ω, αα, αβ).
194    /// <https://www.w3.org/TR/css-counter-styles-3/#lower-greek>
195    LowerGreek,
196    /// Dictionary-order hiragana lettering (e.g., あ, い, う, ..., ん, ああ, あい).
197    /// <https://www.w3.org/TR/css-counter-styles-3/#hiragana>
198    Hiragana,
199    /// Iroha-order hiragana lettering (e.g., い, ろ, は, ..., す, いい, いろ).
200    /// <https://www.w3.org/TR/css-counter-styles-3/#hiragana-iroha>
201    HiraganaIroha,
202    /// Dictionary-order katakana lettering (e.g., ア, イ, ウ, ..., ン, アア, アイ).
203    /// <https://www.w3.org/TR/css-counter-styles-3/#katakana>
204    Katakana,
205    /// Iroha-order katakana lettering (e.g., イ, ロ, ハ, ..., ス, イイ, イロ)
206    /// <https://www.w3.org/TR/css-counter-styles-3/#katakana-iroha>
207    KatakanaIroha,
208}
209
210#[cfg(feature = "servo")]
211impl ListStyleType {
212    /// Initial specified value for `list-style-type`.
213    #[inline]
214    pub fn disc() -> Self {
215        Self::Disc
216    }
217
218    /// none value.
219    #[inline]
220    pub fn none() -> Self {
221        Self::None
222    }
223}
224
225/// A quote pair.
226#[derive(
227    Clone,
228    Debug,
229    MallocSizeOf,
230    PartialEq,
231    SpecifiedValueInfo,
232    ToComputedValue,
233    ToCss,
234    ToResolvedValue,
235    ToShmem,
236)]
237#[repr(C)]
238pub struct QuotePair {
239    /// The opening quote.
240    pub opening: crate::OwnedStr,
241
242    /// The closing quote.
243    pub closing: crate::OwnedStr,
244}
245
246/// List of quote pairs for the specified/computed value of `quotes` property.
247#[derive(
248    Clone,
249    Debug,
250    Default,
251    MallocSizeOf,
252    PartialEq,
253    SpecifiedValueInfo,
254    ToComputedValue,
255    ToCss,
256    ToResolvedValue,
257    ToShmem,
258)]
259#[repr(transparent)]
260pub struct QuoteList(
261    #[css(iterable, if_empty = "none")]
262    #[ignore_malloc_size_of = "Arc"]
263    pub crate::ArcSlice<QuotePair>,
264);
265
266/// Specified and computed `quotes` property: `auto`, `none`, or a list
267/// of characters.
268#[derive(
269    Clone,
270    Debug,
271    MallocSizeOf,
272    PartialEq,
273    SpecifiedValueInfo,
274    ToComputedValue,
275    ToCss,
276    ToResolvedValue,
277    ToShmem,
278    ToTyped,
279)]
280#[repr(C)]
281pub enum Quotes {
282    /// list of quote pairs
283    QuoteList(QuoteList),
284    /// auto (use lang-dependent quote marks)
285    Auto,
286}
287
288impl Parse for Quotes {
289    fn parse<'i, 't>(
290        _: &ParserContext,
291        input: &mut Parser<'i, 't>,
292    ) -> Result<Quotes, ParseError<'i>> {
293        if input
294            .try_parse(|input| input.expect_ident_matching("auto"))
295            .is_ok()
296        {
297            return Ok(Quotes::Auto);
298        }
299
300        if input
301            .try_parse(|input| input.expect_ident_matching("none"))
302            .is_ok()
303        {
304            return Ok(Quotes::QuoteList(QuoteList::default()));
305        }
306
307        let mut quotes = Vec::new();
308        loop {
309            let location = input.current_source_location();
310            let opening = match input.next() {
311                Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into(),
312                Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
313                Err(_) => break,
314            };
315
316            let closing = input.expect_string()?.as_ref().to_owned().into();
317            quotes.push(QuotePair { opening, closing });
318        }
319
320        if !quotes.is_empty() {
321            Ok(Quotes::QuoteList(QuoteList(crate::ArcSlice::from_iter(
322                quotes.into_iter(),
323            ))))
324        } else {
325            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
326        }
327    }
328}