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