float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const { ASSERT(!m_keyPoints.isEmpty()); ASSERT(calcMode() != CalcModePaced); ASSERT(m_keyTimes.size() > 1); ASSERT(m_keyPoints.size() == m_keyTimes.size()); if (percent == 1) return m_keyPoints[m_keyPoints.size() - 1]; unsigned index = calculateKeyTimesIndex(percent); float fromPercent = m_keyTimes[index]; float toPercent = m_keyTimes[index + 1]; float fromKeyPoint = m_keyPoints[index]; float toKeyPoint = m_keyPoints[index + 1]; if (calcMode() == CalcModeDiscrete) return fromKeyPoint; float keyPointPercent = (percent - fromPercent) / (toPercent - fromPercent); if (calcMode() == CalcModeSpline) { ASSERT(m_keySplines.size() == m_keyPoints.size() - 1); keyPointPercent = calculatePercentForSpline(keyPointPercent, index); } return (toKeyPoint - fromKeyPoint) * keyPointPercent + fromKeyPoint; }
float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const { ASSERT(!m_keyPoints.isEmpty()); ASSERT(calcMode() != CalcModePaced); unsigned keyTimesCount = m_keyTimes.size(); ASSERT(keyTimesCount > 1); ASSERT(m_keyPoints.size() == keyTimesCount); unsigned index; for (index = 1; index < keyTimesCount; ++index) { if (m_keyTimes[index] >= percent) { break; } } --index; float fromPercent = m_keyTimes[index]; float toPercent = m_keyTimes[index + 1]; float fromKeyPoint = m_keyPoints[index]; float toKeyPoint = m_keyPoints[index + 1]; if (calcMode() == CalcModeDiscrete) { return percent == 1.0f ? toKeyPoint : fromKeyPoint; } float keyPointPercent = percent == 1.0f ? 1.0f : (percent - fromPercent) / (toPercent - fromPercent); if (calcMode() == CalcModeSpline) { ASSERT(m_keySplines.size() == m_keyPoints.size() - 1); keyPointPercent = calculatePercentForSpline(keyPointPercent, index); } return (toKeyPoint - fromKeyPoint) * keyPointPercent + fromKeyPoint; }
float SVGAnimationElement::calculatePercentForFromTo(float percent) const { if (calcMode() == CalcModeDiscrete && m_keyTimes.size() == 2) return percent > m_keyTimes[1] ? 1 : 0; return percent; }
void SVGAnimationElement::calculateKeyTimesForCalcModePaced() { ASSERT(calcMode() == CalcModePaced); ASSERT(animationMode() == ValuesAnimation); unsigned valuesCount = m_values.size(); ASSERT(valuesCount >= 1); if (valuesCount == 1) return; // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this function. m_keyTimes.clear(); Vector<float> keyTimesForPaced; float totalDistance = 0; keyTimesForPaced.append(0); for (unsigned n = 0; n < valuesCount - 1; ++n) { // Distance in any units float distance = calculateDistance(m_values[n], m_values[n + 1]); if (distance < 0) return; totalDistance += distance; keyTimesForPaced.append(distance); } if (!totalDistance) return; // Normalize. for (unsigned n = 1; n < keyTimesForPaced.size() - 1; ++n) keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance; keyTimesForPaced[keyTimesForPaced.size() - 1] = 1; // Use key times calculated based on pacing instead of the user provided ones. m_keyTimes = keyTimesForPaced; }
void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement* resultElement) { ASSERT(resultElement); SVGElement* targetElement = this->targetElement(); if (!targetElement || !isSVGAnimateElement(*resultElement)) return; ASSERT(percentage >= 0 && percentage <= 1); ASSERT(m_animator); ASSERT(animatedPropertyType() != AnimatedTransformList || isSVGAnimateTransformElement(*this)); ASSERT(animatedPropertyType() != AnimatedUnknown); ASSERT(m_fromProperty); ASSERT(m_fromProperty->type() == animatedPropertyType()); ASSERT(m_toProperty); SVGAnimateElement* resultAnimationElement = toSVGAnimateElement(resultElement); ASSERT(resultAnimationElement->m_animatedProperty); ASSERT(resultAnimationElement->animatedPropertyType() == animatedPropertyType()); if (isSVGSetElement(*this)) percentage = 1; if (calcMode() == CalcModeDiscrete) percentage = percentage < 0.5 ? 0 : 1; // Target element might have changed. m_animator->setContextElement(targetElement); // Values-animation accumulates using the last values entry corresponding to the end of duration time. SVGPropertyBase* toAtEndOfDurationProperty = m_toAtEndOfDurationProperty ? m_toAtEndOfDurationProperty.get() : m_toProperty.get(); m_animator->calculateAnimatedValue(percentage, repeatCount, m_fromProperty.get(), m_toProperty.get(), toAtEndOfDurationProperty, resultAnimationElement->m_animatedProperty.get()); }
void SVGAnimationElement::updateAnimation(float percent, unsigned repeat, SVGSMILElement *resultElement) { if (!m_animationValid) { return; } float effectivePercent; if (animationMode() == ValuesAnimation) { String from; String to; currentValuesForValuesAnimation(percent, effectivePercent, from, to); if (from != m_lastValuesAnimationFrom || to != m_lastValuesAnimationTo) { m_animationValid = calculateFromAndToValues(from, to); if (!m_animationValid) { return; } m_lastValuesAnimationFrom = from; m_lastValuesAnimationTo = to; } } else if (!m_keyPoints.isEmpty() && calcMode() != CalcModePaced) { effectivePercent = calculatePercentFromKeyPoints(percent); } else { effectivePercent = percent; } calculateAnimatedValue(effectivePercent, repeat, resultElement); }
void SVGAnimationElement::calculateKeyTimesForCalcModePaced() { ASSERT(calcMode() == CalcModePaced); ASSERT(animationMode() == ValuesAnimation); unsigned valuesCount = m_values.size(); ASSERT(valuesCount > 1); Vector<float> keyTimesForPaced; float totalDistance = 0; keyTimesForPaced.append(0); for (unsigned n = 0; n < valuesCount - 1; ++n) { // Distance in any units float distance = calculateDistance(m_values[n], m_values[n + 1]); if (distance < 0) { return; } totalDistance += distance; keyTimesForPaced.append(distance); } if (!totalDistance) { return; } // Normalize. for (unsigned n = 1; n < keyTimesForPaced.size() - 1; ++n) { keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance; } keyTimesForPaced[keyTimesForPaced.size() - 1] = 1.f; // Use key times calculated based on pacing instead of the user provided ones. m_keyTimes.swap(keyTimesForPaced); }
void SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const { ASSERT(!m_keyPoints.isEmpty()); ASSERT(m_keyPoints.size() == m_keyTimes.size()); ASSERT(calcMode() != CalcModePaced); effectivePercent = calculatePercentFromKeyPoints(percent); unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1)); from = m_values[index]; to = m_values[index + 1]; }
float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const { ASSERT(calcMode() == CalcModeSpline); ASSERT_WITH_SECURITY_IMPLICATION(splineIndex < m_keySplines.size()); UnitBezier bezier = m_keySplines[splineIndex]; SMILTime duration = simpleDuration(); if (!duration.isFinite()) duration = 100.0; return narrowPrecisionToFloat(bezier.solve(percent, solveEpsilon(duration.value()))); }
unsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const { unsigned index; unsigned keyTimesCount = m_keyTimes.size(); // For linear and spline animations, the last value must be '1'. In those // cases we don't need to consider the last value, since |percent| is never // greater than one. if (keyTimesCount && calcMode() != CalcModeDiscrete) keyTimesCount--; for (index = 1; index < keyTimesCount; ++index) { if (m_keyTimes[index] > percent) break; } return --index; }
void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement* resultElement) { ASSERT(resultElement); SVGElement* targetElement = this->targetElement(); if (!targetElement) return; ASSERT(m_animatedPropertyType == determineAnimatedPropertyType(targetElement)); ASSERT(percentage >= 0 && percentage <= 1); ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag)); ASSERT(m_animatedPropertyType != AnimatedUnknown); ASSERT(m_animator); ASSERT(m_animator->type() == m_animatedPropertyType); ASSERT(m_fromType); ASSERT(m_fromType->type() == m_animatedPropertyType); ASSERT(m_toType); ASSERT(resultElement->hasTagName(SVGNames::animateTag) || resultElement->hasTagName(SVGNames::animateColorTag) || resultElement->hasTagName(SVGNames::animateTransformTag) || resultElement->hasTagName(SVGNames::setTag)); SVGAnimateElement* resultAnimationElement = static_cast<SVGAnimateElement*>(resultElement); ASSERT(resultAnimationElement->m_animatedType); ASSERT(resultAnimationElement->m_animatedPropertyType == m_animatedPropertyType); if (hasTagName(SVGNames::setTag)) percentage = 1; if (calcMode() == CalcModeDiscrete) percentage = percentage < 0.5 ? 0 : 1; // Target element might have changed. m_animator->setContextElement(targetElement); // Be sure to detach list wrappers before we modfiy their underlying value. If we'd do // if after calculateAnimatedValue() ran the cached pointers in the list propery tear // offs would point nowhere, and we couldn't create copies of those values anymore, // while detaching. This is covered by assertions, moving this down would fire them. if (!m_animatedProperties.isEmpty()) m_animator->animValWillChange(m_animatedProperties); // Values-animation accumulates using the last values entry corresponding to the end of duration time. SVGAnimatedType* toAtEndOfDurationType = m_toAtEndOfDurationType ? m_toAtEndOfDurationType.get() : m_toType.get(); m_animator->calculateAnimatedValue(percentage, repeatCount, m_fromType.get(), m_toType.get(), toAtEndOfDurationType, resultAnimationElement->m_animatedType.get()); }
void SVGAnimationElement::startedActiveInterval() { m_animationValid = false; if (!hasValidTarget()) { return; } AnimationMode animationMode = this->animationMode(); if (animationMode == NoAnimation) { return; } if (animationMode == FromToAnimation) { m_animationValid = calculateFromAndToValues(fromValue(), toValue()); } else if (animationMode == ToAnimation) { // For to-animations the from value is the current accumulated value from lower priority animations. // The value is not static and is determined during the animation. m_animationValid = calculateFromAndToValues(String(), toValue()); } else if (animationMode == FromByAnimation) { m_animationValid = calculateFromAndByValues(fromValue(), byValue()); } else if (animationMode == ByAnimation) { m_animationValid = calculateFromAndByValues(String(), byValue()); } else if (animationMode == ValuesAnimation) { CalcMode calcMode = this->calcMode(); m_animationValid = m_values.size() > 1 && (calcMode == CalcModePaced || !hasAttribute(SVGNames::keyTimesAttr) || hasAttribute(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size())) && (calcMode == CalcModeDiscrete || !m_keyTimes.size() || m_keyTimes.last() == 1.0) && (calcMode != CalcModeSpline || (m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1) || m_keySplines.size() == m_keyPoints.size() - 1)) && (!hasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size())); if (calcMode == CalcModePaced && m_animationValid) { calculateKeyTimesForCalcModePaced(); } } else if (animationMode == PathAnimation) { m_animationValid = calcMode() == CalcModePaced || !hasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()); } }