From 67799f9445f7e09a61b6ae42c1a85ad32c6c6884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 1 Apr 2017 01:57:47 +0300 Subject: [PATCH 1/2] Create a generic flag system for properties --- components/style/properties/data.py | 10 +++--- .../style/properties/longhand/box.mako.rs | 14 +++----- .../style/properties/longhand/effects.mako.rs | 7 ++-- .../properties/longhand/position.mako.rs | 3 +- .../style/properties/longhand/svg.mako.rs | 4 +-- .../style/properties/properties.mako.rs | 33 +++++++++++-------- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index ec982a1cbe1..b0d704970c7 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -128,8 +128,7 @@ class Longhand(object): 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, - creates_stacking_context=False, fixpos_cb=False, abspos_cb=False, - allowed_in_page_rule=False): + flags=None, allowed_in_page_rule=False): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) @@ -153,9 +152,7 @@ class Longhand(object): 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) + self.flags = flags.split() if flags else [] self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule) # https://drafts.csswg.org/css-animations/#keyframes @@ -190,7 +187,7 @@ class Longhand(object): class Shorthand(object): def __init__(self, name, sub_properties, spec=None, experimental=False, internal=False, allowed_in_keyframe_block=True, alias=None, extra_prefixes=None, - allowed_in_page_rule=False): + allowed_in_page_rule=False, flags=None): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) @@ -204,6 +201,7 @@ class Shorthand(object): self.alias = alias.split() if alias else [] self.extra_prefixes = extra_prefixes.split() if extra_prefixes else [] self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule) + self.flags = flags.split() if flags else [] # https://drafts.csswg.org/css-animations/#keyframes # > The inside of accepts any CSS property diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 851beb6267c..c167349c4df 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -107,8 +107,7 @@ ${helpers.single_keyword("position", "static absolute relative fixed", need_clone="True", extra_gecko_values="sticky", animation_type="none", - creates_stacking_context="True", - abspos_cb="True", + flags="CREATES_STACKING_CONTEXT ABSPOS_CB", spec="https://drafts.csswg.org/css-position/#position-property")} <%helpers:single_keyword_computed name="float" @@ -1111,8 +1110,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", <%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit" animation_type="normal" - creates_stacking_context="True" - fixpos_cb="True" + flags="CREATES_STACKING_CONTEXT FIXPOS_CB" spec="https://drafts.csswg.org/css-transforms/#propdef-transform"> use app_units::Au; use values::specified::{Angle, Length, LengthOrPercentage, Number}; @@ -1825,7 +1823,7 @@ ${helpers.single_keyword("isolation", "auto isolate", products="gecko", spec="https://drafts.fxtf.org/compositing/#isolation", - creates_stacking_context=True, + flags="CREATES_STACKING_CONTEXT", animation_type="none")} // TODO add support for logical values recto and verso @@ -1864,8 +1862,7 @@ ${helpers.predefined_type("perspective", gecko_ffi_name="mChildPerspective", spec="https://drafts.csswg.org/css-transforms/#perspective", extra_prefixes="moz webkit", - creates_stacking_context=True, - fixpos_cb=True, + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", animation_type="normal")} <%helpers:longhand name="perspective-origin" boxed="True" animation_type="normal" extra_prefixes="moz webkit" @@ -1963,8 +1960,7 @@ ${helpers.single_keyword("transform-style", "flat preserve-3d", spec="https://drafts.csswg.org/css-transforms/#transform-style-property", extra_prefixes="moz webkit", - creates_stacking_context=True, - fixpos_cb=True, + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", animation_type="none")} <%helpers:longhand name="transform-origin" animation_type="normal" extra_prefixes="moz webkit" boxed="True" diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs index 93d1100d4a0..efc7b48088e 100644 --- a/components/style/properties/longhand/effects.mako.rs +++ b/components/style/properties/longhand/effects.mako.rs @@ -11,7 +11,7 @@ ${helpers.predefined_type("opacity", "Opacity", "1.0", animation_type="normal", - creates_stacking_context=True, + flags="CREATES_STACKING_CONTEXT", spec="https://drafts.csswg.org/css-color/#opacity")} <%helpers:vector_longhand name="box-shadow" allow_empty="True" @@ -87,8 +87,7 @@ ${helpers.predefined_type("clip", // FIXME: This prop should be animatable <%helpers:longhand name="filter" animation_type="none" extra_prefixes="webkit" - creates_stacking_context="True" - fixpos_cb="True" + flags="CREATES_STACKING_CONTEXT FIXPOS_CB" spec="https://drafts.fxtf.org/filters/#propdef-filter"> //pub use self::computed_value::T as SpecifiedValue; use cssparser; @@ -526,5 +525,5 @@ ${helpers.single_keyword("mix-blend-mode", color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND", animation_type="none", - creates_stacking_context=True, + flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode")} diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index ed41a227de8..eedab26f452 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -26,9 +26,10 @@ ${helpers.predefined_type("z-index", "IntegerOrAuto", "Either::Second(Auto)", spec="https://www.w3.org/TR/CSS2/visuren.html#z-index", - creates_stacking_context=True, + flags="CREATES_STACKING_CONTEXT", animation_type="normal")} + // CSS Flexible Box Layout Module Level 1 // http://www.w3.org/TR/css3-flexbox/ diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 7de3b078690..dea04984cf1 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -59,7 +59,7 @@ ${helpers.single_keyword("mask-type", "luminance alpha", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")} <%helpers:longhand name="clip-path" animation_type="none" products="gecko" boxed="True" - creates_stacking_context="True" + flags="CREATES_STACKING_CONTEXT" spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path"> use std::fmt; use style_traits::ToCss; @@ -200,7 +200,7 @@ ${helpers.single_keyword("mask-composite", <%helpers:vector_longhand name="mask-image" products="gecko" animation_type="none" extra_prefixes="webkit" has_uncacheable_values="${product == 'gecko'}" - creates_stacking_context="True" + flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image"> use std::fmt; use style_traits::ToCss; diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 767bb39385c..b0ab39c2505 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -469,13 +469,13 @@ bitflags! { /// A set of flags for properties. pub flags PropertyFlags: u8 { /// This property requires a stacking context. - const CREATES_STACKING_CONTEXT = 0x01, + const CREATES_STACKING_CONTEXT = 1 << 0, /// This property has values that can establish a containing block for /// fixed positioned and absolutely positioned elements. - const FIXPOS_CB = 0x02, + const FIXPOS_CB = 1 << 1, /// This property has values that can establish a containing block for /// absolutely positioned elements. - const ABSPOS_CB = 0x04, + const ABSPOS_CB = 1 << 2, } } @@ -518,20 +518,14 @@ impl LonghandId { } } - /// Returns PropertyFlags for given property. + /// Returns PropertyFlags for given longhand 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 + % for flag in property.flags: + ${flag} | + % endfor PropertyFlags::empty(), % endfor } @@ -658,6 +652,19 @@ impl ShorthandId { None } + + /// Returns PropertyFlags for given shorthand property. + pub fn flags(&self) -> PropertyFlags { + match *self { + % for property in data.shorthands: + ShorthandId::${property.camel_case} => + % for flag in property.flags: + ${flag} | + % endfor + PropertyFlags::empty(), + % endfor + } + } } /// Servo's representation of a declared value for a given `T`, which is the From f9225d84aa32ba3b713c6626ebdbcc666714685c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 7 Apr 2017 23:49:18 +0300 Subject: [PATCH 2/2] Implement moz-transform property --- components/layout/fragment.rs | 4 + .../style/properties/declaration_block.rs | 23 +- components/style/properties/gecko.mako.rs | 49 ++-- .../helpers/animated_properties.mako.rs | 7 + .../style/properties/longhand/box.mako.rs | 261 ++++++++++++++++-- .../style/properties/properties.mako.rs | 2 + .../style/properties/shorthand/box.mako.rs | 20 ++ 7 files changed, 320 insertions(+), 46 deletions(-) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index b43cf1d2339..420fb2c42ae 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2902,6 +2902,10 @@ impl Fragment { transform::ComputedOperation::Matrix(m) => { m.to_gfx_matrix() } + transform::ComputedOperation::MatrixWithPercents(_) => { + // `-moz-transform` is not implemented in Servo yet. + unreachable!() + } transform::ComputedOperation::Skew(theta_x, theta_y) => { Matrix4D::create_skew(Radians::new(theta_x.radians()), Radians::new(theta_y.radians())) diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index b1b03f9a7ef..d652ab21c96 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -479,12 +479,23 @@ impl ToCss for PropertyDeclarationBlock { }; // Substeps 7 and 8 - append_serialization::<_, Cloned>, _>( - dest, - &shorthand, - value, - importance, - &mut is_first_serialization)?; + // We need to check the shorthand whether it's an alias property or not. + // If it's an alias property, it should be serialized like its longhand. + if shorthand.flags().contains(ALIAS_PROPERTY) { + append_serialization::<_, Cloned>, _>( + dest, + &property, + value, + importance, + &mut is_first_serialization)?; + } else { + append_serialization::<_, Cloned>, _>( + dest, + &shorthand, + value, + importance, + &mut is_first_serialization)?; + } for current_longhand in ¤t_longhands { // Substep 9 diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 23daca26c86..6197306879b 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1834,12 +1834,14 @@ fn static_assert() { <%def name="transform_function_arm(name, keyword, items)"> <% pattern = None - if name == "matrix": - # m11, m12, m13, .. - indices = [str(i) + str(j) for i in range(1, 5) for j in range(1, 5)] + if keyword == "matrix3d": # m11: number1, m12: number2, .. - single_patterns = ["m%s: number%s" % (index, i + 1) for (i, index) in enumerate(indices)] - pattern = "ComputedMatrix { %s }" % ", ".join(single_patterns) + single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b) + in enumerate(items)] + if name == "Matrix": + pattern = "ComputedMatrix { %s }" % ", ".join(single_patterns) + else: + pattern = "ComputedMatrixWithPercents { %s }" % ", ".join(single_patterns) else: # Generate contents of pattern from items pattern = ", ".join([b + str(a+1) for (a,b) in enumerate(items)]) @@ -1854,7 +1856,7 @@ fn static_assert() { "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)", } %> - longhands::transform::computed_value::ComputedOperation::${name.title()}(${pattern}) => { + longhands::transform::computed_value::ComputedOperation::${name}(${pattern}) => { bindings::Gecko_CSSValue_SetFunction(gecko_value, ${len(items) + 1}); bindings::Gecko_CSSValue_SetKeyword( bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), @@ -1873,6 +1875,7 @@ fn static_assert() { use gecko_bindings::structs::nsCSSKeyword::*; use gecko_bindings::sugar::refptr::RefPtr; use properties::longhands::transform::computed_value::ComputedMatrix; + use properties::longhands::transform::computed_value::ComputedMatrixWithPercents; unsafe { output.clear() }; @@ -1888,12 +1891,14 @@ fn static_assert() { value list of the same length as the transform vector"); unsafe { match servo { - ${transform_function_arm("matrix", "matrix3d", ["number"] * 16)} - ${transform_function_arm("skew", "skew", ["angle"] * 2)} - ${transform_function_arm("translate", "translate3d", ["lop", "lop", "length"])} - ${transform_function_arm("scale", "scale3d", ["number"] * 3)} - ${transform_function_arm("rotate", "rotate3d", ["number"] * 3 + ["angle"])} - ${transform_function_arm("perspective", "perspective", ["length"])} + ${transform_function_arm("Matrix", "matrix3d", ["number"] * 16)} + ${transform_function_arm("MatrixWithPercents", "matrix3d", ["number"] * 12 + ["lop"] * 2 + + ["length"] + ["number"])} + ${transform_function_arm("Skew", "skew", ["angle"] * 2)} + ${transform_function_arm("Translate", "translate3d", ["lop", "lop", "length"])} + ${transform_function_arm("Scale", "scale3d", ["number"] * 3)} + ${transform_function_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} + ${transform_function_arm("Perspective", "perspective", ["length"])} } cur = (*cur).mNext; } @@ -1929,19 +1934,19 @@ fn static_assert() { } %> eCSSKeyword_${keyword} => { - ComputedOperation::${name.title()}( - % if name == "matrix": + ComputedOperation::${name}( + % if keyword == "matrix3d": ComputedMatrix { % endif % for index, item in enumerate(items): - % if name == "matrix": + % if keyword == "matrix3d": m${index / 4 + 1}${index % 4 + 1}: % endif ${css_value_getters[item] % ( "bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1) )}, % endfor - % if name == "matrix": + % if keyword == "matrix3d": } % endif ) @@ -1968,12 +1973,12 @@ fn static_assert() { }; let servo = unsafe { match transform_function { - ${computed_operation_arm("matrix", "matrix3d", ["number"] * 16)} - ${computed_operation_arm("skew", "skew", ["angle"] * 2)} - ${computed_operation_arm("translate", "translate3d", ["lop", "lop", "length"])} - ${computed_operation_arm("scale", "scale3d", ["number"] * 3)} - ${computed_operation_arm("rotate", "rotate3d", ["number"] * 3 + ["angle"])} - ${computed_operation_arm("perspective", "perspective", ["length"])} + ${computed_operation_arm("Matrix", "matrix3d", ["number"] * 16)} + ${computed_operation_arm("Skew", "skew", ["angle"] * 2)} + ${computed_operation_arm("Translate", "translate3d", ["lop", "lop", "length"])} + ${computed_operation_arm("Scale", "scale3d", ["number"] * 3)} + ${computed_operation_arm("Rotate", "rotate3d", ["number"] * 3 + ["angle"])} + ${computed_operation_arm("Perspective", "perspective", ["length"])} _ => panic!("We shouldn't set any other transform function types"), } }; diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 5e49b263605..ee90f5283b7 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -1127,6 +1127,7 @@ fn build_identity_transform_list(list: &[TransformOperation]) -> Vec {} TransformOperation::Skew(..) => { result.push(TransformOperation::Skew(Angle::zero(), Angle::zero())) } @@ -1167,6 +1168,12 @@ fn interpolate_transform_list(from_list: &[TransformOperation], let interpolated = from.interpolate(&_to, progress).unwrap(); result.push(TransformOperation::Matrix(interpolated)); } + (&TransformOperation::MatrixWithPercents(_), + &TransformOperation::MatrixWithPercents(_)) => { + // We don't interpolate `-moz-transform` matrices yet. + // They contain percentage values. + {} + } (&TransformOperation::Skew(fx, fy), &TransformOperation::Skew(tx, ty)) => { let ix = fx.interpolate(&tx, progress).unwrap(); diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index c167349c4df..9f539243fd2 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -1108,22 +1108,26 @@ ${helpers.predefined_type("scroll-snap-coordinate", -<%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit" +<%helpers:longhand name="transform" extra_prefixes="webkit" animation_type="normal" flags="CREATES_STACKING_CONTEXT FIXPOS_CB" spec="https://drafts.csswg.org/css-transforms/#propdef-transform"> use app_units::Au; - use values::specified::{Angle, Length, LengthOrPercentage, Number}; + use values::computed::{LengthOrPercentageOrNumber as ComputedLoPoNumber, LengthOrNumber as ComputedLoN}; + use values::computed::{LengthOrPercentage as ComputedLoP, Length as ComputedLength}; + use values::specified::{Angle, Length, LengthOrPercentage}; + use values::specified::{LengthOrNumber, LengthOrPercentageOrNumber as LoPoNumber, Number}; use style_traits::ToCss; use style_traits::values::Css; - use values::CSSFloat; use values::HasViewportPercentage; use std::fmt::{self, Display}; pub mod computed_value { + use app_units::Au; use values::CSSFloat; use values::computed; + use values::computed::{Length, LengthOrPercentage}; #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -1134,6 +1138,16 @@ ${helpers.predefined_type("scroll-snap-coordinate", pub m41: CSSFloat, pub m42: CSSFloat, pub m43: CSSFloat, pub m44: CSSFloat, } + #[derive(Clone, Copy, Debug, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct ComputedMatrixWithPercents { + pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat, + pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat, + pub m31: CSSFloat, pub m32: CSSFloat, pub m33: CSSFloat, pub m34: CSSFloat, + pub m41: LengthOrPercentage, pub m42: LengthOrPercentage, + pub m43: Length, pub m44: CSSFloat, + } + impl ComputedMatrix { pub fn identity() -> ComputedMatrix { ComputedMatrix { @@ -1145,10 +1159,24 @@ ${helpers.predefined_type("scroll-snap-coordinate", } } + impl ComputedMatrixWithPercents { + pub fn identity() -> ComputedMatrixWithPercents { + ComputedMatrixWithPercents { + m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, + m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0, + m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, + m41: LengthOrPercentage::zero(), m42: LengthOrPercentage::zero(), + m43: Au(0), m44: 1.0 + } + } + } + #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum ComputedOperation { Matrix(ComputedMatrix), + // For `-moz-transform` matrix and matrix3d. + MatrixWithPercents(ComputedMatrixWithPercents), Skew(computed::Angle, computed::Angle), Translate(computed::LengthOrPercentage, computed::LengthOrPercentage, @@ -1174,6 +1202,9 @@ ${helpers.predefined_type("scroll-snap-coordinate", pub enum SpecifiedOperation { /// Represents a 2D 2x3 matrix. Matrix { a: Number, b: Number, c: Number, d: Number, e: Number, f: Number }, + /// Represents a 3D 4x4 matrix with percentage and length values. + /// For `moz-transform`. + PrefixedMatrix { a: Number, b: Number, c: Number, d: Number, e: LoPoNumber, f: LoPoNumber }, /// Represents a 3D 4x4 matrix. Matrix3D { m11: Number, m12: Number, m13: Number, m14: Number, @@ -1181,6 +1212,14 @@ ${helpers.predefined_type("scroll-snap-coordinate", m31: Number, m32: Number, m33: Number, m34: Number, m41: Number, m42: Number, m43: Number, m44: Number, }, + /// Represents a 3D 4x4 matrix with percentage and length values. + /// For `moz-transform`. + PrefixedMatrix3D { + m11: Number, m12: Number, m13: Number, m14: Number, + m21: Number, m22: Number, m23: Number, m24: Number, + m31: Number, m32: Number, m33: Number, m34: Number, + m41: LoPoNumber, m42: LoPoNumber, m43: LengthOrNumber, m44: Number, + }, /// A 2D skew. /// /// If the second angle is not provided it is assumed zero. @@ -1254,6 +1293,15 @@ ${helpers.predefined_type("scroll-snap-coordinate", l3.has_viewport_percentage() }, SpecifiedOperation::Perspective(ref length) => length.has_viewport_percentage(), + SpecifiedOperation::PrefixedMatrix{ ref e, ref f, .. } => { + e.has_viewport_percentage() || + f.has_viewport_percentage() + }, + SpecifiedOperation::PrefixedMatrix3D{ ref m41, ref m42, ref m43, .. } => { + m41.has_viewport_percentage() || + m42.has_viewport_percentage() || + m43.has_viewport_percentage() + }, _ => false } } @@ -1266,6 +1314,9 @@ ${helpers.predefined_type("scroll-snap-coordinate", Matrix { a, b, c, d, e, f} => write!( dest, "matrix({}, {}, {}, {}, {}, {})", Css(a), Css(b), Css(c), Css(d), Css(e), Css(f)), + PrefixedMatrix { a, b, c, d, ref e, ref f} => write!( + dest, "matrix({}, {}, {}, {}, {}, {})", + Css(a), Css(b), Css(c), Css(d), Css(e), Css(f)), Matrix3D { m11, m12, m13, m14, m21, m22, m23, m24, @@ -1276,6 +1327,16 @@ ${helpers.predefined_type("scroll-snap-coordinate", Css(m21), Css(m22), Css(m23), Css(m24), Css(m31), Css(m32), Css(m33), Css(m34), Css(m41), Css(m42), Css(m43), Css(m44)), + PrefixedMatrix3D { + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + ref m41, ref m42, ref m43, m44 } => write!( + dest, "matrix3d({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {})", + Css(m11), Css(m12), Css(m13), Css(m14), + Css(m21), Css(m22), Css(m23), Css(m24), + Css(m31), Css(m32), Css(m33), Css(m34), + Css(m41), Css(m42), Css(m43), Css(m44)), Skew(ax, None) => write!(dest, "skew({})", Css(ax)), Skew(ax, Some(ay)) => write!(dest, "skew({}, {})", Css(ax), Css(ay)), SkewX(angle) => write!(dest, "skewX({})", Css(angle)), @@ -1341,7 +1402,8 @@ ${helpers.predefined_type("scroll-snap-coordinate", } // Allow unitless zero angle for rotate() and skew() to align with gecko - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse_internal(context: &ParserContext, input: &mut Parser, prefixed: bool) + -> Result { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) } @@ -1356,34 +1418,110 @@ ${helpers.predefined_type("scroll-snap-coordinate", &name, "matrix" => { try!(input.parse_nested_block(|input| { - let values = try!(input.parse_comma_separated(|input| { - specified::parse_number(context, input) - })); - if values.len() != 6 { - return Err(()) + // Standard matrix parsing. + if !prefixed { + let values = try!(input.parse_comma_separated(|input| { + specified::parse_number(context, input) + })); + if values.len() != 6 { + return Err(()) + } + + result.push(SpecifiedOperation::Matrix { + a: values[0], + b: values[1], + c: values[2], + d: values[3], + e: values[4], + f: values[5], + }); + return Ok(()); } - result.push(SpecifiedOperation::Matrix { + + // Non-standard prefixed matrix parsing. + // + // -moz-transform accepts LengthOrPercentageOrNumber in the + // nondiagonal homogeneous components. transform accepts only number. + let mut values = Vec::with_capacity(4); + let mut lengths = Vec::with_capacity(2); + + // Consume first number + values.push(specified::parse_number(context, input)?); + + // Parse other 5 number/LengthOrPercentageOrNumber + for i in 0..5 { + input.expect_comma()?; + if i < 3 { + values.push(specified::parse_number(context, input)?); + } else { + // -moz-transform accepts LengthOrPercentageOrNumber in the nondiagonal + // homogeneous components. transform accepts only number. + lengths.push(LoPoNumber::parse(context, input)?) + } + } + + result.push(SpecifiedOperation::PrefixedMatrix { a: values[0], b: values[1], c: values[2], d: values[3], - e: values[4], - f: values[5] + e: lengths[0].clone(), + f: lengths[1].clone(), }); Ok(()) })) }, "matrix3d" => { try!(input.parse_nested_block(|input| { - let values = try!(input.parse_comma_separated(|i| specified::parse_number(context, i))); - if values.len() != 16 { - return Err(()) + // Standard matrix3d parsing. + if !prefixed { + let values = try!(input.parse_comma_separated(|i| specified::parse_number(context, i))); + if values.len() != 16 { + return Err(()) + } + + result.push(SpecifiedOperation::Matrix3D { + m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3], + m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7], + m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], + m41: values[12], m42: values[13], m43: values[14], m44: values[15] + }); + return Ok(()); } - result.push(SpecifiedOperation::Matrix3D { + + // Non-standard prefixed matrix3d parsing. + // + // -moz-transform accepts LengthOrPercentageOrNumber in the + // nondiagonal homogeneous components. transform accepts only number. + let mut values = Vec::with_capacity(13); + let mut lops = Vec::with_capacity(2); + let mut length_or_number = None; + + // Parse first number + values.push(specified::parse_number(context, input)?); + + // Parse other 15 number/LengthOrPercentageOrNumber + for i in 0..15 { + input.expect_comma()?; + // -moz-transform accepts LengthOrPercentageOrNumber in the nondiagonal + // homogeneous components. transform accepts only number. + if i < 11 || i > 13 { + values.push(specified::parse_number(context, input)?); + } else if i == 13 { + // m43 + length_or_number = Some(LengthOrNumber::parse(context, input)?); + } else { + // m41 and m42 + lops.push(LoPoNumber::parse(context, input)?); + } + } + + result.push(SpecifiedOperation::PrefixedMatrix3D { m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3], m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7], m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], - m41: values[12], m42: values[13], m43: values[14], m44: values[15] + m41: lops[0].clone(), m42: lops[1].clone(), m43: length_or_number.unwrap(), + m44: values[12] }); Ok(()) })) @@ -1562,12 +1700,26 @@ ${helpers.predefined_type("scroll-snap-coordinate", } } + /// Parses `transform` property. + #[inline] + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + parse_internal(context, input, false) + } + + /// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage + /// in the nondiagonal homogeneous components of matrix and matrix3d. + #[inline] + pub fn parse_prefixed(context: &ParserContext, input: &mut Parser) -> Result { + parse_internal(context, input, true) + } + impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T; #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { use self::SpecifiedOperation::*; + if self.0.is_empty() { return computed_value::T(None) } @@ -1585,11 +1737,21 @@ ${helpers.predefined_type("scroll-snap-coordinate", comp.m42 = f.to_computed_value(context); result.push(computed_value::ComputedOperation::Matrix(comp)); } + PrefixedMatrix { a, b, c, d, ref e, ref f } => { + let mut comp = computed_value::ComputedMatrixWithPercents::identity(); + comp.m11 = a.to_computed_value(context); + comp.m12 = b.to_computed_value(context); + comp.m21 = c.to_computed_value(context); + comp.m22 = d.to_computed_value(context); + comp.m41 = lopon_to_lop(&e.to_computed_value(context)); + comp.m42 = lopon_to_lop(&f.to_computed_value(context)); + result.push(computed_value::ComputedOperation::MatrixWithPercents(comp)); + } Matrix3D { m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, - m41, m42, m43, m44 } => { + ref m41, ref m42, ref m43, m44 } => { let comp = computed_value::ComputedMatrix { m11: m11.to_computed_value(context), m12: m12.to_computed_value(context), @@ -1610,6 +1772,31 @@ ${helpers.predefined_type("scroll-snap-coordinate", }; result.push(computed_value::ComputedOperation::Matrix(comp)); } + PrefixedMatrix3D { + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + ref m41, ref m42, ref m43, m44 } => { + let comp = computed_value::ComputedMatrixWithPercents { + m11: m11.to_computed_value(context), + m12: m12.to_computed_value(context), + m13: m13.to_computed_value(context), + m14: m14.to_computed_value(context), + m21: m21.to_computed_value(context), + m22: m22.to_computed_value(context), + m23: m23.to_computed_value(context), + m24: m24.to_computed_value(context), + m31: m31.to_computed_value(context), + m32: m32.to_computed_value(context), + m33: m33.to_computed_value(context), + m34: m34.to_computed_value(context), + m41: lopon_to_lop(&m41.to_computed_value(context)), + m42: lopon_to_lop(&m42.to_computed_value(context)), + m43: lon_to_length(&m43.to_computed_value(context)), + m44: m44.to_computed_value(context), + }; + result.push(computed_value::ComputedOperation::MatrixWithPercents(comp)); + } Translate(ref tx, None) => { let tx = tx.to_computed_value(context); result.push(computed_value::ComputedOperation::Translate( @@ -1755,6 +1942,26 @@ ${helpers.predefined_type("scroll-snap-coordinate", m44: Number::from_computed_value(&computed.m44), }); } + computed_value::ComputedOperation::MatrixWithPercents(ref computed) => { + result.push(SpecifiedOperation::PrefixedMatrix3D { + m11: Number::from_computed_value(&computed.m11), + m12: Number::from_computed_value(&computed.m12), + m13: Number::from_computed_value(&computed.m13), + m14: Number::from_computed_value(&computed.m14), + m21: Number::from_computed_value(&computed.m21), + m22: Number::from_computed_value(&computed.m22), + m23: Number::from_computed_value(&computed.m23), + m24: Number::from_computed_value(&computed.m24), + m31: Number::from_computed_value(&computed.m31), + m32: Number::from_computed_value(&computed.m32), + m33: Number::from_computed_value(&computed.m33), + m34: Number::from_computed_value(&computed.m34), + m41: Either::First(LengthOrPercentage::from_computed_value(&computed.m41)), + m42: Either::First(LengthOrPercentage::from_computed_value(&computed.m42)), + m43: LengthOrNumber::from_computed_value(&Either::First(computed.m43)), + m44: Number::from_computed_value(&computed.m44), + }); + } computed_value::ComputedOperation::Translate(ref tx, ref ty, ref tz) => { // XXXManishearth we lose information here; perhaps we should try to // recover the original function? Not sure if this can be observed. @@ -1792,6 +1999,24 @@ ${helpers.predefined_type("scroll-snap-coordinate", }).unwrap_or(Vec::new())) } } + + // Converts computed LengthOrPercentageOrNumber into computed + // LengthOrPercentage. Number maps into Length + fn lopon_to_lop(value: &ComputedLoPoNumber) -> ComputedLoP { + match *value { + Either::First(length_or_percentage) => length_or_percentage, + Either::Second(number) => ComputedLoP::Length(Au::from_f32_px(number)), + } + } + + // Converts computed LengthOrNumber into computed Length. + // Number maps into Length. + fn lon_to_length(value: &ComputedLoN) -> ComputedLength { + match *value { + Either::First(length) => length, + Either::Second(number) => Au::from_f32_px(number), + } + } // CSSOM View Module diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index b0ab39c2505..bb5edb137aa 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -476,6 +476,8 @@ bitflags! { /// This property has values that can establish a containing block for /// absolutely positioned elements. const ABSPOS_CB = 1 << 2, + /// This property(shorthand) is an alias of another property. + const ALIAS_PROPERTY = 1 << 3, } } diff --git a/components/style/properties/shorthand/box.mako.rs b/components/style/properties/shorthand/box.mako.rs index d135bf87e77..c3d612f9d99 100644 --- a/components/style/properties/shorthand/box.mako.rs +++ b/components/style/properties/shorthand/box.mako.rs @@ -288,3 +288,23 @@ macro_rules! try_parse_one { } } + + +<%helpers:shorthand name="-moz-transform" products="gecko" + sub_properties="transform" + flags="ALIAS_PROPERTY" + spec="Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/transform"> + use properties::longhands::transform; + + pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + Ok(Longhands { + transform: transform::parse_prefixed(context, input)?, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.transform.to_css(dest) + } + } +