OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
3 * (C) 2000 Antti Koivisto (koivisto@kde.org) | 3 * (C) 2000 Antti Koivisto (koivisto@kde.org) |
4 * (C) 2000 Dirk Mueller (mueller@kde.org) | 4 * (C) 2000 Dirk Mueller (mueller@kde.org) |
5 * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 5 * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) | 6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 21 matching lines...) Expand all Loading... | |
32 #include "wtf/PassOwnPtr.h" | 32 #include "wtf/PassOwnPtr.h" |
33 #include "wtf/PassRefPtr.h" | 33 #include "wtf/PassRefPtr.h" |
34 #include "wtf/RefCounted.h" | 34 #include "wtf/RefCounted.h" |
35 #include "wtf/Vector.h" | 35 #include "wtf/Vector.h" |
36 #include <algorithm> | 36 #include <algorithm> |
37 #include <iosfwd> | 37 #include <iosfwd> |
38 | 38 |
39 | 39 |
40 namespace WebCore { | 40 namespace WebCore { |
41 | 41 |
42 class TimingFunction; | |
43 | |
42 class TimingFunction : public RefCounted<TimingFunction> { | 44 class TimingFunction : public RefCounted<TimingFunction> { |
43 public: | 45 public: |
44 | 46 |
45 enum Type { | 47 enum Type { |
46 LinearFunction, CubicBezierFunction, StepsFunction, ChainedFunction | 48 LinearFunction, CubicBezierFunction, StepsFunction, ChainedFunction |
47 }; | 49 }; |
48 | 50 |
49 virtual ~TimingFunction() { } | 51 virtual ~TimingFunction() { } |
50 | 52 |
51 Type type() const { return m_type; } | 53 Type type() const { return m_type; } |
52 | 54 |
53 // Evaluates the timing function at the given fraction. The accuracy paramet er provides a hint as to the required | 55 // Evaluates the timing function at the given fraction. The accuracy paramet er provides a hint as to the required |
54 // accuracy and is not guaranteed. | 56 // accuracy and is not guaranteed. |
55 virtual double evaluate(double fraction, double accuracy) const = 0; | 57 virtual double evaluate(double fraction, double accuracy) const = 0; |
56 virtual bool operator==(const TimingFunction& other) const = 0; | 58 virtual bool operator==(const TimingFunction& other) const = 0; |
59 virtual bool operator!=(const TimingFunction& other) const { return !operato r==(other); } | |
60 | |
61 virtual PassRefPtr<TimingFunction> reverse() const = 0; | |
Steve Block
2013/11/03 09:52:32
Can you add a comment describing exactly what you
| |
57 | 62 |
58 protected: | 63 protected: |
59 TimingFunction(Type type) | 64 TimingFunction(Type type) |
60 : m_type(type) | 65 : m_type(type) |
61 { | 66 { |
62 } | 67 } |
63 | 68 |
64 private: | 69 private: |
65 Type m_type; | 70 Type m_type; |
66 }; | 71 }; |
(...skipping 12 matching lines...) Expand all Loading... | |
79 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); | 84 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); |
80 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); | 85 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); |
81 return fraction; | 86 return fraction; |
82 } | 87 } |
83 | 88 |
84 virtual bool operator==(const TimingFunction& other) const | 89 virtual bool operator==(const TimingFunction& other) const |
85 { | 90 { |
86 return other.type() == LinearFunction; | 91 return other.type() == LinearFunction; |
87 } | 92 } |
88 | 93 |
94 virtual PassRefPtr<TimingFunction> reverse() const | |
95 { | |
96 return const_cast<LinearTimingFunction*>(this); | |
97 } | |
98 | |
89 private: | 99 private: |
90 LinearTimingFunction() | 100 LinearTimingFunction() |
91 : TimingFunction(LinearFunction) | 101 : TimingFunction(LinearFunction) |
92 { | 102 { |
93 } | 103 } |
94 }; | 104 }; |
95 | 105 |
96 class CubicBezierTimingFunction : public TimingFunction { | 106 class CubicBezierTimingFunction : public TimingFunction { |
97 public: | 107 public: |
98 enum SubType { | 108 enum SubType { |
99 Ease, | 109 Ease, |
100 EaseIn, | 110 EaseIn, |
101 EaseOut, | 111 EaseOut, |
102 EaseInOut, | 112 EaseInOut, |
103 Custom | 113 Custom |
104 }; | 114 }; |
105 | 115 |
106 static PassRefPtr<CubicBezierTimingFunction> create(double x1, double y1, do uble x2, double y2) | 116 static PassRefPtr<CubicBezierTimingFunction> create(double x1, double y1, do uble x2, double y2) |
107 { | 117 { |
118 // Prevent accidental creation of presets via this method (makes operato r== easier too). | |
119 if (x1 == 0.25 && y1 == 0.1 && x2 == 0.25 && y2 == 1.0) { | |
120 return preset(Ease); | |
121 } | |
122 if (x1 == 0.42 && y1 == 0.0 && x2 == 1.0 && y2 == 1.0) { | |
123 return preset(EaseIn); | |
124 } | |
125 if (x1 == 0.0 && y1 == 0.0 && x2 == 0.58 && y2 == 1.0) { | |
126 return preset(EaseOut); | |
127 } | |
128 if (x1 == 0.42 && y1 == 0.0 && x2 == 0.58 && y2 == 1.0) { | |
129 return preset(EaseInOut); | |
130 } | |
131 | |
Steve Block
2013/11/03 09:52:32
This introduces a change in behavior for CSS. The
| |
108 return adoptRef(new CubicBezierTimingFunction(Custom, x1, y1, x2, y2)); | 132 return adoptRef(new CubicBezierTimingFunction(Custom, x1, y1, x2, y2)); |
109 } | 133 } |
110 | 134 |
111 static CubicBezierTimingFunction* preset(SubType subType) | 135 static CubicBezierTimingFunction* preset(SubType subType) |
112 { | 136 { |
113 switch (subType) { | 137 switch (subType) { |
114 case Ease: | 138 case Ease: |
115 { | 139 { |
116 static CubicBezierTimingFunction* ease = adoptRef(new CubicBezie rTimingFunction(Ease, 0.25, 0.1, 0.25, 1.0)).leakRef(); | 140 static CubicBezierTimingFunction* ease = adoptRef(new CubicBezie rTimingFunction(Ease, 0.25, 0.1, 0.25, 1.0)).leakRef(); |
117 return ease; | 141 return ease; |
(...skipping 25 matching lines...) Expand all Loading... | |
143 { | 167 { |
144 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); | 168 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); |
145 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); | 169 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); |
146 if (!m_bezier) | 170 if (!m_bezier) |
147 m_bezier = adoptPtr(new UnitBezier(m_x1, m_y1, m_x2, m_y2)); | 171 m_bezier = adoptPtr(new UnitBezier(m_x1, m_y1, m_x2, m_y2)); |
148 return m_bezier->solve(fraction, accuracy); | 172 return m_bezier->solve(fraction, accuracy); |
149 } | 173 } |
150 | 174 |
151 virtual bool operator==(const TimingFunction& other) const | 175 virtual bool operator==(const TimingFunction& other) const |
152 { | 176 { |
153 if (other.type() == CubicBezierFunction) { | 177 if (other.type() != CubicBezierFunction) |
154 const CubicBezierTimingFunction* ctf = static_cast<const CubicBezier TimingFunction*>(&other); | 178 return false; |
155 if (m_subType != Custom) | |
156 return m_subType == ctf->m_subType; | |
157 | 179 |
Steve Block
2013/11/03 09:52:32
Why don't you test for 'this == &other' here, like
| |
180 const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimi ngFunction*>(&other); | |
181 if (m_subType == Custom && ctf->m_subType == Custom) | |
158 return m_x1 == ctf->m_x1 && m_y1 == ctf->m_y1 && m_x2 == ctf->m_x2 & & m_y2 == ctf->m_y2; | 182 return m_x1 == ctf->m_x1 && m_y1 == ctf->m_y1 && m_x2 == ctf->m_x2 & & m_y2 == ctf->m_y2; |
159 } | 183 |
160 return false; | 184 return m_subType == ctf->m_subType; |
161 } | 185 } |
162 | 186 |
163 double x1() const { return m_x1; } | 187 double x1() const { return m_x1; } |
164 double y1() const { return m_y1; } | 188 double y1() const { return m_y1; } |
165 double x2() const { return m_x2; } | 189 double x2() const { return m_x2; } |
166 double y2() const { return m_y2; } | 190 double y2() const { return m_y2; } |
167 | 191 |
168 SubType subType() const { return m_subType; } | 192 SubType subType() const { return m_subType; } |
169 | 193 |
194 virtual PassRefPtr<TimingFunction> reverse() const | |
195 { | |
196 switch (m_subType) { | |
197 case Ease: | |
198 return const_cast<CubicBezierTimingFunction*>(this); | |
Steve Block
2013/11/03 09:52:32
This is incorrect. 'Ease' is not symmetric about x
| |
199 case EaseIn: | |
200 return preset(EaseOut); | |
201 case EaseOut: | |
202 return preset(EaseIn); | |
203 case EaseInOut: | |
204 return const_cast<CubicBezierTimingFunction*>(this); | |
205 case Custom: | |
206 // Flip the timing function in x. We also have to flip it in y to | |
207 // maintain the invariant that it runs from (0, 0) to (1, 1). | |
208 return create(1 - m_x2, 1 - m_y2, 1 - m_x1, 1 - m_y1); | |
209 default: | |
210 ASSERT_NOT_REACHED(); | |
211 } | |
212 } | |
213 | |
170 private: | 214 private: |
171 explicit CubicBezierTimingFunction(SubType subType, double x1, double y1, do uble x2, double y2) | 215 explicit CubicBezierTimingFunction(SubType subType, double x1, double y1, do uble x2, double y2) |
172 : TimingFunction(CubicBezierFunction) | 216 : TimingFunction(CubicBezierFunction) |
173 , m_x1(x1) | 217 , m_x1(x1) |
174 , m_y1(y1) | 218 , m_y1(y1) |
175 , m_x2(x2) | 219 , m_x2(x2) |
176 , m_y2(y2) | 220 , m_y2(y2) |
177 , m_subType(subType) | 221 , m_subType(subType) |
178 { | 222 { |
179 } | 223 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 { | 255 { |
212 static StepsTimingFunction* end = adoptRef(new StepsTimingFuncti on(End, 1, false)).leakRef(); | 256 static StepsTimingFunction* end = adoptRef(new StepsTimingFuncti on(End, 1, false)).leakRef(); |
213 return end; | 257 return end; |
214 } | 258 } |
215 default: | 259 default: |
216 ASSERT_NOT_REACHED(); | 260 ASSERT_NOT_REACHED(); |
217 return 0; | 261 return 0; |
218 } | 262 } |
219 } | 263 } |
220 | 264 |
221 | |
222 ~StepsTimingFunction() { } | 265 ~StepsTimingFunction() { } |
223 | 266 |
224 virtual double evaluate(double fraction, double) const | 267 virtual double evaluate(double fraction, double) const |
225 { | 268 { |
226 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); | 269 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled() || (fraction >= 0 && fraction <= 1)); |
227 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); | 270 RELEASE_ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsEnable d() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Ti ming function behavior outside the range [0, 1] is not yet specified"); |
228 return std::min(1.0, (floor(m_steps * fraction) + m_stepAtStart) / m_ste ps); | 271 return std::min(1.0, (floor(m_steps * fraction) + m_stepAtStart) / m_ste ps); |
229 } | 272 } |
230 | 273 |
231 virtual bool operator==(const TimingFunction& other) const | 274 virtual bool operator==(const TimingFunction& other) const |
232 { | 275 { |
233 if (other.type() == StepsFunction) { | 276 if (other.type() != StepsFunction) |
234 const StepsTimingFunction* stf = static_cast<const StepsTimingFuncti on*>(&other); | 277 return false; |
235 if (m_subType != Custom) | 278 |
236 return m_subType == stf->m_subType; | 279 if (this == &other) |
237 return m_steps == stf->m_steps && m_stepAtStart == stf->m_stepAtStar t; | 280 return true; |
238 } | 281 |
239 return false; | 282 const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*> (&other); |
283 if (m_subType != Custom) | |
284 return m_subType == stf->m_subType; | |
285 return m_steps == stf->m_steps && m_stepAtStart == stf->m_stepAtStart; | |
240 } | 286 } |
241 | 287 |
242 int numberOfSteps() const { return m_steps; } | 288 int numberOfSteps() const { return m_steps; } |
243 bool stepAtStart() const { return m_stepAtStart; } | 289 bool stepAtStart() const { return m_stepAtStart; } |
244 | 290 |
245 SubType subType() const { return m_subType; } | 291 SubType subType() const { return m_subType; } |
246 | 292 |
293 virtual PassRefPtr<TimingFunction> reverse() const | |
294 { | |
295 switch (m_subType) { | |
296 case Start: | |
297 return preset(End); | |
Steve Block
2013/11/03 09:52:32
If I'm right about how I think you intend to use r
Steve Block
2013/11/04 04:36:08
Sorry, should be ...
A step-start has output 1 for
Steve Block
2013/11/04 04:40:57
step-start has an output of 1 at input 0. See http
| |
298 case End: | |
299 return preset(Start); | |
300 case Custom: | |
301 return create(m_steps, !m_stepAtStart); | |
302 default: | |
303 ASSERT_NOT_REACHED(); | |
304 return 0; | |
305 } | |
306 } | |
307 | |
247 private: | 308 private: |
248 StepsTimingFunction(SubType subType, int steps, bool stepAtStart) | 309 StepsTimingFunction(SubType subType, int steps, bool stepAtStart) |
249 : TimingFunction(StepsFunction) | 310 : TimingFunction(StepsFunction) |
250 , m_steps(steps) | 311 , m_steps(steps) |
251 , m_stepAtStart(stepAtStart) | 312 , m_stepAtStart(stepAtStart) |
252 , m_subType(subType) | 313 , m_subType(subType) |
253 { | 314 { |
254 } | 315 } |
255 | 316 |
256 int m_steps; | 317 int m_steps; |
257 bool m_stepAtStart; | 318 bool m_stepAtStart; |
258 SubType m_subType; | 319 SubType m_subType; |
259 }; | 320 }; |
260 | 321 |
261 class ChainedTimingFunction : public TimingFunction { | 322 class ChainedTimingFunction : public TimingFunction { |
262 public: | 323 public: |
263 static PassRefPtr<ChainedTimingFunction> create() | 324 static PassRefPtr<ChainedTimingFunction> create() |
264 { | 325 { |
265 return adoptRef(new ChainedTimingFunction); | 326 return adoptRef(new ChainedTimingFunction); |
266 } | 327 } |
267 | 328 |
268 void appendSegment(double upperBound, TimingFunction* timingFunction) | 329 void appendSegment(double upperBound, TimingFunction* timingFunction) |
269 { | 330 { |
270 double max = m_segments.isEmpty() ? 0 : m_segments.last().max(); | 331 double max = m_segments.isEmpty() ? 0 : m_segments.last().max(); |
271 ASSERT(upperBound > max); | 332 ASSERT(upperBound > max); |
272 m_segments.append(Segment(max, upperBound, timingFunction)); | 333 m_segments.append(Segment(max, upperBound, timingFunction)); |
273 } | 334 } |
335 | |
274 virtual double evaluate(double fraction, double accuracy) const | 336 virtual double evaluate(double fraction, double accuracy) const |
275 { | 337 { |
276 RELEASE_ASSERT_WITH_MESSAGE(fraction >= 0 && fraction <= 1, "Web Animati ons not yet implemented: Timing function behavior outside the range [0, 1] is no t yet specified"); | 338 RELEASE_ASSERT_WITH_MESSAGE(fraction >= 0 && fraction <= 1, "Web Animati ons not yet implemented: Timing function behavior outside the range [0, 1] is no t yet specified"); |
277 ASSERT(!m_segments.isEmpty()); | 339 ASSERT(!m_segments.isEmpty()); |
278 ASSERT(m_segments.last().max() == 1); | 340 ASSERT(m_segments.last().max() == 1); |
279 size_t i = 0; | 341 size_t i = 0; |
280 const Segment* segment = &m_segments[i++]; | 342 const Segment* segment = &m_segments[i++]; |
281 while (fraction >= segment->max() && i < m_segments.size()) { | 343 while (fraction >= segment->max() && i < m_segments.size()) { |
282 segment = &m_segments[i++]; | 344 segment = &m_segments[i++]; |
283 } | 345 } |
284 return segment->evaluate(fraction, accuracy); | 346 return segment->evaluate(fraction, accuracy); |
285 } | 347 } |
286 | 348 |
287 virtual bool operator==(const TimingFunction& other) const | 349 virtual bool operator==(const TimingFunction& other) const |
Steve Block
2013/11/03 09:52:32
What exactly do you need operator==() for? Current
| |
288 { | 350 { |
289 // This class is not exposed to CSS, so this method is not required. | 351 if (other.type() != ChainedFunction) |
290 ASSERT_NOT_REACHED(); | 352 return false; |
291 return false; | 353 |
354 if (this == &other) | |
355 return true; | |
356 | |
357 const ChainedTimingFunction* ctf = static_cast<const ChainedTimingFuncti on*>(&other); | |
358 if (ctf->m_segments.size() != m_segments.size()) | |
359 return false; | |
360 | |
361 for (size_t i = 0; i < m_segments.size(); i++) { | |
362 if (m_segments[i] != ctf->m_segments[i]) | |
363 return false; | |
364 } | |
365 return true; | |
366 } | |
367 | |
368 virtual PassRefPtr<TimingFunction> reverse() const | |
369 { | |
370 RefPtr<ChainedTimingFunction> reversed = create(); | |
371 for (size_t i = 0; i < m_segments.size(); i++) { | |
372 size_t index = m_segments.size() - i - 1; | |
373 | |
374 reversed->appendSegment(1 - m_segments[index].m_min, m_segments[inde x].m_timingFunction->reverse().get()); | |
375 } | |
376 return reversed; | |
292 } | 377 } |
293 | 378 |
294 private: | 379 private: |
295 class Segment { | 380 class Segment { |
296 public: | 381 public: |
297 Segment(double min, double max, TimingFunction* timingFunction) | 382 Segment(double min, double max, TimingFunction* timingFunction) |
298 : m_min(min) | 383 : m_min(min) |
299 , m_max(max) | 384 , m_max(max) |
300 , m_timingFunction(timingFunction) | 385 , m_timingFunction(timingFunction) |
301 { } | 386 { } |
302 | 387 |
303 double max() const { return m_max; } | 388 double max() const { return m_max; } |
304 double evaluate(double fraction, double accuracy) const | 389 double evaluate(double fraction, double accuracy) const |
305 { | 390 { |
306 return scaleFromLocal(m_timingFunction->evaluate(scaleToLocal(fracti on), accuracy)); | 391 return scaleFromLocal(m_timingFunction->evaluate(scaleToLocal(fracti on), accuracy)); |
307 } | 392 } |
308 | 393 |
394 bool operator==(const Segment& other) const | |
395 { | |
396 if (this == &other) | |
397 return true; | |
398 | |
399 return m_min == other.m_min && m_max == other.m_max && m_timingFunct ion == other.m_timingFunction; | |
400 } | |
401 bool operator!=(const Segment& other) const | |
402 { | |
403 return !operator==(other); | |
404 } | |
309 private: | 405 private: |
310 double scaleToLocal(double x) const { return (x - m_min) / (m_max - m_mi n); } | 406 double scaleToLocal(double x) const { return (x - m_min) / (m_max - m_mi n); } |
311 double scaleFromLocal(double x) const { return blend(m_min, m_max, x); } | 407 double scaleFromLocal(double x) const { return blend(m_min, m_max, x); } |
312 | 408 |
313 double m_min; | 409 double m_min; |
314 double m_max; | 410 double m_max; |
315 RefPtr<TimingFunction> m_timingFunction; | 411 RefPtr<TimingFunction> m_timingFunction; |
316 | 412 |
413 friend class ChainedTimingFunction; | |
414 | |
317 // Allow printing of our segments. Can be removed once | 415 // Allow printing of our segments. Can be removed once |
318 // ChainedTimingFunction has a public API for segments. | 416 // ChainedTimingFunction has a public API for segments. |
319 friend void PrintTo(const ChainedTimingFunction&, ::std::ostream*, bool) ; | 417 friend void PrintTo(const ChainedTimingFunction&, ::std::ostream*, bool) ; |
320 }; | 418 }; |
321 | 419 |
322 ChainedTimingFunction() | 420 ChainedTimingFunction() |
323 : TimingFunction(ChainedFunction) | 421 : TimingFunction(ChainedFunction) |
324 { | 422 { |
325 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled()); | 423 ASSERT(RuntimeEnabledFeatures::webAnimationsEnabled()); |
326 } | 424 } |
327 | 425 |
328 Vector<Segment> m_segments; | 426 Vector<Segment> m_segments; |
329 | 427 |
330 // Allow printing of our segments. Can be removed once | 428 // Allow printing of our segments. Can be removed once |
331 // ChainedTimingFunction has a public API for segments. | 429 // ChainedTimingFunction has a public API for segments. |
332 friend void PrintTo(const ChainedTimingFunction&, ::std::ostream*, bool); | 430 friend void PrintTo(const ChainedTimingFunction&, ::std::ostream*, bool); |
333 }; | 431 }; |
334 | 432 |
335 } // namespace WebCore | 433 } // namespace WebCore |
336 | 434 |
337 #endif // TimingFunction_h | 435 #endif // TimingFunction_h |
OLD | NEW |