Update To 11.40.268.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/AnimationNode.h"
35 #include "core/animation/AnimationTranslationUtil.h"
36 #include "core/animation/CompositorAnimationsImpl.h"
37 #include "core/animation/animatable/AnimatableDouble.h"
38 #include "core/animation/animatable/AnimatableFilterOperations.h"
39 #include "core/animation/animatable/AnimatableTransform.h"
40 #include "core/animation/animatable/AnimatableValue.h"
41 #include "core/rendering/RenderBoxModelObject.h"
42 #include "core/rendering/RenderLayer.h"
43 #include "core/rendering/RenderObject.h"
44 #include "core/rendering/compositing/CompositedLayerMapping.h"
45 #include "platform/geometry/FloatBox.h"
46 #include "public/platform/Platform.h"
47 #include "public/platform/WebCompositorAnimation.h"
48 #include "public/platform/WebCompositorSupport.h"
49 #include "public/platform/WebFilterAnimationCurve.h"
50 #include "public/platform/WebFilterKeyframe.h"
51 #include "public/platform/WebFloatAnimationCurve.h"
52 #include "public/platform/WebFloatKeyframe.h"
53 #include "public/platform/WebTransformAnimationCurve.h"
54 #include "public/platform/WebTransformKeyframe.h"
55
56 #include <algorithm>
57 #include <cmath>
58
59 namespace blink {
60
61 namespace {
62
63 void getKeyframeValuesForProperty(const KeyframeEffectModelBase* effect, CSSPropertyID id, double scale, PropertySpecificKeyframeVector& values)
64 {
65     ASSERT(values.isEmpty());
66
67     for (const auto& keyframe : effect->getPropertySpecificKeyframes(id)) {
68         double offset = keyframe->offset() * scale;
69         values.append(keyframe->cloneWithOffset(offset));
70     }
71 }
72
73 }
74
75 bool CompositorAnimations::getAnimatedBoundingBox(FloatBox& box, const AnimationEffect& effect, double minValue, double maxValue) const
76 {
77     const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect);
78
79     PropertySet properties = keyframeEffect.properties();
80
81     if (properties.isEmpty())
82         return true;
83
84     minValue = std::min(minValue, 0.0);
85     maxValue = std::max(maxValue, 1.0);
86
87     for (const auto& property : properties) {
88         // TODO: Add the ability to get expanded bounds for filters as well.
89         if (property != CSSPropertyTransform && property != CSSPropertyWebkitTransform)
90             continue;
91
92         const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropertySpecificKeyframes(property);
93         if (frames.isEmpty() || frames.size() < 2)
94             continue;
95
96         FloatBox originalBox(box);
97
98         for (size_t j = 0; j < frames.size() - 1; ++j) {
99             const AnimatableTransform* startTransform = toAnimatableTransform(frames[j]->getAnimatableValue().get());
100             const AnimatableTransform* endTransform = toAnimatableTransform(frames[j+1]->getAnimatableValue().get());
101             // TODO: Add support for inflating modes other than Replace.
102             if (frames[j]->composite() != AnimationEffect::CompositeReplace)
103                 return false;
104
105             const TimingFunction& timing = frames[j]->easing();
106             double min = 0;
107             double max = 1;
108             if (j == 0) {
109                 float frameLength = frames[j+1]->offset();
110                 if (frameLength > 0) {
111                     min = minValue / frameLength;
112                 }
113             }
114
115             if (j == frames.size() - 2) {
116                 float frameLength = frames[j+1]->offset() - frames[j]->offset();
117                 if (frameLength > 0) {
118                     max = 1 + (maxValue - 1) / frameLength;
119                 }
120             }
121
122             FloatBox bounds;
123             timing.range(&min, &max);
124             if (!endTransform->transformOperations().blendedBoundsForBox(originalBox, startTransform->transformOperations(), min, max, &bounds))
125                 return false;
126             box.expandTo(bounds);
127         }
128     }
129     return true;
130 }
131
132 // -----------------------------------------------------------------------
133 // CompositorAnimations public API
134 // -----------------------------------------------------------------------
135
136 bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const AnimationEffect& effect, double playerPlaybackRate)
137 {
138     const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect);
139
140     PropertySet properties = keyframeEffect.properties();
141
142     if (properties.isEmpty())
143         return false;
144
145     for (const auto& property : properties) {
146         const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getPropertySpecificKeyframes(property);
147         ASSERT(keyframes.size() >= 2);
148         auto* lastKeyframe = keyframes.last().get();
149         for (const auto& keyframe : keyframes) {
150             // FIXME: Determine candidacy based on the CSSValue instead of a snapshot AnimatableValue.
151             if (keyframe->composite() != AnimationEffect::CompositeReplace || !keyframe->getAnimatableValue())
152                 return false;
153
154             switch (property) {
155             case CSSPropertyOpacity:
156                 break;
157             case CSSPropertyTransform:
158                 if (toAnimatableTransform(keyframe->getAnimatableValue().get())->transformOperations().dependsOnBoxSize())
159                     return false;
160                 break;
161             case CSSPropertyWebkitFilter: {
162                 const FilterOperations& operations = toAnimatableFilterOperations(keyframe->getAnimatableValue().get())->operations();
163                 if (operations.hasFilterThatMovesPixels())
164                     return false;
165                 break;
166             }
167             default:
168                 return false;
169             }
170
171             // FIXME: Remove this check when crbug.com/229405 is resolved
172             if (keyframe != lastKeyframe && keyframe->easing().type() == TimingFunction::StepsFunction)
173                 return false;
174         }
175     }
176
177     CompositorAnimationsImpl::CompositorTiming out;
178     if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, playerPlaybackRate))
179         return false;
180
181     if (timing.timingFunction->type() != TimingFunction::LinearFunction) {
182         // Checks the of size of KeyframeVector instead of PropertySpecificKeyframeVector.
183         const KeyframeVector& keyframes = keyframeEffect.getFrames();
184         if (keyframes.size() == 2 && keyframes.first()->easing().type() == TimingFunction::LinearFunction && timing.timingFunction->type() != TimingFunction::StepsFunction)
185             return true;
186
187         // FIXME: Support non-linear timing functions in the compositor for
188         // more than two keyframes and step timing functions in the compositor.
189         return false;
190     }
191
192     return true;
193 }
194
195 bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element)
196 {
197     return element.renderer() && element.renderer()->compositingState() == PaintsIntoOwnBacking;
198 }
199
200 bool CompositorAnimations::startAnimationOnCompositor(const Element& element, double startTime, double timeOffset, const Timing& timing, const AnimationEffect& effect, Vector<int>& startedAnimationIds, double playerPlaybackRate)
201 {
202     ASSERT(startedAnimationIds.isEmpty());
203     ASSERT(isCandidateForAnimationOnCompositor(timing, effect, playerPlaybackRate));
204     ASSERT(canStartAnimationOnCompositor(element));
205
206     const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect);
207
208     RenderLayer* layer = toRenderBoxModelObject(element.renderer())->layer();
209     ASSERT(layer);
210
211     Vector<OwnPtr<WebCompositorAnimation>> animations;
212     CompositorAnimationsImpl::getAnimationOnCompositor(timing, startTime, timeOffset, keyframeEffect, animations, playerPlaybackRate);
213     ASSERT(!animations.isEmpty());
214     for (auto& animation : animations) {
215         int id = animation->id();
216         if (!layer->compositedLayerMapping()->mainGraphicsLayer()->addAnimation(animation.release())) {
217             // FIXME: We should know ahead of time whether these animations can be started.
218             for (int startedAnimationId : startedAnimationIds)
219                 cancelAnimationOnCompositor(element, startedAnimationId);
220             startedAnimationIds.clear();
221             return false;
222         }
223         startedAnimationIds.append(id);
224     }
225     ASSERT(!startedAnimationIds.isEmpty());
226     return true;
227 }
228
229 void CompositorAnimations::cancelAnimationOnCompositor(const Element& element, int id)
230 {
231     if (!canStartAnimationOnCompositor(element)) {
232         // When an element is being detached, we cancel any associated
233         // AnimationPlayers for CSS animations. But by the time we get
234         // here the mapping will have been removed.
235         // FIXME: Defer remove/pause operations until after the
236         // compositing update.
237         return;
238     }
239     toRenderBoxModelObject(element.renderer())->layer()->compositedLayerMapping()->mainGraphicsLayer()->removeAnimation(id);
240 }
241
242 void CompositorAnimations::pauseAnimationForTestingOnCompositor(const Element& element, int id, double pauseTime)
243 {
244     // FIXME: canStartAnimationOnCompositor queries compositingState, which is not necessarily up to date.
245     // https://code.google.com/p/chromium/issues/detail?id=339847
246     DisableCompositingQueryAsserts disabler;
247
248     if (!canStartAnimationOnCompositor(element)) {
249         ASSERT_NOT_REACHED();
250         return;
251     }
252     toRenderBoxModelObject(element.renderer())->layer()->compositedLayerMapping()->mainGraphicsLayer()->pauseAnimation(id, pauseTime);
253 }
254
255 // -----------------------------------------------------------------------
256 // CompositorAnimationsImpl
257 // -----------------------------------------------------------------------
258
259 bool CompositorAnimationsImpl::convertTimingForCompositor(const Timing& timing, double timeOffset, CompositorTiming& out, double playerPlaybackRate)
260 {
261     timing.assertValid();
262
263     if (!timing.iterationCount || !timing.iterationDuration)
264         return false;
265
266     if (!std::isfinite(timing.iterationCount)) {
267         out.adjustedIterationCount = -1;
268     } else {
269         out.adjustedIterationCount = timing.iterationCount;
270     }
271
272     out.scaledDuration = timing.iterationDuration;
273     out.direction = timing.direction;
274     // Compositor's time offset is positive for seeking into the animation.
275     out.scaledTimeOffset = -timing.startDelay + timeOffset;
276     out.playbackRate = timing.playbackRate * playerPlaybackRate;
277     out.fillMode = timing.fillMode == Timing::FillModeAuto ? Timing::FillModeNone : timing.fillMode;
278     out.iterationStart = timing.iterationStart;
279     out.assertValid();
280     return true;
281 }
282
283 namespace {
284
285 template<typename PlatformAnimationCurveType, typename PlatformAnimationKeyframeType>
286 void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const PlatformAnimationKeyframeType& keyframe, const TimingFunction* timingFunction)
287 {
288     if (!timingFunction) {
289         curve.add(keyframe);
290         return;
291     }
292
293     switch (timingFunction->type()) {
294     case TimingFunction::LinearFunction:
295         curve.add(keyframe, WebCompositorAnimationCurve::TimingFunctionTypeLinear);
296         return;
297
298     case TimingFunction::CubicBezierFunction: {
299         const CubicBezierTimingFunction* cubic = toCubicBezierTimingFunction(timingFunction);
300
301         if (cubic->subType() == CubicBezierTimingFunction::Custom) {
302             curve.add(keyframe, cubic->x1(), cubic->y1(), cubic->x2(), cubic->y2());
303         } else {
304
305             WebCompositorAnimationCurve::TimingFunctionType easeType;
306             switch (cubic->subType()) {
307             case CubicBezierTimingFunction::Ease:
308                 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEase;
309                 break;
310             case CubicBezierTimingFunction::EaseIn:
311                 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseIn;
312                 break;
313             case CubicBezierTimingFunction::EaseOut:
314                 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseOut;
315                 break;
316             case CubicBezierTimingFunction::EaseInOut:
317                 easeType = WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut;
318                 break;
319
320             // Custom Bezier are handled seperately.
321             case CubicBezierTimingFunction::Custom:
322             default:
323                 ASSERT_NOT_REACHED();
324                 return;
325             }
326
327             curve.add(keyframe, easeType);
328         }
329         return;
330     }
331
332     case TimingFunction::StepsFunction:
333     default:
334         ASSERT_NOT_REACHED();
335         return;
336     }
337 }
338
339 } // namespace anoymous
340
341 void CompositorAnimationsImpl::addKeyframesToCurve(WebCompositorAnimationCurve& curve, const PropertySpecificKeyframeVector& keyframes, const Timing& timing)
342 {
343     auto* lastKeyframe = keyframes.last().get();
344     for (const auto& keyframe : keyframes) {
345         const TimingFunction* keyframeTimingFunction = 0;
346         if (keyframe != lastKeyframe) { // Ignore timing function of last frame.
347             if (keyframes.size() == 2 && keyframes.first()->easing().type() == TimingFunction::LinearFunction)
348                 keyframeTimingFunction = timing.timingFunction.get();
349             else
350                 keyframeTimingFunction = &keyframe->easing();
351         }
352
353         // FIXME: This relies on StringKeyframes being eagerly evaluated, which will
354         // not happen eventually. Instead we should extract the CSSValue here
355         // and convert using another set of toAnimatableXXXOperations functions.
356         const AnimatableValue* value = keyframe->getAnimatableValue().get();
357
358         switch (curve.type()) {
359         case WebCompositorAnimationCurve::AnimationCurveTypeFilter: {
360             OwnPtr<WebFilterOperations> ops = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations());
361             toWebFilterOperations(toAnimatableFilterOperations(value)->operations(), ops.get());
362
363             WebFilterKeyframe filterKeyframe(keyframe->offset(), ops.release());
364             WebFilterAnimationCurve* filterCurve = static_cast<WebFilterAnimationCurve*>(&curve);
365             addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframeTimingFunction);
366             break;
367         }
368         case WebCompositorAnimationCurve::AnimationCurveTypeFloat: {
369             WebFloatKeyframe floatKeyframe(keyframe->offset(), toAnimatableDouble(value)->toDouble());
370             WebFloatAnimationCurve* floatCurve = static_cast<WebFloatAnimationCurve*>(&curve);
371             addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction);
372             break;
373         }
374         case WebCompositorAnimationCurve::AnimationCurveTypeTransform: {
375             OwnPtr<WebTransformOperations> ops = adoptPtr(Platform::current()->compositorSupport()->createTransformOperations());
376             toWebTransformOperations(toAnimatableTransform(value)->transformOperations(), ops.get());
377
378             WebTransformKeyframe transformKeyframe(keyframe->offset(), ops.release());
379             WebTransformAnimationCurve* transformCurve = static_cast<WebTransformAnimationCurve*>(&curve);
380             addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, keyframeTimingFunction);
381             break;
382         }
383         default:
384             ASSERT_NOT_REACHED();
385         }
386     }
387 }
388
389 void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, double startTime, double timeOffset, const KeyframeEffectModelBase& effect, Vector<OwnPtr<WebCompositorAnimation> >& animations, double playerPlaybackRate)
390 {
391     ASSERT(animations.isEmpty());
392     CompositorTiming compositorTiming;
393     bool timingValid = convertTimingForCompositor(timing, timeOffset, compositorTiming, playerPlaybackRate);
394     ASSERT_UNUSED(timingValid, timingValid);
395
396     PropertySet properties = effect.properties();
397     ASSERT(!properties.isEmpty());
398     for (const auto& property : properties) {
399         PropertySpecificKeyframeVector values;
400         getKeyframeValuesForProperty(&effect, property, compositorTiming.scaledDuration, values);
401
402         WebCompositorAnimation::TargetProperty targetProperty;
403         OwnPtr<WebCompositorAnimationCurve> curve;
404         switch (property) {
405         case CSSPropertyOpacity: {
406             targetProperty = WebCompositorAnimation::TargetPropertyOpacity;
407
408             WebFloatAnimationCurve* floatCurve = Platform::current()->compositorSupport()->createFloatAnimationCurve();
409             addKeyframesToCurve(*floatCurve, values, timing);
410             curve = adoptPtr(floatCurve);
411             break;
412         }
413         case CSSPropertyWebkitFilter: {
414             targetProperty = WebCompositorAnimation::TargetPropertyFilter;
415             WebFilterAnimationCurve* filterCurve = Platform::current()->compositorSupport()->createFilterAnimationCurve();
416             addKeyframesToCurve(*filterCurve, values, timing);
417             curve = adoptPtr(filterCurve);
418             break;
419         }
420         case CSSPropertyTransform: {
421             targetProperty = WebCompositorAnimation::TargetPropertyTransform;
422             WebTransformAnimationCurve* transformCurve = Platform::current()->compositorSupport()->createTransformAnimationCurve();
423             addKeyframesToCurve(*transformCurve, values, timing);
424             curve = adoptPtr(transformCurve);
425             break;
426         }
427         default:
428             ASSERT_NOT_REACHED();
429             continue;
430         }
431         ASSERT(curve.get());
432
433         OwnPtr<WebCompositorAnimation> animation = adoptPtr(Platform::current()->compositorSupport()->createAnimation(*curve, targetProperty));
434
435         if (!std::isnan(startTime))
436             animation->setStartTime(startTime);
437
438         animation->setIterations(compositorTiming.adjustedIterationCount);
439         animation->setIterationStart(compositorTiming.iterationStart);
440         animation->setTimeOffset(compositorTiming.scaledTimeOffset);
441
442         switch (compositorTiming.direction) {
443         case Timing::PlaybackDirectionNormal:
444             animation->setDirection(blink::WebCompositorAnimation::DirectionNormal);
445             break;
446         case Timing::PlaybackDirectionReverse:
447             animation->setDirection(blink::WebCompositorAnimation::DirectionReverse);
448             break;
449         case Timing::PlaybackDirectionAlternate:
450             animation->setDirection(blink::WebCompositorAnimation::DirectionAlternate);
451             break;
452         case Timing::PlaybackDirectionAlternateReverse:
453             animation->setDirection(blink::WebCompositorAnimation::DirectionAlternateReverse);
454             break;
455         default:
456             ASSERT_NOT_REACHED();
457         }
458         animation->setPlaybackRate(compositorTiming.playbackRate);
459
460         switch (compositorTiming.fillMode) {
461         case Timing::FillModeNone:
462             animation->setFillMode(blink::WebCompositorAnimation::FillModeNone);
463             break;
464         case Timing::FillModeForwards:
465             animation->setFillMode(blink::WebCompositorAnimation::FillModeForwards);
466             break;
467         case Timing::FillModeBackwards:
468             animation->setFillMode(blink::WebCompositorAnimation::FillModeBackwards);
469             break;
470         case Timing::FillModeBoth:
471             animation->setFillMode(blink::WebCompositorAnimation::FillModeBoth);
472             break;
473         default:
474             ASSERT_NOT_REACHED();
475         }
476         animations.append(animation.release());
477     }
478     ASSERT(!animations.isEmpty());
479 }
480
481 } // namespace blink