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)]
121pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>);
122
123impl<T> FontSettings<T> {
124 #[inline]
126 pub fn normal() -> Self {
127 FontSettings(vec![].into_boxed_slice())
128 }
129}
130
131impl<T: Parse> Parse for FontSettings<T> {
132 fn parse<'i, 't>(
135 context: &ParserContext,
136 input: &mut Parser<'i, 't>,
137 ) -> Result<Self, ParseError<'i>> {
138 if input
139 .try_parse(|i| i.expect_ident_matching("normal"))
140 .is_ok()
141 {
142 return Ok(Self::normal());
143 }
144
145 Ok(FontSettings(
146 input
147 .parse_comma_separated(|i| T::parse(context, i))?
148 .into_boxed_slice(),
149 ))
150 }
151}
152
153#[derive(
160 Clone,
161 Copy,
162 Debug,
163 Eq,
164 MallocSizeOf,
165 PartialEq,
166 SpecifiedValueInfo,
167 ToAnimatedValue,
168 ToComputedValue,
169 ToResolvedValue,
170 ToShmem,
171)]
172#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
173pub struct FontTag(pub u32);
174
175impl ToCss for FontTag {
176 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
177 where
178 W: Write,
179 {
180 use byteorder::ByteOrder;
181 use std::str;
182
183 let mut raw = [0u8; 4];
184 BigEndian::write_u32(&mut raw, self.0);
185 str::from_utf8(&raw).unwrap_or_default().to_css(dest)
186 }
187}
188
189impl Parse for FontTag {
190 fn parse<'i, 't>(
191 _context: &ParserContext,
192 input: &mut Parser<'i, 't>,
193 ) -> Result<Self, ParseError<'i>> {
194 let location = input.current_source_location();
195 let tag = input.expect_string()?;
196
197 if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
199 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
200 }
201
202 let mut raw = Cursor::new(tag.as_bytes());
203 Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
204 }
205}
206
207#[allow(missing_docs)]
211#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
212#[derive(
213 Animate,
214 Clone,
215 ComputeSquaredDistance,
216 Copy,
217 Debug,
218 Hash,
219 MallocSizeOf,
220 PartialEq,
221 SpecifiedValueInfo,
222 ToAnimatedValue,
223 ToAnimatedZero,
224 ToResolvedValue,
225 ToShmem,
226)]
227#[value_info(other_values = "normal")]
228pub enum FontStyle<Angle> {
229 #[value_info(starts_with_keyword)]
231 Oblique(Angle),
232 #[animation(error)]
233 Italic,
234}
235
236impl<Angle: Zero> FontStyle<Angle> {
237 pub fn normal() -> Self {
239 Self::Oblique(Angle::zero())
240 }
241}
242
243#[allow(missing_docs)]
247#[repr(u8)]
248#[derive(
249 Animate,
250 Clone,
251 ComputeSquaredDistance,
252 Copy,
253 Debug,
254 Hash,
255 MallocSizeOf,
256 PartialEq,
257 SpecifiedValueInfo,
258 ToAnimatedValue,
259 ToAnimatedZero,
260 ToComputedValue,
261 ToResolvedValue,
262 ToShmem,
263)]
264pub enum GenericFontSizeAdjust<Factor> {
265 #[animation(error)]
266 None,
267 #[value_info(starts_with_keyword)]
268 ExHeight(Factor),
269 #[value_info(starts_with_keyword)]
270 CapHeight(Factor),
271 #[value_info(starts_with_keyword)]
272 ChWidth(Factor),
273 #[value_info(starts_with_keyword)]
274 IcWidth(Factor),
275 #[value_info(starts_with_keyword)]
276 IcHeight(Factor),
277}
278
279impl<Factor: ToCss> ToCss for GenericFontSizeAdjust<Factor> {
280 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
281 where
282 W: Write,
283 {
284 let (prefix, value) = match self {
285 Self::None => return dest.write_str("none"),
286 Self::ExHeight(v) => ("", v),
287 Self::CapHeight(v) => ("cap-height ", v),
288 Self::ChWidth(v) => ("ch-width ", v),
289 Self::IcWidth(v) => ("ic-width ", v),
290 Self::IcHeight(v) => ("ic-height ", v),
291 };
292
293 dest.write_str(prefix)?;
294 value.to_css(dest)
295 }
296}
297
298impl<Factor: ToTyped> ToTyped for GenericFontSizeAdjust<Factor> {
299 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
300 match self {
301 Self::None => {
302 dest.push(TypedValue::Keyword(KeywordValue(CssString::from("none"))));
303 Ok(())
304 },
305 Self::ExHeight(v) => v.to_typed(dest),
306 _ => Err(()),
307 }
308 }
309}
310
311#[derive(
313 Animate,
314 Clone,
315 ComputeSquaredDistance,
316 Copy,
317 Debug,
318 MallocSizeOf,
319 PartialEq,
320 SpecifiedValueInfo,
321 ToAnimatedValue,
322 ToCss,
323 ToShmem,
324 Parse,
325 ToTyped,
326)]
327#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
328#[repr(C, u8)]
329pub enum GenericLineHeight<N, L> {
330 Normal,
332 #[cfg(feature = "gecko")]
334 #[parse(condition = "ParserContext::in_ua_sheet")]
335 MozBlockHeight,
336 Number(N),
338 Length(L),
340}
341
342pub use self::GenericLineHeight as LineHeight;
343
344impl<N, L> ToAnimatedZero for LineHeight<N, L> {
345 #[inline]
346 fn to_animated_zero(&self) -> Result<Self, ()> {
347 Err(())
348 }
349}
350
351impl<N, L> LineHeight<N, L> {
352 #[inline]
354 pub fn normal() -> Self {
355 LineHeight::Normal
356 }
357}