diff options
Diffstat (limited to 'servo/components/style/stylesheets/font_palette_values_rule.rs')
-rw-r--r-- | servo/components/style/stylesheets/font_palette_values_rule.rs | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/servo/components/style/stylesheets/font_palette_values_rule.rs b/servo/components/style/stylesheets/font_palette_values_rule.rs new file mode 100644 index 0000000000..400d348215 --- /dev/null +++ b/servo/components/style/stylesheets/font_palette_values_rule.rs @@ -0,0 +1,264 @@ +/* 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/. */ + +//! The [`@font-palette-values`][font-palette-values] at-rule. +//! +//! [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values + +use crate::error_reporting::ContextualParseError; +use crate::gecko_bindings::bindings::Gecko_AppendPaletteValueHashEntry; +use crate::gecko_bindings::bindings::{Gecko_SetFontPaletteBase, Gecko_SetFontPaletteOverride}; +use crate::gecko_bindings::structs::gfx::FontPaletteValueSet; +use crate::gecko_bindings::structs::gfx::FontPaletteValueSet_PaletteValues_kDark; +use crate::gecko_bindings::structs::gfx::FontPaletteValueSet_PaletteValues_kLight; +use crate::parser::{Parse, ParserContext}; +use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; +use crate::str::CssStringWriter; +use crate::stylesheets::font_feature_values_rule::parse_family_name_list; +use crate::values::computed::font::FamilyName; +use crate::values::specified::Color as SpecifiedColor; +use crate::values::specified::NonNegativeInteger; +use crate::values::DashedIdent; +use cssparser::{ + AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser, RuleBodyItemParser, + RuleBodyParser, SourceLocation, +}; +use selectors::parser::SelectorParseErrorKind; +use std::fmt::{self, Write}; +use style_traits::{Comma, OneOrMoreSeparated}; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; + +#[allow(missing_docs)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] +pub struct FontPaletteOverrideColor { + index: NonNegativeInteger, + color: SpecifiedColor, +} + +impl Parse for FontPaletteOverrideColor { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<FontPaletteOverrideColor, ParseError<'i>> { + let index = NonNegativeInteger::parse(context, input)?; + let location = input.current_source_location(); + let color = SpecifiedColor::parse(context, input)?; + // Only absolute colors are accepted here. + if let SpecifiedColor::Absolute { .. } = color { + Ok(FontPaletteOverrideColor { index, color }) + } else { + Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } +} + +impl ToCss for FontPaletteOverrideColor { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: fmt::Write, + { + self.index.to_css(dest)?; + dest.write_char(' ')?; + self.color.to_css(dest) + } +} + +impl OneOrMoreSeparated for FontPaletteOverrideColor { + type S = Comma; +} + +impl OneOrMoreSeparated for FamilyName { + type S = Comma; +} + +#[allow(missing_docs)] +#[derive(Clone, Debug, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)] +pub enum FontPaletteBase { + Light, + Dark, + Index(NonNegativeInteger), +} + +/// The [`@font-palette-values`][font-palette-values] at-rule. +/// +/// [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values +#[derive(Clone, Debug, PartialEq, ToShmem)] +pub struct FontPaletteValuesRule { + /// Palette name. + pub name: DashedIdent, + /// Font family list for @font-palette-values rule. + /// Family names cannot contain generic families. FamilyName + /// also accepts only non-generic names. + pub family_names: Vec<FamilyName>, + /// The base palette. + pub base_palette: Option<FontPaletteBase>, + /// The list of override colors. + pub override_colors: Vec<FontPaletteOverrideColor>, + /// The line and column of the rule's source code. + pub source_location: SourceLocation, +} + +impl FontPaletteValuesRule { + /// Creates an empty FontPaletteValuesRule with given location and name. + fn new(name: DashedIdent, location: SourceLocation) -> Self { + FontPaletteValuesRule { + name, + family_names: vec![], + base_palette: None, + override_colors: vec![], + source_location: location, + } + } + + /// Parses a `FontPaletteValuesRule`. + pub fn parse( + context: &ParserContext, + input: &mut Parser, + name: DashedIdent, + location: SourceLocation, + ) -> Self { + let mut rule = FontPaletteValuesRule::new(name, location); + let mut parser = FontPaletteValuesDeclarationParser { + context, + rule: &mut rule, + }; + let mut iter = RuleBodyParser::new(input, &mut parser); + while let Some(declaration) = iter.next() { + if let Err((error, slice)) = declaration { + let location = error.location; + let error = + ContextualParseError::UnsupportedFontPaletteValuesDescriptor(slice, error); + context.log_css_error(location, error); + } + } + rule + } + + /// Prints inside of `@font-palette-values` block. + fn value_to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + if !self.family_names.is_empty() { + dest.write_str("font-family: ")?; + self.family_names.to_css(dest)?; + dest.write_str("; ")?; + } + if let Some(base) = &self.base_palette { + dest.write_str("base-palette: ")?; + base.to_css(dest)?; + dest.write_str("; ")?; + } + if !self.override_colors.is_empty() { + dest.write_str("override-colors: ")?; + self.override_colors.to_css(dest)?; + dest.write_str("; ")?; + } + Ok(()) + } + + /// Convert to Gecko FontPaletteValueSet. + pub fn to_gecko_palette_value_set(&self, dest: *mut FontPaletteValueSet) { + for ref family in self.family_names.iter() { + let family = family.name.to_ascii_lowercase(); + let palette_values = unsafe { + Gecko_AppendPaletteValueHashEntry(dest, family.as_ptr(), self.name.0.as_ptr()) + }; + if let Some(base_palette) = &self.base_palette { + unsafe { + Gecko_SetFontPaletteBase( + palette_values, + match &base_palette { + FontPaletteBase::Light => FontPaletteValueSet_PaletteValues_kLight, + FontPaletteBase::Dark => FontPaletteValueSet_PaletteValues_kDark, + FontPaletteBase::Index(i) => i.0.value() as i32, + }, + ); + } + } + for c in &self.override_colors { + if let SpecifiedColor::Absolute(ref absolute) = c.color { + unsafe { + Gecko_SetFontPaletteOverride( + palette_values, + c.index.0.value(), + (&absolute.color) as *const _ as *mut _, + ); + } + } + } + } + } +} + +impl ToCssWithGuard for FontPaletteValuesRule { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { + dest.write_str("@font-palette-values ")?; + self.name.to_css(&mut CssWriter::new(dest))?; + dest.write_str(" { ")?; + self.value_to_css(&mut CssWriter::new(dest))?; + dest.write_char('}') + } +} + +/// Parser for declarations in `FontPaletteValuesRule`. +struct FontPaletteValuesDeclarationParser<'a> { + context: &'a ParserContext<'a>, + rule: &'a mut FontPaletteValuesRule, +} + +impl<'a, 'i> AtRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> { + type Prelude = (); + type AtRule = (); + type Error = StyleParseErrorKind<'i>; +} + +impl<'a, 'i> QualifiedRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> { + type Prelude = (); + type QualifiedRule = (); + type Error = StyleParseErrorKind<'i>; +} + +fn parse_override_colors<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, +) -> Result<Vec<FontPaletteOverrideColor>, ParseError<'i>> { + input.parse_comma_separated(|i| FontPaletteOverrideColor::parse(context, i)) +} + +impl<'a, 'b, 'i> DeclarationParser<'i> for FontPaletteValuesDeclarationParser<'a> { + type Declaration = (); + type Error = StyleParseErrorKind<'i>; + + fn parse_value<'t>( + &mut self, + name: CowRcStr<'i>, + input: &mut Parser<'i, 't>, + ) -> Result<(), ParseError<'i>> { + match_ignore_ascii_case! { &*name, + "font-family" => { + self.rule.family_names = parse_family_name_list(self.context, input)? + }, + "base-palette" => { + self.rule.base_palette = Some(input.parse_entirely(|i| FontPaletteBase::parse(self.context, i))?) + }, + "override-colors" => { + self.rule.override_colors = parse_override_colors(self.context, input)? + }, + _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))), + } + Ok(()) + } +} + +impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> + for FontPaletteValuesDeclarationParser<'a> +{ + fn parse_declarations(&self) -> bool { + true + } + fn parse_qualified(&self) -> bool { + false + } +} |