aboutsummaryrefslogtreecommitdiffstats
path: root/components/style
diff options
context:
space:
mode:
authorBoris Chiou <boris.chiou@gmail.com>2018-10-26 18:03:37 +0000
committerEmilio Cobos Álvarez <emilio@crisal.io>2018-10-28 23:45:03 +0100
commit0c057d9299e3fbec2677c25b9a76ba61d9dbdad2 (patch)
treeacde100cb3d26f4ca3577c5ca5d62a00caf33433 /components/style
parent3723042937909ec01683b500706d05457d7ab6a7 (diff)
downloadservo-0c057d9299e3fbec2677c25b9a76ba61d9dbdad2.tar.gz
servo-0c057d9299e3fbec2677c25b9a76ba61d9dbdad2.zip
style: Implement steps(jump-*) functions.
1. Add a new preference, layout.css.step-position-jump.enabled, for step(_, jump-*) timing functions. 2. We still keep JumpEnd and End tags, even though there is no difference between them. Therefore, we could disable the preference if needed. 3. Update the calculation of StepTiming to match the algorithm in the spec. 4. For servo, we implement the correct step function algorithm except for the handling of before_flag. This could be fixed later. Depends on D9313 Differential Revision: https://phabricator.services.mozilla.com/D9314
Diffstat (limited to 'components/style')
-rw-r--r--components/style/animation.rs38
-rw-r--r--components/style/values/generics/easing.rs25
-rw-r--r--components/style/values/specified/easing.rs12
3 files changed, 67 insertions, 8 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs
index 311d102729f..057019950a4 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -363,11 +363,39 @@ impl PropertyAnimation {
GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
Bezier::new(x1, y1, x2, y2).solve(time, epsilon)
},
- GenericTimingFunction::Steps(steps, StepPosition::Start) => {
- (time * (steps as f64)).ceil() / (steps as f64)
- },
- GenericTimingFunction::Steps(steps, StepPosition::End) => {
- (time * (steps as f64)).floor() / (steps as f64)
+ GenericTimingFunction::Steps(steps, pos) => {
+ let mut current_step = (time * (steps as f64)).floor() as i32;
+
+ if pos == StepPosition::Start ||
+ pos == StepPosition::JumpStart ||
+ pos == StepPosition::JumpBoth {
+ current_step = current_step + 1;
+ }
+
+ // FIXME: We should update current_step according to the "before flag".
+ // In order to get the before flag, we have to know the current animation phase
+ // and whether the iteration is reversed. For now, we skip this calculation.
+ // (i.e. Treat before_flag is unset,)
+ // https://drafts.csswg.org/css-easing/#step-timing-function-algo
+
+ if time >= 0.0 && current_step < 0 {
+ current_step = 0;
+ }
+
+ let jumps = match pos {
+ StepPosition::JumpBoth => steps + 1,
+ StepPosition::JumpNone => steps - 1,
+ StepPosition::JumpStart |
+ StepPosition::JumpEnd |
+ StepPosition::Start |
+ StepPosition::End => steps,
+ };
+
+ if time <= 1.0 && current_step > jumps {
+ current_step = jumps;
+ }
+
+ (current_step as f64) / (jumps as f64)
},
GenericTimingFunction::Keyword(keyword) => {
let (x1, x2, y1, y2) = keyword.to_bezier();
diff --git a/components/style/values/generics/easing.rs b/components/style/values/generics/easing.rs
index 018f51bba8f..f4f93a45479 100644
--- a/components/style/values/generics/easing.rs
+++ b/components/style/values/generics/easing.rs
@@ -6,6 +6,7 @@
//! https://drafts.csswg.org/css-easing/#timing-functions
use values::CSSFloat;
+use parser::ParserContext;
/// A generic easing function.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
@@ -23,7 +24,8 @@ pub enum TimingFunction<Integer, Number> {
x2: Number,
y2: Number,
},
- /// `step-start | step-end | steps(<integer>, [ start | end ]?)`
+ /// `step-start | step-end | steps(<integer>, [ <step-position> ]?)`
+ /// `<step-position> = jump-start | jump-end | jump-none | jump-both | start | end`
#[css(comma, function)]
#[value_info(other_values = "step-start,step-end")]
Steps(Integer, #[css(skip_if = "is_end")] StepPosition),
@@ -52,18 +54,37 @@ pub enum TimingKeyword {
EaseInOut,
}
+#[cfg(feature = "gecko")]
+fn step_position_jump_enabled(_context: &ParserContext) -> bool {
+ use gecko_bindings::structs;
+ unsafe { structs::StaticPrefs_sVarCache_layout_css_step_position_jump_enabled }
+}
+
+#[cfg(feature = "servo")]
+fn step_position_jump_enabled(_context: &ParserContext) -> bool {
+ false
+}
+
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
#[repr(u8)]
pub enum StepPosition {
+ #[parse(condition = "step_position_jump_enabled")]
+ JumpStart,
+ #[parse(condition = "step_position_jump_enabled")]
+ JumpEnd,
+ #[parse(condition = "step_position_jump_enabled")]
+ JumpNone,
+ #[parse(condition = "step_position_jump_enabled")]
+ JumpBoth,
Start,
End,
}
#[inline]
fn is_end(position: &StepPosition) -> bool {
- *position == StepPosition::End
+ *position == StepPosition::JumpEnd || *position == StepPosition::End
}
impl<Integer, Number> TimingFunction<Integer, Number> {
diff --git a/components/style/values/specified/easing.rs b/components/style/values/specified/easing.rs
index 1bc92e0dd48..017643cdab7 100644
--- a/components/style/values/specified/easing.rs
+++ b/components/style/values/specified/easing.rs
@@ -59,8 +59,18 @@ impl Parse for TimingFunction {
let steps = Integer::parse_positive(context, i)?;
let position = i.try(|i| {
i.expect_comma()?;
- StepPosition::parse(i)
+ StepPosition::parse(context, i)
}).unwrap_or(StepPosition::End);
+
+ // jump-none accepts a positive integer greater than 1.
+ // FIXME(emilio): The spec asks us to avoid rejecting it at parse
+ // time except until computed value time.
+ //
+ // It's not totally clear it's worth it though, and no other browser
+ // does this.
+ if position == StepPosition::JumpNone && 2 > steps.value() {
+ return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
Ok(GenericTimingFunction::Steps(steps, position))
},
_ => Err(()),