Bug 1357663 - Make font-stretch animatable. r?hiro
MozReview-Commit-ID: 7XcOXbipbhP
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -122,16 +122,25 @@ class Keyword(object):
return self.gecko_constant_prefix + "_" + suffix.upper()
def needs_cast(self):
return self.gecko_enum_prefix is None
def maybe_cast(self, type_str):
return "as " + type_str if self.needs_cast() else ""
+ def casted_constant_name(self, value, cast_type):
+ if cast_type is None:
+ raise TypeError("We should specify the cast_type.")
+
+ if self.gecko_enum_prefix is None:
+ return cast_type.upper() + "_" + self.gecko_constant(value)
+ else:
+ return cast_type.upper() + "_" + self.gecko_constant(value).upper().replace("::", "_")
+
def arg_to_bool(arg):
if isinstance(arg, bool):
return arg
assert arg in ["True", "False"]
return arg == "True"
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -269,24 +269,34 @@ def set_gecko_property(ffi_name, expr):
};
${set_gecko_property(gecko_ffi_name, "result")}
% if on_set:
self.${on_set}();
% endif
}
</%def>
-<%def name="impl_keyword_clone(ident, gecko_ffi_name, keyword)">
+<%def name="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type='u8')">
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use properties::longhands::${ident}::computed_value::T as Keyword;
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
- match ${get_gecko_property(gecko_ffi_name)} ${keyword.maybe_cast("u32")} {
+
+ // Some constant macros in the gecko are defined as negative integer(e.g. font-stretch).
+ // And they are convert to signed integer in Rust bindings. We need to cast then
+ // as signed type when we have both signed/unsigned integer in order to use them
+ // as match's arms.
+ // Also, to use same implementation here we use casted constant if we have only singed values.
+ % for value in keyword.values_for('gecko'):
+ const ${keyword.casted_constant_name(value, cast_type)} : ${cast_type} = structs::${keyword.gecko_constant(value)} as ${cast_type};
+ % endfor
+
+ match ${get_gecko_property(gecko_ffi_name)} as ${cast_type} {
% for value in keyword.values_for('gecko'):
- structs::${keyword.gecko_constant(value)} => Keyword::${to_rust_ident(value)},
+ ${keyword.casted_constant_name(value, cast_type)} => Keyword::${to_rust_ident(value)},
% endfor
% if keyword.gecko_inexhaustive:
x => panic!("Found unexpected value in style struct for ${ident} property: {:?}", x),
% endif
}
}
</%def>
@@ -329,21 +339,21 @@ fn color_to_nscolor_zero_currentcolor(co
% if complex_color:
${get_gecko_property(gecko_ffi_name)}.into()
% else:
Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}))
% endif
}
</%def>
-<%def name="impl_keyword(ident, gecko_ffi_name, keyword, need_clone, **kwargs)">
-<%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, **kwargs)"></%call>
+<%def name="impl_keyword(ident, gecko_ffi_name, keyword, need_clone, cast_type='u8', **kwargs)">
+<%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type, **kwargs)"></%call>
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
%if need_clone:
-<%call expr="impl_keyword_clone(ident, gecko_ffi_name, keyword)"></%call>
+<%call expr="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type)"></%call>
% endif
</%def>
<%def name="impl_simple(ident, gecko_ffi_name, need_clone=False)">
<%call expr="impl_simple_setter(ident, gecko_ffi_name)"></%call>
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
% if need_clone:
<%call expr="impl_simple_clone(ident, gecko_ffi_name)"></%call>
@@ -1875,16 +1885,17 @@ fn static_assert() {
"table-header-group table-footer-group table-row table-column-group " +
"table-column table-cell table-caption list-item flex none " +
"inline-flex grid inline-grid ruby ruby-base ruby-base-container " +
"ruby-text ruby-text-container contents flow-root -webkit-box " +
"-webkit-inline-box -moz-box -moz-inline-box -moz-grid -moz-inline-grid " +
"-moz-grid-group -moz-grid-line -moz-stack -moz-inline-stack -moz-deck " +
"-moz-popup -moz-groupbox",
gecko_enum_prefix="StyleDisplay",
+ gecko_inexhaustive="True",
gecko_strip_moz_prefix=False) %>
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
use properties::longhands::display::computed_value::T as Keyword;
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
let result = match v {
% for value in display_keyword.values_for('gecko'):
Keyword::${to_rust_ident(value)} =>
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -12,16 +12,17 @@ use euclid::{Point2D, Size2D};
#[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
#[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
#[cfg(feature = "gecko")] use gecko_string_cache::Atom;
use properties::{CSSWideKeyword, PropertyDeclaration};
use properties::longhands;
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
use properties::longhands::font_weight::computed_value::T as FontWeight;
+use properties::longhands::font_stretch::computed_value::T as FontStretch;
use properties::longhands::line_height::computed_value::T as LineHeight;
use properties::longhands::text_shadow::computed_value::T as TextShadowList;
use properties::longhands::text_shadow::computed_value::TextShadow;
use properties::longhands::box_shadow::computed_value::T as BoxShadowList;
use properties::longhands::box_shadow::single_value::computed_value::T as BoxShadow;
use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use properties::longhands::transform::computed_value::T as TransformList;
@@ -1357,16 +1358,64 @@ impl Animatable for FontWeight {
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
let a = (*self as u32) as f64;
let b = (*other as u32) as f64;
a.compute_distance(&b)
}
}
+/// https://drafts.csswg.org/css-fonts/#font-stretch-prop
+impl Animatable for FontStretch {
+ #[inline]
+ fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+ let from = f64::from(*self);
+ let to = f64::from(*other);
+ let interpolated_mapped_index = ((from * self_portion + to * other_portion) + 0.5).floor();
+ Ok(interpolated_mapped_index.into())
+ }
+
+ #[inline]
+ fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+ let from = f64::from(*self);
+ let to = f64::from(*other);
+ from.compute_distance(&to)
+ }
+}
+
+/// We should treat font stretch as real number in order to interpolate this property.
+/// https://drafts.csswg.org/css-fonts-3/#font-stretch-animation
+impl From<FontStretch> for f64 {
+ fn from(stretch: FontStretch) -> f64 {
+ use self::FontStretch::*;
+ match stretch {
+ ultra_condensed => 1.0,
+ extra_condensed => 2.0,
+ condensed => 3.0,
+ semi_condensed => 4.0,
+ normal => 5.0,
+ semi_expanded => 6.0,
+ expanded => 7.0,
+ extra_expanded => 8.0,
+ ultra_expanded => 9.0,
+ }
+ }
+}
+
+impl Into<FontStretch> for f64 {
+ fn into(self) -> FontStretch {
+ use properties::longhands::font_stretch::computed_value::T::*;
+ debug_assert!(self >= 1.0 && self <= 9.0);
+ static FONT_STRETCH_ENUM_MAP: [FontStretch; 9] =
+ [ ultra_condensed, extra_condensed, condensed, semi_condensed, normal,
+ semi_expanded, expanded, extra_expanded, ultra_expanded ];
+ FONT_STRETCH_ENUM_MAP[(self - 1.0) as usize]
+ }
+}
+
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, V> {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(generic_position::Position {
horizontal: try!(self.horizontal.add_weighted(&other.horizontal,
self_portion, other_portion)),
vertical: try!(self.vertical.add_weighted(&other.vertical,
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -1174,33 +1174,32 @@
}
Ok(result)
},
_ => Err(())
}
}
</%helpers:longhand>
-// FIXME: This prop should be animatable
${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_value_type="none")}
+ animation_value_type="ComputedValue")}
${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",
+ spec="https://drafts.csswg.org/css-fonts/#propdef-font-kerning",
animation_value_type="none")}
/// FIXME: Implement proper handling of each values.
/// https://github.com/servo/servo/issues/15957
<%helpers:longhand name="font-variant-alternates" products="gecko" animation_value_type="none"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-alternates">
use properties::longhands::system_font::SystemFont;
use std::fmt;