From 2c5ac9fc2d0726b6faeae004d51a7721c31a5c46 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 1/7] stylo: Add basic system font support, use for font-size and font-family --- components/script/dom/element.rs | 2 +- components/style/gecko_bindings/bindings.rs | 11 + components/style/gecko_string_cache/mod.rs | 13 ++ components/style/properties/gecko.mako.rs | 4 + components/style/properties/helpers.mako.rs | 5 + .../helpers/animated_properties.mako.rs | 7 +- .../style/properties/longhand/font.mako.rs | 205 +++++++++++++++++- .../style/properties/shorthand/font.mako.rs | 20 +- ports/geckolib/glue.rs | 4 +- 9 files changed, 260 insertions(+), 11 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 8baba9bb54d..921083fb6dd 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -468,7 +468,7 @@ impl LayoutElementHelpers for LayoutJS { hints.push(from_declaration( shared_lock, PropertyDeclaration::FontFamily( - font_family::computed_value::T(vec![ + font_family::SpecifiedValue::Values(vec![ font_family::computed_value::FontFamily::from_atom( font_family)])))); } diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 2ea1f286db5..2a122f482e9 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -695,6 +695,9 @@ extern "C" { pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32) -> *mut nsIAtom; } +extern "C" { + pub fn Gecko_Atomize16(aString: *const nsAString) -> *mut nsIAtom; +} extern "C" { pub fn Gecko_AddRefAtom(aAtom: *mut nsIAtom); } @@ -731,6 +734,14 @@ extern "C" { extern "C" { pub fn Gecko_CopyFontFamilyFrom(dst: *mut nsFont, src: *const nsFont); } +extern "C" { + pub fn Gecko_nsFont_InitSystem(dst: *mut nsFont, font_id: i32, + font: *const nsStyleFont, + pres_context: RawGeckoPresContextBorrowed); +} +extern "C" { + pub fn Gecko_nsFont_Destroy(dst: *mut nsFont); +} extern "C" { pub fn Gecko_SetImageOrientation(aVisibility: *mut nsStyleVisibility, aRadians: f64, aFlip: bool); diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index ca2c37ec213..9db8374f9a5 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -8,9 +8,11 @@ use gecko_bindings::bindings::Gecko_AddRefAtom; use gecko_bindings::bindings::Gecko_Atomize; +use gecko_bindings::bindings::Gecko_Atomize16; use gecko_bindings::bindings::Gecko_ReleaseAtom; use gecko_bindings::structs::nsIAtom; use precomputed_hash::PrecomputedHash; +use nsstring::nsAString; use std::borrow::{Cow, Borrow}; use std::char::{self, DecodeUtf16}; use std::fmt::{self, Write}; @@ -281,6 +283,17 @@ impl<'a> From<&'a str> for Atom { } } +impl<'a> From<&'a nsAString> for Atom { + #[inline] + fn from(string: &nsAString) -> Atom { + unsafe { + Atom(WeakAtom::new( + Gecko_Atomize16(string) + )) + } + } +} + impl<'a> From> for Atom { #[inline] fn from(string: Cow<'a, str>) -> Atom { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 23daca26c86..2a75da38d9f 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -95,6 +95,7 @@ pub struct ComputedValues { /// When this is Some, we compute font sizes by computing the keyword against /// the generic font, and then multiplying it by the ratio. pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, + pub cached_system_font: Option, } impl ComputedValues { @@ -104,6 +105,7 @@ impl ComputedValues { writing_mode: parent.writing_mode, root_font_size: parent.root_font_size, font_size_keyword: parent.font_size_keyword, + cached_system_font: None, % for style_struct in data.style_structs: % if style_struct.inherited: ${style_struct.ident}: parent.${style_struct.ident}.clone(), @@ -126,6 +128,7 @@ impl ComputedValues { custom_properties: custom_properties, writing_mode: writing_mode, root_font_size: root_font_size, + cached_system_font: None, font_size_keyword: font_size_keyword, % for style_struct in data.style_structs: ${style_struct.ident}: ${style_struct.ident}, @@ -139,6 +142,7 @@ impl ComputedValues { writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious? font_size_keyword: Some((Default::default(), 1.)), + cached_system_font: None, % for style_struct in data.style_structs: ${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context), % endfor diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 49a751bd59f..2dfcc7a837c 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -265,6 +265,11 @@ <% 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 let Some(sf) = specified_value.get_system() { + longhands::system_font::resolve_system_font(sf, context); + } + % endif let computed = specified_value.to_computed_value(context); % if property.ident == "font_size": if let longhands::font_size::SpecifiedValue::Keyword(kw, fraction) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 7c6031ca09c..68e5ce6cb90 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -358,7 +358,7 @@ impl AnimationValue { } /// Construct an AnimationValue from a property declaration - pub fn from_declaration(decl: &PropertyDeclaration, context: &Context, initial: &ComputedValues) -> Option { + pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, initial: &ComputedValues) -> Option { use error_reporting::StdoutErrorReporter; use properties::LonghandId; use properties::DeclaredValue; @@ -367,6 +367,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 Some(AnimationValue::${prop.camel_case}(val.to_computed_value(context))) }, % endif diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index df95d9f464c..09870f66edc 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -3,22 +3,33 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> -<% from data import Method %> +<% from data import Method, to_camel_case, to_rust_ident %> <% data.new_style_struct("Font", inherited=True) %> + +<%def name="nongecko_unreachable()"> + %if product == "gecko": + ${caller.body()} + %else: + unreachable!() + %endif + + <%helpers:longhand name="font-family" animation_type="none" need_index="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-family"> + use properties::longhands::system_font::SystemFont; use self::computed_value::{FontFamily, FamilyName}; + use std::fmt; + use style_traits::ToCss; use values::HasViewportPercentage; use values::computed::ComputedValueAsSpecified; - pub use self::computed_value::T as SpecifiedValue; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); pub mod computed_value { use cssparser::{CssStringWriter, Parser, serialize_identifier}; + use properties::longhands::system_font::SystemFont; use std::fmt::{self, Write}; use Atom; use style_traits::ToCss; @@ -200,9 +211,61 @@ SpecifiedValue::parse(input) } + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + pub enum SpecifiedValue { + Values(Vec), + System(SystemFont), + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue { + match *self { + SpecifiedValue::Values(ref v) => computed_value::T(v.clone()), + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + _cx.style.cached_system_font.as_ref().unwrap().font_family.clone() + + } + } + } + fn from_computed_value(other: &computed_value::T) -> Self { + SpecifiedValue::Values(other.0.clone()) + } + } + 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 + } + } + pub fn parse(input: &mut Parser) -> Result { - input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue) + input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue::Values) + } + } + + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Values(ref v) => { + let mut iter = v.iter(); + iter.next().unwrap().to_css(dest)?; + for family in iter { + dest.write_str(", ")?; + family.to_css(dest)?; + } + Ok(()) + } + _ => Ok(()) + } } } @@ -418,6 +481,7 @@ ${helpers.single_keyword("font-variant-caps", use values::{FONT_MEDIUM_PX, HasViewportPercentage}; use values::specified::{FontRelativeLength, LengthOrPercentage, Length}; use values::specified::{NoCalcLength, Percentage}; + use properties::longhands::system_font::SystemFont; impl ToCss for SpecifiedValue { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { @@ -426,6 +490,7 @@ ${helpers.single_keyword("font-variant-caps", SpecifiedValue::Keyword(kw, _) => kw.to_css(dest), SpecifiedValue::Smaller => dest.write_str("smaller"), SpecifiedValue::Larger => dest.write_str("larger"), + SpecifiedValue::System(_) => Ok(()), } } } @@ -452,6 +517,7 @@ ${helpers.single_keyword("font-variant-caps", Keyword(KeywordSize, f32), Smaller, Larger, + System(SystemFont) } impl From for SpecifiedValue { @@ -677,6 +743,12 @@ ${helpers.single_keyword("font-variant-caps", FontRelativeLength::Em(1.2).to_computed_value(context, /* use_inherited */ true) } + + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + context.style.cached_system_font.as_ref().unwrap().font_size + + } } } @@ -703,6 +775,18 @@ ${helpers.single_keyword("font-variant-caps", _ => Err(()) } } + 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 + } + } + } <%helpers:longhand products="gecko" name="font-size-adjust" animation_type="normal" @@ -1801,3 +1885,116 @@ ${helpers.single_keyword("-moz-math-variant", } + +% if product == "gecko": + pub mod system_font { + use app_units::Au; + use cssparser::Parser; + use properties::longhands; + use values::computed::{ToComputedValue, Context}; + <% + system_fonts = """caption icon menu message-box small-caption status-bar + -moz-window -moz-document -moz-workspace -moz-desktop + -moz-info -moz-dialog -moz-button -moz-pull-down-menu + -moz-list -moz-field""".split() + %> + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub enum SystemFont { + % for font in system_fonts: + ${to_camel_case(font)}, + % endfor + } + + impl ToComputedValue for SystemFont { + type ComputedValue = ComputedSystemFont; + + fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { + use gecko_bindings::bindings; + use gecko_bindings::structs::{LookAndFeel_FontID, nsFont}; + use std::mem; + + let id = match *self { + % for font in system_fonts: + SystemFont::${to_camel_case(font)} => { + LookAndFeel_FontID::eFont_${to_camel_case(font.replace("-moz-", ""))} + } + % endfor + }; + + let mut system: nsFont = unsafe { mem::uninitialized() }; + unsafe { + bindings::Gecko_nsFont_InitSystem(&mut system, id as i32, + cx.style.get_font().gecko(), + &*cx.device.pres_context) + } + let family = system.fontlist.mFontlist.iter().map(|font| { + use properties::longhands::font_family::computed_value::*; + FontFamily::FamilyName(FamilyName { + name: (&*font.mName).into(), + quoted: true + }) + }).collect::>(); + let ret = ComputedSystemFont { + font_family: longhands::font_family::computed_value::T(family), + font_size: Au(system.size), + system_font: *self, + }; + unsafe { bindings::Gecko_nsFont_Destroy(&mut system); } + ret + } + + fn from_computed_value(_: &ComputedSystemFont) -> Self { + unreachable!() + } + } + + #[inline] + /// Compute and cache a system font + /// + /// Must be called before attempting to compute a system font + /// specified value + pub fn resolve_system_font(system: SystemFont, context: &mut Context) { + if context.style.cached_system_font.is_none() { + let computed = system.to_computed_value(context); + context.style.cached_system_font = Some(computed); + } + debug_assert!(system == context.style.cached_system_font.as_ref().unwrap().system_font) + } + + #[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, + pub system_font: SystemFont, + } + + impl SystemFont { + pub fn parse(input: &mut Parser) -> Result { + Ok(match_ignore_ascii_case! { &*input.expect_ident()?, + % for font in system_fonts: + "${font}" => SystemFont::${to_camel_case(font)}, + % endfor + _ => return Err(()) + }) + } + } + } +% else: + pub mod system_font { + use cssparser::Parser; + + // We don't parse system fonts, but in the interest of not littering + // a lot of code with `if product == gecko` conditionals, we have a + // dummy system font module that does nothing + + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + /// void enum for system font, can never exist + pub enum SystemFont {} + impl SystemFont { + pub fn parse(_: &mut Parser) -> Result { + Err(()) + } + } + } +% endif diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 6459d2c68c9..a4fd93b843a 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -16,8 +16,9 @@ ${'font-variant-position' if product == 'gecko' or data.testing else ''} ${'font-language-override' if product == 'gecko' or data.testing else ''}" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> - use properties::longhands::{font_style, font_variant_caps, font_weight, font_stretch}; - use properties::longhands::{font_size, line_height}; + use properties::longhands::{font_family, font_style, font_weight, font_stretch}; + use properties::longhands::{font_size, line_height, font_variant_caps}; + use properties::longhands::system_font::SystemFont; <% gecko_sub_properties = "kerning language_override size_adjust \ variant_alternates variant_east_asian \ @@ -38,6 +39,19 @@ let mut weight = None; let mut stretch = None; let size; + % 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), + % endfor + % for name in "style weight stretch variant_caps".split() + gecko_sub_properties: + font_${name}: font_${name}::get_initial_specified_value(), + % endfor + line_height: line_height::get_initial_specified_value(), + }) + } + % endif loop { // Special-case 'normal' because it is valid in each of // font-style, font-weight, font-variant and font-stretch. @@ -88,7 +102,7 @@ }; let family = FontFamily::parse(input)?; Ok(Longhands { - % for name in "style variant_caps weight stretch size".split(): + % for name in "style weight stretch size variant_caps".split(): font_${name}: unwrap_or_initial!(font_${name}, ${name}), % endfor line_height: unwrap_or_initial!(line_height), diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 8c7d2175a16..ac8a4a39450 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1928,7 +1928,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis let default_values = data.default_computed_values(); let metrics = get_metrics_provider_for_product(); - let context = Context { + let mut context = Context { is_root_element: false, device: &data.stylist.device, inherited_style: parent_style.unwrap_or(default_values), @@ -1956,7 +1956,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis .filter_map(|&(ref decl, imp)| { if imp == Importance::Normal { let property = TransitionProperty::from_declaration(decl); - let animation = AnimationValue::from_declaration(decl, &context, default_values); + let animation = AnimationValue::from_declaration(decl, &mut context, default_values); debug_assert!(property.is_none() == animation.is_none(), "The failure condition of TransitionProperty::from_declaration \ and AnimationValue::from_declaration should be the same"); From 5b06a3203240fbaed05517ad4bcdecf1bb87e2b2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 2/7] 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 | 90 ++++++----- .../style/properties/shorthand/font.mako.rs | 11 +- ports/geckolib/glue.rs | 2 +- 7 files changed, 193 insertions(+), 75 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index f12a7ffd3b3..f19e4b76cd5 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -13,6 +13,9 @@ LOGICAL_SIZES = ["block-size", "inline-size"] 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 2dfcc7a837c..978bce1ea44 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 68e5ce6cb90..920d6114728 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 851beb6267c..ebae07f710c 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 09870f66edc..d15be7f76c8 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_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("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-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 a4fd93b843a..5e8c79bf4b0 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 ac8a4a39450..4894f841e07 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), From 4a899530be3a32fd2d0f224f7638f54ac85078ad Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 3/7] stylo: System font support for font-weight --- components/style/properties/data.py | 2 +- components/style/properties/gecko.mako.rs | 5 +-- .../style/properties/longhand/font.mako.rs | 38 ++++++++++++++++++- .../style/properties/shorthand/font.mako.rs | 2 +- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index f19e4b76cd5..f53b73c9a8d 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -15,7 +15,7 @@ ALL_SIZES = [(size, False) for size in PHYSICAL_SIZES] + [(size, True) for size SYSTEM_FONT_LONGHANDS = """font_family font_size font_style font_variant_caps font_stretch font_kerning - font_variant_position""".split() + font_variant_position font_weight""".split() def maybe_moz_logical_alias(product, side, prop): if product == "gecko" and side[1]: diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 2a75da38d9f..16e7a1d0cf4 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1371,10 +1371,7 @@ fn static_assert() { ${impl_simple_copy('font_weight', 'mFont.weight')} pub fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T { - debug_assert!(self.gecko.mFont.weight >= 100); - debug_assert!(self.gecko.mFont.weight <= 900); - debug_assert!(self.gecko.mFont.weight % 10 == 0); - unsafe { transmute(self.gecko.mFont.weight) } + unsafe { longhands::font_weight::computed_value::T::from_gecko_weight(self.gecko.mFont.weight) } } pub fn set_font_synthesis(&mut self, v: longhands::font_synthesis::computed_value::T) { diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index d15be7f76c8..321aa51fae7 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -310,6 +310,7 @@ ${helpers.single_keyword_system("font-variant-caps", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; + use properties::longhands::system_font::SystemFont; no_viewport_percentage!(SpecifiedValue); @@ -323,6 +324,7 @@ ${helpers.single_keyword_system("font-variant-caps", % for weight in range(100, 901, 100): Weight${weight}, % endfor + System(SystemFont), } impl ToCss for SpecifiedValue { @@ -335,9 +337,11 @@ ${helpers.single_keyword_system("font-variant-caps", % for weight in range(100, 901, 100): SpecifiedValue::Weight${weight} => dest.write_str("${weight}"), % endfor + SpecifiedValue::System(_) => Ok(()) } } } + /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { input.try(|input| { @@ -369,6 +373,19 @@ ${helpers.single_keyword_system("font-variant-caps", } } + 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 + } + } + } + /// Used in @font-face, where relative keywords are not allowed. impl Parse for computed_value::T { fn parse(context: &ParserContext, input: &mut Parser) -> Result { @@ -379,7 +396,8 @@ ${helpers.single_keyword_system("font-variant-caps", SpecifiedValue::Normal => Ok(computed_value::T::Weight400), SpecifiedValue::Bold => Ok(computed_value::T::Weight700), SpecifiedValue::Bolder | - SpecifiedValue::Lighter => Err(()) + SpecifiedValue::Lighter => Err(()), + SpecifiedValue::System(..) => unreachable!(), } } } @@ -403,6 +421,15 @@ ${helpers.single_keyword_system("font-variant-caps", _ => false } } + + /// Obtain a Servo computed value from a Gecko computed font-weight + pub unsafe fn from_gecko_weight(weight: u16) -> Self { + use std::mem::transmute; + debug_assert!(weight >= 100); + debug_assert!(weight <= 900); + debug_assert!(weight % 10 == 0); + transmute(weight) + } } } impl ToCss for computed_value::T { @@ -457,6 +484,11 @@ ${helpers.single_keyword_system("font-variant-caps", computed_value::T::Weight800 => computed_value::T::Weight700, computed_value::T::Weight900 => computed_value::T::Weight700, }, + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + context.style.cached_system_font.as_ref().unwrap().font_weight.clone() + + } } } @@ -1934,9 +1966,13 @@ ${helpers.single_keyword("-moz-math-variant", quoted: true }) }).collect::>(); + let weight = unsafe { + longhands::font_weight::computed_value::T::from_gecko_weight(system.weight) + }; let ret = ComputedSystemFont { font_family: longhands::font_family::computed_value::T(family), font_size: Au(system.size), + font_weight: weight, % 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 diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 5e8c79bf4b0..30b06c524b3 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -46,7 +46,7 @@ % for name in SYSTEM_FONT_LONGHANDS: ${name}: ${name}::SpecifiedValue::system_font(sys), % endfor - % for name in gecko_sub_properties + "weight variant_caps stretch".split(): + % for name in gecko_sub_properties + "variant_caps stretch".split(): % if "font_" + name not in SYSTEM_FONT_LONGHANDS: font_${name}: font_${name}::get_initial_specified_value(), % endif From f973a9720d615cc2b47db6f29b0c7e3ebc73e442 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 4/7] stylo: System font support for font-size-adjust --- components/style/properties/data.py | 2 +- components/style/properties/gecko.mako.rs | 5 +- .../style/properties/longhand/font.mako.rs | 52 ++++++++++++++++++- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index f53b73c9a8d..97519122a62 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -15,7 +15,7 @@ ALL_SIZES = [(size, False) for size in PHYSICAL_SIZES] + [(size, True) for size SYSTEM_FONT_LONGHANDS = """font_family font_size font_style font_variant_caps font_stretch font_kerning - font_variant_position font_weight""".split() + font_variant_position font_weight font_size_adjust""".split() def maybe_moz_logical_alias(product, side, prop): if product == "gecko" and side[1]: diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 16e7a1d0cf4..d124a45eaaf 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1405,10 +1405,7 @@ fn static_assert() { pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T { use properties::longhands::font_size_adjust::computed_value::T; - match self.gecko.mFont.sizeAdjust { - -1.0 => T::None, - _ => T::Number(self.gecko.mFont.sizeAdjust), - } + T::from_gecko_adjust(self.gecko.mFont.sizeAdjust) } #[allow(non_snake_case)] diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 321aa51fae7..4bf21656772 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -821,6 +821,7 @@ ${helpers.single_keyword_system("font-variant-caps", <%helpers:longhand products="gecko" name="font-size-adjust" animation_type="normal" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; @@ -832,6 +833,7 @@ ${helpers.single_keyword_system("font-variant-caps", pub enum SpecifiedValue { None, Number(specified::Number), + System(SystemFont), } impl ToCss for SpecifiedValue { @@ -841,6 +843,7 @@ ${helpers.single_keyword_system("font-variant-caps", match *self { SpecifiedValue::None => dest.write_str("none"), SpecifiedValue::Number(number) => number.to_css(dest), + SpecifiedValue::System(_) => Ok(()), } } } @@ -852,6 +855,11 @@ ${helpers.single_keyword_system("font-variant-caps", match *self { SpecifiedValue::None => computed_value::T::None, SpecifiedValue::Number(ref n) => computed_value::T::Number(n.to_computed_value(context)), + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + context.style.cached_system_font.as_ref().unwrap().font_size_adjust + + } } } @@ -863,6 +871,19 @@ ${helpers.single_keyword_system("font-variant-caps", } } + 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 + } + } + } + pub mod computed_value { use properties::animated_properties::Interpolate; use std::fmt; @@ -887,6 +908,15 @@ ${helpers.single_keyword_system("font-variant-caps", } } + impl T { + pub fn from_gecko_adjust(gecko: f32) -> Self { + match gecko { + -1.0 => T::None, + _ => T::Number(gecko), + } + } + } + impl Interpolate for T { fn interpolate(&self, other: &Self, time: f64) -> Result { match (*self, *other) { @@ -1921,6 +1951,7 @@ ${helpers.single_keyword("-moz-math-variant", use app_units::Au; use cssparser::Parser; use properties::longhands; + use std::hash::{Hash, Hasher}; use values::computed::{ToComputedValue, Context}; <% system_fonts = """caption icon menu message-box small-caption status-bar @@ -1937,6 +1968,24 @@ ${helpers.single_keyword("-moz-math-variant", % endfor } + // ComputedValues are compared at times + // so we need these impls. We don't want to + // add Eq to Number (which contains a float) + // so instead we have an eq impl which skips the + // cached values + impl PartialEq for ComputedSystemFont { + fn eq(&self, other: &Self) -> bool { + self.system_font == other.system_font + } + } + impl Eq for ComputedSystemFont {} + + impl Hash for ComputedSystemFont { + fn hash(&self, hasher: &mut H) { + self.system_font.hash(hasher) + } + } + impl ToComputedValue for SystemFont { type ComputedValue = ComputedSystemFont; @@ -1973,6 +2022,7 @@ ${helpers.single_keyword("-moz-math-variant", font_family: longhands::font_family::computed_value::T(family), font_size: Au(system.size), font_weight: weight, + font_size_adjust: longhands::font_size_adjust::computed_value::T::from_gecko_adjust(system.sizeAdjust), % 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 @@ -2002,7 +2052,7 @@ ${helpers.single_keyword("-moz-math-variant", debug_assert!(system == context.style.cached_system_font.as_ref().unwrap().system_font) } - #[derive(Clone, Debug, PartialEq, Eq, Hash)] + #[derive(Clone, Debug)] pub struct ComputedSystemFont { % for name in SYSTEM_FONT_LONGHANDS: pub ${name}: longhands::${name}::computed_value::T, From 681df60191620a9881474bd56573492d9ec02cdb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 5/7] stylo: System font support for bitflag properties and font-language-override --- components/style/properties/data.py | 5 +- components/style/properties/gecko.mako.rs | 104 ++------ components/style/properties/helpers.mako.rs | 38 +++ .../style/properties/longhand/font.mako.rs | 240 +++++++++++++++--- .../style/properties/shorthand/font.mako.rs | 6 +- 5 files changed, 267 insertions(+), 126 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 97519122a62..50952d500cc 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -15,7 +15,10 @@ ALL_SIZES = [(size, False) for size in PHYSICAL_SIZES] + [(size, True) for size SYSTEM_FONT_LONGHANDS = """font_family font_size font_style font_variant_caps font_stretch font_kerning - font_variant_position font_weight font_size_adjust""".split() + font_variant_position font_weight + font_size_adjust font_variant_alternates + font_variant_ligatures font_variant_east_asian + font_variant_numeric font_language_override""".split() def maybe_moz_logical_alias(product, side, prop): if product == "gecko" and side[1]: diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index d124a45eaaf..72cdf4e21a1 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -298,27 +298,6 @@ def set_gecko_property(ffi_name, expr): } -<%def name="impl_bitflags_setter(ident, gecko_ffi_name, bit_map, gecko_bit_prefix, cast_type='u8')"> - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - % for gecko_bit in bit_map.values(): - use gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit}; - % endfor - - let mut bits: ${cast_type} = 0; - // FIXME: if we ensure that the Servo bitflags storage is the same - // as Gecko's one, we can just copy it. - % for servo_bit, gecko_bit in bit_map.iteritems(): - if v.contains(longhands::${ident}::${servo_bit}) { - bits |= ${gecko_bit_prefix}${gecko_bit} as ${cast_type}; - } - % endfor - - self.gecko.${gecko_ffi_name} = bits as ${cast_type}; - } - - - /// Convert a Servo color into an nscolor; with currentColor as 0 /// /// Call sites will need to be updated after https://bugzilla.mozilla.org/show_bug.cgi?id=760345 @@ -1371,7 +1350,10 @@ fn static_assert() { ${impl_simple_copy('font_weight', 'mFont.weight')} pub fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T { - unsafe { longhands::font_weight::computed_value::T::from_gecko_weight(self.gecko.mFont.weight) } + debug_assert!(self.gecko.mFont.weight >= 100); + debug_assert!(self.gecko.mFont.weight <= 900); + debug_assert!(self.gecko.mFont.weight % 10 == 0); + unsafe { transmute(self.gecko.mFont.weight) } } pub fn set_font_synthesis(&mut self, v: longhands::font_synthesis::computed_value::T) { @@ -1405,7 +1387,10 @@ fn static_assert() { pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T { use properties::longhands::font_size_adjust::computed_value::T; - T::from_gecko_adjust(self.gecko.mFont.sizeAdjust) + match self.gecko.mFont.sizeAdjust { + -1.0 => T::None, + _ => T::Number(self.gecko.mFont.sizeAdjust), + } } #[allow(non_snake_case)] @@ -1429,20 +1414,10 @@ fn static_assert() { } ${impl_simple_copy('font_language_override', 'mFont.languageOverride')} - <% font_variant_alternates_map = { "HISTORICAL_FORMS": "HISTORICAL", - "STYLISTIC": "STYLISTIC", - "STYLESET": "STYLESET", - "CHARACTER_VARIANT": "CHARACTER_VARIANT", - "SWASH": "SWASH", - "ORNAMENTS": "ORNAMENTS", - "ANNOTATION": "ANNOTATION" } %> - // FIXME: Set alternateValues as well. - // self.gecko.mFont.alternateValues = xxx; - ${impl_bitflags_setter('font_variant_alternates', - 'mFont.variantAlternates', - font_variant_alternates_map, - 'NS_FONT_VARIANT_ALTERNATES_', - cast_type='u16')} + pub fn set_font_variant_alternates(&mut self, v: longhands::font_variant_alternates::computed_value::T) { + self.gecko.mFont.variantAlternates = v.to_gecko_keyword() + } + #[allow(non_snake_case)] pub fn copy_font_variant_alternates_from(&mut self, other: &Self) { self.gecko.mFont.variantAlternates = other.gecko.mFont.variantAlternates; @@ -1450,53 +1425,22 @@ fn static_assert() { // self.gecko.mFont.alternateValues = other.gecko.mFont.alternateValues; } - // servo_bit: gecko_bit - <% font_variant_ligatures_map = { "NONE": "NONE", - "COMMON_LIGATURES": "COMMON", - "NO_COMMON_LIGATURES": "NO_COMMON", - "DISCRETIONARY_LIGATURES": "DISCRETIONARY", - "NO_DISCRETIONARY_LIGATURES": "NO_DISCRETIONARY", - "HISTORICAL_LIGATURES": "HISTORICAL", - "NO_HISTORICAL_LIGATURES": "NO_HISTORICAL", - "CONTEXTUAL": "CONTEXTUAL", - "NO_CONTEXTUAL": "NO_CONTEXTUAL" } %> - ${impl_bitflags_setter('font_variant_ligatures', - 'mFont.variantLigatures', - font_variant_ligatures_map, - 'NS_FONT_VARIANT_LIGATURES_', - cast_type='u16')} + pub fn set_font_variant_ligatures(&mut self, v: longhands::font_variant_ligatures::computed_value::T) { + self.gecko.mFont.variantLigatures = v.to_gecko_keyword() + } + ${impl_simple_copy('font_variant_ligatures', 'mFont.variantLigatures')} - // servo_bit: gecko_bit - <% font_variant_east_asian_map = { "JIS78": "JIS78", - "JIS83": "JIS83", - "JIS90": "JIS90", - "JIS04": "JIS04", - "SIMPLIFIED": "SIMPLIFIED", - "TRADITIONAL": "TRADITIONAL", - "FULL_WIDTH": "FULL_WIDTH", - "PROPORTIONAL_WIDTH": "PROP_WIDTH", - "RUBY": "RUBY" } %> - ${impl_bitflags_setter('font_variant_east_asian', - 'mFont.variantEastAsian', - font_variant_east_asian_map, - 'NS_FONT_VARIANT_EAST_ASIAN_', - cast_type='u16')} + pub fn set_font_variant_east_asian(&mut self, v: longhands::font_variant_east_asian::computed_value::T) { + self.gecko.mFont.variantEastAsian = v.to_gecko_keyword() + } + ${impl_simple_copy('font_variant_east_asian', 'mFont.variantEastAsian')} - // servo_bit: gecko_bit - <% font_variant_numeric_map = { "LINING_NUMS": "LINING", - "OLDSTYLE_NUMS": "OLDSTYLE", - "PROPORTIONAL_NUMS": "PROPORTIONAL", - "TABULAR_NUMS": "TABULAR", - "DIAGONAL_FRACTIONS": "DIAGONAL_FRACTIONS", - "STACKED_FRACTIONS": "STACKED_FRACTIONS", - "SLASHED_ZERO": "SLASHZERO", - "ORDINAL": "ORDINAL" } %> - ${impl_bitflags_setter('font_variant_numeric', - 'mFont.variantNumeric', - font_variant_numeric_map, - 'NS_FONT_VARIANT_NUMERIC_')} + pub fn set_font_variant_numeric(&mut self, v: longhands::font_variant_numeric::computed_value::T) { + self.gecko.mFont.variantNumeric = v.to_gecko_keyword() + } + ${impl_simple_copy('font_variant_numeric', 'mFont.variantNumeric')} diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 978bce1ea44..4f425bc5362 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -566,6 +566,44 @@ } +<%def name="gecko_bitflags_conversion(bit_map, gecko_bit_prefix, type, kw_type='u8')"> + #[cfg(feature = "gecko")] + impl ${type} { + /// Obtain a specified value from a Gecko keyword value + /// + /// Intended for use with presentation attributes, not style structs + pub fn from_gecko_keyword(kw: ${kw_type}) -> Self { + % for gecko_bit in bit_map.values(): + use gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit}; + % endfor + + let mut bits = ${type}::empty(); + % for servo_bit, gecko_bit in bit_map.iteritems(): + if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 { + bits |= ${servo_bit}; + } + % endfor + bits + } + + pub fn to_gecko_keyword(self) -> ${kw_type} { + % for gecko_bit in bit_map.values(): + use gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit}; + % endfor + + let mut bits: ${kw_type} = 0; + // FIXME: if we ensure that the Servo bitflags storage is the same + // as Gecko's one, we can just copy it. + % for servo_bit, gecko_bit in bit_map.iteritems(): + if self.contains(${servo_bit}) { + bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type}; + } + % endfor + bits + } + } + + <%def name="single_keyword_computed(name, values, vector=False, extra_specified=None, needs_conversion=False, **kwargs)"> <% diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 4bf21656772..99d16bdc23b 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -16,6 +16,52 @@ %endif +// Define ToComputedValue, ToCss, and other boilerplate for a specified value +// which is of the form `enum SpecifiedValue {Value(..), System(SystemFont)}` +<%def name="simple_system_boilerplate(name)"> + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Value(v) => v.to_css(dest), + SpecifiedValue::System(_) => Ok(()) + } + } + } + + + 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 + } + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + fn to_computed_value(&self, context: &Context) -> computed_value::T { + match *self { + SpecifiedValue::Value(v) => v, + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + context.style.cached_system_font.as_ref().unwrap().${name} + + } + } + } + + fn from_computed_value(other: &computed_value::T) -> Self { + SpecifiedValue::Value(*other) + } + } + + <%helpers:longhand name="font-family" animation_type="none" need_index="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-family"> use properties::longhands::system_font::SystemFont; @@ -1036,17 +1082,16 @@ ${helpers.single_keyword_system("font-kerning", /// https://github.com/servo/servo/issues/15957 <%helpers:longhand name="font-variant-alternates" products="gecko" animation_type="none" spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-alternates"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); bitflags! { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub flags SpecifiedValue: u8 { + pub flags VariantAlternates: u8 { const NORMAL = 0, const HISTORICAL_FORMS = 0x01, const STYLISTIC = 0x02, @@ -1058,7 +1103,25 @@ ${helpers.single_keyword_system("font-kerning", } } - impl ToCss for SpecifiedValue { + #[derive(Debug, Clone, PartialEq)] + pub enum SpecifiedValue { + Value(VariantAlternates), + System(SystemFont) + } + + <%self:simple_system_boilerplate name="font_variant_alternates"> + + <% font_variant_alternates_map = { "HISTORICAL_FORMS": "HISTORICAL", + "STYLISTIC": "STYLISTIC", + "STYLESET": "STYLESET", + "CHARACTER_VARIANT": "CHARACTER_VARIANT", + "SWASH": "SWASH", + "ORNAMENTS": "ORNAMENTS", + "ANNOTATION": "ANNOTATION" } %> + ${helpers.gecko_bitflags_conversion(font_variant_alternates_map, 'NS_FONT_VARIANT_ALTERNATES_', + 'VariantAlternates', kw_type='u16')} + + impl ToCss for VariantAlternates { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.is_empty() { return dest.write_str("normal") @@ -1092,7 +1155,7 @@ ${helpers.single_keyword_system("font-kerning", } pub mod computed_value { - pub type T = super::SpecifiedValue; + pub type T = super::VariantAlternates; } #[inline] pub fn get_initial_value() -> computed_value::T { @@ -1100,7 +1163,7 @@ ${helpers.single_keyword_system("font-kerning", } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::empty() + SpecifiedValue::Value(VariantAlternates::empty()) } /// normal | @@ -1112,10 +1175,10 @@ ${helpers.single_keyword_system("font-kerning", /// ornaments() || /// annotation() ] pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut result = SpecifiedValue::empty(); + let mut result = VariantAlternates::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(result) + return Ok(SpecifiedValue::Value(result)) } while let Ok(ident) = input.try(|input| input.expect_ident()) { @@ -1136,7 +1199,7 @@ ${helpers.single_keyword_system("font-kerning", } if !result.is_empty() { - Ok(result) + Ok(SpecifiedValue::Value(result)) } else { Err(()) } @@ -1155,17 +1218,16 @@ macro_rules! exclusive_value { <%helpers:longhand name="font-variant-east-asian" products="gecko" animation_type="none" 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; use values::HasViewportPercentage; - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); bitflags! { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub flags SpecifiedValue: u16 { + pub flags VariantEastAsian: u16 { const NORMAL = 0, const JIS78 = 0x01, const JIS83 = 0x02, @@ -1179,7 +1241,31 @@ macro_rules! exclusive_value { } } - impl ToCss for SpecifiedValue { + + #[derive(Debug, Clone, PartialEq)] + pub enum SpecifiedValue { + Value(VariantEastAsian), + System(SystemFont) + } + + <%self:simple_system_boilerplate name="font_variant_east_asian"> + + // servo_bit: gecko_bit + <% font_variant_east_asian_map = { "JIS78": "JIS78", + "JIS83": "JIS83", + "JIS90": "JIS90", + "JIS04": "JIS04", + "SIMPLIFIED": "SIMPLIFIED", + "TRADITIONAL": "TRADITIONAL", + "FULL_WIDTH": "FULL_WIDTH", + "PROPORTIONAL_WIDTH": "PROP_WIDTH", + "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(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.is_empty() { return dest.write_str("normal") @@ -1215,7 +1301,7 @@ macro_rules! exclusive_value { } pub mod computed_value { - pub type T = super::SpecifiedValue; + pub type T = super::VariantEastAsian; } #[inline] pub fn get_initial_value() -> computed_value::T { @@ -1223,7 +1309,7 @@ macro_rules! exclusive_value { } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::empty() + SpecifiedValue::Value(VariantEastAsian::empty()) } /// normal | [ || || ruby ] @@ -1232,10 +1318,10 @@ macro_rules! exclusive_value { <% east_asian_variant_values = "JIS78 | JIS83 | JIS90 | JIS04 | SIMPLIFIED | TRADITIONAL" %> <% east_asian_width_values = "FULL_WIDTH | PROPORTIONAL_WIDTH" %> pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut result = SpecifiedValue::empty(); + let mut result = VariantEastAsian::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(result) + return Ok(SpecifiedValue::Value(result)) } while let Ok(ident) = input.try(|input| input.expect_ident()) { @@ -1264,7 +1350,7 @@ macro_rules! exclusive_value { } if !result.is_empty() { - Ok(result) + Ok(SpecifiedValue::Value(result)) } else { Err(()) } @@ -1273,17 +1359,16 @@ macro_rules! exclusive_value { <%helpers:longhand name="font-variant-ligatures" products="gecko" animation_type="none" spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-ligatures"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); bitflags! { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub flags SpecifiedValue: u16 { + pub flags VariantLigatures: u16 { const NORMAL = 0, const NONE = 0x01, const COMMON_LIGATURES = 0x02, @@ -1297,7 +1382,30 @@ macro_rules! exclusive_value { } } - impl ToCss for SpecifiedValue { + + #[derive(Debug, Clone, PartialEq)] + pub enum SpecifiedValue { + Value(VariantLigatures), + System(SystemFont) + } + + <%self:simple_system_boilerplate name="font_variant_ligatures"> + + // servo_bit: gecko_bit + <% font_variant_ligatures_map = { "NONE": "NONE", + "COMMON_LIGATURES": "COMMON", + "NO_COMMON_LIGATURES": "NO_COMMON", + "DISCRETIONARY_LIGATURES": "DISCRETIONARY", + "NO_DISCRETIONARY_LIGATURES": "NO_DISCRETIONARY", + "HISTORICAL_LIGATURES": "HISTORICAL", + "NO_HISTORICAL_LIGATURES": "NO_HISTORICAL", + "CONTEXTUAL": "CONTEXTUAL", + "NO_CONTEXTUAL": "NO_CONTEXTUAL" } %> + + ${helpers.gecko_bitflags_conversion(font_variant_ligatures_map, 'NS_FONT_VARIANT_LIGATURES_', + 'VariantLigatures', kw_type='u16')} + + impl ToCss for VariantLigatures { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.is_empty() { return dest.write_str("normal") @@ -1335,7 +1443,7 @@ macro_rules! exclusive_value { } pub mod computed_value { - pub type T = super::SpecifiedValue; + pub type T = super::VariantLigatures; } #[inline] pub fn get_initial_value() -> computed_value::T { @@ -1343,7 +1451,7 @@ macro_rules! exclusive_value { } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::empty() + SpecifiedValue::Value(VariantLigatures::empty()) } /// normal | none | @@ -1360,13 +1468,13 @@ macro_rules! exclusive_value { <% historical_lig_values = "HISTORICAL_LIGATURES | NO_HISTORICAL_LIGATURES" %> <% contextual_alt_values = "CONTEXTUAL | NO_CONTEXTUAL" %> pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut result = SpecifiedValue::empty(); + let mut result = VariantLigatures::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(result) + return Ok(SpecifiedValue::Value(result)) } if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(NONE) + return Ok(SpecifiedValue::Value(NONE)) } while let Ok(ident) = input.try(|input| input.expect_ident()) { @@ -1393,7 +1501,7 @@ macro_rules! exclusive_value { } if !result.is_empty() { - Ok(result) + Ok(SpecifiedValue::Value(result)) } else { Err(()) } @@ -1402,17 +1510,16 @@ macro_rules! exclusive_value { <%helpers:longhand name="font-variant-numeric" products="gecko" animation_type="none" spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-numeric"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); bitflags! { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub flags SpecifiedValue: u8 { + pub flags VariantNumeric: u8 { const NORMAL = 0, const LINING_NUMS = 0x01, const OLDSTYLE_NUMS = 0x02, @@ -1425,7 +1532,31 @@ macro_rules! exclusive_value { } } - impl ToCss for SpecifiedValue { + + + #[derive(Debug, Clone, PartialEq)] + pub enum SpecifiedValue { + Value(VariantNumeric), + System(SystemFont) + } + + <%self:simple_system_boilerplate name="font_variant_numeric"> + + + // servo_bit: gecko_bit + <% font_variant_numeric_map = { "LINING_NUMS": "LINING", + "OLDSTYLE_NUMS": "OLDSTYLE", + "PROPORTIONAL_NUMS": "PROPORTIONAL", + "TABULAR_NUMS": "TABULAR", + "DIAGONAL_FRACTIONS": "DIAGONAL_FRACTIONS", + "STACKED_FRACTIONS": "STACKED_FRACTIONS", + "SLASHED_ZERO": "SLASHZERO", + "ORDINAL": "ORDINAL" } %> + + ${helpers.gecko_bitflags_conversion(font_variant_numeric_map, 'NS_FONT_VARIANT_NUMERIC_', + 'VariantNumeric')} + + impl ToCss for VariantNumeric { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.is_empty() { return dest.write_str("normal") @@ -1460,7 +1591,7 @@ macro_rules! exclusive_value { } pub mod computed_value { - pub type T = super::SpecifiedValue; + pub type T = super::VariantNumeric; } #[inline] pub fn get_initial_value() -> computed_value::T { @@ -1468,7 +1599,7 @@ macro_rules! exclusive_value { } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::empty() + SpecifiedValue::Value(VariantNumeric::empty()) } /// normal | @@ -1484,10 +1615,10 @@ macro_rules! exclusive_value { <% numeric_spacing_values = "PROPORTIONAL_NUMS | TABULAR_NUMS" %> <% numeric_fraction_values = "DIAGONAL_FRACTIONS | STACKED_FRACTIONS" %> pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut result = SpecifiedValue::empty(); + let mut result = VariantNumeric::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(result) + return Ok(SpecifiedValue::Value(result)) } while let Ok(ident) = input.try(|input| input.expect_ident()) { @@ -1514,7 +1645,7 @@ macro_rules! exclusive_value { } if !result.is_empty() { - Ok(result) + Ok(SpecifiedValue::Value(result)) } else { Err(()) } @@ -1641,6 +1772,7 @@ ${helpers.single_keyword_system("font-variant-position", <%helpers:longhand name="font-language-override" products="gecko" animation_type="none" extra_prefixes="moz" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override"> + use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; use byteorder::{BigEndian, ByteOrder}; @@ -1652,6 +1784,7 @@ ${helpers.single_keyword_system("font-variant-position", pub enum SpecifiedValue { Normal, Override(String), + System(SystemFont) } impl ToCss for SpecifiedValue { @@ -1661,6 +1794,20 @@ ${helpers.single_keyword_system("font-variant-position", SpecifiedValue::Normal => dest.write_str("normal"), SpecifiedValue::Override(ref lang) => cssparser::serialize_string(lang, dest), + SpecifiedValue::System(_) => Ok(()) + } + } + } + + 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 } } } @@ -1711,7 +1858,7 @@ ${helpers.single_keyword_system("font-variant-position", type ComputedValue = computed_value::T; #[inline] - fn to_computed_value(&self, _: &Context) -> computed_value::T { + fn to_computed_value(&self, context: &Context) -> computed_value::T { use std::ascii::AsciiExt; match *self { SpecifiedValue::Normal => computed_value::T(0), @@ -1726,6 +1873,11 @@ ${helpers.single_keyword_system("font-variant-position", let bytes = computed_lang.into_bytes(); computed_value::T(BigEndian::read_u32(&bytes)) } + SpecifiedValue::System(_) => { + <%self:nongecko_unreachable> + context.style.cached_system_font.as_ref().unwrap().font_language_override + + } } } #[inline] @@ -1959,7 +2111,11 @@ ${helpers.single_keyword("-moz-math-variant", -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() + font_kerning font_variant_position font_variant_alternates + font_variant_ligatures font_variant_east_asian + font_variant_numeric""".split() + kw_cast = """font_style font_variant_caps font_stretch + font_kerning font_variant_position""".split() %> #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum SystemFont { @@ -2025,9 +2181,13 @@ ${helpers.single_keyword("-moz-math-variant", font_size_adjust: longhands::font_size_adjust::computed_value::T::from_gecko_adjust(system.sizeAdjust), % 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 + system.${to_camel_case_lower(kwprop.replace('font_', ''))} + % if kwprop in kw_cast: + as u32 + % endif ), % endfor + font_language_override: longhands::font_language_override::computed_value::T(system.languageOverride), system_font: *self, }; unsafe { bindings::Gecko_nsFont_Destroy(&mut system); } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 30b06c524b3..8be68523ff5 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -46,11 +46,7 @@ % for name in SYSTEM_FONT_LONGHANDS: ${name}: ${name}::SpecifiedValue::system_font(sys), % endfor - % for name in gecko_sub_properties + "variant_caps stretch".split(): - % if "font_" + name not in SYSTEM_FONT_LONGHANDS: - font_${name}: font_${name}::get_initial_specified_value(), - % endif - % endfor + // line-height is just reset to initial line_height: line_height::get_initial_specified_value(), }) } From 59f16b57e74f3e853e760cee43df70f605b8a531 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 21 Mar 2017 20:38:12 -0700 Subject: [PATCH 6/7] Bug 1349417 - Part 8: stylo: Serialize system fonts correctly; r?xidorn MozReview-Commit-ID: 4q1zZUcw6zF --- .../style/properties/longhand/font.mako.rs | 12 ++++++ .../style/properties/shorthand/font.mako.rs | 42 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 99d16bdc23b..bb7e193c80c 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -2103,7 +2103,9 @@ ${helpers.single_keyword("-moz-math-variant", use app_units::Au; use cssparser::Parser; use properties::longhands; + use std::fmt; use std::hash::{Hash, Hasher}; + use style_traits::ToCss; use values::computed::{ToComputedValue, Context}; <% system_fonts = """caption icon menu message-box small-caption status-bar @@ -2124,6 +2126,16 @@ ${helpers.single_keyword("-moz-math-variant", % endfor } + impl ToCss for SystemFont { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(match *self { + % for font in system_fonts: + SystemFont::${to_camel_case(font)} => "${font}", + % endfor + }) + } + } + // ComputedValues are compared at times // so we need these impls. We don't want to // add Eq to Number (which contains a float) diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 8be68523ff5..ff3c96a1575 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -114,9 +114,51 @@ }) } + enum CheckSystemResult { + AllSystem(SystemFont), + SomeSystem, + None + } + + % if product == "gecko": + impl<'a> LonghandsToSerialize<'a> { + /// Check if some or all members are system fonts + fn check_system(&self) -> CheckSystemResult { + let mut sys = None; + let mut all = true; + + % for prop in SYSTEM_FONT_LONGHANDS: + if let Some(s) = self.${prop}.get_system() { + debug_assert!(sys.is_none() || s == sys.unwrap()); + sys = Some(s); + } else { + all = false; + } + % endfor + if self.line_height != &line_height::get_initial_specified_value() { + all = false + } + if all { + CheckSystemResult::AllSystem(sys.unwrap()) + } else if sys.is_some() { + CheckSystemResult::SomeSystem + } else { + CheckSystemResult::None + } + } + } + % endif + // This may be a bit off, unsure, possibly needs changes impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + % if product == "gecko": + match self.check_system() { + CheckSystemResult::AllSystem(sys) => return sys.to_css(dest), + CheckSystemResult::SomeSystem => return Ok(()), + CheckSystemResult::None => () + } + % endif % if product == "gecko" or data.testing: % for name in gecko_sub_properties: From 14c632408ce8bea7aeac89c3c4e3af5858529299 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 18 Apr 2017 10:51:04 -0700 Subject: [PATCH 7/7] tidy and test fixes --- components/style/gecko_string_cache/mod.rs | 2 +- components/style/properties/data.py | 4 ++- components/style/properties/gecko.mako.rs | 1 + .../helpers/animated_properties.mako.rs | 3 +- .../style/properties/longhand/font.mako.rs | 34 ++++++++++++++----- .../style/properties/shorthand/font.mako.rs | 15 ++++---- ports/geckolib/glue.rs | 5 +-- 7 files changed, 44 insertions(+), 20 deletions(-) diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index 9db8374f9a5..82589b645ea 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -11,8 +11,8 @@ use gecko_bindings::bindings::Gecko_Atomize; use gecko_bindings::bindings::Gecko_Atomize16; use gecko_bindings::bindings::Gecko_ReleaseAtom; use gecko_bindings::structs::nsIAtom; -use precomputed_hash::PrecomputedHash; use nsstring::nsAString; +use precomputed_hash::PrecomputedHash; use std::borrow::{Cow, Borrow}; use std::char::{self, DecodeUtf16}; use std::fmt::{self, Write}; diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 50952d500cc..42998f5a1cb 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -20,6 +20,7 @@ SYSTEM_FONT_LONGHANDS = """font_family font_size font_style font_variant_ligatures font_variant_east_asian font_variant_numeric font_language_override""".split() + def maybe_moz_logical_alias(product, side, prop): if product == "gecko" and side[1]: axis, dir = side[0].split("-") @@ -38,9 +39,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:] + return camel[0].lower() + camel[1:] def parse_aliases(value): diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 72cdf4e21a1..2c84a7120ea 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -95,6 +95,7 @@ pub struct ComputedValues { /// When this is Some, we compute font sizes by computing the keyword against /// the generic font, and then multiplying it by the ratio. pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, + /// The cached system font. See longhand/font.mako.rs pub cached_system_font: Option, } diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 920d6114728..5e775f29831 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -360,7 +360,8 @@ impl AnimationValue { } /// Construct an AnimationValue from a property declaration - pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, initial: &ComputedValues) -> Option { + pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, + initial: &ComputedValues) -> Option { use error_reporting::StdoutErrorReporter; use properties::LonghandId; use properties::DeclaredValue; diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index bb7e193c80c..59981c80c84 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -45,12 +45,12 @@ impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T; - fn to_computed_value(&self, context: &Context) -> computed_value::T { + fn to_computed_value(&self, _context: &Context) -> computed_value::T { match *self { SpecifiedValue::Value(v) => v, SpecifiedValue::System(_) => { <%self:nongecko_unreachable> - context.style.cached_system_font.as_ref().unwrap().${name} + _context.style.cached_system_font.as_ref().unwrap().${name} } } @@ -62,7 +62,7 @@ } -<%helpers:longhand name="font-family" animation_type="none" need_index="True" +<%helpers:longhand name="font-family" animation_type="none" need_index="True" boxed="${product == 'gecko'}" spec="https://drafts.csswg.org/css-fonts/#propdef-font-family"> use properties::longhands::system_font::SystemFont; use self::computed_value::{FontFamily, FamilyName}; @@ -1770,7 +1770,8 @@ ${helpers.single_keyword_system("font-variant-position", } -<%helpers:longhand name="font-language-override" products="gecko" animation_type="none" extra_prefixes="moz" +<%helpers:longhand name="font-language-override" products="gecko" animation_type="none" + extra_prefixes="moz" boxed="True" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override"> use properties::longhands::system_font::SystemFont; use std::fmt; @@ -1858,7 +1859,7 @@ ${helpers.single_keyword_system("font-variant-position", type ComputedValue = computed_value::T; #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { + fn to_computed_value(&self, _context: &Context) -> computed_value::T { use std::ascii::AsciiExt; match *self { SpecifiedValue::Normal => computed_value::T(0), @@ -1875,7 +1876,7 @@ ${helpers.single_keyword_system("font-variant-position", } SpecifiedValue::System(_) => { <%self:nongecko_unreachable> - context.style.cached_system_font.as_ref().unwrap().font_language_override + _context.style.cached_system_font.as_ref().unwrap().font_language_override } } @@ -2100,6 +2101,21 @@ ${helpers.single_keyword("-moz-math-variant", % if product == "gecko": pub mod system_font { + //! We deal with system fonts here + //! + //! System fonts can only be set as a group via the font shorthand. + //! They resolve at compute time (not parse time -- this lets the + //! browser respond to changes to the OS font settings). + //! + //! While Gecko handles these as a separate property and keyword + //! values on each property indicating that the font should be picked + //! from the -x-system-font property, we avoid this. Instead, + //! each font longhand has a special SystemFont variant which contains + //! the specified system font. When the cascade function (in helpers) + //! detects that a value has a system font, it will resolve it, and + //! cache it on the ComputedValues. After this, it can be just fetched + //! whenever a font longhand on the same element needs the system font. + use app_units::Au; use cssparser::Parser; use properties::longhands; @@ -2190,7 +2206,8 @@ ${helpers.single_keyword("-moz-math-variant", font_family: longhands::font_family::computed_value::T(family), font_size: Au(system.size), font_weight: weight, - font_size_adjust: longhands::font_size_adjust::computed_value::T::from_gecko_adjust(system.sizeAdjust), + font_size_adjust: longhands::font_size_adjust::computed_value + ::T::from_gecko_adjust(system.sizeAdjust), % for kwprop in kw_font_props: ${kwprop}: longhands::${kwprop}::computed_value::T::from_gecko_keyword( system.${to_camel_case_lower(kwprop.replace('font_', ''))} @@ -2199,7 +2216,8 @@ ${helpers.single_keyword("-moz-math-variant", % endif ), % endfor - font_language_override: longhands::font_language_override::computed_value::T(system.languageOverride), + font_language_override: longhands::font_language_override::computed_value + ::T(system.languageOverride), system_font: *self, }; unsafe { bindings::Gecko_nsFont_Destroy(&mut system); } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index ff3c96a1575..f82aea164cc 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -19,6 +19,7 @@ spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> use properties::longhands::{font_family, font_style, font_weight, font_stretch}; use properties::longhands::{font_size, line_height, font_variant_caps}; + #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont; <% gecko_sub_properties = "kerning language_override size_adjust \ @@ -31,7 +32,7 @@ use properties::longhands::font_${prop}; % endfor % endif - use properties::longhands::font_family::SpecifiedValue as FontFamily; + use self::font_family::SpecifiedValue as FontFamily; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { let mut nb_normals = 0; @@ -114,13 +115,13 @@ }) } - enum CheckSystemResult { - AllSystem(SystemFont), - SomeSystem, - None - } - % if product == "gecko": + enum CheckSystemResult { + AllSystem(SystemFont), + SomeSystem, + None + } + impl<'a> LonghandsToSerialize<'a> { /// Check if some or all members are system fonts fn check_system(&self) -> CheckSystemResult { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 4894f841e07..599d3473175 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1631,7 +1631,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations: let mut parser = Parser::new(&string); if let Ok(family) = FontFamily::parse(&mut parser) { if parser.is_exhausted() { - let decl = PropertyDeclaration::FontFamily(family); + let decl = PropertyDeclaration::FontFamily(Box::new(family)); write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { decls.push(decl, Importance::Normal); }) @@ -1956,7 +1956,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis .filter_map(|&(ref decl, imp)| { if imp == Importance::Normal { let property = TransitionProperty::from_declaration(decl); - let animation = AnimationValue::from_declaration(decl, &mut context, default_values); + let animation = AnimationValue::from_declaration(decl, &mut context, + default_values); debug_assert!(property.is_none() == animation.is_none(), "The failure condition of TransitionProperty::from_declaration \ and AnimationValue::from_declaration should be the same");