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