Eric Seidel e0fd75b5ab Make absolute and sort all Sky headers
This caused us to lose our gn check certification. :(

Turns out gn check was just ignoring all the header
paths it didn't understand and so gn check passing
for sky wasn't meaning much.  I tried to straighten
out some of the mess in this CL, but its going to take
several more rounds of massaging before gn check
passes again.  On the bright side (almost) all of
our headers are absolute now.  Turns out my script
(attached to the bug) didn't notice ../ includes
but I'll fix that in the next patch.

R=abarth@chromium.org
BUG=435361

Review URL: https://codereview.chromium.org/746023002
2014-11-20 17:42:05 -08:00

230 lines
7.3 KiB
C++

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sky/engine/config.h"
#include "sky/engine/platform/animation/TimingFunction.h"
#include "sky/engine/wtf/MathExtras.h"
namespace blink {
String LinearTimingFunction::toString() const
{
return "linear";
}
double LinearTimingFunction::evaluate(double fraction, double) const
{
return fraction;
}
void LinearTimingFunction::range(double* minValue, double* maxValue) const
{
}
String CubicBezierTimingFunction::toString() const
{
switch (this->subType()) {
case CubicBezierTimingFunction::Ease:
return "ease";
case CubicBezierTimingFunction::EaseIn:
return "ease-in";
case CubicBezierTimingFunction::EaseOut:
return "ease-out";
case CubicBezierTimingFunction::EaseInOut:
return "ease-in-out";
case CubicBezierTimingFunction::Custom:
return "cubic-bezier(" + String::numberToStringECMAScript(this->x1()) + ", " +
String::numberToStringECMAScript(this->y1()) + ", " + String::numberToStringECMAScript(this->x2()) +
", " + String::numberToStringECMAScript(this->y2()) + ")";
default:
ASSERT_NOT_REACHED();
}
return "";
}
double CubicBezierTimingFunction::evaluate(double fraction, double accuracy) const
{
if (!m_bezier)
m_bezier = adoptPtr(new UnitBezier(m_x1, m_y1, m_x2, m_y2));
return m_bezier->solve(fraction, accuracy);
}
// This works by taking taking the derivative of the cubic bezier, on the y
// axis. We can then solve for where the derivative is zero to find the min
// and max distace along the line. We the have to solve those in terms of time
// rather than distance on the x-axis
void CubicBezierTimingFunction::range(double* minValue, double* maxValue) const
{
if (0 <= m_y1 && m_y2 < 1 && 0 <= m_y2 && m_y2 <= 1) {
return;
}
double a = 3.0 * (m_y1 - m_y2) + 1.0;
double b = 2.0 * (m_y2 - 2.0 * m_y1);
double c = m_y1;
if (std::abs(a) < std::numeric_limits<double>::epsilon()
&& std::abs(b) < std::numeric_limits<double>::epsilon()) {
return;
}
double t1 = 0.0;
double t2 = 0.0;
if (std::abs(a) < std::numeric_limits<double>::epsilon()) {
t1 = -c / b;
} else {
double discriminant = b * b - 4 * a * c;
if (discriminant < 0)
return;
double discriminantSqrt = sqrt(discriminant);
t1 = (-b + discriminantSqrt) / (2 * a);
t2 = (-b - discriminantSqrt) / (2 * a);
}
double solution1 = 0.0;
double solution2 = 0.0;
// If the solution is in the range [0,1] then we include it, otherwise we
// ignore it.
if (!m_bezier)
m_bezier = adoptPtr(new UnitBezier(m_x1, m_y1, m_x2, m_y2));
// An interesting fact about these beziers is that they are only
// actually evaluated in [0,1]. After that we take the tangent at that point
// and linearly project it out.
if (0 < t1 && t1 < 1)
solution1= m_bezier->sampleCurveY(t1);
if (0 < t2 && t2 < 1)
solution2 = m_bezier->sampleCurveY(t2);
// Since our input values can be out of the range 0->1 so we must also
// consider the minimum and maximum points.
double solutionMin = m_bezier->solve(*minValue, std::numeric_limits<double>::epsilon());
double solutionMax = m_bezier->solve(*maxValue, std::numeric_limits<double>::epsilon());
*minValue = std::min(std::min(solutionMin, solutionMax), 0.0);
*maxValue = std::max(std::max(solutionMin, solutionMax), 1.0);
*minValue = std::min(std::min(*minValue, solution1), solution2);
*maxValue = std::max(std::max(*maxValue, solution1), solution2);
}
String StepsTimingFunction::toString() const
{
StringBuilder builder;
switch (this->subType()) {
case StepsTimingFunction::Start:
return "step-start";
case StepsTimingFunction::Middle:
return "step-middle";
case StepsTimingFunction::End:
return "step-end";
case StepsTimingFunction::Custom:
builder.append("steps(" + String::numberToStringECMAScript(this->numberOfSteps()) + ", ");
if (this->stepAtPosition() == StepsTimingFunction::StepAtStart)
builder.appendLiteral("start");
else if (this->stepAtPosition() == StepsTimingFunction::StepAtMiddle)
builder.appendLiteral("middle");
else if (this->stepAtPosition() == StepsTimingFunction::StepAtEnd)
builder.appendLiteral("end");
else
ASSERT_NOT_REACHED();
builder.append(')');
break;
default:
ASSERT_NOT_REACHED();
}
return builder.toString();
}
void StepsTimingFunction::range(double* minValue, double* maxValue) const
{
*minValue = 0;
*maxValue = 1;
}
double StepsTimingFunction::evaluate(double fraction, double) const
{
double startOffset = 0;
switch (m_stepAtPosition) {
case StepAtStart:
startOffset = 1;
break;
case StepAtMiddle:
startOffset = 0.5;
break;
case StepAtEnd:
startOffset = 0;
break;
default:
ASSERT_NOT_REACHED();
break;
}
return clampTo(floor((m_steps * fraction) + startOffset) / m_steps, 0.0, 1.0);
}
// Equals operators
bool operator==(const LinearTimingFunction& lhs, const TimingFunction& rhs)
{
return rhs.type() == TimingFunction::LinearFunction;
}
bool operator==(const CubicBezierTimingFunction& lhs, const TimingFunction& rhs)
{
if (rhs.type() != TimingFunction::CubicBezierFunction)
return false;
const CubicBezierTimingFunction& ctf = toCubicBezierTimingFunction(rhs);
if ((lhs.subType() == CubicBezierTimingFunction::Custom) && (ctf.subType() == CubicBezierTimingFunction::Custom))
return (lhs.x1() == ctf.x1()) && (lhs.y1() == ctf.y1()) && (lhs.x2() == ctf.x2()) && (lhs.y2() == ctf.y2());
return lhs.subType() == ctf.subType();
}
bool operator==(const StepsTimingFunction& lhs, const TimingFunction& rhs)
{
if (rhs.type() != TimingFunction::StepsFunction)
return false;
const StepsTimingFunction& stf = toStepsTimingFunction(rhs);
if ((lhs.subType() == StepsTimingFunction::Custom) && (stf.subType() == StepsTimingFunction::Custom))
return (lhs.numberOfSteps() == stf.numberOfSteps()) && (lhs.stepAtPosition() == stf.stepAtPosition());
return lhs.subType() == stf.subType();
}
// The generic operator== *must* come after the
// non-generic operator== otherwise it will end up calling itself.
bool operator==(const TimingFunction& lhs, const TimingFunction& rhs)
{
switch (lhs.type()) {
case TimingFunction::LinearFunction: {
const LinearTimingFunction& linear = toLinearTimingFunction(lhs);
return (linear == rhs);
}
case TimingFunction::CubicBezierFunction: {
const CubicBezierTimingFunction& cubic = toCubicBezierTimingFunction(lhs);
return (cubic == rhs);
}
case TimingFunction::StepsFunction: {
const StepsTimingFunction& step = toStepsTimingFunction(lhs);
return (step == rhs);
}
default:
ASSERT_NOT_REACHED();
}
return false;
}
// No need to define specific operator!= as they can all come via this function.
bool operator!=(const TimingFunction& lhs, const TimingFunction& rhs)
{
return !(lhs == rhs);
}
} // namespace blink