1use crate::derives::*;
8use crate::parser::{Parse, ParserContext};
9use crate::typed_om::{KeywordValue, ToTyped, TypedValue};
10use crate::values::animated::ToAnimatedZero;
11use crate::{One, Zero};
12use byteorder::{BigEndian, ReadBytesExt};
13use cssparser::Parser;
14use std::fmt::{self, Write};
15use std::io::Cursor;
16use style_traits::{CssString, CssWriter, ParseError, StyleParseErrorKind, ToCss};
17use thin_vec::ThinVec;
18
19pub trait TaggedFontValue {
22 fn tag(&self) -> FontTag;
24}
25
26#[derive(
28 Clone,
29 Debug,
30 Deserialize,
31 Eq,
32 Hash,
33 MallocSizeOf,
34 PartialEq,
35 Serialize,
36 SpecifiedValueInfo,
37 ToAnimatedValue,
38 ToComputedValue,
39 ToResolvedValue,
40 ToShmem,
41)]
42pub struct FeatureTagValue<Integer> {
43 pub tag: FontTag,
45 pub value: Integer,
47}
48
49impl<T> TaggedFontValue for FeatureTagValue<T> {
50 fn tag(&self) -> FontTag {
51 self.tag
52 }
53}
54
55impl<Integer> ToCss for FeatureTagValue<Integer>
56where
57 Integer: One + ToCss + PartialEq,
58{
59 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
60 where
61 W: Write,
62 {
63 self.tag.to_css(dest)?;
64 if !self.value.is_one() {
66 dest.write_char(' ')?;
67 self.value.to_css(dest)?;
68 }
69
70 Ok(())
71 }
72}
73
74#[derive(
78 Animate,
79 Clone,
80 ComputeSquaredDistance,
81 Debug,
82 Deserialize,
83 Eq,
84 MallocSizeOf,
85 PartialEq,
86 Serialize,
87 SpecifiedValueInfo,
88 ToAnimatedValue,
89 ToComputedValue,
90 ToCss,
91 ToResolvedValue,
92 ToShmem,
93)]
94pub struct VariationValue<Number> {
95 #[animation(constant)]
97 pub tag: FontTag,
98 pub value: Number,
100}
101
102impl<T> TaggedFontValue for VariationValue<T> {
103 fn tag(&self) -> FontTag {
104 self.tag
105 }
106}
107
108#[derive(
110 Clone,
111 Debug,
112 Deserialize,
113 Eq,
114 Hash,
115 MallocSizeOf,
116 PartialEq,
117 Serialize,
118 SpecifiedValueInfo,
119 ToAnimatedValue,
120 ToCss,
121 ToResolvedValue,
122 ToShmem,
123 ToTyped,
124)]
125#[css(comma)]
126#[typed(todo_derive_fields)]
127pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>);
128
129impl<T> FontSettings<T> {
130 #[inline]
132 pub fn normal() -> Self {
133 FontSettings(vec![].into_boxed_slice())
134 }
135}
136
137impl<T: Parse> Parse for FontSettings<T> {
138 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
141 if input
142 .try_parse(|i| i.expect_ident_matching("normal"))
143 .is_ok()
144 {
145 return Ok(Self::normal());
146 }
147
148 Ok(FontSettings(
149 input
150 .parse_comma_separated(|i| T::parse(context, i))?
151 .into_boxed_slice(),
152 ))
153 }
154}
155
156#[derive(
163 Clone,
164 Copy,
165 Deserialize,
166 Eq,
167 Hash,
168 MallocSizeOf,
169 PartialEq,
170 Serialize,
171 SpecifiedValueInfo,
172 ToAnimatedValue,
173 ToComputedValue,
174 ToResolvedValue,
175 ToShmem,
176)]
177pub struct FontTag(pub u32);
178
179impl fmt::Debug for FontTag {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let tag_bytes = self.0.to_be_bytes();
182
183 let mut tuple = f.debug_tuple("FontTag");
184 if let Ok(utf8_tag) = str::from_utf8(&tag_bytes) {
185 tuple.field(&utf8_tag);
186 } else {
187 tuple.field(&tag_bytes);
188 };
189 tuple.finish()
190 }
191}
192
193impl ToCss for FontTag {
194 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
195 where
196 W: Write,
197 {
198 use byteorder::ByteOrder;
199 use std::str;
200
201 let mut raw = [0u8; 4];
202 BigEndian::write_u32(&mut raw, self.0);
203 str::from_utf8(&raw).unwrap_or_default().to_css(dest)
204 }
205}
206
207impl Parse for FontTag {
208 fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
209 let tag = input.expect_string()?;
210
211 if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
213 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
214 }
215
216 let mut raw = Cursor::new(tag.as_bytes());
217 Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
218 }
219}
220
221#[allow(missing_docs)]
225#[derive(
226 Animate,
227 Clone,
228 ComputeSquaredDistance,
229 Copy,
230 Debug,
231 Deserialize,
232 Hash,
233 MallocSizeOf,
234 PartialEq,
235 Serialize,
236 SpecifiedValueInfo,
237 ToAnimatedValue,
238 ToAnimatedZero,
239 ToResolvedValue,
240 ToShmem,
241)]
242#[value_info(other_values = "normal")]
243pub enum FontStyle<Angle> {
244 #[value_info(starts_with_keyword)]
246 Oblique(Angle),
247 #[animation(error)]
248 Italic,
249}
250
251impl<Angle: Zero> FontStyle<Angle> {
252 pub fn normal() -> Self {
254 Self::Oblique(Angle::zero())
255 }
256}
257
258#[allow(missing_docs)]
262#[repr(u8)]
263#[derive(
264 Animate,
265 Clone,
266 ComputeSquaredDistance,
267 Copy,
268 Debug,
269 Deserialize,
270 Hash,
271 MallocSizeOf,
272 PartialEq,
273 Serialize,
274 SpecifiedValueInfo,
275 ToAnimatedValue,
276 ToAnimatedZero,
277 ToComputedValue,
278 ToResolvedValue,
279 ToShmem,
280)]
281pub enum GenericFontSizeAdjust<Factor> {
282 #[animation(error)]
283 None,
284 #[value_info(starts_with_keyword)]
285 ExHeight(Factor),
286 #[value_info(starts_with_keyword)]
287 CapHeight(Factor),
288 #[value_info(starts_with_keyword)]
289 ChWidth(Factor),
290 #[value_info(starts_with_keyword)]
291 IcWidth(Factor),
292 #[value_info(starts_with_keyword)]
293 IcHeight(Factor),
294}
295
296impl<Factor: ToCss> ToCss for GenericFontSizeAdjust<Factor> {
297 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
298 where
299 W: Write,
300 {
301 let (prefix, value) = match self {
302 Self::None => return dest.write_str("none"),
303 Self::ExHeight(v) => ("", v),
304 Self::CapHeight(v) => ("cap-height ", v),
305 Self::ChWidth(v) => ("ch-width ", v),
306 Self::IcWidth(v) => ("ic-width ", v),
307 Self::IcHeight(v) => ("ic-height ", v),
308 };
309
310 dest.write_str(prefix)?;
311 value.to_css(dest)
312 }
313}
314
315impl<Factor: ToTyped> ToTyped for GenericFontSizeAdjust<Factor> {
316 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
317 match self {
318 Self::None => {
319 dest.push(TypedValue::Keyword(KeywordValue(CssString::from("none"))));
320 Ok(())
321 },
322 Self::ExHeight(v) => v.to_typed(dest),
323 _ => Err(()),
324 }
325 }
326}
327
328#[derive(
330 Animate,
331 Clone,
332 ComputeSquaredDistance,
333 Copy,
334 Debug,
335 Deserialize,
336 MallocSizeOf,
337 PartialEq,
338 Serialize,
339 SpecifiedValueInfo,
340 ToAnimatedValue,
341 ToCss,
342 ToShmem,
343 ToTyped,
344)]
345#[repr(C, u8)]
346pub enum GenericLineHeight<N, L> {
347 Normal,
349 Number(N),
351 Length(L),
353}
354
355pub use self::GenericLineHeight as LineHeight;
356
357impl<N, L> ToAnimatedZero for LineHeight<N, L> {
358 #[inline]
359 fn to_animated_zero(&self) -> Result<Self, ()> {
360 Err(())
361 }
362}
363
364impl<N, L> LineHeight<N, L> {
365 #[inline]
367 pub fn normal() -> Self {
368 LineHeight::Normal
369 }
370
371 #[inline]
373 pub fn is_normal(&self) -> bool {
374 matches!(self, Self::Normal)
375 }
376}