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