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<'i, 't>(
141 context: &ParserContext,
142 input: &mut Parser<'i, 't>,
143 ) -> Result<Self, ParseError<'i>> {
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_boxed_slice(),
155 ))
156 }
157}
158
159#[derive(
166 Clone,
167 Copy,
168 Deserialize,
169 Eq,
170 Hash,
171 MallocSizeOf,
172 PartialEq,
173 Serialize,
174 SpecifiedValueInfo,
175 ToAnimatedValue,
176 ToComputedValue,
177 ToResolvedValue,
178 ToShmem,
179)]
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<'i, 't>(
212 _context: &ParserContext,
213 input: &mut Parser<'i, 't>,
214 ) -> Result<Self, ParseError<'i>> {
215 let location = input.current_source_location();
216 let tag = input.expect_string()?;
217
218 if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
220 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
221 }
222
223 let mut raw = Cursor::new(tag.as_bytes());
224 Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
225 }
226}
227
228#[allow(missing_docs)]
232#[derive(
233 Animate,
234 Clone,
235 ComputeSquaredDistance,
236 Copy,
237 Debug,
238 Deserialize,
239 Hash,
240 MallocSizeOf,
241 PartialEq,
242 Serialize,
243 SpecifiedValueInfo,
244 ToAnimatedValue,
245 ToAnimatedZero,
246 ToResolvedValue,
247 ToShmem,
248)]
249#[value_info(other_values = "normal")]
250pub enum FontStyle<Angle> {
251 #[value_info(starts_with_keyword)]
253 Oblique(Angle),
254 #[animation(error)]
255 Italic,
256}
257
258impl<Angle: Zero> FontStyle<Angle> {
259 pub fn normal() -> Self {
261 Self::Oblique(Angle::zero())
262 }
263}
264
265#[allow(missing_docs)]
269#[repr(u8)]
270#[derive(
271 Animate,
272 Clone,
273 ComputeSquaredDistance,
274 Copy,
275 Debug,
276 Deserialize,
277 Hash,
278 MallocSizeOf,
279 PartialEq,
280 Serialize,
281 SpecifiedValueInfo,
282 ToAnimatedValue,
283 ToAnimatedZero,
284 ToComputedValue,
285 ToResolvedValue,
286 ToShmem,
287)]
288pub enum GenericFontSizeAdjust<Factor> {
289 #[animation(error)]
290 None,
291 #[value_info(starts_with_keyword)]
292 ExHeight(Factor),
293 #[value_info(starts_with_keyword)]
294 CapHeight(Factor),
295 #[value_info(starts_with_keyword)]
296 ChWidth(Factor),
297 #[value_info(starts_with_keyword)]
298 IcWidth(Factor),
299 #[value_info(starts_with_keyword)]
300 IcHeight(Factor),
301}
302
303impl<Factor: ToCss> ToCss for GenericFontSizeAdjust<Factor> {
304 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
305 where
306 W: Write,
307 {
308 let (prefix, value) = match self {
309 Self::None => return dest.write_str("none"),
310 Self::ExHeight(v) => ("", v),
311 Self::CapHeight(v) => ("cap-height ", v),
312 Self::ChWidth(v) => ("ch-width ", v),
313 Self::IcWidth(v) => ("ic-width ", v),
314 Self::IcHeight(v) => ("ic-height ", v),
315 };
316
317 dest.write_str(prefix)?;
318 value.to_css(dest)
319 }
320}
321
322impl<Factor: ToTyped> ToTyped for GenericFontSizeAdjust<Factor> {
323 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
324 match self {
325 Self::None => {
326 dest.push(TypedValue::Keyword(KeywordValue(CssString::from("none"))));
327 Ok(())
328 },
329 Self::ExHeight(v) => v.to_typed(dest),
330 _ => Err(()),
331 }
332 }
333}
334
335#[derive(
337 Animate,
338 Clone,
339 ComputeSquaredDistance,
340 Copy,
341 Debug,
342 Deserialize,
343 MallocSizeOf,
344 PartialEq,
345 Serialize,
346 SpecifiedValueInfo,
347 ToAnimatedValue,
348 ToCss,
349 ToShmem,
350 Parse,
351 ToTyped,
352)]
353#[repr(C, u8)]
354pub enum GenericLineHeight<N, L> {
355 Normal,
357 Number(N),
359 Length(L),
361}
362
363pub use self::GenericLineHeight as LineHeight;
364
365impl<N, L> ToAnimatedZero for LineHeight<N, L> {
366 #[inline]
367 fn to_animated_zero(&self) -> Result<Self, ()> {
368 Err(())
369 }
370}
371
372impl<N, L> LineHeight<N, L> {
373 #[inline]
375 pub fn normal() -> Self {
376 LineHeight::Normal
377 }
378
379 #[inline]
381 pub fn is_normal(&self) -> bool {
382 matches!(self, Self::Normal)
383 }
384}