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