void InspectorAnimationAgent::setTiming(ErrorString* errorString, const String& animationId, double duration, double delay) { Animation* animation = assertAnimation(errorString, animationId); if (!animation) return; AnimationType type = m_idToAnimationType.get(animationId); if (type == AnimationType::CSSTransition) { KeyframeEffect* effect = toKeyframeEffect(animation->effect()); KeyframeEffectModelBase* model = toKeyframeEffectModelBase(effect->model()); const AnimatableValueKeyframeEffectModel* oldModel = toAnimatableValueKeyframeEffectModel(model); // Refer to CSSAnimations::calculateTransitionUpdateForProperty() for the structure of transitions. const KeyframeVector& frames = oldModel->getFrames(); ASSERT(frames.size() == 3); KeyframeVector newFrames; for (int i = 0; i < 3; i++) newFrames.append(toAnimatableValueKeyframe(frames[i]->clone().get())); // Update delay, represented by the distance between the first two keyframes. newFrames[1]->setOffset(delay / (delay + duration)); model->setFrames(newFrames); AnimationEffectTiming* timing = animation->effect()->timing(); UnrestrictedDoubleOrString unrestrictedDuration; unrestrictedDuration.setUnrestrictedDouble(duration + delay); timing->setDuration(unrestrictedDuration); } else if (type == AnimationType::WebAnimation) { AnimationEffectTiming* timing = animation->effect()->timing(); UnrestrictedDoubleOrString unrestrictedDuration; unrestrictedDuration.setUnrestrictedDouble(duration); timing->setDuration(unrestrictedDuration); timing->setDelay(delay); } }
KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes) { double lastOffset = 0; KeyframeVector result; result.reserveCapacity(keyframes.size()); for (size_t i = 0; i < keyframes.size(); ++i) { double offset = keyframes[i]->offset(); if (!isNull(offset)) { ASSERT(offset >= 0); ASSERT(offset <= 1); ASSERT(offset >= lastOffset); lastOffset = offset; } result.append(keyframes[i]->clone()); } if (result.isEmpty()) { return result; } if (isNull(result.last()->offset())) result.last()->setOffset(1); if (result.size() > 1 && isNull(result[0]->offset())) result[0]->setOffset(0); size_t lastIndex = 0; lastOffset = result[0]->offset(); for (size_t i = 1; i < result.size(); ++i) { double offset = result[i]->offset(); if (!isNull(offset)) { for (size_t j = 1; j < i - lastIndex; ++j) result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex)); lastIndex = i; lastOffset = offset; } } return result; }
KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes) { // keyframes [beginIndex, endIndex) will remain after removing all keyframes if they are not // loosely sorted by offset, and after removing keyframes with positional offset outide [0, 1]. size_t beginIndex = 0; size_t endIndex = keyframes.size(); // Becomes the most recent keyframe with an explicit offset. size_t lastIndex = endIndex; double lastOffset = std::numeric_limits<double>::quiet_NaN(); for (size_t i = 0; i < keyframes.size(); ++i) { double offset = keyframes[i]->offset(); if (!isNull(offset)) { if (lastIndex < i && offset < lastOffset) { // The keyframes are not loosely sorted by offset. Exclude all. endIndex = beginIndex; break; } if (offset < 0) { // Remove all keyframes up to and including this keyframe. beginIndex = i + 1; } else if (offset > 1) { // Remove all keyframes from this keyframe onwards. Note we must complete our checking // that the keyframes are loosely sorted by offset, so we can't exit the loop early. endIndex = std::min(i, endIndex); } lastIndex = i; lastOffset = offset; } } KeyframeVector result; if (beginIndex != endIndex) { result.reserveCapacity(endIndex - beginIndex); for (size_t i = beginIndex; i < endIndex; ++i) { result.append(keyframes[i]->clone()); } if (isNull(result[result.size() - 1]->offset())) result[result.size() - 1]->setOffset(1); if (result.size() > 1 && isNull(result[0]->offset())) result[0]->setOffset(0); lastIndex = 0; lastOffset = result[0]->offset(); for (size_t i = 1; i < result.size(); ++i) { double offset = result[i]->offset(); if (!isNull(offset)) { if (lastIndex + 1 < i) { for (size_t j = 1; j < i - lastIndex; ++j) result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex)); } lastIndex = i; lastOffset = offset; } } } return result; }