tor-browser

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

font_palette_values_rule.rs (9874B)


      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 //! The [`@font-palette-values`][font-palette-values] at-rule.
      6 //!
      7 //! [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values
      8 
      9 use crate::derives::*;
     10 use crate::error_reporting::ContextualParseError;
     11 #[cfg(feature = "gecko")]
     12 use crate::gecko_bindings::{
     13    bindings::Gecko_AppendPaletteValueHashEntry,
     14    bindings::{Gecko_SetFontPaletteBase, Gecko_SetFontPaletteOverride},
     15    structs::gfx::FontPaletteValueSet,
     16    structs::gfx::FontPaletteValueSet_PaletteValues_kDark,
     17    structs::gfx::FontPaletteValueSet_PaletteValues_kLight,
     18 };
     19 use crate::parser::{Parse, ParserContext};
     20 use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
     21 use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
     22 use crate::values::computed::font::FamilyName;
     23 use crate::values::specified::Color as SpecifiedColor;
     24 use crate::values::specified::NonNegativeInteger;
     25 use crate::values::DashedIdent;
     26 use cssparser::{
     27    match_ignore_ascii_case, AtRuleParser, CowRcStr, DeclarationParser, Parser, ParserState,
     28    QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation,
     29 };
     30 use selectors::parser::SelectorParseErrorKind;
     31 use std::fmt::{self, Write};
     32 use style_traits::{Comma, OneOrMoreSeparated};
     33 use style_traits::{CssStringWriter, CssWriter, ParseError, StyleParseErrorKind, ToCss};
     34 
     35 #[allow(missing_docs)]
     36 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
     37 pub struct FontPaletteOverrideColor {
     38    index: NonNegativeInteger,
     39    color: SpecifiedColor,
     40 }
     41 
     42 impl Parse for FontPaletteOverrideColor {
     43    fn parse<'i, 't>(
     44        context: &ParserContext,
     45        input: &mut Parser<'i, 't>,
     46    ) -> Result<FontPaletteOverrideColor, ParseError<'i>> {
     47        let index = NonNegativeInteger::parse(context, input)?;
     48        let location = input.current_source_location();
     49        let color = SpecifiedColor::parse(context, input)?;
     50        // Only absolute colors are accepted here:
     51        //   https://drafts.csswg.org/css-fonts/#override-color
     52        //   https://drafts.csswg.org/css-color-5/#absolute-color
     53        // so check that the specified color can be resolved without a context
     54        // or currentColor value.
     55        if color.resolve_to_absolute().is_some() {
     56            // We store the specified color (not the resolved absolute color)
     57            // because that is what the rule exposes to authors.
     58            return Ok(FontPaletteOverrideColor { index, color });
     59        }
     60        Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
     61    }
     62 }
     63 
     64 impl ToCss for FontPaletteOverrideColor {
     65    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     66    where
     67        W: fmt::Write,
     68    {
     69        self.index.to_css(dest)?;
     70        dest.write_char(' ')?;
     71        self.color.to_css(dest)
     72    }
     73 }
     74 
     75 impl OneOrMoreSeparated for FontPaletteOverrideColor {
     76    type S = Comma;
     77 }
     78 
     79 impl OneOrMoreSeparated for FamilyName {
     80    type S = Comma;
     81 }
     82 
     83 #[allow(missing_docs)]
     84 #[derive(Clone, Debug, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
     85 pub enum FontPaletteBase {
     86    Light,
     87    Dark,
     88    Index(NonNegativeInteger),
     89 }
     90 
     91 /// The [`@font-palette-values`][font-palette-values] at-rule.
     92 ///
     93 /// [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values
     94 #[derive(Clone, Debug, PartialEq, ToShmem)]
     95 pub struct FontPaletteValuesRule {
     96    /// Palette name.
     97    pub name: DashedIdent,
     98    /// Font family list for @font-palette-values rule.
     99    /// Family names cannot contain generic families. FamilyName
    100    /// also accepts only non-generic names.
    101    pub family_names: Vec<FamilyName>,
    102    /// The base palette.
    103    pub base_palette: Option<FontPaletteBase>,
    104    /// The list of override colors.
    105    pub override_colors: Vec<FontPaletteOverrideColor>,
    106    /// The line and column of the rule's source code.
    107    pub source_location: SourceLocation,
    108 }
    109 
    110 impl FontPaletteValuesRule {
    111    /// Creates an empty FontPaletteValuesRule with given location and name.
    112    fn new(name: DashedIdent, location: SourceLocation) -> Self {
    113        FontPaletteValuesRule {
    114            name,
    115            family_names: vec![],
    116            base_palette: None,
    117            override_colors: vec![],
    118            source_location: location,
    119        }
    120    }
    121 
    122    /// Parses a `FontPaletteValuesRule`.
    123    pub fn parse(
    124        context: &ParserContext,
    125        input: &mut Parser,
    126        name: DashedIdent,
    127        location: SourceLocation,
    128    ) -> Self {
    129        let mut rule = FontPaletteValuesRule::new(name, location);
    130        let mut parser = FontPaletteValuesDeclarationParser {
    131            context,
    132            rule: &mut rule,
    133        };
    134        let mut iter = RuleBodyParser::new(input, &mut parser);
    135        while let Some(declaration) = iter.next() {
    136            if let Err((error, slice)) = declaration {
    137                let location = error.location;
    138                let error =
    139                    ContextualParseError::UnsupportedFontPaletteValuesDescriptor(slice, error);
    140                context.log_css_error(location, error);
    141            }
    142        }
    143        rule
    144    }
    145 
    146    /// Prints inside of `@font-palette-values` block.
    147    fn value_to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    148    where
    149        W: Write,
    150    {
    151        if !self.family_names.is_empty() {
    152            dest.write_str("font-family: ")?;
    153            self.family_names.to_css(dest)?;
    154            dest.write_str("; ")?;
    155        }
    156        if let Some(base) = &self.base_palette {
    157            dest.write_str("base-palette: ")?;
    158            base.to_css(dest)?;
    159            dest.write_str("; ")?;
    160        }
    161        if !self.override_colors.is_empty() {
    162            dest.write_str("override-colors: ")?;
    163            self.override_colors.to_css(dest)?;
    164            dest.write_str("; ")?;
    165        }
    166        Ok(())
    167    }
    168 
    169    /// Convert to Gecko FontPaletteValueSet.
    170    #[cfg(feature = "gecko")]
    171    pub fn to_gecko_palette_value_set(&self, dest: *mut FontPaletteValueSet) {
    172        for ref family in self.family_names.iter() {
    173            let family = family.name.to_ascii_lowercase();
    174            let palette_values = unsafe {
    175                Gecko_AppendPaletteValueHashEntry(dest, family.as_ptr(), self.name.0.as_ptr())
    176            };
    177            if let Some(base_palette) = &self.base_palette {
    178                unsafe {
    179                    Gecko_SetFontPaletteBase(
    180                        palette_values,
    181                        match &base_palette {
    182                            FontPaletteBase::Light => FontPaletteValueSet_PaletteValues_kLight,
    183                            FontPaletteBase::Dark => FontPaletteValueSet_PaletteValues_kDark,
    184                            FontPaletteBase::Index(i) => i.0.value() as i32,
    185                        },
    186                    );
    187                }
    188            }
    189            for c in &self.override_colors {
    190                // We checked at parse time that the specified color can be resolved
    191                // in this way, so the unwrap() here will succeed.
    192                let absolute = c.color.resolve_to_absolute().unwrap();
    193                unsafe {
    194                    Gecko_SetFontPaletteOverride(
    195                        palette_values,
    196                        c.index.0.value(),
    197                        (&absolute) as *const _ as *mut _,
    198                    );
    199                }
    200            }
    201        }
    202    }
    203 }
    204 
    205 impl ToCssWithGuard for FontPaletteValuesRule {
    206    fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
    207        dest.write_str("@font-palette-values ")?;
    208        self.name.to_css(&mut CssWriter::new(dest))?;
    209        dest.write_str(" { ")?;
    210        self.value_to_css(&mut CssWriter::new(dest))?;
    211        dest.write_char('}')
    212    }
    213 }
    214 
    215 /// Parser for declarations in `FontPaletteValuesRule`.
    216 struct FontPaletteValuesDeclarationParser<'a> {
    217    context: &'a ParserContext<'a>,
    218    rule: &'a mut FontPaletteValuesRule,
    219 }
    220 
    221 impl<'a, 'i> AtRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> {
    222    type Prelude = ();
    223    type AtRule = ();
    224    type Error = StyleParseErrorKind<'i>;
    225 }
    226 
    227 impl<'a, 'i> QualifiedRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> {
    228    type Prelude = ();
    229    type QualifiedRule = ();
    230    type Error = StyleParseErrorKind<'i>;
    231 }
    232 
    233 fn parse_override_colors<'i, 't>(
    234    context: &ParserContext,
    235    input: &mut Parser<'i, 't>,
    236 ) -> Result<Vec<FontPaletteOverrideColor>, ParseError<'i>> {
    237    input.parse_comma_separated(|i| FontPaletteOverrideColor::parse(context, i))
    238 }
    239 
    240 impl<'a, 'b, 'i> DeclarationParser<'i> for FontPaletteValuesDeclarationParser<'a> {
    241    type Declaration = ();
    242    type Error = StyleParseErrorKind<'i>;
    243 
    244    fn parse_value<'t>(
    245        &mut self,
    246        name: CowRcStr<'i>,
    247        input: &mut Parser<'i, 't>,
    248        _declaration_start: &ParserState,
    249    ) -> Result<(), ParseError<'i>> {
    250        match_ignore_ascii_case! { &*name,
    251            "font-family" => {
    252                self.rule.family_names = parse_family_name_list(self.context, input)?
    253            },
    254            "base-palette" => {
    255                self.rule.base_palette = Some(input.parse_entirely(|i| FontPaletteBase::parse(self.context, i))?)
    256            },
    257            "override-colors" => {
    258                self.rule.override_colors = parse_override_colors(self.context, input)?
    259            },
    260            _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
    261        }
    262        Ok(())
    263    }
    264 }
    265 
    266 impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
    267    for FontPaletteValuesDeclarationParser<'a>
    268 {
    269    fn parse_declarations(&self) -> bool {
    270        true
    271    }
    272    fn parse_qualified(&self) -> bool {
    273        false
    274    }
    275 }