bool GraphicsLayerAndroid::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime, const IntSize& boxSize) { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); TLOG("createTransformAnimationFromKeyframes, name(%s) beginTime(%.2f)", keyframesName.latin1().data(), beginTime); KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyWebkitTransform); for (unsigned int i = 0; i < valueList.size(); i++) { TransformAnimationValue* originalValue = (TransformAnimationValue*)valueList.at(i); PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); TransformAnimationValue* value = new TransformAnimationValue(originalValue->keyTime(), originalValue->value(), timingFunction); operationsList->insert(value); } RefPtr<AndroidTransformAnimation> anim = AndroidTransformAnimation::create(animation, operationsList, beginTime); if (keyframesName.isEmpty()) anim->setName(propertyIdToString(valueList.property())); else anim->setName(keyframesName); m_contentLayer->addAnimation(anim.release()); needsNotifyClient(); return true; }
bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) { ASSERT(!keyframesName.isEmpty()); if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyTransform && valueList.property() != AnimatedPropertyOpacity)) return false; if (valueList.property() == AnimatedPropertyFilter) { int listIndex = validateFilterOperations(valueList); if (listIndex < 0) return false; const auto& filters = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value(); if (!filtersCanBeComposited(filters)) return false; } bool listsMatch = false; bool hasBigRotation; if (valueList.property() == AnimatedPropertyTransform) listsMatch = validateTransformOperations(valueList, hasBigRotation) >= 0; const double currentTime = monotonicallyIncreasingTime(); m_animations.add(TextureMapperAnimation(keyframesName, valueList, boxSize, *anim, listsMatch, currentTime - timeOffset, 0, TextureMapperAnimation::AnimationState::Playing)); // m_animationStartTime is the time of the first real frame of animation, now or delayed by a negative offset. if (timeOffset > 0) m_animationStartTime = currentTime; else m_animationStartTime = currentTime - timeOffset; notifyChange(AnimationChange); notifyChange(AnimationStarted); return true; }
bool GraphicsLayerAndroid::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime) { bool isKeyframe = valueList.size() > 2; TLOG("createAnimationFromKeyframes(%d), name(%s) beginTime(%.2f)", isKeyframe, keyframesName.latin1().data(), beginTime); switch (valueList.property()) { case AnimatedPropertyInvalid: break; case AnimatedPropertyWebkitTransform: break; case AnimatedPropertyBackgroundColor: break; case AnimatedPropertyOpacity: { MLOG("ANIMATEDPROPERTYOPACITY"); KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyOpacity); for (unsigned int i = 0; i < valueList.size(); i++) { FloatAnimationValue* originalValue = (FloatAnimationValue*)valueList.at(i); PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); FloatAnimationValue* value = new FloatAnimationValue(originalValue->keyTime(), originalValue->value(), timingFunction); operationsList->insert(value); } RefPtr<AndroidOpacityAnimation> anim = AndroidOpacityAnimation::create(animation, operationsList, beginTime); if (keyframesName.isEmpty()) anim->setName(propertyIdToString(valueList.property())); else anim->setName(keyframesName); m_contentLayer->addAnimation(anim.release()); needsNotifyClient(); return true; } break; } return false; }
PassOwnPtr<WebKit::WebAnimation> createWebAnimation(const KeyframeValueList& valueList, const CSSAnimationData* animation, int animationId, double timeOffset, Curve* curve, WebKit::WebAnimation::TargetProperty targetProperty, const FloatSize& boxSize) { bool alternate = false; bool reverse = false; if (animation && animation->isDirectionSet()) { CSSAnimationData::AnimationDirection direction = animation->direction(); if (direction == CSSAnimationData::AnimationDirectionAlternate || direction == CSSAnimationData::AnimationDirectionAlternateReverse) alternate = true; if (direction == CSSAnimationData::AnimationDirectionReverse || direction == CSSAnimationData::AnimationDirectionAlternateReverse) reverse = true; } for (size_t i = 0; i < valueList.size(); i++) { size_t index = reverse ? valueList.size() - i - 1 : i; const Value* originalValue = static_cast<const Value*>(valueList.at(index)); const Value* lastOriginalValue = 0; if (valueList.size() > 1 && ((reverse && index + 1 < valueList.size()) || (!reverse && index > 0))) lastOriginalValue = static_cast<const Value*>(valueList.at(reverse ? index + 1 : index - 1)); const TimingFunction* originalTimingFunction = originalValue->timingFunction(); // If there hasn't been a timing function associated with this keyframe, use the // animation's timing function, if we have one. if (!originalTimingFunction && animation->isTimingFunctionSet()) originalTimingFunction = animation->timingFunction().get(); // Ease is the default timing function. WebKit::WebAnimationCurve::TimingFunctionType timingFunctionType = WebKit::WebAnimationCurve::TimingFunctionTypeEase; bool isUsingCustomBezierTimingFunction = false; double x1 = 0; double y1 = 0; double x2 = 1; double y2 = 1; if (originalTimingFunction) { switch (originalTimingFunction->type()) { case TimingFunction::StepsFunction: // FIXME: add support for steps timing function. return nullptr; case TimingFunction::LinearFunction: timingFunctionType = WebKit::WebAnimationCurve::TimingFunctionTypeLinear; break; case TimingFunction::CubicBezierFunction: const CubicBezierTimingFunction* originalBezierTimingFunction = static_cast<const CubicBezierTimingFunction*>(originalTimingFunction); isUsingCustomBezierTimingFunction = true; x1 = originalBezierTimingFunction->x1(); y1 = originalBezierTimingFunction->y1(); x2 = originalBezierTimingFunction->x2(); y2 = originalBezierTimingFunction->y2(); break; } // switch } double duration = (animation && animation->isDurationSet()) ? animation->duration() : 1; double keyTime = originalValue->keyTime() * duration; if (reverse) keyTime = duration - keyTime; bool addedKeyframe = false; if (isUsingCustomBezierTimingFunction) addedKeyframe = appendKeyframeWithCustomBezierTimingFunction<Value, Keyframe, Curve>(curve, keyTime, originalValue, lastOriginalValue, x1, y1, x2, y2, boxSize); else addedKeyframe = appendKeyframeWithStandardTimingFunction<Value, Keyframe, Curve>(curve, keyTime, originalValue, lastOriginalValue, timingFunctionType, boxSize); if (!addedKeyframe) return nullptr; } OwnPtr<WebKit::WebAnimation> webAnimation = adoptPtr(Platform::current()->compositorSupport()->createAnimation(*curve, targetProperty, animationId)); int iterations = (animation && animation->isIterationCountSet()) ? animation->iterationCount() : 1; webAnimation->setIterations(iterations); webAnimation->setAlternatesDirection(alternate); // If timeOffset > 0, then the animation has started in the past. webAnimation->setTimeOffset(timeOffset); return webAnimation.release(); }