mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #16231 - canaltinova:moz-transform, r=Manishearth
stylo: Implement -moz-transform property -moz-transform property is an alias shorthand property. It has transform as sub-property but their parsing is different in some cases(matrix/matrix3d). -moz-transform also accepts LengthOrPercentage in the nondiagonal homogeneous components of matrix and matrix3d. It looks like length and percentage values are getting computed to number directly. For example 120px converts into 120 and calc(120px + 20%) converts into 140. So I did like this. But we need to check this behavior again to be sure, I guess. Also I spent half day investigating why matrices are not serializing after this change and found out their ToCss functions is not completely implemented yet 😄 I was going to implement them but there is an easy issue about it(#15194) so I left it that way. Probably all tests won't pass without it. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #16003 and [Bug 1351356](https://bugzilla.mozilla.org/show_bug.cgi?id=1351356) <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16231) <!-- Reviewable:end -->
This commit is contained in:
commit
b8b4ec92df
11 changed files with 356 additions and 81 deletions
|
@ -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()))
|
||||
|
|
|
@ -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 <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||
|
|
|
@ -479,12 +479,23 @@ impl ToCss for PropertyDeclarationBlock {
|
|||
};
|
||||
|
||||
// Substeps 7 and 8
|
||||
append_serialization::<_, Cloned<slice::Iter< _>>, _>(
|
||||
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<slice::Iter< _>>, _>(
|
||||
dest,
|
||||
&property,
|
||||
value,
|
||||
importance,
|
||||
&mut is_first_serialization)?;
|
||||
} else {
|
||||
append_serialization::<_, Cloned<slice::Iter< _>>, _>(
|
||||
dest,
|
||||
&shorthand,
|
||||
value,
|
||||
importance,
|
||||
&mut is_first_serialization)?;
|
||||
}
|
||||
|
||||
for current_longhand in ¤t_longhands {
|
||||
// Substep 9
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1127,6 +1127,7 @@ fn build_identity_transform_list(list: &[TransformOperation]) -> Vec<TransformOp
|
|||
let identity = ComputedMatrix::identity();
|
||||
result.push(TransformOperation::Matrix(identity));
|
||||
}
|
||||
TransformOperation::MatrixWithPercents(..) => {}
|
||||
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();
|
||||
|
|
|
@ -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"
|
||||
|
@ -1109,23 +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"
|
||||
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};
|
||||
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))]
|
||||
|
@ -1136,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 {
|
||||
|
@ -1147,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,
|
||||
|
@ -1176,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,
|
||||
|
@ -1183,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.
|
||||
|
@ -1256,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
|
||||
}
|
||||
}
|
||||
|
@ -1268,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,
|
||||
|
@ -1278,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)),
|
||||
|
@ -1343,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<SpecifiedValue,()> {
|
||||
fn parse_internal(context: &ParserContext, input: &mut Parser, prefixed: bool)
|
||||
-> Result<SpecifiedValue,()> {
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(SpecifiedValue(Vec::new()))
|
||||
}
|
||||
|
@ -1358,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(())
|
||||
}))
|
||||
|
@ -1564,12 +1700,26 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
|||
}
|
||||
}
|
||||
|
||||
/// Parses `transform` property.
|
||||
#[inline]
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
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<SpecifiedValue,()> {
|
||||
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)
|
||||
}
|
||||
|
@ -1587,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),
|
||||
|
@ -1612,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(
|
||||
|
@ -1757,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.
|
||||
|
@ -1794,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),
|
||||
}
|
||||
}
|
||||
</%helpers:longhand>
|
||||
|
||||
// CSSOM View Module
|
||||
|
@ -1825,7 +2048,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 +2087,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 +2185,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"
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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/
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -469,13 +469,15 @@ 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,
|
||||
/// This property(shorthand) is an alias of another property.
|
||||
const ALIAS_PROPERTY = 1 << 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,20 +520,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 +654,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
|
||||
|
|
|
@ -288,3 +288,23 @@ macro_rules! try_parse_one {
|
|||
}
|
||||
}
|
||||
</%helpers:shorthand>
|
||||
|
||||
|
||||
<%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<Longhands, ()> {
|
||||
Ok(Longhands {
|
||||
transform: transform::parse_prefixed(context, input)?,
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
self.transform.to_css(dest)
|
||||
}
|
||||
}
|
||||
</%helpers:shorthand>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue