diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:41 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:41 -0800 |
commit | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /WebCore/svg/SVGAnimationElement.cpp | |
parent | a65af38181ac7d34544586bdb5cd004de93897ad (diff) | |
download | external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.zip external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.gz external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/svg/SVGAnimationElement.cpp')
-rw-r--r-- | WebCore/svg/SVGAnimationElement.cpp | 533 |
1 files changed, 0 insertions, 533 deletions
diff --git a/WebCore/svg/SVGAnimationElement.cpp b/WebCore/svg/SVGAnimationElement.cpp deleted file mode 100644 index 5910ac8..0000000 --- a/WebCore/svg/SVGAnimationElement.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/* - Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> - 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> - Copyright (C) 2007 Eric Seidel <eric@webkit.org> - Copyright (C) 2008 Apple Inc. All rights reserved. - - This file is part of the KDE project - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#if ENABLE(SVG_ANIMATION) -#include "SVGAnimationElement.h" - -#include "CSSComputedStyleDeclaration.h" -#include "CSSParser.h" -#include "CSSPropertyNames.h" -#include "Document.h" -#include "Event.h" -#include "EventListener.h" -#include "FloatConversion.h" -#include "HTMLNames.h" -#include "SVGElementInstance.h" -#include "SVGNames.h" -#include "SVGURIReference.h" -#include "SVGUseElement.h" -#include "XLinkNames.h" -#include <math.h> - -using namespace std; - -namespace WebCore { - -SVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, Document* doc) - : SVGSMILElement(tagName, doc) - , SVGTests() - , SVGExternalResourcesRequired() - , m_animationValid(false) -{ -} - -SVGAnimationElement::~SVGAnimationElement() -{ -} - -static void parseKeyTimes(const String& parse, Vector<float>& result, bool verifyOrder) -{ - result.clear(); - Vector<String> parseList; - parse.split(';', parseList); - for (unsigned n = 0; n < parseList.size(); ++n) { - String timeString = parseList[n]; - bool ok; - float time = timeString.toFloat(&ok); - if (!ok || time < 0 || time > 1.f) - goto fail; - if (verifyOrder) { - if (!n) { - if (time != 0) - goto fail; - } else if (time < result.last()) - goto fail; - } - result.append(time); - } - return; -fail: - result.clear(); -} - -static void parseKeySplines(const String& parse, Vector<UnitBezier>& result) -{ - result.clear(); - Vector<String> parseList; - parse.split(';', parseList); - for (unsigned n = 0; n < parseList.size(); ++n) { - Vector<String> parseSpline; - parseList[n].split(',', parseSpline); - // The spec says the sepator is a space, all tests use commas. Weird. - if (parseSpline.size() == 1) - parseList[n].split(' ', parseSpline); - if (parseSpline.size() != 4) - goto fail; - double curveValues[4]; - for (unsigned i = 0; i < 4; ++i) { - String parseNumber = parseSpline[i]; - bool ok; - curveValues[i] = parseNumber.toDouble(&ok); - if (!ok || curveValues[i] < 0.0 || curveValues[i] > 1.0) - goto fail; - } - result.append(UnitBezier(curveValues[0], curveValues[1], curveValues[2], curveValues[3])); - } - return; -fail: - result.clear(); -} - -void SVGAnimationElement::parseMappedAttribute(MappedAttribute* attr) -{ - if (attr->name() == SVGNames::valuesAttr) - attr->value().string().split(';', m_values); - else if (attr->name() == SVGNames::keyTimesAttr) - parseKeyTimes(attr->value(), m_keyTimes, true); - else if (attr->name() == SVGNames::keyPointsAttr && hasTagName(SVGNames::animateMotionTag)) { - // This is specified to be an animateMotion attribute only but it is simpler to put it here - // where the other timing calculatations are. - parseKeyTimes(attr->value(), m_keyPoints, false); - } else if (attr->name() == SVGNames::keySplinesAttr) - parseKeySplines(attr->value(), m_keySplines); - else { - if (SVGTests::parseMappedAttribute(attr)) - return; - if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) - return; - SVGSMILElement::parseMappedAttribute(attr); - } -} - -void SVGAnimationElement::attributeChanged(Attribute* attr, bool preserveDecls) -{ - // Assumptions may not hold after an attribute change. - m_animationValid = false; - SVGSMILElement::attributeChanged(attr, preserveDecls); -} - -float SVGAnimationElement::getStartTime() const -{ - return narrowPrecisionToFloat(intervalBegin().value()); -} - -float SVGAnimationElement::getCurrentTime() const -{ - return narrowPrecisionToFloat(elapsed().value()); -} - -float SVGAnimationElement::getSimpleDuration(ExceptionCode&) const -{ - return narrowPrecisionToFloat(simpleDuration().value()); -} - -bool SVGAnimationElement::beginElement(ExceptionCode& ec) -{ - return beginElementAt(0, ec); -} - -bool SVGAnimationElement::beginElementAt(float offset, ExceptionCode& ec) -{ - addBeginTime(elapsed() + offset); - return true; -} - -bool SVGAnimationElement::endElement(ExceptionCode& ec) -{ - return endElementAt(0, ec); -} - -bool SVGAnimationElement::endElementAt(float offset, ExceptionCode& ec) -{ - if (offset < 0) - return false; - - addEndTime(elapsed() + offset); - return true; -} - -SVGAnimationElement::AnimationMode SVGAnimationElement::animationMode() const -{ - // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues - if (hasTagName(SVGNames::setTag)) - return ToAnimation; - if (!animationPath().isEmpty()) - return PathAnimation; - if (hasAttribute(SVGNames::valuesAttr)) - return ValuesAnimation; - if (!toValue().isEmpty()) - return fromValue().isEmpty() ? ToAnimation : FromToAnimation; - if (!byValue().isEmpty()) - return fromValue().isEmpty() ? ByAnimation : FromByAnimation; - return NoAnimation; -} - -SVGAnimationElement::CalcMode SVGAnimationElement::calcMode() const -{ - static const AtomicString discrete("discrete"); - static const AtomicString linear("linear"); - static const AtomicString paced("paced"); - static const AtomicString spline("spline"); - const AtomicString& value = getAttribute(SVGNames::calcModeAttr); - if (value == discrete) - return CalcModeDiscrete; - if (value == linear) - return CalcModeLinear; - if (value == paced) - return CalcModePaced; - if (value == spline) - return CalcModeSpline; - return hasTagName(SVGNames::animateMotionTag) ? CalcModePaced : CalcModeLinear; -} - -SVGAnimationElement::AttributeType SVGAnimationElement::attributeType() const -{ - static const AtomicString css("CSS"); - static const AtomicString xml("XML"); - const AtomicString& value = getAttribute(SVGNames::attributeTypeAttr); - if (value == css) - return AttributeTypeCSS; - if (value == xml) - return AttributeTypeXML; - return AttributeTypeAuto; -} - -String SVGAnimationElement::toValue() const -{ - return getAttribute(SVGNames::toAttr); -} - -String SVGAnimationElement::byValue() const -{ - return getAttribute(SVGNames::byAttr); -} - -String SVGAnimationElement::fromValue() const -{ - return getAttribute(SVGNames::fromAttr); -} - -bool SVGAnimationElement::isAdditive() const -{ - static const AtomicString sum("sum"); - const AtomicString& value = getAttribute(SVGNames::additiveAttr); - return value == sum || animationMode() == ByAnimation; -} - -bool SVGAnimationElement::isAccumulated() const -{ - static const AtomicString sum("sum"); - const AtomicString& value = getAttribute(SVGNames::accumulateAttr); - return value == sum && animationMode() != ToAnimation; -} - -bool SVGAnimationElement::hasValidTarget() const -{ - return targetElement(); -} - -bool SVGAnimationElement::attributeIsCSS(const String& attributeName) -{ - // FIXME: We should have a map of all SVG properties and their attribute types so we - // could validate animations better. The spec is very vague about this. - unsigned id = cssPropertyID(attributeName); - // SVG range - if (id >= CSSPropertyClipPath && id <= CSSPropertyWritingMode) - return true; - // Regular CSS properties also in SVG - return id == CSSPropertyColor || id == CSSPropertyDisplay || id == CSSPropertyOpacity - || (id >= CSSPropertyFont && id <= CSSPropertyFontWeight) - || id == CSSPropertyOverflow || id == CSSPropertyVisibility; -} - -bool SVGAnimationElement::targetAttributeIsCSS() const -{ - AttributeType type = attributeType(); - if (type == AttributeTypeCSS) - return true; - if (type == AttributeTypeXML) - return false; - return attributeIsCSS(attributeName()); -} - -void SVGAnimationElement::setTargetAttributeAnimatedValue(const String& value) -{ - if (!hasValidTarget()) - return; - SVGElement* target = targetElement(); - String attributeName = this->attributeName(); - if (!target || attributeName.isEmpty() || value.isNull()) - return; - - // We don't want the instance tree to get rebuild. Instances are updated in the loop below. - if (target->isStyled()) - static_cast<SVGStyledElement*>(target)->setInstanceUpdatesBlocked(true); - - ExceptionCode ec; - bool isCSS = targetAttributeIsCSS(); - if (isCSS) { - // FIXME: This should set the override style, not the inline style. - // Sadly override styles are not yet implemented. - target->style()->setProperty(attributeName, value, "", ec); - } else { - // FIXME: This should set the 'presentation' value, not the actual - // attribute value. Whatever that means in practice. - target->setAttribute(attributeName, value, ec); - } - - if (target->isStyled()) - static_cast<SVGStyledElement*>(target)->setInstanceUpdatesBlocked(false); - - // If the target element is used in an <use> instance tree, update that as well. - HashSet<SVGElementInstance*> instances = target->instancesForElement(); - HashSet<SVGElementInstance*>::iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) { - SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); - ASSERT(shadowTreeElement); - if (isCSS) - shadowTreeElement->style()->setProperty(attributeName, value, "", ec); - else - shadowTreeElement->setAttribute(attributeName, value, ec); - (*it)->correspondingUseElement()->setChanged(); - } -} - -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); -} - -static inline double solveEpsilon(double duration) { return 1. / (200. * duration); } - -float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const -{ - ASSERT(calcMode() == CalcModeSpline); - ASSERT(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()))); -} - -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; -} - -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.0f ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1)); - from = m_values[index]; - to = m_values[index + 1]; -} - -void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to) const -{ - unsigned valuesCount = m_values.size(); - ASSERT(m_animationValid); - ASSERT(valuesCount > 1); - - CalcMode calcMode = this->calcMode(); - if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced) - return currentValuesFromKeyPoints(percent, effectivePercent, from, to); - - unsigned keyTimesCount = m_keyTimes.size(); - ASSERT(!keyTimesCount || valuesCount == keyTimesCount); - ASSERT(!keyTimesCount || (keyTimesCount > 1 && m_keyTimes[0] == 0)); - - unsigned index; - for (index = 1; index < keyTimesCount; ++index) { - if (m_keyTimes[index] >= percent) - break; - } - --index; - - if (calcMode == CalcModeDiscrete) { - if (!keyTimesCount) - index = percent == 1.0f ? valuesCount - 1 : static_cast<unsigned>(percent * valuesCount); - from = m_values[index]; - to = m_values[index]; - effectivePercent = 0.0f; - return; - } - - float fromPercent; - float toPercent; - if (keyTimesCount) { - fromPercent = m_keyTimes[index]; - toPercent = m_keyTimes[index + 1]; - } else { - index = static_cast<unsigned>(percent * (valuesCount - 1)); - fromPercent = static_cast<float>(index) / (valuesCount - 1); - toPercent = static_cast<float>(index + 1) / (valuesCount - 1); - } - - if (index == valuesCount - 1) - --index; - from = m_values[index]; - to = m_values[index + 1]; - ASSERT(toPercent > fromPercent); - effectivePercent = percent == 1.0f ? 1.0f : (percent - fromPercent) / (toPercent - fromPercent); - - if (calcMode == CalcModeSpline) { - ASSERT(m_keySplines.size() == m_values.size() - 1); - effectivePercent = calculatePercentForSpline(effectivePercent, index); - } -} - -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()); -} - -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::endedActiveInterval() -{ -} - -} - -// vim:ts=4:noet -#endif // ENABLE(SVG_ANIMATION) - |