From 5b06a3203240fbaed05517ad4bcdecf1bb87e2b2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH] stylo: System font support for keyword font longhands --- components/style/properties/data.py | 7 + components/style/properties/helpers.mako.rs | 143 +++++++++++++++--- .../helpers/animated_properties.mako.rs | 12 +- .../style/properties/longhand/box.mako.rs | 3 +- .../style/properties/longhand/font.mako.rs | 92 +++++------ .../style/properties/shorthand/font.mako.rs | 11 +- ports/geckolib/glue.rs | 2 +- 7 files changed, 194 insertions(+), 76 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index f12a7ffd3b39..f19e4b76cd5e 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -13,6 +13,9 @@ ALL_SIDES = [(side, False) for side in PHYSICAL_SIDES] + [(side, True) for side in LOGICAL_SIDES] ALL_SIZES = [(size, False) for size in PHYSICAL_SIZES] + [(size, True) for size in LOGICAL_SIZES] +SYSTEM_FONT_LONGHANDS = """font_family font_size font_style + font_variant_caps font_stretch font_kerning + font_variant_position""".split() def maybe_moz_logical_alias(product, side, prop): if product == "gecko" and side[1]: @@ -32,6 +35,10 @@ def to_rust_ident(name): def to_camel_case(ident): return re.sub("(^|_|-)([a-z])", lambda m: m.group(2).upper(), ident.strip("_").strip("-")) +def to_camel_case_lower(ident): + camel = to_camel_case(ident) + return camel[0].lower() + camel[1:] + def parse_aliases(value): aliases = {} diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 2dfcc7a837cd..978bce1ea44d 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -2,7 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -<%! from data import Keyword, to_rust_ident, to_camel_case, LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES %> +<%! + from data import Keyword, to_rust_ident, to_camel_case + from data import LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES, SYSTEM_FONT_LONGHANDS +%> <%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, vector=False, initial_specified_value=None, **kwargs)"> @@ -199,7 +202,6 @@ % endif - <%def name="longhand(*args, **kwargs)"> <% property = data.declare_longhand(*args, **kwargs) @@ -265,7 +267,7 @@ <% maybe_wm = ", wm" if property.logical else "" %> match *value { DeclaredValue::Value(ref specified_value) => { - % if property.ident in "font_size font_family".split() and product == "gecko": + % if property.ident in SYSTEM_FONT_LONGHANDS and product == "gecko": if let Some(sf) = specified_value.get_system() { longhands::system_font::resolve_system_font(sf, context); } @@ -398,6 +400,110 @@ } +<%def name="single_keyword_system(name, values, **kwargs)"> + <% + keyword_kwargs = {a: kwargs.pop(a, None) for a in [ + 'gecko_constant_prefix', 'gecko_enum_prefix', + 'extra_gecko_values', 'extra_servo_values', + 'custom_consts', 'gecko_inexhaustive', + ]} + keyword = keyword=Keyword(name, values, **keyword_kwargs) + %> + <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> + use values::HasViewportPercentage; + use properties::longhands::system_font::SystemFont; + use std::fmt; + use style_traits::ToCss; + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + use cssparser::Parser; + use parser::{Parse, ParserContext}; + + use style_traits::ToCss; + define_css_keyword_enum! { T: + % for value in keyword.values_for(product): + "${value}" => ${to_rust_ident(value)}, + % endfor + } + + impl Parse for T { + fn parse(_: &ParserContext, input: &mut Parser) -> Result { + T::parse(input) + } + } + + ${gecko_keyword_conversion(keyword, keyword.values_for(product), type="T", cast_to="i32")} + } + + #[derive(Debug, Clone, PartialEq, Eq, Copy)] + pub enum SpecifiedValue { + Keyword(computed_value::T), + System(SystemFont), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Keyword(k) => k.to_css(dest), + SpecifiedValue::System(_) => Ok(()) + } + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + Ok(SpecifiedValue::Keyword(computed_value::T::parse(input)?)) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue { + match *self { + SpecifiedValue::Keyword(v) => v, + SpecifiedValue::System(_) => { + % if product == "gecko": + _cx.style.cached_system_font.as_ref().unwrap().${to_rust_ident(name)} + % else: + unreachable!() + % endif + } + } + } + fn from_computed_value(other: &computed_value::T) -> Self { + SpecifiedValue::Keyword(*other) + } + } + + impl From for SpecifiedValue { + fn from(other: computed_value::T) -> Self { + SpecifiedValue::Keyword(other) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::${to_rust_ident(values.split()[0])} + } + #[inline] + pub fn get_initial_specified_value() -> SpecifiedValue { + SpecifiedValue::Keyword(computed_value::T::${to_rust_ident(values.split()[0])}) + } + + impl SpecifiedValue { + pub fn system_font(f: SystemFont) -> Self { + SpecifiedValue::System(f) + } + pub fn get_system(&self) -> Option { + if let SpecifiedValue::System(s) = *self { + Some(s) + } else { + None + } + } + } + + + <%def name="single_keyword(name, values, vector=False, **kwargs)"> <%call expr="single_keyword_computed(name, values, vector, **kwargs)"> % if not "extra_specified" in kwargs and ("aliases" in kwargs or (("extra_%s_aliases" % product) in kwargs)): @@ -431,10 +537,12 @@ -<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue')"> +<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue', cast_to=None)"> <% if not values: values = keyword.values_for(product) + maybe_cast = "as %s" % cast_to if cast_to else "" + const_type = cast_to if cast_to else "u32" %> #[cfg(feature = "gecko")] impl ${type} { @@ -443,26 +551,17 @@ /// Intended for use with presentation attributes, not style structs pub fn from_gecko_keyword(kw: u32) -> Self { use gecko_bindings::structs; - % if keyword.gecko_enum_prefix: + % for value in values: + // We can't match on enum values if we're matching on a u32 + const ${to_rust_ident(value).upper()}: ${const_type} + = structs::${keyword.gecko_constant(value)} as ${const_type}; + % endfor + match kw ${maybe_cast} { % for value in values: - // We can't match on enum values if we're matching on a u32 - const ${to_rust_ident(value).upper()}: u32 - = structs::${keyword.gecko_enum_prefix}::${to_camel_case(value)} as u32; + ${to_rust_ident(value).upper()} => ${type}::${to_rust_ident(value)}, % endfor - match kw { - % for value in values: - ${to_rust_ident(value).upper()} => ${type}::${to_rust_ident(value)}, - % endfor - x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x), - } - % else: - match kw { - % for value in values: - structs::${keyword.gecko_constant(value)} => ${type}::${to_rust_ident(value)}, - % endfor - x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x), - } - % endif + x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x), + } } } diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 68e5ce6cb90b..920d61147286 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -4,6 +4,8 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> +<% from data import SYSTEM_FONT_LONGHANDS %> + use app_units::Au; use cssparser::{Color as CSSParserColor, Parser, RGBA}; use euclid::{Point2D, Size2D}; @@ -367,11 +369,11 @@ impl AnimationValue { % for prop in data.longhands: % if prop.animatable: PropertyDeclaration::${prop.camel_case}(ref val) => { - % if prop.ident in "font_size font_family".split() and product == "gecko": - if let Some(sf) = val.get_system() { - longhands::system_font::resolve_system_font(sf, context); - } - % endif + % if prop.ident in SYSTEM_FONT_LONGHANDS and product == "gecko": + if let Some(sf) = val.get_system() { + longhands::system_font::resolve_system_font(sf, context); + } + % endif Some(AnimationValue::${prop.camel_case}(val.to_computed_value(context))) }, % endif diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 851beb6267cb..ebae07f710c9 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -93,7 +93,8 @@ % endif ${helpers.gecko_keyword_conversion(Keyword('display', ' '.join(values), - gecko_enum_prefix='StyleDisplay'))} + gecko_enum_prefix='StyleDisplay', + gecko_strip_moz_prefix=False))} diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 09870f66edc6..d15be7f76c81 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> -<% from data import Method, to_camel_case, to_rust_ident %> +<% from data import Method, to_camel_case, to_rust_ident, to_camel_case_lower, SYSTEM_FONT_LONGHANDS %> <% data.new_style_struct("Font", inherited=True) %> @@ -282,14 +282,12 @@ } - -${helpers.single_keyword("font-style", - "normal italic oblique", - gecko_constant_prefix="NS_FONT_STYLE", - gecko_ffi_name="mFont.style", - spec="https://drafts.csswg.org/css-fonts/#propdef-font-style", - animation_type="none", - needs_conversion=True)} +${helpers.single_keyword_system("font-style", + "normal italic oblique", + gecko_constant_prefix="NS_FONT_STYLE", + gecko_ffi_name="mFont.style", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-style", + animation_type="none")} <% font_variant_caps_custom_consts= { "small-caps": "SMALLCAPS", @@ -298,14 +296,14 @@ ${helpers.single_keyword("font-style", "all-petite": "ALLPETITE", "titling-caps": "TITLING" } %> -${helpers.single_keyword("font-variant-caps", - "normal small-caps", - extra_gecko_values="all-small petite-caps unicase titling-caps", - gecko_constant_prefix="NS_FONT_VARIANT_CAPS", - gecko_ffi_name="mFont.variantCaps", - spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps", - custom_consts=font_variant_caps_custom_consts, - animation_type="none")} +${helpers.single_keyword_system("font-variant-caps", + "normal small-caps", + extra_gecko_values="all-small petite-caps unicase titling-caps", + gecko_constant_prefix="NS_FONT_VARIANT_CAPS", + gecko_ffi_name="mFont.variantCaps", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps", + custom_consts=font_variant_caps_custom_consts, + animation_type="none")} <%helpers:longhand name="font-weight" need_clone="True" animation_type="normal" spec="https://drafts.csswg.org/css-fonts/#propdef-font-weight"> @@ -954,23 +952,23 @@ ${helpers.single_keyword("font-variant-caps", // FIXME: This prop should be animatable -${helpers.single_keyword("font-stretch", - "normal ultra-condensed extra-condensed condensed \ - semi-condensed semi-expanded expanded extra-expanded \ - ultra-expanded", - gecko_ffi_name="mFont.stretch", - gecko_constant_prefix="NS_FONT_STRETCH", - cast_type='i16', - spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch", - animation_type="none")} - -${helpers.single_keyword("font-kerning", - "auto none normal", - products="gecko", - gecko_ffi_name="mFont.kerning", - gecko_constant_prefix="NS_FONT_KERNING", - spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch", - animation_type="none")} +${helpers.single_keyword_system("font-stretch", + "normal ultra-condensed extra-condensed condensed \ + semi-condensed semi-expanded expanded extra-expanded \ + ultra-expanded", + gecko_ffi_name="mFont.stretch", + gecko_constant_prefix="NS_FONT_STRETCH", + cast_type='i16', + spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch", + animation_type="none")} + +${helpers.single_keyword_system("font-kerning", + "auto none normal", + products="gecko", + gecko_ffi_name="mFont.kerning", + gecko_constant_prefix="NS_FONT_KERNING", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch", + animation_type="none")} /// FIXME: Implement proper handling of each values. /// https://github.com/servo/servo/issues/15957 @@ -1461,13 +1459,13 @@ macro_rules! exclusive_value { } -${helpers.single_keyword("font-variant-position", - "normal sub super", - products="gecko", - gecko_ffi_name="mFont.variantPosition", - gecko_constant_prefix="NS_FONT_VARIANT_POSITION", - spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-position", - animation_type="none")} +${helpers.single_keyword_system("font-variant-position", + "normal sub super", + products="gecko", + gecko_ffi_name="mFont.variantPosition", + gecko_constant_prefix="NS_FONT_VARIANT_POSITION", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-position", + animation_type="none")} <%helpers:longhand name="font-feature-settings" products="none" animation_type="none" extra_prefixes="moz" spec="https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings"> @@ -1897,6 +1895,8 @@ ${helpers.single_keyword("-moz-math-variant", -moz-window -moz-document -moz-workspace -moz-desktop -moz-info -moz-dialog -moz-button -moz-pull-down-menu -moz-list -moz-field""".split() + kw_font_props = """font_style font_variant_caps font_stretch + font_kerning font_variant_position""".split() %> #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum SystemFont { @@ -1937,6 +1937,11 @@ ${helpers.single_keyword("-moz-math-variant", let ret = ComputedSystemFont { font_family: longhands::font_family::computed_value::T(family), font_size: Au(system.size), + % for kwprop in kw_font_props: + ${kwprop}: longhands::${kwprop}::computed_value::T::from_gecko_keyword( + system.${to_camel_case_lower(kwprop.replace('font_', ''))} as u32 + ), + % endfor system_font: *self, }; unsafe { bindings::Gecko_nsFont_Destroy(&mut system); } @@ -1963,8 +1968,9 @@ ${helpers.single_keyword("-moz-math-variant", #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ComputedSystemFont { - pub font_family: longhands::font_family::computed_value::T, - pub font_size: longhands::font_size::computed_value::T, + % for name in SYSTEM_FONT_LONGHANDS: + pub ${name}: longhands::${name}::computed_value::T, + % endfor pub system_font: SystemFont, } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index a4fd93b843a6..5e8c79bf4b0d 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> +<% from data import SYSTEM_FONT_LONGHANDS %> <%helpers:shorthand name="font" sub_properties="font-style font-variant-caps font-weight font-stretch @@ -42,11 +43,13 @@ % if product == "gecko": if let Ok(sys) = input.try(SystemFont::parse) { return Ok(Longhands { - % for name in "family size".split(): - font_${name}: font_${name}::SpecifiedValue::system_font(sys), + % for name in SYSTEM_FONT_LONGHANDS: + ${name}: ${name}::SpecifiedValue::system_font(sys), % endfor - % for name in "style weight stretch variant_caps".split() + gecko_sub_properties: - font_${name}: font_${name}::get_initial_specified_value(), + % for name in gecko_sub_properties + "weight variant_caps stretch".split(): + % if "font_" + name not in SYSTEM_FONT_LONGHANDS: + font_${name}: font_${name}::get_initial_specified_value(), + % endif % endfor line_height: line_height::get_initial_specified_value(), }) diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index ac8a4a394503..4894f841e070 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1393,7 +1393,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: // We rely on Gecko passing in font-size values (0...7) here. longhands::font_size::SpecifiedValue::from_html_size(value as u8) }, - FontStyle => longhands::font_style::SpecifiedValue::from_gecko_keyword(value), + FontStyle => longhands::font_style::computed_value::T::from_gecko_keyword(value).into(), FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value), ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value), MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),