tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }