1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Generic types for font stuff. 6 7 use crate::parser::{Parse, ParserContext}; 8 use crate::One; 9 use byteorder::{BigEndian, ReadBytesExt}; 10 use cssparser::Parser; 11 use std::fmt::{self, Write}; 12 use std::io::Cursor; 13 use style_traits::{CssWriter, ParseError}; 14 use style_traits::{StyleParseErrorKind, ToCss}; 15 16 /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value 17 #[derive( 18 Clone, 19 Debug, 20 Eq, 21 MallocSizeOf, 22 PartialEq, 23 SpecifiedValueInfo, 24 ToComputedValue, 25 ToResolvedValue, 26 ToShmem, 27 )] 28 pub struct FeatureTagValue<Integer> { 29 /// A four-character tag, packed into a u32 (one byte per character). 30 pub tag: FontTag, 31 /// The actual value. 32 pub value: Integer, 33 } 34 35 impl<Integer> ToCss for FeatureTagValue<Integer> 36 where 37 Integer: One + ToCss + PartialEq, 38 { to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,39 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 40 where 41 W: Write, 42 { 43 self.tag.to_css(dest)?; 44 // Don't serialize the default value. 45 if !self.value.is_one() { 46 dest.write_char(' ')?; 47 self.value.to_css(dest)?; 48 } 49 50 Ok(()) 51 } 52 } 53 54 /// Variation setting for a single feature, see: 55 /// 56 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def 57 #[derive( 58 Animate, 59 Clone, 60 ComputeSquaredDistance, 61 Debug, 62 Eq, 63 MallocSizeOf, 64 PartialEq, 65 SpecifiedValueInfo, 66 ToComputedValue, 67 ToCss, 68 ToResolvedValue, 69 ToShmem, 70 )] 71 pub struct VariationValue<Number> { 72 /// A four-character tag, packed into a u32 (one byte per character). 73 #[animation(constant)] 74 pub tag: FontTag, 75 /// The actual value. 76 pub value: Number, 77 } 78 79 /// A value both for font-variation-settings and font-feature-settings. 80 #[css(comma)] 81 #[derive( 82 Clone, 83 Debug, 84 Eq, 85 MallocSizeOf, 86 PartialEq, 87 SpecifiedValueInfo, 88 ToComputedValue, 89 ToCss, 90 ToResolvedValue, 91 ToShmem, 92 )] 93 pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>); 94 95 impl<T> FontSettings<T> { 96 /// Default value of font settings as `normal`. 97 #[inline] normal() -> Self98 pub fn normal() -> Self { 99 FontSettings(vec![].into_boxed_slice()) 100 } 101 } 102 103 impl<T: Parse> Parse for FontSettings<T> { 104 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings 105 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>106 fn parse<'i, 't>( 107 context: &ParserContext, 108 input: &mut Parser<'i, 't>, 109 ) -> Result<Self, ParseError<'i>> { 110 if input.try(|i| i.expect_ident_matching("normal")).is_ok() { 111 return Ok(Self::normal()); 112 } 113 114 Ok(FontSettings( 115 input 116 .parse_comma_separated(|i| T::parse(context, i))? 117 .into_boxed_slice(), 118 )) 119 } 120 } 121 122 /// A font four-character tag, represented as a u32 for convenience. 123 /// 124 /// See: 125 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def 126 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings 127 /// 128 #[derive( 129 Clone, 130 Copy, 131 Debug, 132 Eq, 133 MallocSizeOf, 134 PartialEq, 135 SpecifiedValueInfo, 136 ToComputedValue, 137 ToResolvedValue, 138 ToShmem, 139 )] 140 pub struct FontTag(pub u32); 141 142 impl ToCss for FontTag { to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,143 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 144 where 145 W: Write, 146 { 147 use byteorder::ByteOrder; 148 use std::str; 149 150 let mut raw = [0u8; 4]; 151 BigEndian::write_u32(&mut raw, self.0); 152 str::from_utf8(&raw).unwrap_or_default().to_css(dest) 153 } 154 } 155 156 impl Parse for FontTag { parse<'i, 't>( _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>157 fn parse<'i, 't>( 158 _context: &ParserContext, 159 input: &mut Parser<'i, 't>, 160 ) -> Result<Self, ParseError<'i>> { 161 let location = input.current_source_location(); 162 let tag = input.expect_string()?; 163 164 // allowed strings of length 4 containing chars: <U+20, U+7E> 165 if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') { 166 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); 167 } 168 169 let mut raw = Cursor::new(tag.as_bytes()); 170 Ok(FontTag(raw.read_u32::<BigEndian>().unwrap())) 171 } 172 } 173 174 /// A generic value for the `font-style` property. 175 /// 176 /// https://drafts.csswg.org/css-fonts-4/#font-style-prop 177 #[allow(missing_docs)] 178 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] 179 #[derive( 180 Animate, 181 Clone, 182 ComputeSquaredDistance, 183 Copy, 184 Debug, 185 Hash, 186 MallocSizeOf, 187 PartialEq, 188 SpecifiedValueInfo, 189 ToAnimatedValue, 190 ToAnimatedZero, 191 ToResolvedValue, 192 ToShmem, 193 )] 194 pub enum FontStyle<Angle> { 195 #[animation(error)] 196 Normal, 197 #[animation(error)] 198 Italic, 199 #[value_info(starts_with_keyword)] 200 Oblique(Angle), 201 } 202