diff options
-rw-r--r-- | components/style/macros.rs | 10 | ||||
-rw-r--r-- | components/style/properties/longhand/font.mako.rs | 154 | ||||
-rw-r--r-- | components/style/values/computed/font.rs | 3 | ||||
-rw-r--r-- | components/style/values/computed/mod.rs | 3 | ||||
-rw-r--r-- | components/style/values/specified/font.rs | 244 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 3 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 1 |
7 files changed, 270 insertions, 148 deletions
diff --git a/components/style/macros.rs b/components/style/macros.rs index c614a2292ca..236a03f1f8a 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -4,6 +4,16 @@ //! Various macro helpers. +macro_rules! exclusive_value { + (($value:ident, $set:expr) => $ident:path) => { + if $value.intersects($set) { + return Err(()) + } else { + $ident + } + } +} + macro_rules! trivial_to_computed_value { ($name:ty) => { impl $crate::values::computed::ToComputedValue for $name { diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 4defee919a8..428d9d8c1c1 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -690,152 +690,14 @@ macro_rules! exclusive_value { } } -<%helpers:longhand name="font-variant-east-asian" products="gecko" animation_value_type="discrete" - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" - spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian"> - use properties::longhands::system_font::SystemFont; - use std::fmt; - use style_traits::ToCss; - - - bitflags! { - #[derive(MallocSizeOf)] - pub struct VariantEastAsian: u16 { - const NORMAL = 0; - const JIS78 = 0x01; - const JIS83 = 0x02; - const JIS90 = 0x04; - const JIS04 = 0x08; - const SIMPLIFIED = 0x10; - const TRADITIONAL = 0x20; - const FULL_WIDTH = 0x40; - const PROPORTIONAL_WIDTH = 0x80; - const RUBY = 0x100; - } - } - - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Debug, PartialEq, ToCss)] - pub enum SpecifiedValue { - Value(VariantEastAsian), - System(SystemFont) - } - - <%self:simple_system_boilerplate name="font_variant_east_asian"></%self:simple_system_boilerplate> - - // servo_bit: gecko_bit - <% font_variant_east_asian_map = { "VariantEastAsian::JIS78": "JIS78", - "VariantEastAsian::JIS83": "JIS83", - "VariantEastAsian::JIS90": "JIS90", - "VariantEastAsian::JIS04": "JIS04", - "VariantEastAsian::SIMPLIFIED": "SIMPLIFIED", - "VariantEastAsian::TRADITIONAL": "TRADITIONAL", - "VariantEastAsian::FULL_WIDTH": "FULL_WIDTH", - "VariantEastAsian::PROPORTIONAL_WIDTH": "PROP_WIDTH", - "VariantEastAsian::RUBY": "RUBY" } %> - - ${helpers.gecko_bitflags_conversion(font_variant_east_asian_map, 'NS_FONT_VARIANT_EAST_ASIAN_', - 'VariantEastAsian', kw_type='u16')} - - - impl ToCss for VariantEastAsian { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.is_empty() { - return dest.write_str("normal") - } - - let mut has_any = false; - - macro_rules! write_value { - ($ident:path => $str:expr) => { - if self.intersects($ident) { - if has_any { - dest.write_str(" ")?; - } - has_any = true; - dest.write_str($str)?; - } - } - } - - write_value!(VariantEastAsian::JIS78 => "jis78"); - write_value!(VariantEastAsian::JIS83 => "jis83"); - write_value!(VariantEastAsian::JIS90 => "jis90"); - write_value!(VariantEastAsian::JIS04 => "jis04"); - write_value!(VariantEastAsian::SIMPLIFIED => "simplified"); - write_value!(VariantEastAsian::TRADITIONAL => "traditional"); - write_value!(VariantEastAsian::FULL_WIDTH => "full-width"); - write_value!(VariantEastAsian::PROPORTIONAL_WIDTH => "proportional-width"); - write_value!(VariantEastAsian::RUBY => "ruby"); - - debug_assert!(has_any); - Ok(()) - } - } - - pub mod computed_value { - pub type T = super::VariantEastAsian; - } - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::empty() - } - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::Value(VariantEastAsian::empty()) - } - - /// normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ] - /// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ] - /// <east-asian-width-values> = [ full-width | proportional-width ] - <% east_asian_variant_values = """VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | - VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | - VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL""" %> - <% east_asian_width_values = "VariantEastAsian::FULL_WIDTH | VariantEastAsian::PROPORTIONAL_WIDTH" %> - pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<SpecifiedValue, ParseError<'i>> { - let mut result = VariantEastAsian::empty(); - - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(SpecifiedValue::Value(result)) - } - - while let Ok(flag) = input.try(|input| { - Ok(match_ignore_ascii_case! { &input.expect_ident().map_err(|_| ())?, - "jis78" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::JIS78), - "jis83" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::JIS83), - "jis90" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::JIS90), - "jis04" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::JIS04), - "simplified" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::SIMPLIFIED), - "traditional" => - exclusive_value!((result, ${east_asian_variant_values}) => VariantEastAsian::TRADITIONAL), - "full-width" => - exclusive_value!((result, ${east_asian_width_values}) => VariantEastAsian::FULL_WIDTH), - "proportional-width" => - exclusive_value!((result, ${east_asian_width_values}) => VariantEastAsian::PROPORTIONAL_WIDTH), - "ruby" => - exclusive_value!((result, VariantEastAsian::RUBY) => VariantEastAsian::RUBY), - _ => return Err(()), - }) - }) { - result.insert(flag); - } - - if !result.is_empty() { - Ok(SpecifiedValue::Value(result)) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } - } - - #[cfg(feature = "gecko")] - impl_gecko_keyword_conversions!(VariantEastAsian, u16); -</%helpers:longhand> +${helpers.predefined_type("font-variant-east-asian", + "FontVariantEastAsian", + products="gecko", + initial_value="computed::FontVariantEastAsian::empty()", + initial_specified_value="specified::FontVariantEastAsian::empty()", + animation_value_type="discrete", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian")} <%helpers:longhand name="font-variant-ligatures" products="gecko" animation_value_type="discrete" flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index cc3487f7a12..70981d6bf74 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -277,6 +277,9 @@ impl FontVariantAlternates { } } +/// Use VariantEastAsian as computed type of FontVariantEastAsian +pub type FontVariantEastAsian = specified::VariantEastAsian; + /// font-language-override can only have a single three-letter /// OpenType "language system" tag, so we should be able to compute /// it and store it as a 32-bit integer diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index e613ee18d16..d5dda639464 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -37,7 +37,8 @@ pub use self::background::{BackgroundSize, BackgroundRepeat}; pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth}; pub use self::border::{BorderRadius, BorderCornerRadius, BorderSpacing}; pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates}; -pub use self::font::{FontLanguageOverride, FontVariantSettings, MozScriptLevel, MozScriptMinSize, XTextZoom}; +pub use self::font::{FontLanguageOverride, FontVariantSettings, FontVariantEastAsian}; +pub use self::font::{MozScriptLevel, MozScriptMinSize, XTextZoom}; pub use self::box_::{AnimationIterationCount, AnimationName, ScrollSnapType, VerticalAlign}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index a078283565e..839978e1222 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -851,6 +851,250 @@ impl Parse for FontVariantAlternates { } } +bitflags! { + #[derive(MallocSizeOf)] + /// Vairants for east asian variant + pub struct VariantEastAsian: u16 { + /// None of the features + const NORMAL = 0; + /// Enables rendering of JIS78 forms (OpenType feature: jp78) + const JIS78 = 0x01; + /// Enables rendering of JIS83 forms (OpenType feature: jp83). + const JIS83 = 0x02; + /// Enables rendering of JIS90 forms (OpenType feature: jp90). + const JIS90 = 0x04; + /// Enables rendering of JIS2004 forms (OpenType feature: jp04). + const JIS04 = 0x08; + /// Enables rendering of simplified forms (OpenType feature: smpl). + const SIMPLIFIED = 0x10; + /// Enables rendering of traditional forms (OpenType feature: trad). + const TRADITIONAL = 0x20; + /// Enables rendering of full-width variants (OpenType feature: fwid). + const FULL_WIDTH = 0x40; + /// Enables rendering of proportionally-spaced variants (OpenType feature: pwid). + const PROPORTIONAL_WIDTH = 0x80; + /// Enables display of ruby variant glyphs (OpenType feature: ruby). + const RUBY = 0x100; + } +} + +#[cfg(feature = "gecko")] +impl VariantEastAsian { + /// Obtain a specified value from a Gecko keyword value + /// + /// Intended for use with presentation attributes, not style structs + pub fn from_gecko_keyword(kw: u16) -> Self { + Self::from_bits_truncate(kw) + } + + /// Transform into gecko keyword + pub fn to_gecko_keyword(self) -> u16 { + self.bits() + } +} + +impl ToCss for VariantEastAsian { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.is_empty() { + return dest.write_str("normal") + } + + let mut has_any = false; + + macro_rules! write_value { + ($ident:path => $str:expr) => { + if self.intersects($ident) { + if has_any { + dest.write_str(" ")?; + } + has_any = true; + dest.write_str($str)?; + } + } + } + + write_value!(VariantEastAsian::JIS78 => "jis78"); + write_value!(VariantEastAsian::JIS83 => "jis83"); + write_value!(VariantEastAsian::JIS90 => "jis90"); + write_value!(VariantEastAsian::JIS04 => "jis04"); + write_value!(VariantEastAsian::SIMPLIFIED => "simplified"); + write_value!(VariantEastAsian::TRADITIONAL => "traditional"); + write_value!(VariantEastAsian::FULL_WIDTH => "full-width"); + write_value!(VariantEastAsian::PROPORTIONAL_WIDTH => "proportional-width"); + write_value!(VariantEastAsian::RUBY => "ruby"); + + debug_assert!(has_any); + Ok(()) + } +} + +#[cfg(feature = "gecko")] +impl From<u16> for VariantEastAsian { + fn from(bits: u16) -> VariantEastAsian { + VariantEastAsian::from_gecko_keyword(bits) + } +} + +#[cfg(feature = "gecko")] +impl From<VariantEastAsian> for u16 { + fn from(v: VariantEastAsian) -> u16 { + v.to_gecko_keyword() + } +} + +/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. +#[cfg(feature = "gecko")] +#[inline] +pub fn assert_variant_east_asian_matches() { + use gecko_bindings::structs; + + macro_rules! check_variant_east_asian { + ( $( $a:ident => $b:path),*, ) => { + if cfg!(debug_assertions) { + $( + assert_eq!(structs::$a as u16, $b.bits()); + )* + } + } + } + + check_variant_east_asian! { + NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH => VariantEastAsian::FULL_WIDTH, + NS_FONT_VARIANT_EAST_ASIAN_JIS04 => VariantEastAsian::JIS04, + NS_FONT_VARIANT_EAST_ASIAN_JIS78 => VariantEastAsian::JIS78, + NS_FONT_VARIANT_EAST_ASIAN_JIS83 => VariantEastAsian::JIS83, + NS_FONT_VARIANT_EAST_ASIAN_JIS90 => VariantEastAsian::JIS90, + NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH => VariantEastAsian::PROPORTIONAL_WIDTH, + NS_FONT_VARIANT_EAST_ASIAN_RUBY => VariantEastAsian::RUBY, + NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED => VariantEastAsian::SIMPLIFIED, + NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL => VariantEastAsian::TRADITIONAL, + } +} + +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq, ToCss)] +/// Allows control of glyph substitution and sizing in East Asian text. +pub enum FontVariantEastAsian { + /// Value variant with `variant-east-asian` + Value(VariantEastAsian), + /// System font variant + System(SystemFont) +} + +impl FontVariantEastAsian { + #[inline] + /// Get default `font-variant-east-asian` with `empty` variant + pub fn empty() -> Self { + FontVariantEastAsian::Value(VariantEastAsian::empty()) + } + + /// Get `font-variant-east-asian` with system font + pub fn system_font(f: SystemFont) -> Self { + FontVariantEastAsian::System(f) + } + + /// Get system font + pub fn get_system(&self) -> Option<SystemFont> { + if let FontVariantEastAsian::System(s) = *self { + Some(s) + } else { + None + } + } +} + +impl ToComputedValue for FontVariantEastAsian { + type ComputedValue = computed::FontVariantEastAsian; + + fn to_computed_value(&self, _context: &Context) -> computed::FontVariantEastAsian { + match *self { + FontVariantEastAsian::Value(ref v) => v.clone(), + FontVariantEastAsian::System(_) => { + #[cfg(feature = "gecko")] { + _context.cached_system_font.as_ref().unwrap().font_variant_east_asian.clone() + } + #[cfg(feature = "servo")] { + unreachable!() + } + } + } + } + + fn from_computed_value(other: &computed::FontVariantEastAsian) -> Self { + FontVariantEastAsian::Value(other.clone()) + } +} + +impl Parse for FontVariantEastAsian { + /// normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ] + /// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ] + /// <east-asian-width-values> = [ full-width | proportional-width ] + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result<FontVariantEastAsian, ParseError<'i>> { + let mut result = VariantEastAsian::empty(); + + if input.try(|input| input.expect_ident_matching("normal")).is_ok() { + return Ok(FontVariantEastAsian::Value(result)) + } + + while let Ok(flag) = input.try(|input| { + Ok(match_ignore_ascii_case! { &input.expect_ident().map_err(|_| ())?, + "jis78" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::JIS78), + "jis83" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::JIS83), + "jis90" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::JIS90), + "jis04" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::JIS04), + "simplified" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::SIMPLIFIED), + "traditional" => + exclusive_value!((result, VariantEastAsian::JIS78 | VariantEastAsian::JIS83 | + VariantEastAsian::JIS90 | VariantEastAsian::JIS04 | + VariantEastAsian::SIMPLIFIED | VariantEastAsian::TRADITIONAL + ) => VariantEastAsian::TRADITIONAL), + "full-width" => + exclusive_value!((result, VariantEastAsian::FULL_WIDTH | + VariantEastAsian::PROPORTIONAL_WIDTH + ) => VariantEastAsian::FULL_WIDTH), + "proportional-width" => + exclusive_value!((result, VariantEastAsian::FULL_WIDTH | + VariantEastAsian::PROPORTIONAL_WIDTH + ) => VariantEastAsian::PROPORTIONAL_WIDTH), + "ruby" => + exclusive_value!((result, VariantEastAsian::RUBY) => VariantEastAsian::RUBY), + _ => return Err(()), + }) + }) { + result.insert(flag); + } + + if !result.is_empty() { + Ok(FontVariantEastAsian::Value(result)) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } +} + #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] /// Whether user agents are allowed to synthesize bold or oblique font faces /// when a font family lacks bold or italic faces diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 2dab11fb457..d85ecb7d435 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -31,7 +31,8 @@ pub use self::background::{BackgroundRepeat, BackgroundSize}; pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth}; pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth, BorderSpacing}; pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates}; -pub use self::font::{FontLanguageOverride, FontVariantSettings, MozScriptLevel, MozScriptMinSize, XTextZoom}; +pub use self::font::{FontLanguageOverride, FontVariantSettings, FontVariantEastAsian}; +pub use self::font::{MozScriptLevel, MozScriptMinSize, XTextZoom}; pub use self::box_::{AnimationIterationCount, AnimationName, ScrollSnapType, VerticalAlign}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index e0032eea5c9..f002d440185 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -186,6 +186,7 @@ pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { origin_flags::assert_flags_match(); parser::assert_parsing_mode_match(); traversal_flags::assert_traversal_flags_match(); + specified::font::assert_variant_east_asian_matches(); // Initialize the dummy url data unsafe { DUMMY_URL_DATA = dummy_url_data; } |