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 #[inline]
46 pub fn is_name(&self, n: &crate::Atom) -> bool {
47 self.0.is_name(n)
48 }
49
50 #[cfg(feature = "gecko")]
55 pub fn from_gecko_keyword(value: u32) -> Self {
56 use crate::gecko_bindings::structs;
57 use crate::values::CustomIdent;
58 let v8 = value as u8;
59 if v8 == structs::ListStyle_None {
60 return Self::none();
61 }
62
63 Self(CounterStyle::Name(CustomIdent(match v8 {
64 structs::ListStyle_Disc => atom!("disc"),
65 structs::ListStyle_Circle => atom!("circle"),
66 structs::ListStyle_Square => atom!("square"),
67 structs::ListStyle_Decimal => atom!("decimal"),
68 structs::ListStyle_LowerRoman => atom!("lower-roman"),
69 structs::ListStyle_UpperRoman => atom!("upper-roman"),
70 structs::ListStyle_LowerAlpha => atom!("lower-alpha"),
71 structs::ListStyle_UpperAlpha => atom!("upper-alpha"),
72 _ => unreachable!("Unknown counter style keyword value"),
73 })))
74 }
75
76 #[inline]
78 pub fn is_bullet(&self) -> bool {
79 self.0.is_bullet()
80 }
81}
82
83impl Parse for ListStyleType {
84 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
85 let flags = CounterStyleParsingFlags::ALLOW_NONE | CounterStyleParsingFlags::ALLOW_STRING;
86 Ok(Self(CounterStyle::parse(context, input, flags)?))
87 }
88}
89
90#[derive(
92 Clone,
93 Debug,
94 MallocSizeOf,
95 PartialEq,
96 SpecifiedValueInfo,
97 ToComputedValue,
98 ToCss,
99 ToResolvedValue,
100 ToShmem,
101)]
102#[repr(C)]
103pub struct QuotePair {
104 pub opening: crate::OwnedStr,
106
107 pub closing: crate::OwnedStr,
109}
110
111#[derive(
113 Clone,
114 Debug,
115 Default,
116 MallocSizeOf,
117 PartialEq,
118 SpecifiedValueInfo,
119 ToComputedValue,
120 ToCss,
121 ToResolvedValue,
122 ToShmem,
123)]
124#[repr(transparent)]
125pub struct QuoteList(
126 #[css(iterable, if_empty = "none")]
127 #[ignore_malloc_size_of = "Arc"]
128 pub crate::ArcSlice<QuotePair>,
129);
130
131#[derive(
134 Clone,
135 Debug,
136 MallocSizeOf,
137 PartialEq,
138 SpecifiedValueInfo,
139 ToComputedValue,
140 ToCss,
141 ToResolvedValue,
142 ToShmem,
143 ToTyped,
144)]
145#[repr(C)]
146#[typed(todo_derive_fields)]
147pub enum Quotes {
148 QuoteList(QuoteList),
150 Auto,
152}
153
154impl Parse for Quotes {
155 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Quotes, ParseError> {
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 opening = match input.next() {
173 Ok(Token::QuotedString(value)) => value.as_ref().to_owned().into(),
174 Ok(_) => return Err(ParseError::unexpected_token()),
175 Err(_) => break,
176 };
177
178 let closing = input.expect_string()?.as_ref().to_owned().into();
179 quotes.push(QuotePair { opening, closing });
180 }
181
182 if !quotes.is_empty() {
183 Ok(Quotes::QuoteList(QuoteList(crate::ArcSlice::from_iter(
184 quotes.into_iter(),
185 ))))
186 } else {
187 Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
188 }
189 }
190}