18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2008 Apple Inc. All rights reserved.
6dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
7dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) Research In Motion Limited 2010. All rights reserved.
8dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
9dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * This library is free software; you can redistribute it and/or
10dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * modify it under the terms of the GNU Library General Public
11dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * License as published by the Free Software Foundation; either
12dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * version 2 of the License, or (at your option) any later version.
13dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
14dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * This library is distributed in the hope that it will be useful,
15dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
16dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Library General Public License for more details.
18dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
19dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * You should have received a copy of the GNU Library General Public License
20dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * along with this library; see the file COPYING.LIB.  If not, write to
21dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Boston, MA 02110-1301, USA.
23dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch */
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if ENABLE(SVG_ANIMATION)
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGAnimationElement.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
30e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "Attribute.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CSSComputedStyleDeclaration.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CSSParser.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CSSPropertyNames.h"
34e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "Color.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Event.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EventListener.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FloatConversion.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "PlatformString.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGElementInstance.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGNames.h"
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGParserUtilities.h"
4481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "SVGStyledElement.h"
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGURIReference.h"
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGUseElement.h"
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "XLinkNames.h"
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/StdLibExtras.h>
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
53f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
54f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch// Animated property definitions
55f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochDEFINE_ANIMATED_BOOLEAN(SVGAnimationElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
56f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
575ddde30071f639962dd557c453f2ad01f8f0fd00Kristian MonsenSVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, Document* document)
585ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    : SVGSMILElement(tagName, document)
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_animationValid(false)
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void parseKeyTimes(const String& parse, Vector<float>& result, bool verifyOrder)
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.clear();
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<String> parseList;
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse.split(';', parseList);
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (unsigned n = 0; n < parseList.size(); ++n) {
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        String timeString = parseList[n];
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool ok;
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float time = timeString.toFloat(&ok);
7281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (!ok || time < 0 || time > 1)
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            goto fail;
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (verifyOrder) {
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!n) {
76f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                if (time)
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    goto fail;
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else if (time < result.last())
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                goto fail;
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(time);
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return;
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfail:
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.clear();
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void parseKeySplines(const String& parse, Vector<UnitBezier>& result)
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.clear();
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (parse.isEmpty())
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const UChar* cur = parse.characters();
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const UChar* end = cur + parse.length();
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    skipOptionalSpaces(cur, end);
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool delimParsed = false;
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    while (cur < end) {
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        delimParsed = false;
10181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        float posA = 0;
102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!parseNumber(cur, end, posA)) {
103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            result.clear();
104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
10781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        float posB = 0;
108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!parseNumber(cur, end, posB)) {
109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            result.clear();
110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
11381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        float posC = 0;
114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!parseNumber(cur, end, posC)) {
115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            result.clear();
116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
11981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        float posD = 0;
120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!parseNumber(cur, end, posD, false)) {
121dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            result.clear();
122dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        skipOptionalSpaces(cur, end);
126dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (cur < end && *cur == ';') {
128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            delimParsed = true;
129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            cur++;
130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        skipOptionalSpaces(cur, end);
132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        result.append(UnitBezier(posA, posB, posC, posD));
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!(cur == end && !delimParsed))
136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        result.clear();
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
139e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockvoid SVGAnimationElement::parseMappedAttribute(Attribute* attr)
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (attr->name() == SVGNames::valuesAttr)
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        attr->value().string().split(';', m_values);
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (attr->name() == SVGNames::keyTimesAttr)
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parseKeyTimes(attr->value(), m_keyTimes, true);
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (attr->name() == SVGNames::keyPointsAttr && hasTagName(SVGNames::animateMotionTag)) {
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This is specified to be an animateMotion attribute only but it is simpler to put it here
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // where the other timing calculatations are.
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parseKeyTimes(attr->value(), m_keyPoints, false);
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (attr->name() == SVGNames::keySplinesAttr)
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parseKeySplines(attr->value(), m_keySplines);
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (SVGTests::parseMappedAttribute(attr))
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        SVGSMILElement::parseMappedAttribute(attr);
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::attributeChanged(Attribute* attr, bool preserveDecls)
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Assumptions may not hold after an attribute change.
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_animationValid = false;
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SVGSMILElement::attributeChanged(attr, preserveDecls);
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
167d0825bca7fe65beaee391d30da42e937db621564Steve Blockvoid SVGAnimationElement::synchronizeProperty(const QualifiedName& attrName)
168d0825bca7fe65beaee391d30da42e937db621564Steve Block{
169d0825bca7fe65beaee391d30da42e937db621564Steve Block    SVGSMILElement::synchronizeProperty(attrName);
170d0825bca7fe65beaee391d30da42e937db621564Steve Block
1714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    if (attrName == anyQName()) {
172d0825bca7fe65beaee391d30da42e937db621564Steve Block        synchronizeExternalResourcesRequired();
1734576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        SVGTests::synchronizeProperties(this, attrName);
1744576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return;
1754576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    }
1764576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
1774576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
1784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        synchronizeExternalResourcesRequired();
1794576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    else if (SVGTests::isKnownAttribute(attrName))
1804576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        SVGTests::synchronizeProperties(this, attrName);
181d0825bca7fe65beaee391d30da42e937db621564Steve Block}
182d0825bca7fe65beaee391d30da42e937db621564Steve Block
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfloat SVGAnimationElement::getStartTime() const
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return narrowPrecisionToFloat(intervalBegin().value());
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfloat SVGAnimationElement::getCurrentTime() const
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return narrowPrecisionToFloat(elapsed().value());
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfloat SVGAnimationElement::getSimpleDuration(ExceptionCode&) const
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return narrowPrecisionToFloat(simpleDuration().value());
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
198231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid SVGAnimationElement::beginElement()
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
200231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    beginElementAt(0);
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
203231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid SVGAnimationElement::beginElementAt(float offset)
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    addBeginTime(elapsed() + offset);
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
208231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid SVGAnimationElement::endElement()
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
210231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    endElementAt(0);
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
213231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid SVGAnimationElement::endElementAt(float offset)
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    addEndTime(elapsed() + offset);
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSVGAnimationElement::AnimationMode SVGAnimationElement::animationMode() const
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hasTagName(SVGNames::setTag))
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return ToAnimation;
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!animationPath().isEmpty())
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return PathAnimation;
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hasAttribute(SVGNames::valuesAttr))
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return ValuesAnimation;
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!toValue().isEmpty())
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return fromValue().isEmpty() ? ToAnimation : FromToAnimation;
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!byValue().isEmpty())
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return fromValue().isEmpty() ? ByAnimation : FromByAnimation;
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return NoAnimation;
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSVGAnimationElement::CalcMode SVGAnimationElement::calcMode() const
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, discrete, ("discrete"));
237635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, linear, ("linear"));
238635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, paced, ("paced"));
239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, spline, ("spline"));
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const AtomicString& value = getAttribute(SVGNames::calcModeAttr);
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == discrete)
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return CalcModeDiscrete;
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == linear)
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return CalcModeLinear;
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == paced)
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return CalcModePaced;
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == spline)
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return CalcModeSpline;
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hasTagName(SVGNames::animateMotionTag) ? CalcModePaced : CalcModeLinear;
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSVGAnimationElement::AttributeType SVGAnimationElement::attributeType() const
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, css, ("CSS"));
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, xml, ("XML"));
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const AtomicString& value = getAttribute(SVGNames::attributeTypeAttr);
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == css)
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return AttributeTypeCSS;
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (value == xml)
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return AttributeTypeXML;
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return AttributeTypeAuto;
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString SVGAnimationElement::toValue() const
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return getAttribute(SVGNames::toAttr);
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString SVGAnimationElement::byValue() const
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return getAttribute(SVGNames::byAttr);
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString SVGAnimationElement::fromValue() const
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return getAttribute(SVGNames::fromAttr);
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool SVGAnimationElement::isAdditive() const
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum"));
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const AtomicString& value = getAttribute(SVGNames::additiveAttr);
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return value == sum || animationMode() == ByAnimation;
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool SVGAnimationElement::isAccumulated() const
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum"));
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const AtomicString& value = getAttribute(SVGNames::accumulateAttr);
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return value == sum && animationMode() != ToAnimation;
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
29381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* targetElement, const QualifiedName& attributeName)
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
29581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    ASSERT(targetElement);
29681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!targetElement->isStyled())
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
29881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
29981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return SVGStyledElement::isAnimatableCSSProperty(attributeName);
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::setTargetAttributeAnimatedValue(const String& value)
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
30481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!hasValidAttributeType())
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
30681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    SVGElement* targetElement = this->targetElement();
30781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    QualifiedName attributeName = this->attributeName();
30881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!targetElement || attributeName == anyQName() || value.isNull())
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We don't want the instance tree to get rebuild. Instances are updated in the loop below.
31281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (targetElement->isStyled())
31381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        static_cast<SVGStyledElement*>(targetElement)->setInstanceUpdatesBlocked(true);
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
31581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    bool attributeIsCSSProperty = isTargetAttributeCSSProperty(targetElement, attributeName);
31681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Stop animation, if attributeType is set to CSS by the user, but the attribute itself is not a CSS property.
31781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!attributeIsCSSProperty && attributeType() == AttributeTypeCSS)
31881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return;
31981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ExceptionCode ec;
32181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (attributeIsCSSProperty) {
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: This should set the override style, not the inline style.
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Sadly override styles are not yet implemented.
32481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        targetElement->style()->setProperty(attributeName.localName(), value, "", ec);
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: This should set the 'presentation' value, not the actual
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // attribute value. Whatever that means in practice.
32881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        targetElement->setAttribute(attributeName, value, ec);
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
33181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (targetElement->isStyled())
33281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        static_cast<SVGStyledElement*>(targetElement)->setInstanceUpdatesBlocked(false);
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If the target element is used in an <use> instance tree, update that as well.
33581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
336d0825bca7fe65beaee391d30da42e937db621564Steve Block    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
337d0825bca7fe65beaee391d30da42e937db621564Steve Block    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
339cad810f21b803229eb11403f9209855525a25d57Steve Block        if (!shadowTreeElement)
340cad810f21b803229eb11403f9209855525a25d57Steve Block            continue;
34181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (attributeIsCSSProperty)
34281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            shadowTreeElement->style()->setProperty(attributeName.localName(), value, "", ec);
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            shadowTreeElement->setAttribute(attributeName, value, ec);
3455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        (*it)->correspondingUseElement()->setNeedsStyleRecalc();
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::calculateKeyTimesForCalcModePaced()
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(calcMode() == CalcModePaced);
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(animationMode() == ValuesAnimation);
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned valuesCount = m_values.size();
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(valuesCount > 1);
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<float> keyTimesForPaced;
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float totalDistance = 0;
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    keyTimesForPaced.append(0);
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (unsigned n = 0; n < valuesCount - 1; ++n) {
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Distance in any units
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float distance = calculateDistance(m_values[n], m_values[n + 1]);
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (distance < 0)
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        totalDistance += distance;
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keyTimesForPaced.append(distance);
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!totalDistance)
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Normalize.
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (unsigned n = 1; n < keyTimesForPaced.size() - 1; ++n)
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance;
37381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    keyTimesForPaced[keyTimesForPaced.size() - 1] = 1;
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Use key times calculated based on pacing instead of the user provided ones.
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_keyTimes.swap(keyTimesForPaced);
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
37981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic inline double solveEpsilon(double duration) { return 1 / (200 * duration); }
3806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
3816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerunsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const
3826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner{
3836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    unsigned index;
3846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    unsigned keyTimesCount = m_keyTimes.size();
3856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    for (index = 1; index < keyTimesCount; ++index) {
3866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if (m_keyTimes[index] >= percent)
3876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            break;
3886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    }
3896b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    return --index;
3906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner}
3916b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfloat SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(calcMode() == CalcModeSpline);
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(splineIndex < m_keySplines.size());
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UnitBezier bezier = m_keySplines[splineIndex];
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SMILTime duration = simpleDuration();
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!duration.isFinite())
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        duration = 100.0;
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return narrowPrecisionToFloat(bezier.solve(percent, solveEpsilon(duration.value())));
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectfloat SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_keyPoints.isEmpty());
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(calcMode() != CalcModePaced);
4076b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    ASSERT(m_keyTimes.size() > 1);
4086b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    ASSERT(m_keyPoints.size() == m_keyTimes.size());
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4106b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    unsigned index = calculateKeyTimesIndex(percent);
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float fromPercent = m_keyTimes[index];
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float toPercent = m_keyTimes[index + 1];
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float fromKeyPoint = m_keyPoints[index];
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float toKeyPoint = m_keyPoints[index + 1];
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (calcMode() == CalcModeDiscrete)
41781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return percent == 1 ? toKeyPoint : fromKeyPoint;
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
41981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    float keyPointPercent = percent == 1 ? 1 : (percent - fromPercent) / (toPercent - fromPercent);
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (calcMode() == CalcModeSpline) {
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(m_keySplines.size() == m_keyPoints.size() - 1);
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keyPointPercent = calculatePercentForSpline(keyPointPercent, index);
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (toKeyPoint - fromKeyPoint) * keyPointPercent + fromKeyPoint;
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const
4298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_keyPoints.isEmpty());
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_keyPoints.size() == m_keyTimes.size());
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(calcMode() != CalcModePaced);
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    effectivePercent = calculatePercentFromKeyPoints(percent);
43481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1));
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    from = m_values[index];
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    to = m_values[index + 1];
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to) const
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned valuesCount = m_values.size();
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_animationValid);
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(valuesCount > 1);
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CalcMode calcMode = this->calcMode();
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced)
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return currentValuesFromKeyPoints(percent, effectivePercent, from, to);
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned keyTimesCount = m_keyTimes.size();
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!keyTimesCount || valuesCount == keyTimesCount);
451f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    ASSERT(!keyTimesCount || (keyTimesCount > 1 && !m_keyTimes[0]));
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4536b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    unsigned index = calculateKeyTimesIndex(percent);
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (calcMode == CalcModeDiscrete) {
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!keyTimesCount)
45681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            index = percent == 1 ? valuesCount - 1 : static_cast<unsigned>(percent * valuesCount);
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        from = m_values[index];
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        to = m_values[index];
45981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        effectivePercent = 0;
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float fromPercent;
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float toPercent;
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (keyTimesCount) {
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fromPercent = m_keyTimes[index];
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        toPercent = m_keyTimes[index + 1];
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        index = static_cast<unsigned>(percent * (valuesCount - 1));
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fromPercent =  static_cast<float>(index) / (valuesCount - 1);
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        toPercent =  static_cast<float>(index + 1) / (valuesCount - 1);
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (index == valuesCount - 1)
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        --index;
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    from = m_values[index];
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    to = m_values[index + 1];
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(toPercent > fromPercent);
47981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    effectivePercent = percent == 1 ? 1 : (percent - fromPercent) / (toPercent - fromPercent);
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (calcMode == CalcModeSpline) {
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(m_keySplines.size() == m_values.size() - 1);
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        effectivePercent = calculatePercentForSpline(effectivePercent, index);
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::startedActiveInterval()
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_animationValid = false;
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
49181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!hasValidAttributeType())
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
494dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // These validations are appropriate for all animation modes.
495dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (hasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size())
496dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
497dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4986b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    AnimationMode animationMode = this->animationMode();
499dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    CalcMode calcMode = this->calcMode();
500dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (calcMode == CalcModeSpline) {
5016b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        unsigned splinesCount = m_keySplines.size() + 1;
5026b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if ((hasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != splinesCount)
5036b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            || (animationMode == ValuesAnimation && m_values.size() != splinesCount))
504dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
505dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
506dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
507dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    String from = fromValue();
508dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    String to = toValue();
509dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    String by = byValue();
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (animationMode == NoAnimation)
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (animationMode == FromToAnimation)
513dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_animationValid = calculateFromAndToValues(from, to);
5142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    else if (animationMode == ToAnimation) {
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // For to-animations the from value is the current accumulated value from lower priority animations.
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The value is not static and is determined during the animation.
517dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_animationValid = calculateFromAndToValues(String(), to);
5182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    } else if (animationMode == FromByAnimation)
519dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_animationValid = calculateFromAndByValues(from, by);
5202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    else if (animationMode == ByAnimation)
521dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_animationValid = calculateFromAndByValues(String(), by);
5222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    else if (animationMode == ValuesAnimation) {
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_animationValid = m_values.size() > 1
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            && (calcMode == CalcModePaced || !hasAttribute(SVGNames::keyTimesAttr) || hasAttribute(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size()))
5252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            && (calcMode == CalcModeDiscrete || !m_keyTimes.size() || m_keyTimes.last() == 1)
526643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            && (calcMode != CalcModeSpline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1))
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            && (!hasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()));
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (calcMode == CalcModePaced && m_animationValid)
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            calculateKeyTimesForCalcModePaced();
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (animationMode == PathAnimation)
531dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_animationValid = calcMode == CalcModePaced || !hasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size());
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement)
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_animationValid)
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float effectivePercent;
5406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    CalcMode mode = calcMode();
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (animationMode() == ValuesAnimation) {
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        String from;
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        String to;
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        currentValuesForValuesAnimation(percent, effectivePercent, from, to);
545f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (from != m_lastValuesAnimationFrom || to != m_lastValuesAnimationTo) {
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_animationValid = calculateFromAndToValues(from, to);
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!m_animationValid)
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_lastValuesAnimationFrom = from;
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_lastValuesAnimationTo = to;
5518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5526b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    } else if (!m_keyPoints.isEmpty() && mode != CalcModePaced)
5538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        effectivePercent = calculatePercentFromKeyPoints(percent);
5546b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    else if (m_keyPoints.isEmpty() && mode == CalcModeSpline && m_keyTimes.size() > 1)
5556b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        effectivePercent = calculatePercentForSpline(percent, calculateKeyTimesIndex(percent));
5566b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    else
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        effectivePercent = percent;
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    calculateAnimatedValue(effectivePercent, repeat, resultElement);
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SVGAnimationElement::endedActiveInterval()
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif // ENABLE(SVG_ANIMATION)
5688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
569