Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / CompositorAnimations.cpp
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 "config.h"
32 #include "core/animation/CompositorAnimations.h"
33
34 #include "core/animation/AnimatableDouble.h"
35 #include "core/animation/AnimatableFilterOperations.h"
36 #include "core/animation/AnimatableTransform.h"
37 #include "core/animation/AnimatableValue.h"
38 #include "core/animation/AnimationTranslationUtil.h"
39 #include "core/animation/CompositorAnimationsImpl.h"
40 #include "core/rendering/CompositedLayerMapping.h"
41 #include "core/rendering/RenderBoxModelObject.h"
42 #include "core/rendering/RenderLayer.h"
43 #include "core/rendering/RenderObject.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebAnimation.h"
46 #include "public/platform/WebCompositorSupport.h"
47 #include "public/platform/WebFilterAnimationCurve.h"
48 #include "public/platform/WebFilterKeyframe.h"
49 #include "public/platform/WebFloatAnimationCurve.h"
50 #include "public/platform/WebFloatKeyframe.h"
51 #include "public/platform/WebTransformAnimationCurve.h"
52 #include "public/platform/WebTransformKeyframe.h"
53
54 #include <algorithm>
55 #include <cmath>
56
57 namespace WebCore {
58
59 namespace {
60
61 void getKeyframeValuesForProperty(const KeyframeEffectModel* effect, CSSPropertyID id, double scale, bool reverse, KeyframeVector& values)
62 {
63     ASSERT(values.isEmpty());
64     const KeyframeVector& group = effect->getPropertySpecificKeyframes(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(const LinearTimingFunction* timefunc)
86 {
87     return const_cast<LinearTimingFunction*>(timefunc);
88 }
89
90 PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(const CubicBezierTimingFunction* timefunc)
91 {
92     switch (timefunc->subType()) {
93     case CubicBezierTimingFunction::EaseIn:
94         return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
95     case CubicBezierTimingFunction::EaseOut:
96         return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
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(const ChainedTimingFunction* timefunc)
109 {
110     RefPtr<ChainedTimingFunction> reversed = ChainedTimingFunction::create();
111     for (size_t i = 0; i < timefunc->m_segments.size(); i++) {
112         size_t index = timefunc->m_segments.size() - i - 1;
113
114         RefPtr<TimingFunction> rtf = reverse(timefunc->m_segments[index].m_timingFunction.get());
115         reversed->appendSegment(1 - timefunc->m_segments[index].m_min, rtf.get());
116     }
117     return reversed;
118 }
119
120 PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(const TimingFunction* timefunc)
121 {
122     switch (timefunc->type()) {
123     case TimingFunction::LinearFunction: {
124         const LinearTimingFunction* linear = toLinearTimingFunction(timefunc);
125         return reverse(linear);
126     }
127     case TimingFunction::CubicBezierFunction: {
128         const CubicBezierTimingFunction* cubic = toCubicBezierTimingFunction(timefunc);
129         return reverse(cubic);
130     }
131     case TimingFunction::ChainedFunction: {
132         const ChainedTimingFunction* chained = toChainedTimingFunction(timefunc);
133         return reverse(chained);
134     }
135
136     // Steps function can not be reversed.
137     case TimingFunction::StepsFunction:
138     default:
139         ASSERT_NOT_REACHED();
140         return PassRefPtr<TimingFunction>();
141     }
142 }
143
144 // -----------------------------------------------------------------------
145 // CompositorAnimations public API
146 // -----------------------------------------------------------------------
147
148 bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const AnimationEffect& effect)
149 {
150     const KeyframeEffectModel& keyframeEffect = *toKeyframeEffectModel(&effect);
151
152     // Are the keyframes convertible?
153     const KeyframeEffectModel::KeyframeVector frames = keyframeEffect.getFrames();
154     for (size_t i = 0; i < frames.size(); ++i) {
155         // Only replace mode can be accelerated
156         if (frames[i]->composite() != AnimationEffect::CompositeReplace)
157             return false;
158
159         // Check all the properties can be accelerated
160         const PropertySet properties = frames[i]->properties(); // FIXME: properties creates a whole new PropertySet!
161
162         if (properties.isEmpty())
163             return false;
164
165         for (PropertySet::const_iterator it = properties.begin(); it != properties.end(); ++it) {
166             switch (*it) {
167             case CSSPropertyOpacity:
168                 continue;
169             case CSSPropertyWebkitTransform:
170                 if (toAnimatableTransform(frames[i]->propertyValue(CSSPropertyWebkitTransform))->transformOperations().dependsOnBoxSize())
171                     return false;
172                 continue;
173             case CSSPropertyWebkitFilter: {
174                 const FilterOperations& operations = toAnimatableFilterOperations(frames[i]->propertyValue(CSSPropertyWebkitFilter))->operations();
175                 if (operations.hasFilterThatMovesPixels())
176                     return false;
177                 for (size_t i = 0; i < operations.size(); i++) {
178                     const FilterOperation& op = *operations.at(i);
179                     if (op.type() == FilterOperation::VALIDATED_CUSTOM || op.type() == FilterOperation::CUSTOM)
180                         return false;
181                 }
182                 continue;
183             }
184             default:
185                 return false;
186             }
187         }
188     }
189
190     // Is the timing object convertible?
191     CompositorAnimationsImpl::CompositorTiming out;
192     if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, out))
193         return false;
194
195     // Is the timing function convertible?
196     switch (timing.timingFunction->type()) {
197     case TimingFunction::LinearFunction:
198         break;
199
200     case TimingFunction::CubicBezierFunction:
201         // Can have a cubic if we don't have to split it (IE only have two frames).
202         if (frames.size() != 2)
203             return false;
204
205         ASSERT(frames[0]->offset() == 0.0 && frames[1]->offset() == 1.0);
206         break;
207
208     case TimingFunction::StepsFunction:
209         return false;
210
211     case TimingFunction::ChainedFunction: {
212         // Currently we only support chained segments in the form the CSS code
213         // generates. These chained segments are only one level deep and have
214         // one timing function per frame.
215         const ChainedTimingFunction* chained = static_cast<const ChainedTimingFunction*>(timing.timingFunction.get());
216         if (!chained->m_segments.size())
217             return false;
218
219         if (frames.size() != chained->m_segments.size() + 1)
220             return false;
221
222         for (size_t timeIndex = 0; timeIndex < chained->m_segments.size(); timeIndex++) {
223             const ChainedTimingFunction::Segment& segment = chained->m_segments[timeIndex];
224
225             if (frames[timeIndex]->offset() != segment.m_min || frames[timeIndex + 1]->offset() != segment.m_max)
226                 return false;
227
228             switch (segment.m_timingFunction->type()) {
229             case TimingFunction::LinearFunction:
230             case TimingFunction::CubicBezierFunction:
231                 continue;
232
233             case TimingFunction::StepsFunction:
234             case TimingFunction::ChainedFunction:
235             default:
236                 return false;
237             }
238         }
239
240         break;
241     }
242     default:
243         ASSERT_NOT_REACHED();
244         return false;
245     }
246
247     return true;
248 }
249
250 bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element)
251 {
252     return element.renderer() && element.renderer()->compositingState() == PaintsIntoOwnBacking;
253 }
254
255 bool CompositorAnimations::startAnimationOnCompositor(const Element& element, const Timing& timing, const AnimationEffect& effect, Vector<int>& startedAnimationIds)
256 {
257     ASSERT(startedAnimationIds.isEmpty());
258     ASSERT(isCandidateForAnimationOnCompositor(timing, effect));
259     ASSERT(canStartAnimationOnCompositor(element));
260
261     const KeyframeEffectModel& keyframeEffect = *toKeyframeEffectModel(&effect);
262
263     RenderLayer* layer = toRenderBoxModelObject(element.renderer())->layer();
264     ASSERT(layer);
265
266     Vector<OwnPtr<blink::WebAnimation> > animations;
267     CompositorAnimationsImpl::getAnimationOnCompositor(timing, keyframeEffect, animations);
268     ASSERT(!animations.isEmpty());
269     for (size_t i = 0; i < animations.size(); ++i) {
270         int id = animations[i]->id();
271         if (!layer->compositedLayerMapping()->mainGraphicsLayer()->addAnimation(animations[i].release())) {
272             // FIXME: We should know ahead of time whether these animations can be started.
273             for (size_t j = 0; j < startedAnimationIds.size(); ++j)
274                 cancelAnimationOnCompositor(element, startedAnimationIds[j]);
275             startedAnimationIds.clear();
276             return false;
277         }
278         startedAnimationIds.append(id);
279     }
280     ASSERT(!startedAnimationIds.isEmpty());
281     return true;
282 }
283
284 void CompositorAnimations::cancelAnimationOnCompositor(const Element& element, int id)
285 {
286     if (!canStartAnimationOnCompositor(element)) {
287         ASSERT_NOT_REACHED();
288         return;
289     }
290     toRenderBoxModelObject(element.renderer())->layer()->compositedLayerMapping()->mainGraphicsLayer()->removeAnimation(id);
291 }
292
293 void CompositorAnimations::pauseAnimationForTestingOnCompositor(const Element& element, int id, double pauseTime)
294 {
295     if (!canStartAnimationOnCompositor(element)) {
296         ASSERT_NOT_REACHED();
297         return;
298     }
299     toRenderBoxModelObject(element.renderer())->layer()->compositedLayerMapping()->mainGraphicsLayer()->pauseAnimation(id, pauseTime);
300 }
301
302 // -----------------------------------------------------------------------
303 // CompositorAnimationsImpl
304 // -----------------------------------------------------------------------
305
306 bool CompositorAnimationsImpl::convertTimingForCompositor(const Timing& timing, CompositorTiming& out)
307 {
308     timing.assertValid();
309
310     // All fill modes are supported (the calling code handles them).
311
312     // FIXME: Support non-zero iteration start.
313     if (timing.iterationStart)
314         return false;
315
316     // FIXME: Compositor only supports positive, integer iteration counts.
317     // Zero iterations could be converted, but silly.
318     if ((std::floor(timing.iterationCount) != timing.iterationCount) || timing.iterationCount <= 0)
319         return false;
320
321     if (!timing.iterationDuration)
322         return false;
323
324     // FIXME: Support other playback rates
325     if (timing.playbackRate != 1)
326         return false;
327
328     // All directions are supported.
329
330     // Now attempt an actual conversion
331     out.scaledDuration = timing.iterationDuration;
332     ASSERT(out.scaledDuration > 0);
333
334     double scaledStartDelay = timing.startDelay;
335     if (scaledStartDelay > 0 && scaledStartDelay > out.scaledDuration * timing.iterationCount)
336         return false;
337
338     out.reverse = (timing.direction == Timing::PlaybackDirectionReverse
339         || timing.direction == Timing::PlaybackDirectionAlternateReverse);
340     out.alternate = (timing.direction == Timing::PlaybackDirectionAlternate
341         || timing.direction == Timing::PlaybackDirectionAlternateReverse);
342
343     if (!std::isfinite(timing.iterationCount)) {
344         out.adjustedIterationCount = -1;
345     } else {
346         out.adjustedIterationCount = std::floor(timing.iterationCount);
347         ASSERT(out.adjustedIterationCount > 0);
348     }
349
350     // Compositor's time offset is positive for seeking into the animation.
351     out.scaledTimeOffset = -scaledStartDelay;
352     return true;
353 }
354
355 namespace {
356
357 template<typename PlatformAnimationCurveType, typename PlatformAnimationKeyframeType>
358 void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const PlatformAnimationKeyframeType& keyframe, const TimingFunction* timingFunction)
359 {
360     if (!timingFunction) {
361         curve.add(keyframe);
362         return;
363     }
364
365     switch (timingFunction->type()) {
366     case TimingFunction::LinearFunction:
367         curve.add(keyframe, blink::WebAnimationCurve::TimingFunctionTypeLinear);
368         return;
369
370     case TimingFunction::CubicBezierFunction: {
371         const CubicBezierTimingFunction* cubic = toCubicBezierTimingFunction(timingFunction);
372
373         if (cubic->subType() == CubicBezierTimingFunction::Custom) {
374             curve.add(keyframe, cubic->x1(), cubic->y1(), cubic->x2(), cubic->y2());
375         } else {
376
377             blink::WebAnimationCurve::TimingFunctionType easeType;
378             switch (cubic->subType()) {
379             case CubicBezierTimingFunction::Ease:
380                 easeType = blink::WebAnimationCurve::TimingFunctionTypeEase;
381                 break;
382             case CubicBezierTimingFunction::EaseIn:
383                 easeType = blink::WebAnimationCurve::TimingFunctionTypeEaseIn;
384                 break;
385             case CubicBezierTimingFunction::EaseOut:
386                 easeType = blink::WebAnimationCurve::TimingFunctionTypeEaseOut;
387                 break;
388             case CubicBezierTimingFunction::EaseInOut:
389                 easeType = blink::WebAnimationCurve::TimingFunctionTypeEaseInOut;
390                 break;
391
392             // Custom Bezier are handled seperately.
393             case CubicBezierTimingFunction::Custom:
394             default:
395                 ASSERT_NOT_REACHED();
396                 return;
397             }
398
399             curve.add(keyframe, easeType);
400         }
401         return;
402     }
403
404     case TimingFunction::StepsFunction:
405     case TimingFunction::ChainedFunction:
406     default:
407         ASSERT_NOT_REACHED();
408         return;
409     }
410 }
411
412 } // namespace anoymous
413
414 void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const KeyframeVector& keyframes, const TimingFunction& timingFunction)
415 {
416     for (size_t i = 0; i < keyframes.size(); i++) {
417         const TimingFunction* keyframeTimingFunction = 0;
418         if (i + 1 < keyframes.size()) { // Last keyframe has no timing function
419             switch (timingFunction.type()) {
420             case TimingFunction::LinearFunction:
421             case TimingFunction::CubicBezierFunction:
422                 keyframeTimingFunction = &timingFunction;
423                 break;
424
425             case TimingFunction::ChainedFunction: {
426                 const ChainedTimingFunction& chained = toChainedTimingFunction(timingFunction);
427                 // ChainedTimingFunction criteria was checked in isCandidate,
428                 // assert it is valid.
429                 ASSERT(keyframes.size() == chained.m_segments.size() + 1);
430
431                 keyframeTimingFunction = chained.m_segments[i].m_timingFunction.get();
432                 break;
433             }
434             case TimingFunction::StepsFunction:
435             default:
436                 ASSERT_NOT_REACHED();
437             }
438         }
439
440         ASSERT(!keyframes[i]->value()->dependsOnUnderlyingValue());
441         RefPtr<AnimatableValue> value = keyframes[i]->value()->compositeOnto(0);
442
443         switch (curve.type()) {
444         case blink::WebAnimationCurve::AnimationCurveTypeFilter: {
445             OwnPtr<blink::WebFilterOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createFilterOperations());
446             bool converted = toWebFilterOperations(toAnimatableFilterOperations(value.get())->operations(), ops.get());
447             ASSERT_UNUSED(converted, converted);
448
449             blink::WebFilterKeyframe filterKeyframe(keyframes[i]->offset(), ops.release());
450             blink::WebFilterAnimationCurve* filterCurve = static_cast<blink::WebFilterAnimationCurve*>(&curve);
451             addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframeTimingFunction);
452             break;
453         }
454         case blink::WebAnimationCurve::AnimationCurveTypeFloat: {
455             blink::WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableDouble(value.get())->toDouble());
456             blink::WebFloatAnimationCurve* floatCurve = static_cast<blink::WebFloatAnimationCurve*>(&curve);
457             addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction);
458             break;
459         }
460         case blink::WebAnimationCurve::AnimationCurveTypeTransform: {
461             OwnPtr<blink::WebTransformOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createTransformOperations());
462             toWebTransformOperations(toAnimatableTransform(value.get())->transformOperations(), FloatSize(), ops.get());
463
464             blink::WebTransformKeyframe transformKeyframe(keyframes[i]->offset(), ops.release());
465             blink::WebTransformAnimationCurve* transformCurve = static_cast<blink::WebTransformAnimationCurve*>(&curve);
466             addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, keyframeTimingFunction);
467             break;
468         }
469         default:
470             ASSERT_NOT_REACHED();
471         }
472     }
473 }
474
475 void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, const KeyframeEffectModel& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
476 {
477     ASSERT(animations.isEmpty());
478     CompositorTiming compositorTiming;
479     bool timingValid = convertTimingForCompositor(timing, compositorTiming);
480     ASSERT_UNUSED(timingValid, timingValid);
481
482     RefPtr<TimingFunction> timingFunction = timing.timingFunction;
483     if (compositorTiming.reverse)
484         timingFunction = CompositorAnimationsTimingFunctionReverser::reverse(timingFunction.get());
485
486     PropertySet properties = effect.properties();
487     ASSERT(!properties.isEmpty());
488     for (PropertySet::iterator it = properties.begin(); it != properties.end(); ++it) {
489
490         KeyframeVector values;
491         getKeyframeValuesForProperty(&effect, *it, compositorTiming.scaledDuration, compositorTiming.reverse, values);
492
493         blink::WebAnimation::TargetProperty targetProperty;
494         OwnPtr<blink::WebAnimationCurve> curve;
495         switch (*it) {
496         case CSSPropertyOpacity: {
497             targetProperty = blink::WebAnimation::TargetPropertyOpacity;
498
499             blink::WebFloatAnimationCurve* floatCurve = blink::Platform::current()->compositorSupport()->createFloatAnimationCurve();
500             addKeyframesToCurve(*floatCurve, values, *timingFunction.get());
501             curve = adoptPtr(floatCurve);
502             break;
503         }
504         case CSSPropertyWebkitFilter: {
505             targetProperty = blink::WebAnimation::TargetPropertyFilter;
506             blink::WebFilterAnimationCurve* filterCurve = blink::Platform::current()->compositorSupport()->createFilterAnimationCurve();
507             addKeyframesToCurve(*filterCurve, values, *timingFunction);
508             curve = adoptPtr(filterCurve);
509             break;
510         }
511         case CSSPropertyWebkitTransform: {
512             targetProperty = blink::WebAnimation::TargetPropertyTransform;
513             blink::WebTransformAnimationCurve* transformCurve = blink::Platform::current()->compositorSupport()->createTransformAnimationCurve();
514             addKeyframesToCurve(*transformCurve, values, *timingFunction.get());
515             curve = adoptPtr(transformCurve);
516             break;
517         }
518         default:
519             ASSERT_NOT_REACHED();
520             continue;
521         }
522         ASSERT(curve.get());
523
524         OwnPtr<blink::WebAnimation> animation = adoptPtr(blink::Platform::current()->compositorSupport()->createAnimation(*curve, targetProperty));
525
526         animation->setIterations(compositorTiming.adjustedIterationCount);
527         animation->setTimeOffset(compositorTiming.scaledTimeOffset);
528         animation->setAlternatesDirection(compositorTiming.alternate);
529
530         animations.append(animation.release());
531     }
532     ASSERT(!animations.isEmpty());
533 }
534
535 } // namespace WebCore