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 | |
32 | namespace WebCore { |
33 | |
34 | class ConditionEventListener; |
35 | class SMILTimeContainer; |
36 | class SVGSMILElement; |
37 | |
38 | template<typename T> class EventSender; |
39 | |
40 | using SMILEventSender = EventSender<SVGSMILElement>; |
41 | |
42 | // This class implements SMIL interval timing model as needed for SVG animation. |
43 | class SVGSMILElement : public SVGElement { |
44 | WTF_MAKE_ISO_ALLOCATED(SVGSMILElement); |
45 | public: |
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 | |
110 | protected: |
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 | |
124 | private: |
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 | |
228 | SPECIALIZE_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)); } |
231 | SPECIALIZE_TYPE_TRAITS_END() |
232 | |