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