/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Generic types for font stuff. use crate::parser::{Parse, ParserContext}; use crate::One; use byteorder::{BigEndian, ReadBytesExt}; use cssparser::Parser; use std::fmt::{self, Write}; use std::io::Cursor; use style_traits::{CssWriter, ParseError}; use style_traits::{StyleParseErrorKind, ToCss}; /// A trait for values that are labelled with a FontTag (for feature and /// variation settings). pub trait TaggedFontValue { /// The value's tag. fn tag(&self) -> FontTag; } /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value #[derive( Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, )] pub struct FeatureTagValue { /// A four-character tag, packed into a u32 (one byte per character). pub tag: FontTag, /// The actual value. pub value: Integer, } impl TaggedFontValue for FeatureTagValue { fn tag(&self) -> FontTag { self.tag } } impl ToCss for FeatureTagValue where Integer: One + ToCss + PartialEq, { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: Write, { self.tag.to_css(dest)?; // Don't serialize the default value. if !self.value.is_one() { dest.write_char(' ')?; self.value.to_css(dest)?; } Ok(()) } } /// Variation setting for a single feature, see: /// /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def #[derive( Animate, Clone, ComputeSquaredDistance, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] pub struct VariationValue { /// A four-character tag, packed into a u32 (one byte per character). #[animation(constant)] pub tag: FontTag, /// The actual value. pub value: Number, } impl TaggedFontValue for VariationValue { fn tag(&self) -> FontTag { self.tag } } /// A value both for font-variation-settings and font-feature-settings. #[derive( Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToResolvedValue, ToShmem, )] #[css(comma)] pub struct FontSettings(#[css(if_empty = "normal", iterable)] pub Box<[T]>); impl FontSettings { /// Default value of font settings as `normal`. #[inline] pub fn normal() -> Self { FontSettings(vec![].into_boxed_slice()) } } impl Parse for FontSettings { /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { if input .try_parse(|i| i.expect_ident_matching("normal")) .is_ok() { return Ok(Self::normal()); } Ok(FontSettings( input .parse_comma_separated(|i| T::parse(context, i))? .into_boxed_slice(), )) } } /// A font four-character tag, represented as a u32 for convenience. /// /// See: /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings /// #[derive( Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, )] pub struct FontTag(pub u32); impl ToCss for FontTag { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: Write, { use byteorder::ByteOrder; use std::str; let mut raw = [0u8; 4]; BigEndian::write_u32(&mut raw, self.0); str::from_utf8(&raw).unwrap_or_default().to_css(dest) } } impl Parse for FontTag { fn parse<'i, 't>( _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { let location = input.current_source_location(); let tag = input.expect_string()?; // allowed strings of length 4 containing chars: if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') { return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } let mut raw = Cursor::new(tag.as_bytes()); Ok(FontTag(raw.read_u32::().unwrap())) } } /// A generic value for the `font-style` property. /// /// https://drafts.csswg.org/css-fonts-4/#font-style-prop #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive( Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToResolvedValue, ToShmem, )] pub enum FontStyle { #[animation(error)] Normal, #[animation(error)] Italic, #[value_info(starts_with_keyword)] Oblique(Angle), } /// A generic value for the `font-size-adjust` property. /// /// https://www.w3.org/TR/css-fonts-4/#font-size-adjust-prop /// https://github.com/w3c/csswg-drafts/issues/6160 /// https://github.com/w3c/csswg-drafts/issues/6288 #[allow(missing_docs)] #[repr(u8)] #[derive( Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToResolvedValue, ToShmem, )] pub enum GenericFontSizeAdjust { #[animation(error)] None, // 'ex-height' is the implied basis, so the keyword can be omitted ExHeight(Number), #[value_info(starts_with_keyword)] CapHeight(Number), #[value_info(starts_with_keyword)] ChWidth(Number), #[value_info(starts_with_keyword)] IcWidth(Number), #[value_info(starts_with_keyword)] IcHeight(Number), } impl ToCss for GenericFontSizeAdjust { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: Write, { let (prefix, value) = match self { Self::None => return dest.write_str("none"), Self::ExHeight(v) => ("", v), Self::CapHeight(v) => ("cap-height ", v), Self::ChWidth(v) => ("ch-width ", v), Self::IcWidth(v) => ("ic-width ", v), Self::IcHeight(v) => ("ic-height ", v), }; dest.write_str(prefix)?; value.to_css(dest) } }