зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1764126 - Part 5: Enable `linear(...)` timing function on C++ side, r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D148791
This commit is contained in:
Родитель
d3f7b3772d
Коммит
562eecc50f
|
@ -45,8 +45,9 @@ ComputedTimingFunction::Function ComputedTimingFunction::ConstructFunction(
|
||||||
return AsVariant(
|
return AsVariant(
|
||||||
StepFunc{static_cast<uint32_t>(timing.steps._0), timing.steps._1});
|
StepFunc{static_cast<uint32_t>(timing.steps._0), timing.steps._1});
|
||||||
case StyleComputedTimingFunction::Tag::LinearFunction: {
|
case StyleComputedTimingFunction::Tag::LinearFunction: {
|
||||||
// TODO(dshin): To be implemented (bug 1764126)
|
StylePiecewiseLinearFunction result;
|
||||||
return ConstructFunction(nsTimingFunction{StyleTimingKeyword::Linear});
|
Servo_CreatePiecewiseLinearFunction(&timing.linear_function._0, &result);
|
||||||
|
return AsVariant(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MOZ_ASSERT_UNREACHABLE("Unknown timing function.");
|
MOZ_ASSERT_UNREACHABLE("Unknown timing function.");
|
||||||
|
@ -175,6 +176,10 @@ double ComputedTimingFunction::GetValue(
|
||||||
},
|
},
|
||||||
[aPortion, aBeforeFlag](const StepFunc& aFunction) {
|
[aPortion, aBeforeFlag](const StepFunc& aFunction) {
|
||||||
return StepTiming(aFunction, aPortion, aBeforeFlag);
|
return StepTiming(aFunction, aPortion, aBeforeFlag);
|
||||||
|
},
|
||||||
|
[aPortion](const StylePiecewiseLinearFunction& aFunction) {
|
||||||
|
return static_cast<double>(Servo_PiecewiseLinearFunctionAt(
|
||||||
|
&aFunction, static_cast<float>(aPortion)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +199,19 @@ void ComputedTimingFunction::AppendToString(nsACString& aResult) const {
|
||||||
[](const StepFunc& aFunction) {
|
[](const StepFunc& aFunction) {
|
||||||
return StyleComputedTimingFunction::Steps(
|
return StyleComputedTimingFunction::Steps(
|
||||||
static_cast<int>(aFunction.mSteps), aFunction.mPos);
|
static_cast<int>(aFunction.mSteps), aFunction.mPos);
|
||||||
|
},
|
||||||
|
[](const StylePiecewiseLinearFunction& aFunction) {
|
||||||
|
// TODO(dshin, bug 1773493): Having to go back and forth isn't ideal.
|
||||||
|
Vector<StyleComputedLinearStop> stops;
|
||||||
|
bool reserved = stops.initCapacity(aFunction.entries.Length());
|
||||||
|
MOZ_RELEASE_ASSERT(reserved, "Failed to reserve memory");
|
||||||
|
for (const auto& e : aFunction.entries.AsSpan()) {
|
||||||
|
stops.infallibleAppend(StyleComputedLinearStop{
|
||||||
|
e.y, StyleOptional<StylePercentage>::Some(StylePercentage{e.x}),
|
||||||
|
StyleOptional<StylePercentage>::None()});
|
||||||
|
}
|
||||||
|
return StyleComputedTimingFunction::LinearFunction(
|
||||||
|
StyleOwnedSlice<StyleComputedLinearStop>{std::move(stops)});
|
||||||
})};
|
})};
|
||||||
Servo_SerializeEasing(&timing, &aResult);
|
Servo_SerializeEasing(&timing, &aResult);
|
||||||
}
|
}
|
||||||
|
@ -213,6 +231,18 @@ Maybe<ComputedTimingFunction> ComputedTimingFunction::FromLayersTimingFunction(
|
||||||
StyleStepPosition pos = static_cast<StyleStepPosition>(sf.type());
|
StyleStepPosition pos = static_cast<StyleStepPosition>(sf.type());
|
||||||
return Some(ComputedTimingFunction::Steps(sf.steps(), pos));
|
return Some(ComputedTimingFunction::Steps(sf.steps(), pos));
|
||||||
}
|
}
|
||||||
|
case layers::TimingFunction::TLinearFunction: {
|
||||||
|
auto lf = aTimingFunction.get_LinearFunction();
|
||||||
|
Vector<StylePiecewiseLinearFunctionEntry> stops;
|
||||||
|
bool reserved = stops.initCapacity(lf.stops().Length());
|
||||||
|
MOZ_RELEASE_ASSERT(reserved, "Failed to reserve memory");
|
||||||
|
for (const auto& e : lf.stops()) {
|
||||||
|
stops.infallibleAppend(
|
||||||
|
StylePiecewiseLinearFunctionEntry{e.input(), e.output()});
|
||||||
|
}
|
||||||
|
StylePiecewiseLinearFunction result;
|
||||||
|
return Some(ComputedTimingFunction{result});
|
||||||
|
}
|
||||||
case layers::TimingFunction::T__None:
|
case layers::TimingFunction::T__None:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -244,6 +274,13 @@ layers::TimingFunction ComputedTimingFunction::ToLayersTimingFunction(
|
||||||
return layers::TimingFunction{
|
return layers::TimingFunction{
|
||||||
layers::StepFunction{static_cast<int>(aFunction.mSteps),
|
layers::StepFunction{static_cast<int>(aFunction.mSteps),
|
||||||
static_cast<uint8_t>(aFunction.mPos)}};
|
static_cast<uint8_t>(aFunction.mPos)}};
|
||||||
|
},
|
||||||
|
[](const StylePiecewiseLinearFunction& aFunction) {
|
||||||
|
nsTArray<layers::LinearStop> stops{aFunction.entries.Length()};
|
||||||
|
for (const auto& e : aFunction.entries.AsSpan()) {
|
||||||
|
stops.AppendElement(layers::LinearStop{e.x, e.y});
|
||||||
|
}
|
||||||
|
return layers::TimingFunction{layers::LinearFunction{stops}};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,17 @@ class ComputedTimingFunction {
|
||||||
StyleComputedTimingFunction::Tag::Steps &&
|
StyleComputedTimingFunction::Tag::Steps &&
|
||||||
aFunction.mSteps == uint32_t(aOther.mTiming.steps._0) &&
|
aFunction.mSteps == uint32_t(aOther.mTiming.steps._0) &&
|
||||||
aFunction.mPos == aOther.mTiming.steps._1;
|
aFunction.mPos == aOther.mTiming.steps._1;
|
||||||
|
},
|
||||||
|
[&aOther](const StylePiecewiseLinearFunction& aFunction) {
|
||||||
|
if (aOther.mTiming.tag !=
|
||||||
|
StyleComputedTimingFunction::Tag::LinearFunction) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
StylePiecewiseLinearFunction other;
|
||||||
|
// TODO(dshin, bug 1773493): Having to go back and forth isn't ideal.
|
||||||
|
Servo_CreatePiecewiseLinearFunction(
|
||||||
|
&aOther.mTiming.linear_function._0, &other);
|
||||||
|
return aFunction.entries == other.entries;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
bool operator!=(const nsTimingFunction& aOther) const {
|
bool operator!=(const nsTimingFunction& aOther) const {
|
||||||
|
@ -105,13 +116,17 @@ class ComputedTimingFunction {
|
||||||
mozilla::StyleTimingKeyword mKeyword;
|
mozilla::StyleTimingKeyword mKeyword;
|
||||||
SMILKeySpline mFunction;
|
SMILKeySpline mFunction;
|
||||||
};
|
};
|
||||||
using Function = mozilla::Variant<KeywordFunction, SMILKeySpline, StepFunc>;
|
|
||||||
|
using Function = mozilla::Variant<KeywordFunction, SMILKeySpline, StepFunc,
|
||||||
|
StylePiecewiseLinearFunction>;
|
||||||
|
|
||||||
static Function ConstructFunction(const nsTimingFunction& aFunction);
|
static Function ConstructFunction(const nsTimingFunction& aFunction);
|
||||||
ComputedTimingFunction(double x1, double y1, double x2, double y2)
|
ComputedTimingFunction(double x1, double y1, double x2, double y2)
|
||||||
: mFunction{AsVariant(SMILKeySpline{x1, y1, x2, y2})} {}
|
: mFunction{AsVariant(SMILKeySpline{x1, y1, x2, y2})} {}
|
||||||
ComputedTimingFunction(uint32_t aSteps, StyleStepPosition aPos)
|
ComputedTimingFunction(uint32_t aSteps, StyleStepPosition aPos)
|
||||||
: mFunction{AsVariant(StepFunc{aSteps, aPos})} {}
|
: mFunction{AsVariant(StepFunc{aSteps, aPos})} {}
|
||||||
|
explicit ComputedTimingFunction(StylePiecewiseLinearFunction aFunction)
|
||||||
|
: mFunction{AsVariant(std::move(aFunction))} {}
|
||||||
|
|
||||||
Function mFunction;
|
Function mFunction;
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,10 +101,20 @@ struct StepFunction {
|
||||||
uint8_t type; // Converted from StyleStepPosition.
|
uint8_t type; // Converted from StyleStepPosition.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LinearStop {
|
||||||
|
float input;
|
||||||
|
float output;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LinearFunction {
|
||||||
|
LinearStop[] stops;
|
||||||
|
};
|
||||||
|
|
||||||
union TimingFunction {
|
union TimingFunction {
|
||||||
null_t;
|
null_t;
|
||||||
CubicBezierFunction;
|
CubicBezierFunction;
|
||||||
StepFunction;
|
StepFunction;
|
||||||
|
LinearFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LayerColor { DeviceColor value; };
|
struct LayerColor { DeviceColor value; };
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
prefs: [layout.css.linear-easing-function.enabled:true]
|
|
@ -0,0 +1,109 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<meta name="assert" content="This test checks the output of linear timing functions" />
|
||||||
|
<title>Tests for the output of linear timing functions</title>
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/6533">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="support/util.js"></script>
|
||||||
|
<script src="testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function assert_style_left_at(animation, time, expected_y) {
|
||||||
|
animation.currentTime = time;
|
||||||
|
assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
|
||||||
|
expected_y * 100,
|
||||||
|
0.01,
|
||||||
|
'The left of the animation should be approximately ' +
|
||||||
|
expected_y * 100 + ' at ' + time + 'ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_animations_equal_at(actual_animation, expected_animation, time) {
|
||||||
|
actual_animation.currentTime = time;
|
||||||
|
var actual_left = pxToNum(getComputedStyle(actual_animation.effect.target).left);
|
||||||
|
expected_animation.currentTime = time;
|
||||||
|
var expected_left = pxToNum(getComputedStyle(expected_animation.effect.target).left);
|
||||||
|
assert_approx_equals(actual_left,
|
||||||
|
expected_left,
|
||||||
|
0.01,
|
||||||
|
'The left of the animation should be approximately ' +
|
||||||
|
expected_left + ' at ' + time + 'ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_animated_div(t, easing_function) {
|
||||||
|
var target = createDiv(t);
|
||||||
|
target.style.position = 'absolute';
|
||||||
|
return target.animate(
|
||||||
|
[ { left: '0px' },
|
||||||
|
{ left: '100px' } ],
|
||||||
|
{ duration: 1000,
|
||||||
|
fill: 'forwards',
|
||||||
|
easing: easing_function });
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
var anim = create_animated_div(t, 'linear(0, 1.5, 1)');
|
||||||
|
|
||||||
|
assert_style_left_at(anim, 0, 0.0);
|
||||||
|
assert_style_left_at(anim, 250, 0.75);
|
||||||
|
assert_style_left_at(anim, 500, 1.5);
|
||||||
|
assert_style_left_at(anim, 750, 1.25);
|
||||||
|
assert_style_left_at(anim, 1000, 1.00);
|
||||||
|
}, 'linear function easing with output greater than 1');
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
var anim = create_animated_div(t, 'linear(1, -0.5, 0)');
|
||||||
|
|
||||||
|
assert_style_left_at(anim, 0, 1.0);
|
||||||
|
assert_style_left_at(anim, 250, 0.25);
|
||||||
|
assert_style_left_at(anim, 500, -0.5);
|
||||||
|
assert_style_left_at(anim, 750, -0.25);
|
||||||
|
assert_style_left_at(anim, 1000, 0.00);
|
||||||
|
}, 'linear function easing with output less than 1');
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
var anim = create_animated_div(t, 'linear()');
|
||||||
|
var equiv = create_animated_div(t, 'linear');
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 0);
|
||||||
|
assert_animations_equal_at(anim, equiv, 250);
|
||||||
|
assert_animations_equal_at(anim, equiv, 750);
|
||||||
|
assert_animations_equal_at(anim, equiv, 1000);
|
||||||
|
}, 'linear function easing, linear equivalent');
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
var anim = create_animated_div(t, 'linear(0.5)');
|
||||||
|
|
||||||
|
assert_style_left_at(anim, 0, 0.5);
|
||||||
|
assert_style_left_at(anim, 250, 0.5);
|
||||||
|
assert_style_left_at(anim, 500, 0.5);
|
||||||
|
assert_style_left_at(anim, 750, 0.5);
|
||||||
|
assert_style_left_at(anim, 1000, 0.5);
|
||||||
|
}, 'linear function easing, constant');
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
var anim = create_animated_div(t, 'linear(0.2 0% 20%, 0.4 20% 40%, 0.6 40% 60%, 0.8 60% 80%, 1.0 80% 100%)');
|
||||||
|
var equiv = create_animated_div(t, 'steps(5, jump-start)');
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 0);
|
||||||
|
// Spec doesn't specify which way these steps should be continuous,
|
||||||
|
// so just check on each side.
|
||||||
|
assert_animations_equal_at(anim, equiv, 199);
|
||||||
|
assert_animations_equal_at(anim, equiv, 201);
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 399);
|
||||||
|
assert_animations_equal_at(anim, equiv, 401);
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 599);
|
||||||
|
assert_animations_equal_at(anim, equiv, 601);
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 799);
|
||||||
|
assert_animations_equal_at(anim, equiv, 801);
|
||||||
|
|
||||||
|
assert_animations_equal_at(anim, equiv, 1000);
|
||||||
|
}, 'linear function easing, steps equivalent');
|
||||||
|
</script>
|
||||||
|
</body>
|
Загрузка…
Ссылка в новой задаче