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#pragma once
27
28#include "SMILTime.h"
29#include "SVGElement.h"
30#include <wtf/HashSet.h>
31
32namespace WebCore {
33
34class ConditionEventListener;
35class SMILTimeContainer;
36class SVGSMILElement;
37
38template<typename T> class EventSender;
39
40using SMILEventSender = EventSender<SVGSMILElement>;
41
42// This class implements SMIL interval timing model as needed for SVG animation.
43class SVGSMILElement : public SVGElement {
44 WTF_MAKE_ISO_ALLOCATED(SVGSMILElement);
45public:
46 SVGSMILElement(const QualifiedName&, Document&);
47 virtual ~SVGSMILElement();
48
49 void parseAttribute(const QualifiedName&, const AtomicString&) override;
50 void svgAttributeChanged(const QualifiedName&) override;
51 InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override;
52 void removedFromAncestor(RemovalType, ContainerNode&) override;
53
54 virtual bool hasValidAttributeType() const = 0;
55 virtual bool hasValidAttributeName() const;
56 virtual void animationAttributeChanged() = 0;
57
58 SMILTimeContainer* timeContainer() { return m_timeContainer.get(); }
59
60 SVGElement* targetElement() const { return m_targetElement; }
61 const QualifiedName& attributeName() const { return m_attributeName; }
62
63 void beginByLinkActivation();
64
65 enum Restart { RestartAlways, RestartWhenNotActive, RestartNever };
66 Restart restart() const;
67
68 enum FillMode { FillRemove, FillFreeze };
69 FillMode fill() const;
70
71 SMILTime dur() const;
72 SMILTime repeatDur() const;
73 SMILTime repeatCount() const;
74 SMILTime maxValue() const;
75 SMILTime minValue() const;
76
77 SMILTime elapsed() const;
78
79 SMILTime intervalBegin() const { return m_intervalBegin; }
80 SMILTime intervalEnd() const { return m_intervalEnd; }
81 SMILTime previousIntervalBegin() const { return m_previousIntervalBegin; }
82 SMILTime simpleDuration() const;
83
84 void seekToIntervalCorrespondingToTime(SMILTime elapsed);
85 bool progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime);
86 SMILTime nextProgressTime() const;
87
88 void reset();
89
90 static SMILTime parseClockValue(const String&);
91 static SMILTime parseOffsetValue(const String&);
92
93 bool isContributing(SMILTime elapsed) const;
94 bool isInactive() const;
95 bool isFrozen() const;
96
97 unsigned documentOrderIndex() const { return m_documentOrderIndex; }
98 void setDocumentOrderIndex(unsigned index) { m_documentOrderIndex = index; }
99
100 virtual bool isAdditive() const = 0;
101 virtual void resetAnimatedType() = 0;
102 virtual void clearAnimatedType(SVGElement* targetElement) = 0;
103 virtual void applyResultsToTarget() = 0;
104
105 void connectConditions();
106 bool hasConditionsConnected() const { return m_conditionsConnected; }
107
108 void dispatchPendingEvent(SMILEventSender*);
109
110protected:
111 void addBeginTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
112 void addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
113
114 void setInactive() { m_activeState = Inactive; }
115
116 bool rendererIsNeeded(const RenderStyle&) override { return false; }
117
118 // Sub-classes may need to take action when the target is changed.
119 virtual void setTargetElement(SVGElement*);
120 virtual void setAttributeName(const QualifiedName&);
121
122 void didFinishInsertingNode() override;
123
124private:
125 void buildPendingResource() override;
126 void clearResourceReferences();
127
128 void clearTarget() override;
129
130 virtual void startedActiveInterval() = 0;
131 void endedActiveInterval();
132 virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) = 0;
133
134 static bool isSupportedAttribute(const QualifiedName&);
135 QualifiedName constructAttributeName() const;
136 void updateAttributeName();
137
138 enum BeginOrEnd { Begin, End };
139 SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const;
140 void resolveFirstInterval();
141 void resolveNextInterval(bool notifyDependents);
142 void resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const;
143 SMILTime resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const;
144 SMILTime repeatingDuration() const;
145 void checkRestart(SMILTime elapsed);
146 void beginListChanged(SMILTime eventTime);
147 void endListChanged(SMILTime eventTime);
148
149 // This represents conditions on elements begin or end list that need to be resolved on runtime
150 // for example <animate begin="otherElement.begin + 8s; button.click" ... />
151 struct Condition {
152 enum Type { EventBase, Syncbase, AccessKey };
153 Condition(Type, BeginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeats = -1);
154 Type m_type;
155 BeginOrEnd m_beginOrEnd;
156 String m_baseID;
157 String m_name;
158 SMILTime m_offset;
159 int m_repeats { -1 };
160 RefPtr<Element> m_syncbase;
161 RefPtr<ConditionEventListener> m_eventListener;
162 };
163 bool parseCondition(const String&, BeginOrEnd beginOrEnd);
164 void parseBeginOrEnd(const String&, BeginOrEnd beginOrEnd);
165 Element* eventBaseFor(const Condition&);
166
167 void disconnectConditions();
168
169 // Event base timing
170 void handleConditionEvent(Condition*);
171
172 // Syncbase timing
173 enum NewOrExistingInterval { NewInterval, ExistingInterval };
174 void notifyDependentsIntervalChanged(NewOrExistingInterval);
175 void createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval);
176 void addTimeDependent(SVGSMILElement*);
177 void removeTimeDependent(SVGSMILElement*);
178
179 enum ActiveState { Inactive, Active, Frozen };
180 ActiveState determineActiveState(SMILTime elapsed) const;
181 float calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const;
182 SMILTime calculateNextProgressTime(SMILTime elapsed) const;
183
184 bool isSMILElement() const final { return true; }
185
186 QualifiedName m_attributeName;
187
188 SVGElement* m_targetElement;
189
190 Vector<Condition> m_conditions;
191 bool m_conditionsConnected;
192 bool m_hasEndEventConditions;
193
194 bool m_isWaitingForFirstInterval;
195
196 HashSet<SVGSMILElement*> m_timeDependents;
197
198 // Instance time lists
199 Vector<SMILTimeWithOrigin> m_beginTimes;
200 Vector<SMILTimeWithOrigin> m_endTimes;
201
202 // This is the upcoming or current interval
203 SMILTime m_intervalBegin;
204 SMILTime m_intervalEnd;
205
206 SMILTime m_previousIntervalBegin;
207
208 ActiveState m_activeState;
209 float m_lastPercent;
210 unsigned m_lastRepeat;
211
212 SMILTime m_nextProgressTime;
213
214 RefPtr<SMILTimeContainer> m_timeContainer;
215 unsigned m_documentOrderIndex;
216
217 mutable SMILTime m_cachedDur;
218 mutable SMILTime m_cachedRepeatDur;
219 mutable SMILTime m_cachedRepeatCount;
220 mutable SMILTime m_cachedMin;
221 mutable SMILTime m_cachedMax;
222
223 friend class ConditionEventListener;
224};
225
226} // namespace WebCore
227
228SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::SVGSMILElement)
229 static bool isType(const WebCore::SVGElement& element) { return element.isSMILElement(); }
230 static bool isType(const WebCore::Node& node) { return is<WebCore::SVGElement>(node) && isType(downcast<WebCore::SVGElement>(node)); }
231SPECIALIZE_TYPE_TRAITS_END()
232