diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 29d217bfb5b..0a30b4152d9 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -442,6 +442,7 @@ class Longhand(Property): "Display", "FillRule", "Float", + "FontLanguageOverride", "FontSizeAdjust", "FontStretch", "FontStyle", diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index 43744c078a1..c3833a25420 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -223,7 +223,7 @@ ${helpers.predefined_type( "font-language-override", "FontLanguageOverride", engines="gecko", - initial_value="computed::FontLanguageOverride::zero()", + initial_value="computed::FontLanguageOverride::normal()", initial_specified_value="specified::FontLanguageOverride::normal()", animation_value_type="discrete", extra_prefixes="moz:layout.css.prefixes.font-features", diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index c093b4091c8..900a0a0dc5d 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -855,18 +855,30 @@ where } } -/// font-language-override can only have a single three-letter +/// font-language-override can only have a single 1-4 ASCII character /// OpenType "language system" tag, so we should be able to compute /// it and store it as a 32-bit integer /// (see http://www.microsoft.com/typography/otspec/languagetags.htm). -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToResolvedValue)] +#[derive( + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem +)] #[repr(C)] +#[value_info(other_values = "normal")] pub struct FontLanguageOverride(pub u32); impl FontLanguageOverride { #[inline] /// Get computed default value of `font-language-override` with 0 - pub fn zero() -> FontLanguageOverride { + pub fn normal() -> FontLanguageOverride { FontLanguageOverride(0) } @@ -874,7 +886,7 @@ impl FontLanguageOverride { #[inline] pub(crate) fn to_str(self, storage: &mut [u8; 4]) -> &str { *storage = u32::to_be_bytes(self.0); - // Safe because we ensure it's ASCII during computing + // Safe because we ensure it's ASCII during parsing let slice = if cfg!(debug_assertions) { std::str::from_utf8(&storage[..]).unwrap() } else { @@ -883,23 +895,6 @@ impl FontLanguageOverride { slice.trim_end() } - /// Parses a str, return `Self::zero()` if the input isn't a valid OpenType - /// "language system" tag. - #[inline] - pub fn from_str(lang: &str) -> Self { - if lang.is_empty() || lang.len() > 4 { - return Self::zero(); - } - let mut bytes = [b' '; 4]; - for (byte, lang_byte) in bytes.iter_mut().zip(lang.as_bytes()) { - if !lang_byte.is_ascii() { - return Self::zero(); - } - *byte = *lang_byte; - } - Self(u32::from_be_bytes(bytes)) - } - /// Unsafe because `Self::to_str` requires the value to represent a UTF-8 /// string. #[inline] diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 41ae1e49a92..a73e658a2fc 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -1743,55 +1743,8 @@ impl Parse for FontVariantNumeric { /// This property provides low-level control over OpenType or TrueType font features. pub type FontFeatureSettings = FontSettings>; -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] -/// Allows authors to explicitly specify the language system of the font, -/// overriding the language system implied by the content language -pub enum FontLanguageOverride { - /// When rendering with OpenType fonts, - /// the content language of the element is - /// used to infer the OpenType language system - Normal, - /// Single three-letter case-sensitive OpenType language system tag, - /// specifies the OpenType language system to be used instead of - /// the language system implied by the language of the element - Override(Box), -} - -impl FontLanguageOverride { - #[inline] - /// Get default value with `normal` - pub fn normal() -> FontLanguageOverride { - FontLanguageOverride::Normal - } - - /// The ToComputedValue implementation for non-system-font - /// FontLanguageOverride, used for @font-face descriptors. - #[inline] - pub fn compute_non_system(&self) -> computed::FontLanguageOverride { - match *self { - FontLanguageOverride::Normal => computed::FontLanguageOverride::zero(), - FontLanguageOverride::Override(ref lang) => { - computed::FontLanguageOverride::from_str(lang) - }, - } - } -} - -impl ToComputedValue for FontLanguageOverride { - type ComputedValue = computed::FontLanguageOverride; - - #[inline] - fn to_computed_value(&self, _: &Context) -> computed::FontLanguageOverride { - self.compute_non_system() - } - #[inline] - fn from_computed_value(computed: &computed::FontLanguageOverride) -> Self { - if *computed == computed::FontLanguageOverride::zero() { - return FontLanguageOverride::Normal; - } - FontLanguageOverride::Override(computed.to_str(&mut [0; 4]).into()) - } -} +/// For font-language-override, use the same representation as the computed value. +pub use crate::values::computed::font::FontLanguageOverride; impl Parse for FontLanguageOverride { /// normal | @@ -1803,13 +1756,23 @@ impl Parse for FontLanguageOverride { .try_parse(|input| input.expect_ident_matching("normal")) .is_ok() { - return Ok(FontLanguageOverride::Normal); + return Ok(FontLanguageOverride::normal()); } let string = input.expect_string()?; - Ok(FontLanguageOverride::Override( - string.as_ref().to_owned().into_boxed_str(), - )) + + // The OpenType spec requires tags to be 1 to 4 ASCII characters: + // https://learn.microsoft.com/en-gb/typography/opentype/spec/otff#data-types + if string.is_empty() || string.len() > 4 || !string.is_ascii() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + let mut bytes = [b' '; 4]; + for (byte, str_byte) in bytes.iter_mut().zip(string.as_bytes()) { + *byte = *str_byte; + } + + Ok(FontLanguageOverride(u32::from_be_bytes(bytes))) } }