1use crate::parser::{Parse, ParserContext};
8use crate::values::animated::ToAnimatedZero;
9use crate::{One, Zero};
10use byteorder::{BigEndian, ReadBytesExt};
11use cssparser::Parser;
12use std::fmt::{self, Write};
13use std::io::Cursor;
14use style_traits::{CssWriter, ParseError};
15use style_traits::{StyleParseErrorKind, ToCss};
16
17pub trait TaggedFontValue {
20 fn tag(&self) -> FontTag;
22}
23
24#[derive(
26 Clone,
27 Debug,
28 Eq,
29 MallocSizeOf,
30 PartialEq,
31 SpecifiedValueInfo,
32 ToAnimatedValue,
33 ToComputedValue,
34 ToResolvedValue,
35 ToShmem,
36)]
37pub struct FeatureTagValue<Integer> {
38 pub tag: FontTag,
40 pub value: Integer,
42}
43
44impl<T> TaggedFontValue for FeatureTagValue<T> {
45 fn tag(&self) -> FontTag {
46 self.tag
47 }
48}
49
50impl<Integer> ToCss for FeatureTagValue<Integer>
51where
52 Integer: One + ToCss + PartialEq,
53{
54 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
55 where
56 W: Write,
57 {
58 self.tag.to_css(dest)?;
59 if !self.value.is_one() {
61 dest.write_char(' ')?;
62 self.value.to_css(dest)?;
63 }
64
65 Ok(())
66 }
67}
68
69#[derive(
73 Animate,
74 Clone,
75 ComputeSquaredDistance,
76 Debug,
77 Eq,
78 MallocSizeOf,
79 PartialEq,
80 SpecifiedValueInfo,
81 ToAnimatedValue,
82 ToComputedValue,
83 ToCss,
84 ToResolvedValue,
85 ToShmem,
86)]
87#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
88pub struct VariationValue<Number> {
89 #[animation(constant)]
91 pub tag: FontTag,
92 pub value: Number,
94}
95
96impl<T> TaggedFontValue for VariationValue<T> {
97 fn tag(&self) -> FontTag {
98 self.tag
99 }
100}
101
102#[derive(
104 Clone,
105 Debug,
106 Eq,
107 MallocSizeOf,
108 PartialEq,
109 SpecifiedValueInfo,
110 ToAnimatedValue,
111 ToCss,
112 ToResolvedValue,
113 ToShmem,
114 ToTyped,
115)]
116#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
117#[css(comma)]
118pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>);
119
120impl<T> FontSettings<T> {
121 #[inline]
123 pub fn normal() -> Self {
124 FontSettings(vec![].into_boxed_slice())
125 }
126}
127
128impl<T: Parse> Parse for FontSettings<T> {
129 fn parse<'i, 't>(
132 context: &ParserContext,
133 input: &mut Parser<'i, 't>,
134 ) -> Result<Self, ParseError<'i>> {
135 if input
136 .try_parse(|i| i.expect_ident_matching("normal"))
137 .is_ok()
138 {
139 return Ok(Self::normal());
140 }
141
142 Ok(FontSettings(
143 input
144 .parse_comma_separated(|i| T::parse(context, i))?
145 .into_boxed_slice(),
146 ))
147 }
148}
149
150#[derive(
157 Clone,
158 Copy,
159 Debug,
160 Eq,
161 MallocSizeOf,
162 PartialEq,
163 SpecifiedValueInfo,
164 ToAnimatedValue,
165 ToComputedValue,
166 ToResolvedValue,
167 ToShmem,
168)]
169#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
170pub struct FontTag(pub u32);
171
172impl ToCss for FontTag {
173 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
174 where
175 W: Write,
176 {
177 use byteorder::ByteOrder;
178 use std::str;
179
180 let mut raw = [0u8; 4];
181 BigEndian::write_u32(&mut raw, self.0);
182 str::from_utf8(&raw).unwrap_or_default().to_css(dest)
183 }
184}
185
186impl Parse for FontTag {
187 fn parse<'i, 't>(
188 _context: &ParserContext,
189 input: &mut Parser<'i, 't>,
190 ) -> Result<Self, ParseError<'i>> {
191 let location = input.current_source_location();
192 let tag = input.expect_string()?;
193
194 if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
196 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
197 }
198
199 let mut raw = Cursor::new(tag.as_bytes());
200 Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
201 }
202}
203
204#[allow(missing_docs)]
208#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
209#[derive(
210 Animate,
211 Clone,
212 ComputeSquaredDistance,
213 Copy,
214 Debug,
215 Hash,
216 MallocSizeOf,
217 PartialEq,
218 SpecifiedValueInfo,
219 ToAnimatedValue,
220 ToAnimatedZero,
221 ToResolvedValue,
222 ToShmem,
223)]
224#[value_info(other_values = "normal")]
225pub enum FontStyle<Angle> {
226 #[value_info(starts_with_keyword)]
228 Oblique(Angle),
229 #[animation(error)]
230 Italic,
231}
232
233impl<Angle: Zero> FontStyle<Angle> {
234 pub fn normal() -> Self {
236 Self::Oblique(Angle::zero())
237 }
238}
239
240#[allow(missing_docs)]
244#[repr(u8)]
245#[derive(
246 Animate,
247 Clone,
248 ComputeSquaredDistance,
249 Copy,
250 Debug,
251 Hash,
252 MallocSizeOf,
253 PartialEq,
254 SpecifiedValueInfo,
255 ToAnimatedValue,
256 ToAnimatedZero,
257 ToComputedValue,
258 ToResolvedValue,
259 ToShmem,
260 ToTyped,
261)]
262pub enum GenericFontSizeAdjust<Factor> {
263 #[animation(error)]
264 None,
265 #[value_info(starts_with_keyword)]
266 ExHeight(Factor),
267 #[value_info(starts_with_keyword)]
268 CapHeight(Factor),
269 #[value_info(starts_with_keyword)]
270 ChWidth(Factor),
271 #[value_info(starts_with_keyword)]
272 IcWidth(Factor),
273 #[value_info(starts_with_keyword)]
274 IcHeight(Factor),
275}
276
277impl<Factor: ToCss> ToCss for GenericFontSizeAdjust<Factor> {
278 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
279 where
280 W: Write,
281 {
282 let (prefix, value) = match self {
283 Self::None => return dest.write_str("none"),
284 Self::ExHeight(v) => ("", v),
285 Self::CapHeight(v) => ("cap-height ", v),
286 Self::ChWidth(v) => ("ch-width ", v),
287 Self::IcWidth(v) => ("ic-width ", v),
288 Self::IcHeight(v) => ("ic-height ", v),
289 };
290
291 dest.write_str(prefix)?;
292 value.to_css(dest)
293 }
294}
295
296#[derive(
298 Animate,
299 Clone,
300 ComputeSquaredDistance,
301 Copy,
302 Debug,
303 MallocSizeOf,
304 PartialEq,
305 SpecifiedValueInfo,
306 ToAnimatedValue,
307 ToCss,
308 ToShmem,
309 Parse,
310 ToTyped,
311)]
312#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
313#[repr(C, u8)]
314pub enum GenericLineHeight<N, L> {
315 Normal,
317 #[cfg(feature = "gecko")]
319 #[parse(condition = "ParserContext::in_ua_sheet")]
320 MozBlockHeight,
321 Number(N),
323 Length(L),
325}
326
327pub use self::GenericLineHeight as LineHeight;
328
329impl<N, L> ToAnimatedZero for LineHeight<N, L> {
330 #[inline]
331 fn to_animated_zero(&self) -> Result<Self, ()> {
332 Err(())
333 }
334}
335
336impl<N, L> LineHeight<N, L> {
337 #[inline]
339 pub fn normal() -> Self {
340 LineHeight::Normal
341 }
342}