author | Nazım Can Altınova <canaltinova@gmail.com> |
Tue, 21 Mar 2017 21:56:23 -0700 | |
changeset 348751 | e9c5e7c44f857855f13a259cfe7db2322d7e89db |
parent 348750 | 5bd473699d777438dae3c43892732f83ca3a7163 |
child 348752 | 68e06a8f32fbe464f7d255017c35b5dd7dfa77d6 |
push id | 31535 |
push user | cbook@mozilla.com |
push date | Wed, 22 Mar 2017 13:25:07 +0000 |
treeherder | mozilla-central@ee30286771eb [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | upsuper, emilio |
milestone | 55.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/servo/components/style/gecko_bindings/bindings.rs +++ b/servo/components/style/gecko_bindings/bindings.rs @@ -777,16 +777,27 @@ extern "C" { len: usize); } extern "C" { pub fn Gecko_EnsureStyleTransitionArrayLength(array: *mut ::std::os::raw::c_void, len: usize); } extern "C" { + pub fn Gecko_ClearWillChange(display: *mut nsStyleDisplay, length: usize); +} +extern "C" { + pub fn Gecko_AppendWillChange(display: *mut nsStyleDisplay, + atom: *mut nsIAtom); +} +extern "C" { + pub fn Gecko_CopyWillChangeFrom(dest: *mut nsStyleDisplay, + src: *mut nsStyleDisplay); +} +extern "C" { pub fn Gecko_AnimationAppendKeyframe(keyframes: RawGeckoKeyframeListBorrowedMut, offset: f32, timingFunction: *const nsTimingFunction) -> *mut Keyframe; } extern "C" {
--- a/servo/components/style/properties/data.py +++ b/servo/components/style/properties/data.py @@ -91,17 +91,18 @@ def arg_to_bool(arg): return arg == "True" class Longhand(object): def __init__(self, style_struct, name, spec=None, animatable=None, derived_from=None, keyword=None, predefined_type=None, custom_cascade=False, experimental=False, internal=False, need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False, allowed_in_keyframe_block=True, complex_color=False, cast_type='u8', - has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False): + has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False, + creates_stacking_context=False, fixpos_cb=False, abspos_cb=False): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) self.spec = spec self.keyword = keyword self.predefined_type = predefined_type self.ident = to_rust_ident(name) self.camel_case = to_camel_case(self.ident) @@ -115,16 +116,19 @@ class Longhand(object): self.depend_on_viewport_size = depend_on_viewport_size self.derived_from = (derived_from or "").split() self.complex_color = complex_color self.cast_type = cast_type self.logical = arg_to_bool(logical) self.alias = alias.split() if alias else [] self.extra_prefixes = extra_prefixes.split() if extra_prefixes else [] self.boxed = arg_to_bool(boxed) + self.creates_stacking_context = arg_to_bool(creates_stacking_context) + self.fixpos_cb = arg_to_bool(fixpos_cb) + self.abspos_cb = arg_to_bool(abspos_cb) # https://drafts.csswg.org/css-animations/#keyframes # > The <declaration-list> inside of <keyframe-block> accepts any CSS property # > except those defined in this specification, # > but does accept the `animation-play-state` property and interprets it specially. self.allowed_in_keyframe_block = allowed_in_keyframe_block \ and allowed_in_keyframe_block != "False"
--- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -1418,17 +1418,17 @@ fn static_assert() { animation-name animation-delay animation-duration animation-direction animation-fill-mode animation-play-state animation-iteration-count animation-timing-function transition-duration transition-delay transition-timing-function transition-property page-break-before page-break-after scroll-snap-points-x scroll-snap-points-y transform scroll-snap-type-y scroll-snap-coordinate - perspective-origin transform-origin -moz-binding""" %> + perspective-origin transform-origin -moz-binding will-change""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> // We manually-implement the |display| property until we get general // infrastructure for preffing certain values. <% display_keyword = Keyword("display", "inline block inline-block table inline-table table-row-group " + "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 " + @@ -1913,16 +1913,102 @@ fn static_assert() { horizontal: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[0]) .expect("clone for LengthOrPercentage failed"), vertical: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[1]) .expect("clone for LengthOrPercentage failed"), depth: Au::from_gecko_style_coord(&self.gecko.mTransformOrigin[2]) .expect("clone for Length failed"), } } + + pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) { + use gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange}; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_OPACITY; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_SCROLL; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_TRANSFORM; + use properties::PropertyId; + use properties::longhands::will_change::computed_value::T; + + fn will_change_bitfield_from_prop_flags(prop: &LonghandId) -> u8 { + use properties::{ABSPOS_CB, CREATES_STACKING_CONTEXT, FIXPOS_CB}; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_ABSPOS_CB; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_FIXPOS_CB; + use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_STACKING_CONTEXT; + let servo_flags = prop.flags(); + let mut bitfield = 0; + + if servo_flags.contains(CREATES_STACKING_CONTEXT) { + bitfield |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT; + } + if servo_flags.contains(FIXPOS_CB) { + bitfield |= NS_STYLE_WILL_CHANGE_FIXPOS_CB; + } + if servo_flags.contains(ABSPOS_CB) { + bitfield |= NS_STYLE_WILL_CHANGE_ABSPOS_CB; + } + + bitfield as u8 + } + + self.gecko.mWillChangeBitField = 0; + + match v { + T::AnimateableFeatures(features) => { + unsafe { + Gecko_ClearWillChange(&mut self.gecko, features.len()); + } + + for feature in features.iter() { + if feature == &atom!("scroll-position") { + self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL as u8; + } else if feature == &atom!("opacity") { + self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY as u8; + } else if feature == &atom!("transform") { + self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM as u8; + } + + unsafe { + Gecko_AppendWillChange(&mut self.gecko, feature.as_ptr()); + } + + if let Ok(prop_id) = PropertyId::parse(feature.to_string().into()) { + match prop_id.as_shorthand() { + Ok(shorthand) => { + for longhand in shorthand.longhands() { + self.gecko.mWillChangeBitField |= + will_change_bitfield_from_prop_flags(longhand); + } + }, + Err(longhand_or_custom) => { + if let PropertyDeclarationId::Longhand(longhand) + = longhand_or_custom { + self.gecko.mWillChangeBitField |= + will_change_bitfield_from_prop_flags(&longhand); + } + }, + } + } + } + }, + T::Auto => { + unsafe { + Gecko_ClearWillChange(&mut self.gecko, 0); + } + }, + }; + } + + pub fn copy_will_change_from(&mut self, other: &Self) { + use gecko_bindings::bindings::Gecko_CopyWillChangeFrom; + + self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField; + unsafe { + Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko as *const _ as *mut _); + } + } </%self:impl_trait> <%def name="simple_image_array_property(name, shorthand, field_name)"> <% image_layers_field = "mImage" if shorthand == "background" else "mMask" %> pub fn copy_${shorthand}_${name}_from(&mut self, other: &Self) { use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
--- a/servo/components/style/properties/longhand/box.mako.rs +++ b/servo/components/style/properties/longhand/box.mako.rs @@ -103,16 +103,18 @@ products="gecko", animatable=False, internal=True, spec="Internal (not web-exposed)")} <%helpers:single_keyword_computed name="position" values="static absolute relative fixed" need_clone="True" extra_gecko_values="sticky" animatable="False" + creates_stacking_context="True" + abspos_cb="True" spec="https://drafts.csswg.org/css-position/#position-property"> impl SpecifiedValue { pub fn is_absolutely_positioned_style(&self) -> bool { matches!(*self, SpecifiedValue::absolute | SpecifiedValue::fixed) } } use values::HasViewportPercentage; @@ -1111,16 +1113,18 @@ animatable=True, allow_empty=True, delegate_animate=True)} <%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit" animatable="True" + creates_stacking_context="True" + fixpos_cb="True" spec="https://drafts.csswg.org/css-transforms/#propdef-transform"> use app_units::Au; use style_traits::ToCss; use values::CSSFloat; use values::HasViewportPercentage; use std::fmt; @@ -1667,16 +1671,17 @@ </%helpers:longhand> // Compositing and Blending Level 1 // http://www.w3.org/TR/compositing-1/ ${helpers.single_keyword("isolation", "auto isolate", products="gecko", spec="https://drafts.fxtf.org/compositing/#isolation", + creates_stacking_context=True, animatable=False)} // TODO add support for logical values recto and verso ${helpers.single_keyword("page-break-after", "auto always avoid left right", products="gecko", spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after", animatable=False)} @@ -1705,16 +1710,18 @@ ${helpers.predefined_type("perspective", "LengthOrNone", "Either::Second(None_)", gecko_ffi_name="mChildPerspective", spec="https://drafts.csswg.org/css-transforms/#perspective", extra_prefixes="moz webkit", boxed=True, + creates_stacking_context=True, + fixpos_cb=True, animatable=True)} // FIXME: This prop should be animatable <%helpers:longhand name="perspective-origin" boxed="True" animatable="False" extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property"> use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; @@ -1814,16 +1821,18 @@ animatable=False)} // `auto` keyword is not supported in gecko yet. ${helpers.single_keyword("transform-style", "auto flat preserve-3d" if product == "servo" else "flat preserve-3d", spec="https://drafts.csswg.org/css-transforms/#transform-style-property", extra_prefixes="moz webkit", + creates_stacking_context=True, + fixpos_cb=True, animatable=False)} <%helpers:longhand name="transform-origin" animatable="True" extra_prefixes="moz webkit" boxed="True" spec="https://drafts.csswg.org/css-transforms/#transform-origin-property"> use app_units::Au; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; @@ -1968,8 +1977,72 @@ ${helpers.single_keyword("-moz-orient", "inline block horizontal vertical", products="gecko", gecko_ffi_name="mOrient", gecko_enum_prefix="StyleOrient", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-orient)", animatable=False)} + +<%helpers:longhand name="will-change" products="gecko" animatable="False" + spec="https://drafts.csswg.org/css-will-change/#will-change"> + use cssparser::serialize_identifier; + use std::fmt; + use style_traits::ToCss; + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + pub use super::SpecifiedValue as T; + } + + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum SpecifiedValue { + Auto, + AnimateableFeatures(Vec<Atom>), + } + + impl ToCss for SpecifiedValue { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Auto => dest.write_str("auto"), + SpecifiedValue::AnimateableFeatures(ref features) => { + let (first, rest) = features.split_first().unwrap(); + // handle head element + serialize_identifier(&*first.to_string(), dest)?; + // handle tail, precede each with a delimiter + for feature in rest { + dest.write_str(", ")?; + serialize_identifier(&*feature.to_string(), dest)?; + } + Ok(()) + } + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::Auto + } + + /// auto | <animateable-feature># + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + Ok(computed_value::T::Auto) + } else { + input.parse_comma_separated(|i| { + let ident = i.expect_ident()?; + match_ignore_ascii_case! { &ident, + "will-change" | "none" | "all" | "auto" | + "initial" | "inherit" | "unset" | "default" => return Err(()), + _ => {}, + } + Ok((Atom::from(ident))) + }).map(SpecifiedValue::AnimateableFeatures) + } + } +</%helpers:longhand>
--- a/servo/components/style/properties/longhand/effects.mako.rs +++ b/servo/components/style/properties/longhand/effects.mako.rs @@ -6,16 +6,17 @@ // Box-shadow, etc. <% data.new_style_struct("Effects", inherited=False) %> ${helpers.predefined_type("opacity", "Opacity", "1.0", animatable=True, + creates_stacking_context=True, spec="https://drafts.csswg.org/css-color/#opacity")} <%helpers:vector_longhand name="box-shadow" allow_empty="True" animatable="True" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#box-shadow"> use cssparser; use std::fmt; use style_traits::ToCss; @@ -81,16 +82,18 @@ "ClipRectOrAuto", "computed::ClipRectOrAuto::auto()", animatable=False, boxed="True", spec="https://drafts.fxtf.org/css-masking/#clip-property")} // FIXME: This prop should be animatable <%helpers:longhand name="filter" animatable="False" extra_prefixes="webkit" + creates_stacking_context="True" + fixpos_cb="True" spec="https://drafts.fxtf.org/filters/#propdef-filter"> //pub use self::computed_value::T as SpecifiedValue; use cssparser; use std::fmt; use style_traits::{self, ToCss}; use values::{CSSFloat, HasViewportPercentage}; use values::specified::{Angle, CSSColor, Length, Shadow}; use values::specified::url::SpecifiedUrl; @@ -511,9 +514,10 @@ pub fn parse_origin(context: &ParserCont } } ${helpers.single_keyword("mix-blend-mode", """normal multiply screen overlay darken lighten color-dodge color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND", animatable=False, + creates_stacking_context=True, spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode")}
--- a/servo/components/style/properties/longhand/position.mako.rs +++ b/servo/components/style/properties/longhand/position.mako.rs @@ -21,16 +21,17 @@ "computed::LengthOrPercentageOrAuto::Auto", spec="https://drafts.csswg.org/css-logical-props/#propdef-offset-%s" % side, animatable=True, logical=True)} % endfor ${helpers.predefined_type("z-index", "IntegerOrAuto", "Either::Second(Auto)", spec="https://www.w3.org/TR/CSS2/visuren.html#z-index", + creates_stacking_context=True, animatable="True")} // CSS Flexible Box Layout Module Level 1 // http://www.w3.org/TR/css3-flexbox/ // Flex container properties ${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse", spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
--- a/servo/components/style/properties/longhand/svg.mako.rs +++ b/servo/components/style/properties/longhand/svg.mako.rs @@ -54,16 +54,17 @@ // CSS Masking Module Level 1 // https://drafts.fxtf.org/css-masking ${helpers.single_keyword("mask-type", "luminance alpha", products="gecko", animatable=False, spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")} <%helpers:longhand name="clip-path" animatable="False" products="gecko" boxed="True" + creates_stacking_context="True" spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path"> use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; use values::specified::basic_shape::{ShapeSource, GeometryBox}; pub mod computed_value { use app_units::Au; @@ -184,17 +185,18 @@ "add subtract intersect exclude", vector=True, products="gecko", extra_prefixes="webkit", animatable=False, spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")} <%helpers:vector_longhand name="mask-image" products="gecko" animatable="False" extra_prefixes="webkit" - has_uncacheable_values="${product == 'gecko'}", + has_uncacheable_values="${product == 'gecko'}" + creates_stacking_context="True" spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image"> use std::fmt; use style_traits::ToCss; use std::sync::Arc; use values::specified::Image; use values::specified::url::SpecifiedUrl; use values::HasViewportPercentage;
--- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -415,16 +415,30 @@ impl Parse for CSSWideKeyword { "initial" => Ok(CSSWideKeyword::Initial), "inherit" => Ok(CSSWideKeyword::Inherit), "unset" => Ok(CSSWideKeyword::Unset), _ => Err(()) } } } +bitflags! { + /// A set of flags for properties. + pub flags PropertyFlags: u8 { + /// This property requires a stacking context. + const CREATES_STACKING_CONTEXT = 0x01, + /// This property has values that can establish a containing block for + /// fixed positioned and absolutely positioned elements. + const FIXPOS_CB = 0x02, + /// This property has values that can establish a containing block for + /// absolutely positioned elements. + const ABSPOS_CB = 0x04, + } +} + /// An identifier for a given longhand property. #[derive(Clone, Copy, Eq, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum LonghandId { % for i, property in enumerate(data.longhands): /// ${property.name} ${property.camel_case} = ${i}, % endfor @@ -453,16 +467,35 @@ impl LonghandId { </%def> </%helpers:logical_setter_helper> } % endif % endfor _ => *self } } + + /// Returns PropertyFlags for given property. + pub fn flags(&self) -> PropertyFlags { + match *self { + % for property in data.longhands: + LonghandId::${property.camel_case} => + %if property.creates_stacking_context: + CREATES_STACKING_CONTEXT | + %endif + %if property.fixpos_cb: + FIXPOS_CB | + %endif + %if property.abspos_cb: + ABSPOS_CB | + %endif + PropertyFlags::empty(), + % endfor + } + } } /// An identifier for a given shorthand property. #[derive(Clone, Copy, Eq, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum ShorthandId { % for property in data.shorthands: /// ${property.name}
new file mode 100644 --- /dev/null +++ b/servo/tests/unit/style/parsing/box_.rs @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +use cssparser::Parser; +use media_queries::CSSErrorReporterTest; +use parsing::parse; +use style::parser::ParserContext; +use style::stylesheets::Origin; +use style_traits::ToCss; + +#[test] +fn test_will_change() { + use style::properties::longhands::will_change; + + assert_roundtrip_with_context!(will_change::parse, "auto"); + assert_roundtrip_with_context!(will_change::parse, "scroll-position"); + assert_roundtrip_with_context!(will_change::parse, "contents"); + assert_roundtrip_with_context!(will_change::parse, "transition"); + assert_roundtrip_with_context!(will_change::parse, "opacity, transform"); + + assert!(parse(will_change::parse, "will-change").is_err()); + assert!(parse(will_change::parse, "all").is_err()); + assert!(parse(will_change::parse, "none").is_err()); + assert!(parse(will_change::parse, "contents, auto").is_err()); + assert!(parse(will_change::parse, "contents, inherit, initial").is_err()); + assert!(parse(will_change::parse, "transform scroll-position").is_err()); +}
--- a/servo/tests/unit/style/parsing/mod.rs +++ b/servo/tests/unit/style/parsing/mod.rs @@ -80,16 +80,17 @@ macro_rules! parse_longhand { $name::parse(&context, &mut Parser::new($s)).unwrap() }}; } mod animation; mod background; mod basic_shape; mod border; +mod box_; mod column; mod effects; mod font; mod image; mod inherited_box; mod inherited_text; mod length; mod mask;