style/values/specified/
list.rs1#[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#[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)]
29#[repr(transparent)]
30pub struct ListStyleType(pub CounterStyle);
31
32#[cfg(feature = "gecko")]
33impl ListStyleType {
34 #[inline]
36 pub fn disc() -> Self {
37 Self(CounterStyle::disc())
38 }
39
40 #[inline]
42 pub fn none() -> Self {
43 Self(CounterStyle::None)
44 }
45
46 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 #[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#[cfg(feature = "servo")]
90impl ListStyleType {
91 #[inline]
93 pub fn disc() -> Self {
94 Self::Disc
95 }
96
97 #[inline]
99 pub fn none() -> Self {
100 Self::None
101 }
102}
103
104#[derive(
106 Clone,
107 Debug,
108 MallocSizeOf,
109 PartialEq,
110 SpecifiedValueInfo,
111 ToComputedValue,
112 ToCss,
113 ToResolvedValue,
114 ToShmem,
115)]
116#[repr(C)]
117pub struct QuotePair {
118 pub opening: crate::OwnedStr,
120
121 pub closing: crate::OwnedStr,
123}
124
125#[derive(
127 Clone,
128 Debug,
129 Default,
130 MallocSizeOf,
131 PartialEq,
132 SpecifiedValueInfo,
133 ToComputedValue,
134 ToCss,
135 ToResolvedValue,
136 ToShmem,
137)]
138#[repr(transparent)]
139pub struct QuoteList(
140 #[css(iterable, if_empty = "none")]
141 #[ignore_malloc_size_of = "Arc"]
142 pub crate::ArcSlice<QuotePair>,
143);
144
145#[derive(
148 Clone,
149 Debug,
150 MallocSizeOf,
151 PartialEq,
152 SpecifiedValueInfo,
153 ToComputedValue,
154 ToCss,
155 ToResolvedValue,
156 ToShmem,
157)]
158#[repr(C)]
159pub enum Quotes {
160 QuoteList(QuoteList),
162 Auto,
164}
165
166impl Parse for Quotes {
167 fn parse<'i, 't>(
168 _: &ParserContext,
169 input: &mut Parser<'i, 't>,
170 ) -> Result<Quotes, ParseError<'i>> {
171 if input
172 .try_parse(|input| input.expect_ident_matching("auto"))
173 .is_ok()
174 {
175 return Ok(Quotes::Auto);
176 }
177
178 if input
179 .try_parse(|input| input.expect_ident_matching("none"))
180 .is_ok()
181 {
182 return Ok(Quotes::QuoteList(QuoteList::default()));
183 }
184
185 let mut quotes = Vec::new();
186 loop {
187 let location = input.current_source_location();
188 let opening = match input.next() {
189 Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into(),
190 Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
191 Err(_) => break,
192 };
193
194 let closing = input.expect_string()?.as_ref().to_owned().into();
195 quotes.push(QuotePair { opening, closing });
196 }
197
198 if !quotes.is_empty() {
199 Ok(Quotes::QuoteList(QuoteList(crate::ArcSlice::from_iter(
200 quotes.into_iter(),
201 ))))
202 } else {
203 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
204 }
205 }
206}