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 "core/SVGNames.h" 30 #include "core/svg/SVGElement.h" 31 #include "core/svg/SVGTests.h" 32 #include "core/svg/animation/SMILTime.h" 33 #include "platform/heap/Heap.h" 34 #include "wtf/HashMap.h" 35 36 namespace blink { 37 38 class ConditionEventListener; 39 class SMILTimeContainer; 40 class SVGSMILElement; 41 42 template<typename T> class EventSender; 43 typedef EventSender<SVGSMILElement> SMILEventSender; 44 45 // This class implements SMIL interval timing model as needed for SVG animation. 46 class SVGSMILElement : public SVGElement, public SVGTests { 47 public: 48 SVGSMILElement(const QualifiedName&, Document&); 49 virtual ~SVGSMILElement(); 50 51 bool isSupportedAttribute(const QualifiedName&); 52 virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE; 53 virtual void svgAttributeChanged(const QualifiedName&) OVERRIDE; 54 virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE; 55 virtual void removedFrom(ContainerNode*) OVERRIDE; 56 57 virtual bool hasValidAttributeType() = 0; 58 virtual bool hasValidAttributeName(); 59 virtual void animationAttributeChanged() = 0; 60 61 SMILTimeContainer* timeContainer() const { return m_timeContainer.get(); } 62 63 SVGElement* targetElement() const { return m_targetElement; } 64 const QualifiedName& attributeName() const { return m_attributeName; } 65 66 void beginByLinkActivation(); 67 68 enum Restart { 69 RestartAlways, 70 RestartWhenNotActive, 71 RestartNever 72 }; 73 74 Restart restart() const; 75 76 enum FillMode { 77 FillRemove, 78 FillFreeze 79 }; 80 81 FillMode fill() const; 82 83 SMILTime dur() const; 84 SMILTime repeatDur() const; 85 SMILTime repeatCount() const; 86 SMILTime maxValue() const; 87 SMILTime minValue() const; 88 89 SMILTime elapsed() const; 90 91 SMILTime intervalBegin() const { return m_interval.begin; } 92 SMILTime previousIntervalBegin() const { return m_previousIntervalBegin; } 93 SMILTime simpleDuration() const; 94 95 void seekToIntervalCorrespondingToTime(SMILTime elapsed); 96 bool progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime); 97 SMILTime nextProgressTime() const; 98 99 void reset(); 100 101 static SMILTime parseClockValue(const String&); 102 static SMILTime parseOffsetValue(const String&); 103 104 bool isContributing(SMILTime elapsed) const; 105 bool isFrozen() const; 106 107 unsigned documentOrderIndex() const { return m_documentOrderIndex; } 108 void setDocumentOrderIndex(unsigned index) { m_documentOrderIndex = index; } 109 110 virtual void resetAnimatedType() = 0; 111 virtual void clearAnimatedType(SVGElement* targetElement) = 0; 112 virtual void applyResultsToTarget() = 0; 113 114 void connectSyncBaseConditions(); 115 void connectEventBaseConditions(); 116 117 void dispatchPendingEvent(SMILEventSender*); 118 void dispatchRepeatEvents(unsigned); 119 120 virtual bool isSVGDiscardElement() const { return false; } 121 122 void trace(Visitor*) OVERRIDE; 123 124 protected: 125 void addBeginTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin); 126 void addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin); 127 128 void setInactive() { m_activeState = Inactive; } 129 130 // Sub-classes may need to take action when the target is changed. 131 virtual void setTargetElement(SVGElement*); 132 virtual void setAttributeName(const QualifiedName&); 133 134 private: 135 virtual void buildPendingResource() OVERRIDE; 136 void clearResourceAndEventBaseReferences(); 137 void clearConditions(); 138 139 virtual void startedActiveInterval() = 0; 140 void endedActiveInterval(); 141 virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) = 0; 142 143 virtual bool rendererIsNeeded(const RenderStyle&) OVERRIDE { return false; } 144 145 enum BeginOrEnd { 146 Begin, 147 End 148 }; 149 150 SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const; 151 152 enum ResolveInterval { 153 FirstInterval, 154 NextInterval 155 }; 156 157 SMILInterval resolveInterval(ResolveInterval) const; 158 void resolveFirstInterval(); 159 bool resolveNextInterval(); 160 SMILTime resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const; 161 SMILTime repeatingDuration() const; 162 163 enum RestartedInterval { 164 DidNotRestartInterval, 165 DidRestartInterval 166 }; 167 168 RestartedInterval maybeRestartInterval(SMILTime elapsed); 169 void beginListChanged(SMILTime eventTime); 170 void endListChanged(SMILTime eventTime); 171 172 // This represents conditions on elements begin or end list that need to be resolved on runtime 173 // for example <animate begin="otherElement.begin + 8s; button.click" ... /> 174 class Condition : public NoBaseWillBeGarbageCollectedFinalized<Condition> { 175 public: 176 enum Type { 177 EventBase, 178 Syncbase, 179 AccessKey 180 }; 181 182 Condition(Type, BeginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeat = -1); 183 static PassOwnPtrWillBeRawPtr<Condition> create(Type type, BeginOrEnd beginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeat = -1) 184 { 185 return adoptPtrWillBeNoop(new Condition(type, beginOrEnd, baseID, name, offset, repeat)); 186 } 187 ~Condition(); 188 void trace(Visitor*); 189 190 Type type() const { return m_type; } 191 BeginOrEnd beginOrEnd() const { return m_beginOrEnd; } 192 String baseID() const { return m_baseID; } 193 String name() const { return m_name; } 194 SMILTime offset() const { return m_offset; } 195 int repeat() const { return m_repeat; } 196 SVGSMILElement* syncBase() const { return m_syncBase.get(); } 197 void setSyncBase(SVGSMILElement* element) { m_syncBase = element; } 198 ConditionEventListener* eventListener() const { return m_eventListener.get(); } 199 void setEventListener(PassRefPtr<ConditionEventListener>); 200 201 private: 202 Type m_type; 203 BeginOrEnd m_beginOrEnd; 204 String m_baseID; 205 String m_name; 206 SMILTime m_offset; 207 int m_repeat; 208 RefPtrWillBeMember<SVGSMILElement> m_syncBase; 209 RefPtr<ConditionEventListener> m_eventListener; 210 }; 211 bool parseCondition(const String&, BeginOrEnd beginOrEnd); 212 void parseBeginOrEnd(const String&, BeginOrEnd beginOrEnd); 213 SVGElement* eventBaseFor(const Condition&); 214 215 void disconnectSyncBaseConditions(); 216 void disconnectEventBaseConditions(); 217 218 // Event base timing 219 void handleConditionEvent(Event*, Condition*); 220 221 void notifyDependentsIntervalChanged(); 222 void createInstanceTimesFromSyncbase(SVGSMILElement* syncbase); 223 void addSyncBaseDependent(SVGSMILElement*); 224 void removeSyncBaseDependent(SVGSMILElement*); 225 226 enum ActiveState { 227 Inactive, 228 Active, 229 Frozen 230 }; 231 232 QualifiedName m_attributeName; 233 234 ActiveState determineActiveState(SMILTime elapsed) const; 235 float calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const; 236 SMILTime calculateNextProgressTime(SMILTime elapsed) const; 237 238 RawPtrWillBeMember<SVGElement> m_targetElement; 239 240 WillBeHeapVector<OwnPtrWillBeMember<Condition> > m_conditions; 241 bool m_syncBaseConditionsConnected; 242 bool m_hasEndEventConditions; 243 244 bool m_isWaitingForFirstInterval; 245 246 typedef WillBeHeapHashSet<RawPtrWillBeMember<SVGSMILElement> > TimeDependentSet; 247 TimeDependentSet m_syncBaseDependents; 248 249 // Instance time lists 250 Vector<SMILTimeWithOrigin> m_beginTimes; 251 Vector<SMILTimeWithOrigin> m_endTimes; 252 253 // This is the upcoming or current interval 254 SMILInterval m_interval; 255 256 SMILTime m_previousIntervalBegin; 257 258 ActiveState m_activeState; 259 float m_lastPercent; 260 unsigned m_lastRepeat; 261 262 SMILTime m_nextProgressTime; 263 264 RefPtrWillBeMember<SMILTimeContainer> m_timeContainer; 265 unsigned m_documentOrderIndex; 266 267 Vector<unsigned> m_repeatEventCountList; 268 269 mutable SMILTime m_cachedDur; 270 mutable SMILTime m_cachedRepeatDur; 271 mutable SMILTime m_cachedRepeatCount; 272 mutable SMILTime m_cachedMin; 273 mutable SMILTime m_cachedMax; 274 275 friend class ConditionEventListener; 276 }; 277 278 inline bool isSVGSMILElement(const SVGElement& element) 279 { 280 return element.hasTagName(SVGNames::setTag) || element.hasTagName(SVGNames::animateTag) || element.hasTagName(SVGNames::animateMotionTag) 281 || element.hasTagName(SVGNames::animateTransformTag) || element.hasTagName((SVGNames::discardTag)); 282 } 283 284 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGSMILElement); 285 286 } 287 288 #endif // SVGSMILElement_h 289