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