Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/TimingParams.h"
8 :
9 : #include "mozilla/AnimationUtils.h"
10 : #include "mozilla/dom/AnimatableBinding.h"
11 : #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
12 : #include "mozilla/dom/KeyframeEffectBinding.h"
13 : #include "mozilla/ServoBindings.h"
14 : #include "nsCSSParser.h" // For nsCSSParser
15 : #include "nsIDocument.h"
16 : #include "nsRuleNode.h"
17 :
18 : namespace mozilla {
19 :
20 : template <class OptionsType>
21 : static const dom::AnimationEffectTimingProperties&
22 : GetTimingProperties(const OptionsType& aOptions);
23 :
24 : template <>
25 : /* static */ const dom::AnimationEffectTimingProperties&
26 0 : GetTimingProperties(
27 : const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
28 : {
29 0 : MOZ_ASSERT(aOptions.IsKeyframeEffectOptions());
30 0 : return aOptions.GetAsKeyframeEffectOptions();
31 : }
32 :
33 : template <>
34 : /* static */ const dom::AnimationEffectTimingProperties&
35 0 : GetTimingProperties(
36 : const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions)
37 : {
38 0 : MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions());
39 0 : return aOptions.GetAsKeyframeAnimationOptions();
40 : }
41 :
42 : template <class OptionsType>
43 : /* static */ TimingParams
44 0 : TimingParams::FromOptionsType(const OptionsType& aOptions,
45 : nsIDocument* aDocument,
46 : ErrorResult& aRv)
47 : {
48 0 : TimingParams result;
49 0 : if (aOptions.IsUnrestrictedDouble()) {
50 0 : double durationInMs = aOptions.GetAsUnrestrictedDouble();
51 0 : if (durationInMs >= 0) {
52 0 : result.mDuration.emplace(
53 0 : StickyTimeDuration::FromMilliseconds(durationInMs));
54 : } else {
55 0 : aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
56 0 : return result;
57 : }
58 : } else {
59 : const dom::AnimationEffectTimingProperties& timing =
60 0 : GetTimingProperties(aOptions);
61 :
62 : Maybe<StickyTimeDuration> duration =
63 0 : TimingParams::ParseDuration(timing.mDuration, aRv);
64 0 : if (aRv.Failed()) {
65 0 : return result;
66 : }
67 0 : TimingParams::ValidateIterationStart(timing.mIterationStart, aRv);
68 0 : if (aRv.Failed()) {
69 0 : return result;
70 : }
71 0 : TimingParams::ValidateIterations(timing.mIterations, aRv);
72 0 : if (aRv.Failed()) {
73 0 : return result;
74 : }
75 : Maybe<ComputedTimingFunction> easing =
76 0 : TimingParams::ParseEasing(timing.mEasing, aDocument, aRv);
77 0 : if (aRv.Failed()) {
78 0 : return result;
79 : }
80 :
81 0 : result.mDuration = duration;
82 0 : result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay);
83 0 : result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay);
84 0 : result.mIterations = timing.mIterations;
85 0 : result.mIterationStart = timing.mIterationStart;
86 0 : result.mDirection = timing.mDirection;
87 0 : result.mFill = timing.mFill;
88 0 : result.mFunction = easing;
89 : }
90 0 : result.Update();
91 :
92 0 : return result;
93 : }
94 :
95 : /* static */ TimingParams
96 0 : TimingParams::FromOptionsUnion(
97 : const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
98 : nsIDocument* aDocument,
99 : ErrorResult& aRv)
100 : {
101 0 : return FromOptionsType(aOptions, aDocument, aRv);
102 : }
103 :
104 : /* static */ TimingParams
105 0 : TimingParams::FromOptionsUnion(
106 : const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
107 : nsIDocument* aDocument,
108 : ErrorResult& aRv)
109 : {
110 0 : return FromOptionsType(aOptions, aDocument, aRv);
111 : }
112 :
113 : /* static */ Maybe<ComputedTimingFunction>
114 0 : TimingParams::ParseEasing(const nsAString& aEasing,
115 : nsIDocument* aDocument,
116 : ErrorResult& aRv)
117 : {
118 0 : MOZ_ASSERT(aDocument);
119 :
120 0 : if (aDocument->IsStyledByServo()) {
121 0 : nsTimingFunction timingFunction;
122 : // FIXME this is using the wrong base uri (bug 1343919)
123 0 : RefPtr<URLExtraData> data = new URLExtraData(aDocument->GetDocumentURI(),
124 0 : aDocument->GetDocumentURI(),
125 0 : aDocument->NodePrincipal());
126 0 : if (!Servo_ParseEasing(&aEasing, data, &timingFunction)) {
127 0 : aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
128 0 : return Nothing();
129 : }
130 :
131 0 : if (timingFunction.mType == nsTimingFunction::Type::Linear) {
132 0 : return Nothing();
133 : }
134 :
135 0 : return Some(ComputedTimingFunction(timingFunction));
136 : }
137 :
138 0 : nsCSSValue value;
139 0 : nsCSSParser parser;
140 0 : parser.ParseLonghandProperty(eCSSProperty_animation_timing_function,
141 : aEasing,
142 : aDocument->GetDocumentURI(),
143 : aDocument->GetDocumentURI(),
144 : aDocument->NodePrincipal(),
145 0 : value);
146 :
147 0 : switch (value.GetUnit()) {
148 : case eCSSUnit_List: {
149 0 : const nsCSSValueList* list = value.GetListValue();
150 0 : if (list->mNext) {
151 : // don't support a list of timing functions
152 0 : break;
153 : }
154 0 : switch (list->mValue.GetUnit()) {
155 : case eCSSUnit_Enumerated:
156 : // Return Nothing() if "linear" is passed in.
157 0 : if (list->mValue.GetIntValue() ==
158 : NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) {
159 0 : return Nothing();
160 : }
161 : MOZ_FALLTHROUGH;
162 : case eCSSUnit_Cubic_Bezier:
163 : case eCSSUnit_Function:
164 : case eCSSUnit_Steps: {
165 0 : nsTimingFunction timingFunction;
166 0 : nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction);
167 0 : return Some(ComputedTimingFunction(timingFunction));
168 : }
169 : default:
170 0 : MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function list "
171 : "item unit");
172 : break;
173 : }
174 : break;
175 : }
176 : case eCSSUnit_Inherit:
177 : case eCSSUnit_Initial:
178 : case eCSSUnit_Unset:
179 : case eCSSUnit_TokenStream:
180 : case eCSSUnit_Null:
181 0 : break;
182 : default:
183 0 : MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit");
184 : break;
185 : }
186 :
187 0 : aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
188 0 : return Nothing();
189 : }
190 :
191 : bool
192 0 : TimingParams::operator==(const TimingParams& aOther) const
193 : {
194 : // We don't compare mActiveDuration and mEndTime because they are calculated
195 : // from other timing parameters.
196 0 : return mDuration == aOther.mDuration &&
197 0 : mDelay == aOther.mDelay &&
198 0 : mIterations == aOther.mIterations &&
199 0 : mIterationStart == aOther.mIterationStart &&
200 0 : mDirection == aOther.mDirection &&
201 0 : mFill == aOther.mFill &&
202 0 : mFunction == aOther.mFunction;
203 : }
204 :
205 : } // namespace mozilla
|