--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -664,16 +664,84 @@ def set_gecko_property(ffi_name, expr):
},
x => {
panic!("Found unexpected value in style struct for translate property: {:?}", x)
}
}
}
</%def>
+<%def name="impl_scale(ident, gecko_ffi_name)">
+ #[allow(non_snake_case)]
+ pub fn set_${ident}(&mut self, other: values::computed::Scale) {
+ use values::generics::transform::Scale;
+ use values::generics::transform::TransformOperation;
+
+ unsafe { self.gecko.mSpecifiedScale.clear() };
+
+ match other {
+ Scale::None => (),
+ Scale::Specified(sx, None, None) => {
+ let operation = [TransformOperation::ScaleX(sx)];
+ convert_transform(&operation, &mut self.gecko.mSpecifiedScale);
+ },
+ Scale::Specified(sx, sy, None) => {
+ let operation = [TransformOperation::Scale(sx, sy)];
+ convert_transform(&operation, &mut self.gecko.mSpecifiedScale);
+ },
+ Scale::Specified(sx, Some(sy), Some(sz)) => {
+ let operation = [TransformOperation::Scale3D(sx, sy, sz)];
+ convert_transform(&operation, &mut self.gecko.mSpecifiedScale);
+ },
+ x => {
+ panic!("Found unexpected value in style struct for scale property: {:?}", x)
+ }
+ }
+ }
+
+ #[allow(non_snake_case)]
+ pub fn copy_${ident}_from(&mut self, other: &Self) {
+ unsafe { self.gecko.mSpecifiedScale.set(&other.gecko.mSpecifiedScale); }
+ }
+
+ #[allow(non_snake_case)]
+ pub fn reset_${ident}(&mut self, other: &Self) {
+ self.copy_${ident}_from(other)
+ }
+
+ #[allow(non_snake_case)]
+ pub fn clone_${ident}(&self) -> values::computed::Scale {
+ use values::generics::transform::Scale;
+ use values::generics::transform::TransformOperation;
+
+ if self.gecko.mSpecifiedScale.mRawPtr.is_null() {
+ return Scale::None;
+ }
+
+ let list = unsafe { (*self.gecko.mSpecifiedScale.to_safe().get()).mHead.as_ref() };
+
+ let mut transform = clone_transform_from_list(list);
+ debug_assert!(transform.0.len() == 1);
+ match transform.0.pop() {
+ Some(TransformOperation::Scale3D(sx, sy, sz)) => {
+ Scale::Specified(sx, Some(sy), Some(sz))
+ },
+ Some(TransformOperation::Scale(sx, sy)) => {
+ Scale::Specified(sx, sy, None)
+ },
+ Some(TransformOperation::ScaleX(sx)) => {
+ Scale::Specified(sx, None, None)
+ },
+ x => {
+ panic!("Found unexpected value in style struct for scale property: {:?}", x)
+ }
+ }
+ }
+</%def>
+
<%def name="impl_svg_length(ident, gecko_ffi_name)">
// When context-value is used on an SVG length, the corresponding flag is
// set on mContextFlags, and the length field is set to the initial value.
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber};
use gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
let length = match v {
@@ -1652,16 +1720,17 @@ impl Clone for ${style_struct.gecko_stru
"Rotate": impl_rotate,
"SVGLength": impl_svg_length,
"SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length,
"Transform": impl_transform,
"TransformOrigin": impl_transform_origin,
"Translate": impl_translate,
+ "Scale": impl_scale,
"UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name)
# get the method and pass additional keyword or type-specific arguments
if longhand.logical:
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -615,16 +615,23 @@
${helpers.predefined_type("translate", "Translate",
"generics::transform::Translate::None",
animation_value_type="ComputedValue",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms")}
+${helpers.predefined_type("scale", "Scale",
+ "generics::transform::Scale::None",
+ animation_value_type="ComputedValue",
+ flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
+ gecko_pref="layout.css.individual-transform.enabled",
+ spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms")}
+
// CSSOM View Module
// https://www.w3.org/TR/cssom-view-1/
${helpers.single_keyword("scroll-behavior",
"auto smooth",
gecko_pref="layout.css.scroll-behavior.property-enabled",
products="gecko",
spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior",
animation_value_type="discrete")}
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -57,17 +57,17 @@ pub use self::length::{CSSPixelLength, N
pub use self::list::{ListStyleImage, Quotes};
pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage;
pub use self::position::{Position, GridAutoFlow, GridTemplateAreas};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign, TextOverflow, WordSpacing};
pub use self::time::Time;
-pub use self::transform::{TimingFunction, Transform, TransformOperation, TransformOrigin, Rotate, Translate};
+pub use self::transform::{TimingFunction, Transform, TransformOperation, TransformOrigin, Rotate, Translate, Scale};
pub use self::ui::MozForceBrokenImageIcon;
#[cfg(feature = "gecko")]
pub mod align;
pub mod angle;
pub mod background;
pub mod basic_shape;
pub mod border;
--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -11,16 +11,17 @@ use values::animated::ToAnimatedZero;
use values::computed::{Angle, Integer, Length, LengthOrPercentage, Number, Percentage};
use values::computed::{LengthOrNumber, LengthOrPercentageOrNumber};
use values::generics::transform::{self, Matrix as GenericMatrix, Matrix3D as GenericMatrix3D};
use values::generics::transform::{Transform as GenericTransform, TransformOperation as GenericTransformOperation};
use values::generics::transform::TimingFunction as GenericTimingFunction;
use values::generics::transform::TransformOrigin as GenericTransformOrigin;
use values::generics::transform::Rotate as GenericRotate;
use values::generics::transform::Translate as GenericTranslate;
+use values::generics::transform::Scale as GenericScale;
/// A single operation in a computed CSS `transform`
pub type TransformOperation = GenericTransformOperation<
Angle,
Number,
Length,
Integer,
LengthOrNumber,
@@ -296,8 +297,11 @@ impl ToAnimatedZero for Transform {
}
}
/// A computed CSS `rotate`
pub type Rotate = GenericRotate<Number, Angle>;
/// A computed CSS `translate`
pub type Translate = GenericTranslate<LengthOrPercentage, Length>;
+
+/// A computed CSS `scale`
+pub type Scale = GenericScale<Number>;
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -775,8 +775,20 @@ pub enum Rotate<Number, Angle> {
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum Translate<LengthOrPercentage, Length> {
/// 'none'
None,
/// '<length-percentage> [ <length-percentage> <length>? ]?'
Specified(LengthOrPercentage, Option<LengthOrPercentage>, Option<Length>)
}
+#[derive(ToComputedValue, Animate, ComputeSquaredDistance, ToAnimatedZero)]
+#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
+/// A value of the `Scale` property
+///
+/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
+pub enum Scale<Number> {
+ /// 'none'
+ None,
+ /// '<number>{1,3}'
+ Specified(Number, Option<Number>, Option<Number>)
+}
+
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -54,17 +54,17 @@ pub use self::outline::OutlineStyle;
pub use self::rect::LengthOrNumberRect;
pub use self::percentage::Percentage;
pub use self::position::{Position, PositionComponent, GridAutoFlow, GridTemplateAreas};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextDecorationLine};
pub use self::text::{TextAlign, TextAlignKeyword, TextOverflow, WordSpacing};
pub use self::time::Time;
-pub use self::transform::{TimingFunction, Transform, TransformOrigin, Rotate, Translate};
+pub use self::transform::{TimingFunction, Transform, TransformOrigin, Rotate, Translate, Scale};
pub use self::ui::MozForceBrokenImageIcon;
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
#[cfg(feature = "gecko")]
pub mod align;
pub mod angle;
pub mod background;
pub mod basic_shape;
--- a/servo/components/style/values/specified/transform.rs
+++ b/servo/components/style/values/specified/transform.rs
@@ -7,17 +7,18 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
use values::computed::{Context, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Percentage as ComputedPercentage, ToComputedValue};
use values::computed::transform::TimingFunction as ComputedTimingFunction;
use values::generics::transform::{Matrix3D, Transform as GenericTransform,
- Rotate as GenericRotate, Translate as GenericTranslate};
+ Rotate as GenericRotate, Translate as GenericTranslate,
+ Scale as GenericScale};
use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction, Matrix};
use values::generics::transform::{TimingKeyword, TransformOrigin as GenericTransformOrigin};
use values::generics::transform::TransformOperation as GenericTransformOperation;
use values::specified::{self, Angle, Number, Length, Integer};
use values::specified::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber};
use values::specified::position::{Side, X, Y};
/// A single operation in a specified CSS `transform`
@@ -557,8 +558,36 @@ impl Parse for Translate {
return Ok(GenericTranslate::Specified(tx, Some(ty), None));
}
}
// <number>{1}
Ok(GenericTranslate::Specified(tx, None, None))
}
}
+
+/// A specified CSS `scale`
+pub type Scale = GenericScale<Number>;
+
+impl Parse for Scale {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>
+ ) -> Result<Self, ParseError<'i>> {
+ if input.try(|i| i.expect_ident_matching("none")).is_ok() {
+ return Ok(GenericScale::None);
+ }
+
+ let sx = Number::parse(context, input)?;
+ if let Some(sy) = input.try(|i| Number::parse(context, i)).ok() {
+ if let Some(sz) = input.try(|i| Number::parse(context, i)).ok() {
+ // <length-percentage><length-percentage><length>
+ return Ok(GenericScale::Specified(sx, Some(sy), Some(sz)));
+ } else {
+ // <length-percentage>
+ return Ok(GenericScale::Specified(sx, Some(sy), None));
+ }
+ }
+
+ // <length-percentage>
+ Ok(GenericScale::Specified(sx, None, None))
+ }
+}
\ No newline at end of file