diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 6f1b0d2a74f..8e8bae7a5aa 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2513,8 +2513,12 @@ fn static_assert() { <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %> - pub fn set_font_variant_alternates(&mut self, v: longhands::font_variant_alternates::computed_value::T) { + pub fn set_font_variant_alternates(&mut self, + v: longhands::font_variant_alternates::computed_value::T, + device: &Device) { use gecko_bindings::bindings::{Gecko_ClearAlternateValues, Gecko_AppendAlternateValues}; + use gecko_bindings::bindings::Gecko_nsFont_ResetFontFeatureValuesLookup; + use gecko_bindings::bindings::Gecko_nsFont_SetFontFeatureValuesLookup; % for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split(): use gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()}; % endfor @@ -2526,6 +2530,8 @@ fn static_assert() { if v.0.is_empty() { self.gecko.mFont.variantAlternates = NS_FONT_VARIANT_ALTERNATES_NORMAL as u16; + unsafe { Gecko_nsFont_ResetFontFeatureValuesLookup(&mut self.gecko.mFont); } + return; } for val in v.0.iter() { @@ -2557,6 +2563,10 @@ fn static_assert() { } } } + + unsafe { + Gecko_nsFont_SetFontFeatureValuesLookup(&mut self.gecko.mFont, device.pres_context()); + } } #[allow(non_snake_case)] diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index c2a5e3970c9..fd10112df40 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2722,12 +2722,13 @@ impl<'a> StyleBuilder<'a> { &mut self, value: longhands::${property.ident}::computed_value::T ) { + <% props_need_device = ["content", "list_style_type", "font_variant_alternates"] %> self.${property.style_struct.ident}.mutate() .set_${property.ident}( value, % if property.logical: self.writing_mode, - % elif product == "gecko" and property.ident in ["content", "list_style_type"]: + % elif product == "gecko" and property.ident in props_need_device: self.device, % endif ); diff --git a/components/style/stylesheets/font_feature_values_rule.rs b/components/style/stylesheets/font_feature_values_rule.rs index 6474cb10bf5..c76c5b09833 100644 --- a/components/style/stylesheets/font_feature_values_rule.rs +++ b/components/style/stylesheets/font_feature_values_rule.rs @@ -11,6 +11,10 @@ use computed_values::font_family::FamilyName; use cssparser::{AtRuleParser, AtRuleType, BasicParseError, DeclarationListParser, DeclarationParser, Parser}; use cssparser::{CowRcStr, RuleListParser, SourceLocation, QualifiedRuleParser, Token, serialize_identifier}; use error_reporting::{ContextualParseError, ParseErrorReporter}; +#[cfg(feature = "gecko")] +use gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry; +#[cfg(feature = "gecko")] +use gecko_bindings::structs::{self, gfxFontFeatureValueSet, nsTArray}; use parser::{ParserContext, ParserErrorContext, Parse}; use selectors::parser::SelectorParseError; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; @@ -41,6 +45,13 @@ impl ToCss for FFVDeclaration { } } +/// A trait for @font-feature-values rule to gecko values conversion. +#[cfg(feature = "gecko")] +pub trait ToGeckoFontFeatureValues { + /// Sets the equivalent of declaration to gecko `nsTArray` array. + fn to_gecko_font_feature_values(&self, array: &mut nsTArray); +} + /// A @font-feature-values block declaration value that keeps one value. #[derive(Clone, Debug, PartialEq)] pub struct SingleValue(pub u32); @@ -61,6 +72,14 @@ impl ToCss for SingleValue { } } +#[cfg(feature = "gecko")] +impl ToGeckoFontFeatureValues for SingleValue { + fn to_gecko_font_feature_values(&self, array: &mut nsTArray) { + unsafe { array.set_len_pod(1); } + array[0] = self.0 as u32; + } +} + /// A @font-feature-values block declaration value that keeps one or two values. #[derive(Clone, Debug, PartialEq)] pub struct PairValues(pub u32, pub Option); @@ -94,6 +113,19 @@ impl ToCss for PairValues { } } +#[cfg(feature = "gecko")] +impl ToGeckoFontFeatureValues for PairValues { + fn to_gecko_font_feature_values(&self, array: &mut nsTArray) { + let len = if self.1.is_some() { 2 } else { 1 }; + + unsafe { array.set_len_pod(len); } + array[0] = self.0 as u32; + if let Some(second) = self.1 { + array[1] = second as u32; + }; + } +} + /// A @font-feature-values block declaration value that keeps a list of values. #[derive(Clone, Debug, PartialEq)] pub struct VectorValues(pub Vec); @@ -136,6 +168,16 @@ impl ToCss for VectorValues { } } +#[cfg(feature = "gecko")] +impl ToGeckoFontFeatureValues for VectorValues { + fn to_gecko_font_feature_values(&self, array: &mut nsTArray) { + unsafe { array.set_len_pod(self.0.len() as u32); } + for (dest, value) in array.iter_mut().zip(self.0.iter()) { + *dest = *value; + } + } +} + /// Parses a list of `FamilyName`s. pub fn parse_family_name_list<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result, ParseError<'i>> { @@ -177,7 +219,7 @@ impl<'a, 'b, 'i, T> DeclarationParser<'i> for FFVDeclarationsParser<'a, 'b, T> macro_rules! font_feature_values_blocks { ( blocks = [ - $( #[$doc: meta] $name: tt $ident: ident / $ident_camel: ident: $ty: ty, )* + $( #[$doc: meta] $name: tt $ident: ident / $ident_camel: ident / $gecko_enum: ident: $ty: ty, )* ] ) => { /// The [`@font-feature-values`][font-feature-values] at-rule. @@ -262,6 +304,38 @@ macro_rules! font_feature_values_blocks { )* Ok(()) } + + /// Returns length of all at-rules. + pub fn len(&self) -> usize { + let mut len = 0; + $( + len += self.$ident.len(); + )* + len + } + + /// Convert to Gecko gfxFontFeatureValueSet. + #[cfg(feature = "gecko")] + pub fn set_at_rules(&self, dest: *mut gfxFontFeatureValueSet) { + for ref family in self.family_names.iter() { + let family = family.name.to_ascii_lowercase(); + $( + if self.$ident.len() > 0 { + for val in self.$ident.iter() { + let mut array = unsafe { + Gecko_AppendFeatureValueHashEntry( + dest, + family.as_ptr(), + structs::$gecko_enum, + val.name.as_ptr() + ) + }; + val.value.to_gecko_font_feature_values(&mut array); + } + } + )* + } + } } impl ToCssWithGuard for FontFeatureValuesRule { @@ -366,31 +440,32 @@ font_feature_values_blocks! { #[doc = "A @swash blocksck. \ Specifies a feature name that will work with the swash() \ functional notation of font-variant-alternates."] - "swash" swash / Swash: SingleValue, + "swash" swash / Swash / NS_FONT_VARIANT_ALTERNATES_SWASH: SingleValue, #[doc = "A @stylistic block. \ Specifies a feature name that will work with the annotation() \ functional notation of font-variant-alternates."] - "stylistic" stylistic / Stylistic: SingleValue, + "stylistic" stylistic / Stylistic / NS_FONT_VARIANT_ALTERNATES_STYLISTIC: SingleValue, #[doc = "A @ornaments block. \ Specifies a feature name that will work with the ornaments() ] \ functional notation of font-variant-alternates."] - "ornaments" ornaments / Ornaments: SingleValue, + "ornaments" ornaments / Ornaments / NS_FONT_VARIANT_ALTERNATES_ORNAMENTS: SingleValue, #[doc = "A @annotation block. \ Specifies a feature name that will work with the stylistic() \ functional notation of font-variant-alternates."] - "annotation" annotation / Annotation: SingleValue, + "annotation" annotation / Annotation / NS_FONT_VARIANT_ALTERNATES_ANNOTATION: SingleValue, #[doc = "A @character-variant block. \ Specifies a feature name that will work with the styleset() \ functional notation of font-variant-alternates. The value can be a pair."] - "character-variant" character_variant / CharacterVariant: PairValues, + "character-variant" character_variant / CharacterVariant / NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT: + PairValues, #[doc = "A @styleset block. \ Specifies a feature name that will work with the character-variant() \ functional notation of font-variant-alternates. The value can be a list."] - "styleset" styleset / Styleset: VectorValues, + "styleset" styleset / Styleset / NS_FONT_VARIANT_ALTERNATES_STYLESET: VectorValues, ] } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index b8e587dad92..6e92058a96e 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -40,7 +40,7 @@ use std::ops; use style_traits::viewport::ViewportConstraints; use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, StylesheetIterator, StylesheetFlusher}; #[cfg(feature = "gecko")] -use stylesheets::{CounterStyleRule, FontFaceRule}; +use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule}; use stylesheets::{CssRule, StyleRule}; use stylesheets::{StylesheetInDocument, Origin, OriginSet, PerOrigin, PerOriginIter}; use stylesheets::UserAgentStylesheets; @@ -338,13 +338,19 @@ impl DocumentCascadeData { CssRule::FontFace(ref rule) => { _extra_data .borrow_mut_for_origin(&origin) - .add_font_face(&rule); + .add_font_face(rule); + } + #[cfg(feature = "gecko")] + CssRule::FontFeatureValues(ref rule) => { + _extra_data + .borrow_mut_for_origin(&origin) + .add_font_feature_values(rule); } #[cfg(feature = "gecko")] CssRule::CounterStyle(ref rule) => { _extra_data .borrow_mut_for_origin(&origin) - .add_counter_style(guard, &rule); + .add_counter_style(guard, rule); } // We don't care about any other rule. _ => {} @@ -1516,6 +1522,10 @@ pub struct ExtraStyleData { #[cfg(feature = "gecko")] pub font_faces: Vec>>, + /// A list of effective font-feature-values rules. + #[cfg(feature = "gecko")] + pub font_feature_values: Vec>>, + /// A map of effective counter-style rules. #[cfg(feature = "gecko")] pub counter_styles: PrecomputedHashMap>>, @@ -1528,6 +1538,11 @@ impl ExtraStyleData { self.font_faces.push(rule.clone()); } + /// Add the given @font-feature-values rule. + fn add_font_feature_values(&mut self, rule: &Arc>) { + self.font_feature_values.push(rule.clone()); + } + /// Add the given @counter-style rule. fn add_counter_style( &mut self, @@ -1544,6 +1559,7 @@ impl ExtraStyleData { #[cfg(feature = "gecko")] { self.font_faces.clear(); + self.font_feature_values.clear(); self.counter_styles.clear(); } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 0270c30bcf4..85c9362d05b 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -87,6 +87,7 @@ use style::gecko_bindings::structs::ServoElementSnapshotTable; use style::gecko_bindings::structs::ServoTraversalFlags; use style::gecko_bindings::structs::StyleRuleInclusion; use style::gecko_bindings::structs::URLExtraData; +use style::gecko_bindings::structs::gfxFontFeatureValueSet; use style::gecko_bindings::structs::nsCSSValueSharedList; use style::gecko_bindings::structs::nsCompatibility; use style::gecko_bindings::structs::nsIDocument; @@ -3517,6 +3518,30 @@ pub extern "C" fn Servo_StyleSet_GetCounterStyleRule(raw_data: RawServoStyleSetB }).unwrap_or(ptr::null_mut()) } +#[no_mangle] +pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet( + raw_data: RawServoStyleSetBorrowed, + set: *mut gfxFontFeatureValueSet +) -> bool { + let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); + + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + + let font_feature_values_iter = data.extra_style_data + .iter_origins_rev() + .flat_map(|(d, _)| d.font_feature_values.iter()); + + let mut any_rule = false; + for src in font_feature_values_iter { + any_rule = true; + let rule = src.read_with(&guard); + rule.set_at_rules(set); + } + + any_rule +} + #[no_mangle] pub extern "C" fn Servo_StyleSet_ResolveForDeclarations( raw_data: RawServoStyleSetBorrowed,