text: /*
   * Copyright (C) 2008 Apple Inc. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
   */
  
  #ifndef SVGSMILElement_h
  #define SVGSMILElement_h
  #if ENABLE(SVG_ANIMATION)
  #include "SMILTime.h"
  #include "SVGElement.h"
  
  #include <wtf/HashMap.h>
  
  namespace WebCore {
      
  class ConditionEventListener;
  class SMILTimeContainer;
  
  // This class implements SMIL interval timing model as needed for SVG animation.
  class SVGSMILElement : public SVGElement {
  public:
      SVGSMILElement(const QualifiedName&, Document*);
      virtual ~SVGSMILElement();
  
      static bool isSMILElement(Node*);
  
      virtual void parseMappedAttribute(Attribute*);
      virtual void attributeChanged(Attribute*, bool preserveDecls);
      virtual void insertedIntoDocument();
      virtual void removedFromDocument();
      virtual void finishParsingChildren();
      
      virtual bool hasValidAttributeType() const = 0;
  
      SMILTimeContainer* timeContainer() const { return m_timeContainer.get(); }
  
      SVGElement* targetElement() const;
      void resetTargetElement() { m_targetElement = 0; }
      const QualifiedName& attributeName() const { return m_attributeName; }
  
      void beginByLinkActivation();
  
      enum Restart {
          RestartAlways,
          RestartWhenNotActive,
          RestartNever
      };
  
      Restart restart() const;
  
      enum FillMode {
          FillRemove,
          FillFreeze
      };
  
      FillMode fill() const;
  
      String xlinkHref() const;
  
      SMILTime dur() const;
      SMILTime repeatDur() const;
      SMILTime repeatCount() const;
      SMILTime maxValue() const;
      SMILTime minValue() const;
  
      SMILTime elapsed() const; 
  
      SMILTime intervalBegin() const { return m_intervalBegin; }
      SMILTime intervalEnd() const { return m_intervalEnd; }
      SMILTime previousIntervalBegin() const { return m_previousIntervalBegin; }
      SMILTime simpleDuration() const;
  
      void progress(SMILTime elapsed, SVGSMILElement* resultsElement);
      SMILTime nextProgressTime() const;
  
      static SMILTime parseClockValue(const String&);
      static SMILTime parseOffsetValue(const String&);
  
      bool isContributing(SMILTime elapsed) const;
      bool isInactive() const;
      bool isFrozen() const;
  
      unsigned documentOrderIndex() const { return m_documentOrderIndex; }
      void setDocumentOrderIndex(unsigned index) { m_documentOrderIndex = index; }
  
      virtual bool isAdditive() const = 0;
      virtual void resetToBaseValue(const String&) = 0;
      virtual void applyResultsToTarget() = 0;
  
  protected:
      void addBeginTime(SMILTime);
      void addEndTime(SMILTime);
  
  private:
      virtual void startedActiveInterval() = 0;
      virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) = 0;
      virtual void endedActiveInterval() = 0;
  
      enum BeginOrEnd {
          Begin,
          End
      };
      
      SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const;
      void resolveFirstInterval();
      void resolveNextInterval();
      void resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const;
      SMILTime resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const;
      SMILTime repeatingDuration() const;
      void checkRestart(SMILTime elapsed);
      void beginListChanged();
      void endListChanged();
      void reschedule();
  
      // This represents conditions on elements begin or end list that need to be resolved on runtime
      // for example <animate begin="otherElement.begin + 8s; button.click" ... />
      struct Condition {
          enum Type {
              EventBase,
              Syncbase,
              AccessKey
          };
  
          Condition(Type, BeginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeats = -1);
          Type m_type;
          BeginOrEnd m_beginOrEnd;
          String m_baseID;
          String m_name;
          SMILTime m_offset;
          int m_repeats;
          RefPtr<Element> m_syncbase;
          RefPtr<ConditionEventListener> m_eventListener;
      };
      bool parseCondition(const String&, BeginOrEnd beginOrEnd);
      void parseBeginOrEnd(const String&, BeginOrEnd beginOrEnd);
      Element* eventBaseFor(const Condition&) const;
  
      void connectConditions();
      void disconnectConditions();
  
      // Event base timing
      void handleConditionEvent(Event*, Condition*);
  
      // Syncbase timing
      enum NewOrExistingInterval {
          NewInterval,
          ExistingInterval
      };
  
      void notifyDependentsIntervalChanged(NewOrExistingInterval);
      void createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval);
      void addTimeDependent(SVGSMILElement*);
      void removeTimeDependent(SVGSMILElement*);
  
      enum ActiveState {
          Inactive,
          Active,
          Frozen
      };
  
      QualifiedName m_attributeName;
  
      ActiveState determineActiveState(SMILTime elapsed) const;
      float calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const;
      SMILTime calculateNextProgressTime(SMILTime elapsed) const;
  
      mutable SVGElement* m_targetElement;
  
      Vector<Condition> m_conditions;
      bool m_conditionsConnected;
      bool m_hasEndEventConditions;     
  
      typedef HashSet<SVGSMILElement*> TimeDependentSet;
      TimeDependentSet m_timeDependents;
  
      // Instance time lists
      Vector<SMILTime> m_beginTimes;
      Vector<SMILTime> m_endTimes;
  
      // This is the upcoming or current interval
      SMILTime m_intervalBegin;
      SMILTime m_intervalEnd;
  
      SMILTime m_previousIntervalBegin;
  
      bool m_isWaitingForFirstInterval;
  
      ActiveState m_activeState;
      float m_lastPercent;
      unsigned m_lastRepeat;
  
      SMILTime m_nextProgressTime;
  
      RefPtr<SMILTimeContainer> m_timeContainer;
      unsigned m_documentOrderIndex;
  
      mutable SMILTime m_cachedDur;
      mutable SMILTime m_cachedRepeatDur;
      mutable SMILTime m_cachedRepeatCount;
      mutable SMILTime m_cachedMin;
      mutable SMILTime m_cachedMax;
  
      friend class ConditionEventListener;
  };
  
  }
  
  #endif // ENABLE(SVG)
  #endif // SVGSMILElement_h
  
  