style/values/specified/
list.rs1use crate::counter_style::{CounterStyle, CounterStyleParsingFlags};
8use crate::derives::*;
9use crate::parser::{Parse, ParserContext};
10use cssparser::{Parser, Token};
11use style_traits::{ParseError, StyleParseErrorKind};
12
13#[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 #[inline]
34 pub fn disc() -> Self {
35 Self(CounterStyle::disc())
36 }
37
38 #[inline]
40 pub fn none() -> Self {
41 Self(CounterStyle::None)
42 }
43
44 #[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 #[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#[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 pub opening: crate::OwnedStr,
103
104 pub closing: crate::OwnedStr,
106}
107
108#[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#[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 QuoteList(QuoteList),
147 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}