Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: sky/engine/core/animation/CompositorAnimations.cpp

Issue 772673002: Fix Animations, Remove Compostior Animations. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: CompositorPendingAnimations -> PendingAnimations Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "sky/engine/config.h"
32 #include "sky/engine/core/animation/CompositorAnimations.h"
33
34 #include "sky/engine/core/animation/AnimationTranslationUtil.h"
35 #include "sky/engine/core/animation/CompositorAnimationsImpl.h"
36 #include "sky/engine/core/animation/animatable/AnimatableDouble.h"
37 #include "sky/engine/core/animation/animatable/AnimatableFilterOperations.h"
38 #include "sky/engine/core/animation/animatable/AnimatableTransform.h"
39 #include "sky/engine/core/animation/animatable/AnimatableValue.h"
40 #include "sky/engine/core/rendering/RenderBoxModelObject.h"
41 #include "sky/engine/core/rendering/RenderLayer.h"
42 #include "sky/engine/core/rendering/RenderObject.h"
43 #include "sky/engine/platform/geometry/FloatBox.h"
44 #include "sky/engine/public/platform/Platform.h"
45 #include "sky/engine/public/platform/WebCompositorAnimation.h"
46 #include "sky/engine/public/platform/WebCompositorSupport.h"
47 #include "sky/engine/public/platform/WebFilterAnimationCurve.h"
48 #include "sky/engine/public/platform/WebFilterKeyframe.h"
49 #include "sky/engine/public/platform/WebFloatAnimationCurve.h"
50 #include "sky/engine/public/platform/WebFloatKeyframe.h"
51 #include "sky/engine/public/platform/WebTransformAnimationCurve.h"
52 #include "sky/engine/public/platform/WebTransformKeyframe.h"
53
54 #include <algorithm>
55 #include <cmath>
56
57 namespace blink {
58
59 namespace {
60
61 void getKeyframeValuesForProperty(const KeyframeEffectModelBase* effect, CSSProp ertyID id, double scale, bool reverse, PropertySpecificKeyframeVector& values)
62 {
63 ASSERT(values.isEmpty());
64 const PropertySpecificKeyframeVector& group = effect->getPropertySpecificKey frames(id);
65
66 if (reverse) {
67 for (size_t i = group.size(); i--;) {
68 double offset = (1 - group[i]->offset()) * scale;
69 values.append(group[i]->cloneWithOffset(offset));
70 }
71 } else {
72 for (size_t i = 0; i < group.size(); ++i) {
73 double offset = group[i]->offset() * scale;
74 values.append(group[i]->cloneWithOffset(offset));
75 }
76 }
77 }
78
79 }
80
81 // -----------------------------------------------------------------------
82 // TimingFunctionReverser methods
83 // -----------------------------------------------------------------------
84
85 PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c onst LinearTimingFunction& timefunc)
86 {
87 return const_cast<LinearTimingFunction*>(&timefunc);
88 }
89
90 PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c onst CubicBezierTimingFunction& timefunc)
91 {
92 switch (timefunc.subType()) {
93 case CubicBezierTimingFunction::EaseIn:
94 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease Out);
95 case CubicBezierTimingFunction::EaseOut:
96 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease In);
97 case CubicBezierTimingFunction::EaseInOut:
98 return const_cast<CubicBezierTimingFunction*>(&timefunc);
99 case CubicBezierTimingFunction::Ease: // Ease is not symmetrical
100 case CubicBezierTimingFunction::Custom:
101 return CubicBezierTimingFunction::create(1 - timefunc.x2(), 1 - timefunc .y2(), 1 - timefunc.x1(), 1 - timefunc.y1());
102 default:
103 ASSERT_NOT_REACHED();
104 return PassRefPtr<TimingFunction>();
105 }
106 }
107
108 PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c onst TimingFunction& timefunc)
109 {
110 switch (timefunc.type()) {
111 case TimingFunction::LinearFunction: {
112 const LinearTimingFunction& linear = toLinearTimingFunction(timefunc);
113 return reverse(linear);
114 }
115 case TimingFunction::CubicBezierFunction: {
116 const CubicBezierTimingFunction& cubic = toCubicBezierTimingFunction(tim efunc);
117 return reverse(cubic);
118 }
119
120 // Steps function can not be reversed.
121 case TimingFunction::StepsFunction:
122 default:
123 ASSERT_NOT_REACHED();
124 return PassRefPtr<TimingFunction>();
125 }
126 }
127
128 bool CompositorAnimations::getAnimatedBoundingBox(FloatBox& box, const Animation Effect& effect, double minValue, double maxValue) const
129 {
130 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect);
131
132 PropertySet properties = keyframeEffect.properties();
133
134 if (properties.isEmpty())
135 return true;
136
137 minValue = std::min(minValue, 0.0);
138 maxValue = std::max(maxValue, 1.0);
139
140 for (PropertySet::const_iterator it = properties.begin(); it != properties.e nd(); ++it) {
141 // TODO: Add the ability to get expanded bounds for filters as well.
142 if (*it != CSSPropertyTransform && *it != CSSPropertyWebkitTransform)
143 continue;
144
145 const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropert ySpecificKeyframes(*it);
146 if (frames.isEmpty() || frames.size() < 2)
147 continue;
148
149 FloatBox originalBox(box);
150
151 for (size_t j = 0; j < frames.size() - 1; ++j) {
152 const AnimatableTransform* startTransform = toAnimatableTransform(fr ames[j]->getAnimatableValue().get());
153 const AnimatableTransform* endTransform = toAnimatableTransform(fram es[j+1]->getAnimatableValue().get());
154 // TODO: Add support for inflating modes other than Replace.
155 if (frames[j]->composite() != AnimationEffect::CompositeReplace)
156 return false;
157
158 const TimingFunction& timing = frames[j]->easing();
159 double min = 0;
160 double max = 1;
161 if (j == 0) {
162 float frameLength = frames[j+1]->offset();
163 if (frameLength > 0) {
164 min = minValue / frameLength;
165 }
166 }
167
168 if (j == frames.size() - 2) {
169 float frameLength = frames[j+1]->offset() - frames[j]->offset();
170 if (frameLength > 0) {
171 max = 1 + (maxValue - 1) / frameLength;
172 }
173 }
174
175 FloatBox bounds;
176 timing.range(&min, &max);
177 if (!endTransform->transformOperations().blendedBoundsForBox(origina lBox, startTransform->transformOperations(), min, max, &bounds))
178 return false;
179 box.expandTo(bounds);
180 }
181 }
182 return true;
183 }
184
185 // -----------------------------------------------------------------------
186 // CompositorAnimations public API
187 // -----------------------------------------------------------------------
188
189 bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& tim ing, const AnimationEffect& effect)
190 {
191 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect);
192
193 PropertySet properties = keyframeEffect.properties();
194
195 if (properties.isEmpty())
196 return false;
197
198 for (PropertySet::const_iterator it = properties.begin(); it != properties.e nd(); ++it) {
199 const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropert ySpecificKeyframes(*it);
200 ASSERT(frames.size() >= 2);
201 for (size_t i = 0; i < frames.size(); ++i) {
202 const Keyframe::PropertySpecificKeyframe *frame = frames[i].get();
203 // FIXME: Determine candidacy based on the CSSValue instead of a sna pshot AnimatableValue.
204 if (frame->composite() != AnimationEffect::CompositeReplace || !fram e->getAnimatableValue())
205 return false;
206
207 switch (*it) {
208 case CSSPropertyOpacity:
209 break;
210 case CSSPropertyTransform:
211 if (toAnimatableTransform(frame->getAnimatableValue().get())->tr ansformOperations().dependsOnBoxSize())
212 return false;
213 break;
214 case CSSPropertyWebkitFilter: {
215 const FilterOperations& operations = toAnimatableFilterOperation s(frame->getAnimatableValue().get())->operations();
216 if (operations.hasFilterThatMovesPixels())
217 return false;
218 break;
219 }
220 default:
221 return false;
222 }
223
224 // FIXME: Remove this check when crbug.com/229405 is resolved
225 if (i < frames.size() - 1 && frame->easing().type() == TimingFunctio n::StepsFunction)
226 return false;
227 }
228 }
229
230 CompositorAnimationsImpl::CompositorTiming out;
231 if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out))
232 return false;
233
234 if (timing.timingFunction->type() != TimingFunction::LinearFunction) {
235 // Checks the of size of KeyframeVector instead of PropertySpecificKeyfr ameVector.
236 const KeyframeVector& keyframes = keyframeEffect.getFrames();
237 if (keyframes.size() == 2 && keyframes[0]->easing().type() == TimingFunc tion::LinearFunction && timing.timingFunction->type() != TimingFunction::StepsFu nction)
238 return true;
239
240 // FIXME: Support non-linear timing functions in the compositor for
241 // more than two keyframes and step timing functions in the compositor.
242 return false;
243 }
244
245 return true;
246 }
247
248 bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element)
249 {
250 return false;
251 }
252
253 bool CompositorAnimations::startAnimationOnCompositor(const Element& element, do uble startTime, double timeOffset, const Timing& timing, const AnimationEffect& effect, Vector<int>& startedAnimationIds)
254 {
255 // FIXME(sky): Remove CompositorAnimations entirely.
256 ASSERT_NOT_REACHED();
257 return true;
258 }
259
260 void CompositorAnimations::cancelAnimationOnCompositor(const Element& element, i nt id)
261 {
262 // FIXME(sky): Remove CompositorAnimations entirely.
263 ASSERT_NOT_REACHED();
264 }
265
266 void CompositorAnimations::pauseAnimationForTestingOnCompositor(const Element& e lement, int id, double pauseTime)
267 {
268 // FIXME(sky): Remove CompositorAnimations entirely.
269 ASSERT_NOT_REACHED();
270 }
271
272 // -----------------------------------------------------------------------
273 // CompositorAnimationsImpl
274 // -----------------------------------------------------------------------
275
276 bool CompositorAnimationsImpl::convertTimingForCompositor(const Timing& timing, double timeOffset, CompositorTiming& out)
277 {
278 timing.assertValid();
279
280 // All fill modes are supported (the calling code handles them).
281
282 // FIXME: Support non-zero iteration start.
283 if (timing.iterationStart)
284 return false;
285
286 if (timing.iterationCount <= 0)
287 return false;
288
289 if (std::isnan(timing.iterationDuration) || !timing.iterationDuration)
290 return false;
291
292 // FIXME: Support other playback rates
293 if (timing.playbackRate != 1)
294 return false;
295
296 // All directions are supported.
297
298 // Now attempt an actual conversion
299 out.scaledDuration = timing.iterationDuration;
300 ASSERT(out.scaledDuration > 0);
301
302 double scaledStartDelay = timing.startDelay;
303 if (scaledStartDelay > 0 && scaledStartDelay > out.scaledDuration * timing.i terationCount)
304 return false;
305
306 out.reverse = (timing.direction == Timing::PlaybackDirectionReverse
307 || timing.direction == Timing::PlaybackDirectionAlternateReverse);
308 out.alternate = (timing.direction == Timing::PlaybackDirectionAlternate
309 || timing.direction == Timing::PlaybackDirectionAlternateReverse);
310
311 if (!std::isfinite(timing.iterationCount)) {
312 out.adjustedIterationCount = -1;
313 } else {
314 out.adjustedIterationCount = timing.iterationCount;
315 ASSERT(out.adjustedIterationCount > 0);
316 }
317
318 // Compositor's time offset is positive for seeking into the animation.
319 out.scaledTimeOffset = -scaledStartDelay + timeOffset;
320 return true;
321 }
322
323 namespace {
324
325 template<typename PlatformAnimationCurveType, typename PlatformAnimationKeyframe Type>
326 void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const Plat formAnimationKeyframeType& keyframe, const TimingFunction* timingFunction)
327 {
328 if (!timingFunction) {
329 curve.add(keyframe);
330 return;
331 }
332
333 switch (timingFunction->type()) {
334 case TimingFunction::LinearFunction:
335 curve.add(keyframe, WebCompositorAnimationCurve::TimingFunctionTypeLinea r);
336 return;
337
338 case TimingFunction::CubicBezierFunction: {
339 const CubicBezierTimingFunction* cubic = toCubicBezierTimingFunction(tim ingFunction);
340
341 if (cubic->subType() == CubicBezierTimingFunction::Custom) {
342 curve.add(keyframe, cubic->x1(), cubic->y1(), cubic->x2(), cubic->y2 ());
343 } else {
344
345 WebCompositorAnimationCurve::TimingFunctionType easeType;
346 switch (cubic->subType()) {
347 case CubicBezierTimingFunction::Ease:
348 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEase;
349 break;
350 case CubicBezierTimingFunction::EaseIn:
351 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseIn ;
352 break;
353 case CubicBezierTimingFunction::EaseOut:
354 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseOu t;
355 break;
356 case CubicBezierTimingFunction::EaseInOut:
357 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseIn Out;
358 break;
359
360 // Custom Bezier are handled seperately.
361 case CubicBezierTimingFunction::Custom:
362 default:
363 ASSERT_NOT_REACHED();
364 return;
365 }
366
367 curve.add(keyframe, easeType);
368 }
369 return;
370 }
371
372 case TimingFunction::StepsFunction:
373 default:
374 ASSERT_NOT_REACHED();
375 return;
376 }
377 }
378
379 } // namespace anoymous
380
381 void CompositorAnimationsImpl::addKeyframesToCurve(WebCompositorAnimationCurve& curve, const PropertySpecificKeyframeVector& keyframes, const Timing& timing, bo ol reverse)
382 {
383 for (size_t i = 0; i < keyframes.size(); i++) {
384 RefPtr<TimingFunction> reversedTimingFunction;
385 const TimingFunction* keyframeTimingFunction = 0;
386 if (i < keyframes.size() - 1) { // Ignore timing function of last frame.
387 if (keyframes.size() == 2 && keyframes[0]->easing().type() == Timing Function::LinearFunction) {
388 if (reverse) {
389 reversedTimingFunction = CompositorAnimationsTimingFunctionR everser::reverse(*timing.timingFunction.get());
390 keyframeTimingFunction = reversedTimingFunction.get();
391 } else {
392 keyframeTimingFunction = timing.timingFunction.get();
393 }
394 } else {
395 if (reverse) {
396 reversedTimingFunction = CompositorAnimationsTimingFunctionR everser::reverse(keyframes[i + 1]->easing());
397 keyframeTimingFunction = reversedTimingFunction.get();
398 } else {
399 keyframeTimingFunction = &keyframes[i]->easing();
400 }
401 }
402 }
403
404 // FIXME: This relies on StringKeyframes being eagerly evaluated, which will
405 // not happen eventually. Instead we should extract the CSSValue here
406 // and convert using another set of toAnimatableXXXOperations functions.
407 const AnimatableValue* value = keyframes[i]->getAnimatableValue().get();
408
409 switch (curve.type()) {
410 case WebCompositorAnimationCurve::AnimationCurveTypeFilter: {
411 OwnPtr<WebFilterOperations> ops = adoptPtr(Platform::current()->comp ositorSupport()->createFilterOperations());
412 toWebFilterOperations(toAnimatableFilterOperations(value)->operation s(), ops.get());
413
414 WebFilterKeyframe filterKeyframe(keyframes[i]->offset(), ops.release ());
415 WebFilterAnimationCurve* filterCurve = static_cast<WebFilterAnimatio nCurve*>(&curve);
416 addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframe TimingFunction);
417 break;
418 }
419 case WebCompositorAnimationCurve::AnimationCurveTypeFloat: {
420 WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableD ouble(value)->toDouble());
421 WebFloatAnimationCurve* floatCurve = static_cast<WebFloatAnimationCu rve*>(&curve);
422 addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTi mingFunction);
423 break;
424 }
425 case WebCompositorAnimationCurve::AnimationCurveTypeTransform: {
426 OwnPtr<WebTransformOperations> ops = adoptPtr(Platform::current()->c ompositorSupport()->createTransformOperations());
427 toWebTransformOperations(toAnimatableTransform(value)->transformOper ations(), ops.get());
428
429 WebTransformKeyframe transformKeyframe(keyframes[i]->offset(), ops.r elease());
430 WebTransformAnimationCurve* transformCurve = static_cast<WebTransfor mAnimationCurve*>(&curve);
431 addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, ke yframeTimingFunction);
432 break;
433 }
434 default:
435 ASSERT_NOT_REACHED();
436 }
437 }
438 }
439
440 void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, do uble startTime, double timeOffset, const KeyframeEffectModelBase& effect, Vector <OwnPtr<WebCompositorAnimation> >& animations)
441 {
442 ASSERT(animations.isEmpty());
443 CompositorTiming compositorTiming;
444 bool timingValid = convertTimingForCompositor(timing, timeOffset, compositor Timing);
445 ASSERT_UNUSED(timingValid, timingValid);
446
447 PropertySet properties = effect.properties();
448 ASSERT(!properties.isEmpty());
449 for (PropertySet::iterator it = properties.begin(); it != properties.end(); ++it) {
450
451 PropertySpecificKeyframeVector values;
452 getKeyframeValuesForProperty(&effect, *it, compositorTiming.scaledDurati on, compositorTiming.reverse, values);
453
454 WebCompositorAnimation::TargetProperty targetProperty;
455 OwnPtr<WebCompositorAnimationCurve> curve;
456 switch (*it) {
457 case CSSPropertyOpacity: {
458 targetProperty = WebCompositorAnimation::TargetPropertyOpacity;
459
460 WebFloatAnimationCurve* floatCurve = Platform::current()->compositor Support()->createFloatAnimationCurve();
461 addKeyframesToCurve(*floatCurve, values, timing, compositorTiming.re verse);
462 curve = adoptPtr(floatCurve);
463 break;
464 }
465 case CSSPropertyWebkitFilter: {
466 targetProperty = WebCompositorAnimation::TargetPropertyFilter;
467 WebFilterAnimationCurve* filterCurve = Platform::current()->composit orSupport()->createFilterAnimationCurve();
468 addKeyframesToCurve(*filterCurve, values, timing, compositorTiming.r everse);
469 curve = adoptPtr(filterCurve);
470 break;
471 }
472 case CSSPropertyTransform: {
473 targetProperty = WebCompositorAnimation::TargetPropertyTransform;
474 WebTransformAnimationCurve* transformCurve = Platform::current()->co mpositorSupport()->createTransformAnimationCurve();
475 addKeyframesToCurve(*transformCurve, values, timing, compositorTimin g.reverse);
476 curve = adoptPtr(transformCurve);
477 break;
478 }
479 default:
480 ASSERT_NOT_REACHED();
481 continue;
482 }
483 ASSERT(curve.get());
484
485 OwnPtr<WebCompositorAnimation> animation = adoptPtr(Platform::current()- >compositorSupport()->createAnimation(*curve, targetProperty));
486
487 if (!std::isnan(startTime))
488 animation->setStartTime(startTime);
489
490 animation->setIterations(compositorTiming.adjustedIterationCount);
491 animation->setTimeOffset(compositorTiming.scaledTimeOffset);
492 animation->setAlternatesDirection(compositorTiming.alternate);
493
494 animations.append(animation.release());
495 }
496 ASSERT(!animations.isEmpty());
497 }
498
499 } // namespace blink
OLDNEW
« no previous file with comments | « sky/engine/core/animation/CompositorAnimations.h ('k') | sky/engine/core/animation/CompositorAnimationsImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698