double ComputedTimingFunction::GetValue(double aPortion) const { switch (mType) { case nsTimingFunction::Function: return mTimingFunction.GetSplineValue(aPortion); case nsTimingFunction::StepStart: // There are diagrams in the spec that seem to suggest this check // and the bounds point should not be symmetric with StepEnd, but // should actually step up at rather than immediately after the // fraction points. However, we rely on rounding negative values // up to zero, so we can't do that. And it's not clear the spec // really meant it. return 1.0 - StepEnd(mSteps, 1.0 - aPortion); default: NS_ABORT_IF_FALSE(false, "bad type"); // fall through case nsTimingFunction::StepEnd: return StepEnd(mSteps, aPortion); } }
double ComputedTimingFunction::GetValue(double aPortion) const { if (HasSpline()) { // Check for a linear curve. // (GetSplineValue(), below, also checks this but doesn't work when // aPortion is outside the range [0.0, 1.0]). if (mTimingFunction.X1() == mTimingFunction.Y1() && mTimingFunction.X2() == mTimingFunction.Y2()) { return aPortion; } // For negative values, try to extrapolate with tangent (p1 - p0) or, // if p1 is coincident with p0, with (p2 - p0). if (aPortion < 0.0) { if (mTimingFunction.X1() > 0.0) { return aPortion * mTimingFunction.Y1() / mTimingFunction.X1(); } else if (mTimingFunction.Y1() == 0 && mTimingFunction.X2() > 0.0) { return aPortion * mTimingFunction.Y2() / mTimingFunction.X2(); } // If we can't calculate a sensible tangent, don't extrapolate at all. return 0.0; } // For values greater than 1, try to extrapolate with tangent (p2 - p3) or, // if p2 is coincident with p3, with (p1 - p3). if (aPortion > 1.0) { if (mTimingFunction.X2() < 1.0) { return 1.0 + (aPortion - 1.0) * (mTimingFunction.Y2() - 1) / (mTimingFunction.X2() - 1); } else if (mTimingFunction.Y2() == 1 && mTimingFunction.X1() < 1.0) { return 1.0 + (aPortion - 1.0) * (mTimingFunction.Y1() - 1) / (mTimingFunction.X1() - 1); } // If we can't calculate a sensible tangent, don't extrapolate at all. return 1.0; } return mTimingFunction.GetSplineValue(aPortion); } // Since we use endpoint-exclusive timing, the output of a steps(start) timing // function when aPortion = 0.0 is the top of the first step. When aPortion is // negative, however, we should use the bottom of the first step. We handle // negative values of aPortion specially here since once we clamp aPortion // to [0,1] below we will no longer be able to distinguish to the two cases. if (aPortion < 0.0) { return 0.0; } // Clamp in case of steps(end) and steps(start) for values greater than 1. aPortion = clamped(aPortion, 0.0, 1.0); if (mType == nsTimingFunction::Type::StepStart) { // There are diagrams in the spec that seem to suggest this check // and the bounds point should not be symmetric with StepEnd, but // should actually step up at rather than immediately after the // fraction points. However, we rely on rounding negative values // up to zero, so we can't do that. And it's not clear the spec // really meant it. return 1.0 - StepEnd(mSteps, 1.0 - aPortion); } MOZ_ASSERT(mType == nsTimingFunction::Type::StepEnd, "bad type"); return StepEnd(mSteps, aPortion); }