Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2012 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
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *     notice, this list of conditions and the following disclaimer in the
     11  *     documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #include "core/platform/graphics/chromium/AnimationTranslationUtil.h"
     28 
     29 #include "core/css/LengthFunctions.h"
     30 #include "core/platform/graphics/FloatSize.h"
     31 #include "core/platform/graphics/GraphicsLayer.h"
     32 #include "core/platform/graphics/chromium/TransformSkMatrix44Conversions.h"
     33 #include "core/platform/graphics/transforms/InterpolatedTransformOperation.h"
     34 #include "core/platform/graphics/transforms/Matrix3DTransformOperation.h"
     35 #include "core/platform/graphics/transforms/MatrixTransformOperation.h"
     36 #include "core/platform/graphics/transforms/PerspectiveTransformOperation.h"
     37 #include "core/platform/graphics/transforms/RotateTransformOperation.h"
     38 #include "core/platform/graphics/transforms/ScaleTransformOperation.h"
     39 #include "core/platform/graphics/transforms/SkewTransformOperation.h"
     40 #include "core/platform/graphics/transforms/TransformOperations.h"
     41 #include "core/platform/graphics/transforms/TranslateTransformOperation.h"
     42 
     43 #include "public/platform/Platform.h"
     44 #include "public/platform/WebAnimation.h"
     45 #include "public/platform/WebAnimationCurve.h"
     46 #include "public/platform/WebCompositorSupport.h"
     47 #include "public/platform/WebFloatAnimationCurve.h"
     48 #include "public/platform/WebTransformAnimationCurve.h"
     49 #include "public/platform/WebTransformOperations.h"
     50 
     51 #include "wtf/OwnPtr.h"
     52 #include "wtf/text/CString.h"
     53 
     54 using namespace std;
     55 using namespace WebKit;
     56 
     57 namespace WebCore {
     58 
     59 PassOwnPtr<WebTransformOperations> toWebTransformOperations(const TransformOperations& transformOperations, const FloatSize& boxSize)
     60 {
     61     // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects.
     62     OwnPtr<WebTransformOperations> webTransformOperations = adoptPtr(Platform::current()->compositorSupport()->createTransformOperations());
     63     if (!webTransformOperations)
     64         return nullptr;
     65     for (size_t j = 0; j < transformOperations.size(); ++j) {
     66         TransformOperation::OperationType operationType = transformOperations.operations()[j]->getOperationType();
     67         switch (operationType) {
     68         case TransformOperation::ScaleX:
     69         case TransformOperation::ScaleY:
     70         case TransformOperation::ScaleZ:
     71         case TransformOperation::Scale3D:
     72         case TransformOperation::Scale: {
     73             ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get());
     74             webTransformOperations->appendScale(transform->x(), transform->y(), transform->z());
     75             break;
     76         }
     77         case TransformOperation::TranslateX:
     78         case TransformOperation::TranslateY:
     79         case TransformOperation::TranslateZ:
     80         case TransformOperation::Translate3D:
     81         case TransformOperation::Translate: {
     82             TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get());
     83             webTransformOperations->appendTranslate(floatValueForLength(transform->x(), boxSize.width()), floatValueForLength(transform->y(), boxSize.height()), floatValueForLength(transform->z(), 1));
     84             break;
     85         }
     86         case TransformOperation::RotateX:
     87         case TransformOperation::RotateY:
     88         case TransformOperation::Rotate3D:
     89         case TransformOperation::Rotate: {
     90             RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get());
     91             webTransformOperations->appendRotate(transform->x(), transform->y(), transform->z(), transform->angle());
     92             break;
     93         }
     94         case TransformOperation::SkewX:
     95         case TransformOperation::SkewY:
     96         case TransformOperation::Skew: {
     97             SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get());
     98             webTransformOperations->appendSkew(transform->angleX(), transform->angleY());
     99             break;
    100         }
    101         case TransformOperation::Matrix: {
    102             MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get());
    103             TransformationMatrix m = transform->matrix();
    104             webTransformOperations->appendMatrix(TransformSkMatrix44Conversions::convert(m));
    105             break;
    106         }
    107         case TransformOperation::Matrix3D: {
    108             Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get());
    109             TransformationMatrix m = transform->matrix();
    110             webTransformOperations->appendMatrix(TransformSkMatrix44Conversions::convert(m));
    111             break;
    112         }
    113         case TransformOperation::Perspective: {
    114             PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get());
    115             webTransformOperations->appendPerspective(floatValueForLength(transform->perspective(), 0));
    116             break;
    117         }
    118         case TransformOperation::Interpolated: {
    119             TransformationMatrix m;
    120             transformOperations.operations()[j]->apply(m, boxSize);
    121             webTransformOperations->appendMatrix(TransformSkMatrix44Conversions::convert(m));
    122             break;
    123         }
    124         case TransformOperation::Identity:
    125             webTransformOperations->appendIdentity();
    126             break;
    127         case TransformOperation::None:
    128             // Do nothing.
    129             break;
    130         } // switch
    131     } // for each operation
    132 
    133     return webTransformOperations.release();
    134 }
    135 
    136 template <class Value, class Keyframe, class Curve>
    137 bool appendKeyframeWithStandardTimingFunction(Curve* curve, double keyTime, const Value* value, const Value* lastValue, WebKit::WebAnimationCurve::TimingFunctionType timingFunctionType, const FloatSize&)
    138 {
    139     curve->add(Keyframe(keyTime, value->value()), timingFunctionType);
    140     return true;
    141 }
    142 
    143 template <class Value, class Keyframe, class Curve>
    144 bool appendKeyframeWithCustomBezierTimingFunction(Curve* curve, double keyTime, const Value* value, const Value* lastValue, double x1, double y1, double x2, double y2, const FloatSize&)
    145 {
    146     curve->add(Keyframe(keyTime, value->value()), x1, y1, x2, y2);
    147     return true;
    148 }
    149 
    150 bool isRotationType(TransformOperation::OperationType transformType)
    151 {
    152     return transformType == TransformOperation::Rotate
    153         || transformType == TransformOperation::RotateX
    154         || transformType == TransformOperation::RotateY
    155         || transformType == TransformOperation::RotateZ
    156         || transformType == TransformOperation::Rotate3D;
    157 }
    158 
    159 template <>
    160 bool appendKeyframeWithStandardTimingFunction<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(WebTransformAnimationCurve* curve, double keyTime, const TransformAnimationValue* value, const TransformAnimationValue* lastValue, WebKit::WebAnimationCurve::TimingFunctionType timingFunctionType, const FloatSize& boxSize)
    161 {
    162     bool canBlend = !lastValue;
    163     OwnPtr<WebTransformOperations> operations(toWebTransformOperations(*value->value(), boxSize));
    164     if (!operations)
    165         return false;
    166     if (!canBlend) {
    167         OwnPtr<WebTransformOperations> lastOperations(toWebTransformOperations(*lastValue->value(), boxSize));
    168         if (!lastOperations)
    169             return false;
    170         canBlend = lastOperations->canBlendWith(*operations);
    171     }
    172     if (canBlend) {
    173         curve->add(WebTransformKeyframe(keyTime, operations.leakPtr()), timingFunctionType);
    174         return true;
    175     }
    176     return false;
    177 }
    178 
    179 template <>
    180 bool appendKeyframeWithCustomBezierTimingFunction<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(WebTransformAnimationCurve* curve, double keyTime, const TransformAnimationValue* value, const TransformAnimationValue* lastValue, double x1, double y1, double x2, double y2, const FloatSize& boxSize)
    181 {
    182     bool canBlend = !lastValue;
    183     OwnPtr<WebTransformOperations> operations(toWebTransformOperations(*value->value(), boxSize));
    184     if (!operations)
    185         return false;
    186     if (!canBlend) {
    187         OwnPtr<WebTransformOperations> lastOperations(toWebTransformOperations(*lastValue->value(), boxSize));
    188         if (!lastOperations)
    189             return false;
    190         canBlend = lastOperations->canBlendWith(*operations);
    191     }
    192     if (canBlend) {
    193         curve->add(WebTransformKeyframe(keyTime, operations.leakPtr()), x1, y1, x2, y2);
    194         return true;
    195     }
    196     return false;
    197 }
    198 
    199 template <class Value, class Keyframe, class Curve>
    200 PassOwnPtr<WebKit::WebAnimation> createWebAnimation(const KeyframeValueList& valueList, const CSSAnimationData* animation, int animationId, double timeOffset, Curve* curve, WebKit::WebAnimation::TargetProperty targetProperty, const FloatSize& boxSize)
    201 {
    202     bool alternate = false;
    203     bool reverse = false;
    204     if (animation && animation->isDirectionSet()) {
    205         CSSAnimationData::AnimationDirection direction = animation->direction();
    206         if (direction == CSSAnimationData::AnimationDirectionAlternate || direction == CSSAnimationData::AnimationDirectionAlternateReverse)
    207             alternate = true;
    208         if (direction == CSSAnimationData::AnimationDirectionReverse || direction == CSSAnimationData::AnimationDirectionAlternateReverse)
    209             reverse = true;
    210     }
    211 
    212     for (size_t i = 0; i < valueList.size(); i++) {
    213         size_t index = reverse ? valueList.size() - i - 1 : i;
    214         const Value* originalValue = static_cast<const Value*>(valueList.at(index));
    215         const Value* lastOriginalValue = 0;
    216         if (valueList.size() > 1 && ((reverse && index + 1 < valueList.size()) || (!reverse && index > 0)))
    217             lastOriginalValue = static_cast<const Value*>(valueList.at(reverse ? index + 1 : index - 1));
    218 
    219         const TimingFunction* originalTimingFunction = originalValue->timingFunction();
    220 
    221         // If there hasn't been a timing function associated with this keyframe, use the
    222         // animation's timing function, if we have one.
    223         if (!originalTimingFunction && animation->isTimingFunctionSet())
    224             originalTimingFunction = animation->timingFunction().get();
    225 
    226         // Ease is the default timing function.
    227         WebKit::WebAnimationCurve::TimingFunctionType timingFunctionType = WebKit::WebAnimationCurve::TimingFunctionTypeEase;
    228 
    229         bool isUsingCustomBezierTimingFunction = false;
    230         double x1 = 0;
    231         double y1 = 0;
    232         double x2 = 1;
    233         double y2 = 1;
    234 
    235         if (originalTimingFunction) {
    236             switch (originalTimingFunction->type()) {
    237             case TimingFunction::StepsFunction:
    238                 // FIXME: add support for steps timing function.
    239                 return nullptr;
    240             case TimingFunction::LinearFunction:
    241                 timingFunctionType = WebKit::WebAnimationCurve::TimingFunctionTypeLinear;
    242                 break;
    243             case TimingFunction::CubicBezierFunction:
    244                 const CubicBezierTimingFunction* originalBezierTimingFunction = static_cast<const CubicBezierTimingFunction*>(originalTimingFunction);
    245                 isUsingCustomBezierTimingFunction = true;
    246                 x1 = originalBezierTimingFunction->x1();
    247                 y1 = originalBezierTimingFunction->y1();
    248                 x2 = originalBezierTimingFunction->x2();
    249                 y2 = originalBezierTimingFunction->y2();
    250                 break;
    251             } // switch
    252         }
    253 
    254         double duration = (animation && animation->isDurationSet()) ? animation->duration() : 1;
    255         double keyTime = originalValue->keyTime() * duration;
    256 
    257         if (reverse)
    258             keyTime = duration - keyTime;
    259 
    260         bool addedKeyframe = false;
    261         if (isUsingCustomBezierTimingFunction)
    262             addedKeyframe = appendKeyframeWithCustomBezierTimingFunction<Value, Keyframe, Curve>(curve, keyTime, originalValue, lastOriginalValue, x1, y1, x2, y2, boxSize);
    263         else
    264             addedKeyframe = appendKeyframeWithStandardTimingFunction<Value, Keyframe, Curve>(curve, keyTime, originalValue, lastOriginalValue, timingFunctionType, boxSize);
    265         if (!addedKeyframe)
    266             return nullptr;
    267     }
    268 
    269     OwnPtr<WebKit::WebAnimation> webAnimation = adoptPtr(Platform::current()->compositorSupport()->createAnimation(*curve, targetProperty, animationId));
    270 
    271     int iterations = (animation && animation->isIterationCountSet()) ? animation->iterationCount() : 1;
    272     webAnimation->setIterations(iterations);
    273     webAnimation->setAlternatesDirection(alternate);
    274 
    275     // If timeOffset > 0, then the animation has started in the past.
    276     webAnimation->setTimeOffset(timeOffset);
    277 
    278     return webAnimation.release();
    279 }
    280 
    281 PassOwnPtr<WebKit::WebAnimation> createWebAnimation(const KeyframeValueList& values, const CSSAnimationData* animation, int animationId, double timeOffset, const FloatSize& boxSize)
    282 {
    283 
    284 
    285     if (values.property() == AnimatedPropertyWebkitTransform) {
    286         OwnPtr<WebTransformAnimationCurve> curve = adoptPtr(Platform::current()->compositorSupport()->createTransformAnimationCurve());
    287         return createWebAnimation<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(values, animation, animationId, timeOffset, curve.get(), WebKit::WebAnimation::TargetPropertyTransform, FloatSize(boxSize));
    288     }
    289 
    290     if (values.property() == AnimatedPropertyOpacity) {
    291         OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(Platform::current()->compositorSupport()->createFloatAnimationCurve());
    292         return createWebAnimation<FloatAnimationValue, WebFloatKeyframe, WebFloatAnimationCurve>(values, animation, animationId, timeOffset, curve.get(), WebKit::WebAnimation::TargetPropertyOpacity, FloatSize());
    293     }
    294 
    295     return nullptr;
    296 }
    297 
    298 } // namespace WebCore
    299