font.rs (8369B)
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::derives::*; 8 use crate::parser::{Parse, ParserContext}; 9 use crate::values::animated::ToAnimatedZero; 10 use crate::{One, Zero}; 11 use byteorder::{BigEndian, ReadBytesExt}; 12 use cssparser::Parser; 13 use std::fmt::{self, Write}; 14 use std::io::Cursor; 15 use style_traits::{CssWriter, ParseError}; 16 use style_traits::{StyleParseErrorKind, ToCss}; 17 18 /// A trait for values that are labelled with a FontTag (for feature and 19 /// variation settings). 20 pub trait TaggedFontValue { 21 /// The value's tag. 22 fn tag(&self) -> FontTag; 23 } 24 25 /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value 26 #[derive( 27 Clone, 28 Debug, 29 Eq, 30 MallocSizeOf, 31 PartialEq, 32 SpecifiedValueInfo, 33 ToAnimatedValue, 34 ToComputedValue, 35 ToResolvedValue, 36 ToShmem, 37 )] 38 pub struct FeatureTagValue<Integer> { 39 /// A four-character tag, packed into a u32 (one byte per character). 40 pub tag: FontTag, 41 /// The actual value. 42 pub value: Integer, 43 } 44 45 impl<T> TaggedFontValue for FeatureTagValue<T> { 46 fn tag(&self) -> FontTag { 47 self.tag 48 } 49 } 50 51 impl<Integer> ToCss for FeatureTagValue<Integer> 52 where 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 // Don't serialize the default value. 61 if !self.value.is_one() { 62 dest.write_char(' ')?; 63 self.value.to_css(dest)?; 64 } 65 66 Ok(()) 67 } 68 } 69 70 /// Variation setting for a single feature, see: 71 /// 72 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def 73 #[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))] 89 pub struct VariationValue<Number> { 90 /// A four-character tag, packed into a u32 (one byte per character). 91 #[animation(constant)] 92 pub tag: FontTag, 93 /// The actual value. 94 pub value: Number, 95 } 96 97 impl<T> TaggedFontValue for VariationValue<T> { 98 fn tag(&self) -> FontTag { 99 self.tag 100 } 101 } 102 103 /// A value both for font-variation-settings and font-feature-settings. 104 #[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)] 119 pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>); 120 121 impl<T> FontSettings<T> { 122 /// Default value of font settings as `normal`. 123 #[inline] 124 pub fn normal() -> Self { 125 FontSettings(vec![].into_boxed_slice()) 126 } 127 } 128 129 impl<T: Parse> Parse for FontSettings<T> { 130 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings 131 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def 132 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 /// A font four-character tag, represented as a u32 for convenience. 152 /// 153 /// See: 154 /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def 155 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings 156 /// 157 #[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))] 171 pub struct FontTag(pub u32); 172 173 impl 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 187 impl 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 // allowed strings of length 4 containing chars: <U+20, U+7E> 196 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 /// A generic value for the `font-style` property. 206 /// 207 /// https://drafts.csswg.org/css-fonts-4/#font-style-prop 208 #[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")] 226 pub enum FontStyle<Angle> { 227 // Note that 'oblique 0deg' represents 'normal', and will serialize as such. 228 #[value_info(starts_with_keyword)] 229 Oblique(Angle), 230 #[animation(error)] 231 Italic, 232 } 233 234 impl<Angle: Zero> FontStyle<Angle> { 235 /// Return the 'normal' value, which is represented as 'oblique 0deg'. 236 pub fn normal() -> Self { 237 Self::Oblique(Angle::zero()) 238 } 239 } 240 241 /// A generic value for the `font-size-adjust` property. 242 /// 243 /// https://drafts.csswg.org/css-fonts-5/#font-size-adjust-prop 244 #[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 )] 263 pub 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 278 impl<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 /// A generic value for the `line-height` property. 298 #[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)] 315 pub enum GenericLineHeight<N, L> { 316 /// `normal` 317 Normal, 318 /// `-moz-block-height` 319 #[cfg(feature = "gecko")] 320 #[parse(condition = "ParserContext::in_ua_sheet")] 321 MozBlockHeight, 322 /// `<number>` 323 Number(N), 324 /// `<length-percentage>` 325 Length(L), 326 } 327 328 pub use self::GenericLineHeight as LineHeight; 329 330 impl<N, L> ToAnimatedZero for LineHeight<N, L> { 331 #[inline] 332 fn to_animated_zero(&self) -> Result<Self, ()> { 333 Err(()) 334 } 335 } 336 337 impl<N, L> LineHeight<N, L> { 338 /// Returns `normal`. 339 #[inline] 340 pub fn normal() -> Self { 341 LineHeight::Normal 342 } 343 }