2016-03-07 08:11:11 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "mozilla/TimingParams.h"
|
|
|
|
|
2016-03-22 10:20:31 +03:00
|
|
|
#include "mozilla/AnimationUtils.h"
|
|
|
|
#include "mozilla/dom/AnimatableBinding.h"
|
|
|
|
#include "mozilla/dom/KeyframeEffectBinding.h"
|
2016-03-18 10:28:22 +03:00
|
|
|
#include "nsCSSParser.h" // For nsCSSParser
|
2016-03-11 11:27:34 +03:00
|
|
|
#include "nsIDocument.h"
|
2016-03-22 10:20:31 +03:00
|
|
|
#include "nsRuleNode.h"
|
2016-03-11 11:27:34 +03:00
|
|
|
|
2016-03-07 08:11:11 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
template <class OptionsType>
|
|
|
|
static const dom::AnimationEffectTimingProperties&
|
|
|
|
GetTimingProperties(const OptionsType& aOptions);
|
|
|
|
|
|
|
|
template <>
|
|
|
|
/* static */ const dom::AnimationEffectTimingProperties&
|
|
|
|
GetTimingProperties(
|
|
|
|
const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aOptions.IsKeyframeEffectOptions());
|
|
|
|
return aOptions.GetAsKeyframeEffectOptions();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
/* static */ const dom::AnimationEffectTimingProperties&
|
|
|
|
GetTimingProperties(
|
|
|
|
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions());
|
|
|
|
return aOptions.GetAsKeyframeAnimationOptions();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class OptionsType>
|
|
|
|
static TimingParams
|
2016-03-11 11:27:34 +03:00
|
|
|
TimingParamsFromOptionsUnion(const OptionsType& aOptions,
|
|
|
|
nsIDocument* aDocument,
|
|
|
|
ErrorResult& aRv)
|
2016-03-07 08:11:11 +03:00
|
|
|
{
|
2016-03-09 08:01:45 +03:00
|
|
|
TimingParams result;
|
2016-03-07 08:11:11 +03:00
|
|
|
if (aOptions.IsUnrestrictedDouble()) {
|
2016-03-09 08:01:45 +03:00
|
|
|
double durationInMs = aOptions.GetAsUnrestrictedDouble();
|
|
|
|
if (durationInMs >= 0) {
|
|
|
|
result.mDuration.emplace(
|
|
|
|
StickyTimeDuration::FromMilliseconds(durationInMs));
|
|
|
|
} else {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
|
|
|
}
|
2016-03-07 08:11:11 +03:00
|
|
|
} else {
|
2016-03-09 08:01:45 +03:00
|
|
|
const dom::AnimationEffectTimingProperties& timing =
|
|
|
|
GetTimingProperties(aOptions);
|
2016-03-11 12:04:39 +03:00
|
|
|
|
2016-03-09 08:01:45 +03:00
|
|
|
Maybe<StickyTimeDuration> duration =
|
|
|
|
TimingParams::ParseDuration(timing.mDuration, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return result;
|
|
|
|
}
|
2016-03-11 12:04:39 +03:00
|
|
|
TimingParams::ValidateIterationStart(timing.mIterationStart, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return result;
|
|
|
|
}
|
2016-03-18 04:14:49 +03:00
|
|
|
TimingParams::ValidateIterations(timing.mIterations, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return result;
|
|
|
|
}
|
2016-03-18 10:28:22 +03:00
|
|
|
Maybe<ComputedTimingFunction> easing =
|
|
|
|
TimingParams::ParseEasing(timing.mEasing, aDocument, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return result;
|
|
|
|
}
|
2016-03-11 12:04:39 +03:00
|
|
|
|
2016-03-09 08:01:45 +03:00
|
|
|
result.mDuration = duration;
|
|
|
|
result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay);
|
|
|
|
result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay);
|
|
|
|
result.mIterations = timing.mIterations;
|
|
|
|
result.mIterationStart = timing.mIterationStart;
|
|
|
|
result.mDirection = timing.mDirection;
|
|
|
|
result.mFill = timing.mFill;
|
2016-03-18 10:28:22 +03:00
|
|
|
result.mFunction = easing;
|
2016-03-07 08:11:11 +03:00
|
|
|
}
|
2016-03-09 08:01:45 +03:00
|
|
|
return result;
|
2016-03-07 08:11:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ TimingParams
|
|
|
|
TimingParams::FromOptionsUnion(
|
|
|
|
const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
|
2016-03-11 11:27:34 +03:00
|
|
|
nsIDocument* aDocument,
|
2016-03-09 08:01:45 +03:00
|
|
|
ErrorResult& aRv)
|
2016-03-07 08:11:11 +03:00
|
|
|
{
|
2016-03-11 11:27:34 +03:00
|
|
|
return TimingParamsFromOptionsUnion(aOptions, aDocument, aRv);
|
2016-03-07 08:11:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ TimingParams
|
|
|
|
TimingParams::FromOptionsUnion(
|
|
|
|
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
2016-03-11 11:27:34 +03:00
|
|
|
nsIDocument* aDocument,
|
2016-03-09 08:01:45 +03:00
|
|
|
ErrorResult& aRv)
|
2016-03-07 08:11:11 +03:00
|
|
|
{
|
2016-03-11 11:27:34 +03:00
|
|
|
return TimingParamsFromOptionsUnion(aOptions, aDocument, aRv);
|
2016-03-07 08:11:11 +03:00
|
|
|
}
|
|
|
|
|
2016-03-18 10:28:22 +03:00
|
|
|
/* static */ Maybe<ComputedTimingFunction>
|
|
|
|
TimingParams::ParseEasing(const nsAString& aEasing,
|
|
|
|
nsIDocument* aDocument,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aDocument);
|
|
|
|
|
|
|
|
nsCSSValue value;
|
|
|
|
nsCSSParser parser;
|
|
|
|
parser.ParseLonghandProperty(eCSSProperty_animation_timing_function,
|
|
|
|
aEasing,
|
|
|
|
aDocument->GetDocumentURI(),
|
|
|
|
aDocument->GetDocumentURI(),
|
|
|
|
aDocument->NodePrincipal(),
|
|
|
|
value);
|
|
|
|
|
|
|
|
switch (value.GetUnit()) {
|
|
|
|
case eCSSUnit_List: {
|
|
|
|
const nsCSSValueList* list = value.GetListValue();
|
|
|
|
if (list->mNext) {
|
|
|
|
// don't support a list of timing functions
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (list->mValue.GetUnit()) {
|
|
|
|
case eCSSUnit_Enumerated:
|
|
|
|
// Return Nothing() if "linear" is passed in.
|
|
|
|
if (list->mValue.GetIntValue() ==
|
|
|
|
NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) {
|
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
MOZ_FALLTHROUGH;
|
|
|
|
case eCSSUnit_Cubic_Bezier:
|
|
|
|
case eCSSUnit_Steps: {
|
|
|
|
nsTimingFunction timingFunction;
|
|
|
|
nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction);
|
|
|
|
ComputedTimingFunction computedTimingFunction;
|
|
|
|
computedTimingFunction.Init(timingFunction);
|
|
|
|
return Some(computedTimingFunction);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function list "
|
|
|
|
"item unit");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSUnit_Inherit:
|
|
|
|
case eCSSUnit_Initial:
|
|
|
|
case eCSSUnit_Unset:
|
|
|
|
case eCSSUnit_TokenStream:
|
|
|
|
case eCSSUnit_Null:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit");
|
|
|
|
break;
|
|
|
|
}
|
2016-04-15 09:26:27 +03:00
|
|
|
|
|
|
|
// Bug 1247004
|
|
|
|
//
|
|
|
|
// The Web Animations polyfill had a bug that translated 'linear' into
|
|
|
|
// the string 'function (a){return a}'. This bug has been fixed but older
|
|
|
|
// versions of the polyfill are still widely used. Google are collecting
|
|
|
|
// usage data on this but for now we need to *not* throw on
|
|
|
|
// 'function (a){return a}' or else a lot of sites will break.
|
|
|
|
//
|
|
|
|
// Instead, we should treat this string as equivalent to 'linear' and
|
|
|
|
// return Nothing().
|
|
|
|
//
|
|
|
|
// Chromium has a similar special case path for this string.
|
|
|
|
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=601672
|
|
|
|
if (aEasing == NS_LITERAL_STRING("function (a){return a}")) {
|
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
|
2016-03-31 13:20:42 +03:00
|
|
|
aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
|
2016-03-18 10:28:22 +03:00
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
|
2016-03-07 08:11:11 +03:00
|
|
|
bool
|
|
|
|
TimingParams::operator==(const TimingParams& aOther) const
|
|
|
|
{
|
2016-03-09 08:14:20 +03:00
|
|
|
return mDuration == aOther.mDuration &&
|
2016-03-07 08:11:11 +03:00
|
|
|
mDelay == aOther.mDelay &&
|
|
|
|
mIterations == aOther.mIterations &&
|
|
|
|
mIterationStart == aOther.mIterationStart &&
|
|
|
|
mDirection == aOther.mDirection &&
|
|
|
|
mFill == aOther.mFill &&
|
|
|
|
mFunction == aOther.mFunction;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|