1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef SVGSMILElement_h
27#define SVGSMILElement_h
28
29#include "SMILTime.h"
30#include "SVGElement.h"
31
32#include <wtf/HashMap.h>
33
34namespace WebCore {
35
36class ConditionEventListener;
37class SMILTimeContainer;
38
39// This class implements SMIL interval timing model as needed for SVG animation.
40class SVGSMILElement : public SVGElement {
41public:
42    SVGSMILElement(const QualifiedName&, Document&);
43    virtual ~SVGSMILElement();
44
45    bool isSupportedAttribute(const QualifiedName&);
46    virtual void parseAttribute(const QualifiedName&, const AtomicString&) override;
47    virtual void svgAttributeChanged(const QualifiedName&) override;
48    virtual InsertionNotificationRequest insertedInto(ContainerNode&) override;
49    virtual void removedFrom(ContainerNode&) override;
50
51    virtual bool hasValidAttributeType() = 0;
52    virtual bool hasValidAttributeName();
53    virtual void animationAttributeChanged() = 0;
54
55    SMILTimeContainer* timeContainer() { return m_timeContainer.get(); }
56
57    SVGElement* targetElement() const { return m_targetElement; }
58    const QualifiedName& attributeName() const { return m_attributeName; }
59
60    void beginByLinkActivation();
61
62    enum Restart {
63        RestartAlways,
64        RestartWhenNotActive,
65        RestartNever
66    };
67
68    Restart restart() const;
69
70    enum FillMode {
71        FillRemove,
72        FillFreeze
73    };
74
75    FillMode fill() const;
76
77    SMILTime dur() const;
78    SMILTime repeatDur() const;
79    SMILTime repeatCount() const;
80    SMILTime maxValue() const;
81    SMILTime minValue() const;
82
83    SMILTime elapsed() const;
84
85    SMILTime intervalBegin() const { return m_intervalBegin; }
86    SMILTime intervalEnd() const { return m_intervalEnd; }
87    SMILTime previousIntervalBegin() const { return m_previousIntervalBegin; }
88    SMILTime simpleDuration() const;
89
90    void seekToIntervalCorrespondingToTime(SMILTime elapsed);
91    bool progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime);
92    SMILTime nextProgressTime() const;
93
94    void reset();
95
96    static SMILTime parseClockValue(const String&);
97    static SMILTime parseOffsetValue(const String&);
98
99    bool isContributing(SMILTime elapsed) const;
100    bool isInactive() const;
101    bool isFrozen() const;
102
103    unsigned documentOrderIndex() const { return m_documentOrderIndex; }
104    void setDocumentOrderIndex(unsigned index) { m_documentOrderIndex = index; }
105
106    virtual bool isAdditive() const = 0;
107    virtual void resetAnimatedType() = 0;
108    virtual void clearAnimatedType(SVGElement* targetElement) = 0;
109    virtual void applyResultsToTarget() = 0;
110
111protected:
112    void addBeginTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
113    void addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
114
115    void setInactive() { m_activeState = Inactive; }
116
117    virtual bool rendererIsNeeded(const RenderStyle&) override { return false; }
118
119    // Sub-classes may need to take action when the target is changed.
120    virtual void setTargetElement(SVGElement*);
121    virtual void setAttributeName(const QualifiedName&);
122
123    virtual void didNotifySubtreeInsertions(ContainerNode*) override;
124
125private:
126    void buildPendingResource() override;
127    void clearResourceReferences();
128
129    virtual void clearTarget() override;
130
131    virtual void startedActiveInterval() = 0;
132    void endedActiveInterval();
133    virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) = 0;
134
135    enum BeginOrEnd { Begin, End };
136
137    SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const;
138    void resolveFirstInterval();
139    void resolveNextInterval(bool notifyDependents);
140    void resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const;
141    SMILTime resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const;
142    SMILTime repeatingDuration() const;
143    void checkRestart(SMILTime elapsed);
144    void beginListChanged(SMILTime eventTime);
145    void endListChanged(SMILTime eventTime);
146
147    // This represents conditions on elements begin or end list that need to be resolved on runtime
148    // for example <animate begin="otherElement.begin + 8s; button.click" ... />
149    struct Condition {
150        enum Type {
151            EventBase,
152            Syncbase,
153            AccessKey
154        };
155
156        Condition(Type, BeginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeats = -1);
157        Type m_type;
158        BeginOrEnd m_beginOrEnd;
159        String m_baseID;
160        String m_name;
161        SMILTime m_offset;
162        int m_repeats;
163        RefPtr<Element> m_syncbase;
164        RefPtr<ConditionEventListener> m_eventListener;
165    };
166    bool parseCondition(const String&, BeginOrEnd beginOrEnd);
167    void parseBeginOrEnd(const String&, BeginOrEnd beginOrEnd);
168    Element* eventBaseFor(const Condition&);
169
170    void connectConditions();
171    void disconnectConditions();
172
173    // Event base timing
174    void handleConditionEvent(Event*, Condition*);
175
176    // Syncbase timing
177    enum NewOrExistingInterval {
178        NewInterval,
179        ExistingInterval
180    };
181
182    void notifyDependentsIntervalChanged(NewOrExistingInterval);
183    void createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval);
184    void addTimeDependent(SVGSMILElement*);
185    void removeTimeDependent(SVGSMILElement*);
186
187    enum ActiveState {
188        Inactive,
189        Active,
190        Frozen
191    };
192
193    QualifiedName m_attributeName;
194
195    ActiveState determineActiveState(SMILTime elapsed) const;
196    float calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const;
197    SMILTime calculateNextProgressTime(SMILTime elapsed) const;
198
199    virtual bool isSMILElement() const override final { return true; }
200
201    SVGElement* m_targetElement;
202
203    Vector<Condition> m_conditions;
204    bool m_conditionsConnected;
205    bool m_hasEndEventConditions;
206
207    bool m_isWaitingForFirstInterval;
208
209    typedef HashSet<SVGSMILElement*> TimeDependentSet;
210    TimeDependentSet m_timeDependents;
211
212    // Instance time lists
213    Vector<SMILTimeWithOrigin> m_beginTimes;
214    Vector<SMILTimeWithOrigin> m_endTimes;
215
216    // This is the upcoming or current interval
217    SMILTime m_intervalBegin;
218    SMILTime m_intervalEnd;
219
220    SMILTime m_previousIntervalBegin;
221
222    ActiveState m_activeState;
223    float m_lastPercent;
224    unsigned m_lastRepeat;
225
226    SMILTime m_nextProgressTime;
227
228    RefPtr<SMILTimeContainer> m_timeContainer;
229    unsigned m_documentOrderIndex;
230
231    mutable SMILTime m_cachedDur;
232    mutable SMILTime m_cachedRepeatDur;
233    mutable SMILTime m_cachedRepeatCount;
234    mutable SMILTime m_cachedMin;
235    mutable SMILTime m_cachedMax;
236
237    friend class ConditionEventListener;
238};
239
240void isSVGSMILElement(const SVGSMILElement&); // Catch unnecessary runtime check of type known at compile time.
241inline bool isSVGSMILElement(const SVGElement& element) { return element.isSMILElement(); }
242inline bool isSVGSMILElement(const Node& node) { return node.isSVGElement() && toSVGElement(node).isSMILElement(); }
243template <> inline bool isElementOfType<const SVGSMILElement>(const Element& element) { return isSVGSMILElement(element); }
244
245NODE_TYPE_CASTS(SVGSMILElement)
246
247}
248
249#endif // SVGSMILElement_h
250