27 #if ENABLE(SVG_ANIMATION)
30 #include "CSSPropertyNames.h"
33 #include "EventListener.h"
35 #include "FrameView.h"
36 #include "HTMLNames.h"
44 #include <wtf/MathExtras.h>
45 #include <wtf/Vector.h>
52 static const double invalidCachedTime = -1.;
54 class ConditionEventListener :
public EventListener {
56 ConditionEventListener(SVGSMILElement* animation, Element* eventBase, SVGSMILElement::Condition* condition)
57 : m_animation(animation)
58 , m_condition(condition)
59 , m_eventBase(eventBase)
61 m_eventBase->addEventListener(m_condition->m_name,
this,
false);
68 m_eventBase->removeEventListener(m_condition->m_name,
this,
false);
71 virtual void handleEvent(Event* event,
bool isWindowEvent)
73 m_animation->handleConditionEvent(event, m_condition);
76 SVGSMILElement* m_animation;
77 SVGSMILElement::Condition* m_condition;
81 SVGSMILElement::Condition::Condition(
Type type, BeginOrEnd beginOrEnd,
const String& baseID,
const String& name, SMILTime offset,
int repeats)
83 , m_beginOrEnd(beginOrEnd)
91 SVGSMILElement::SVGSMILElement(
const QualifiedName& tagName, Document* doc)
92 : SVGElement(tagName, doc)
93 , m_conditionsConnected(false)
94 , m_hasEndEventConditions(false)
95 , m_intervalBegin(SMILTime::unresolved())
96 , m_intervalEnd(SMILTime::unresolved())
97 , m_previousIntervalBegin(SMILTime::unresolved())
98 , m_isWaitingForFirstInterval(true)
99 , m_activeState(Inactive)
102 , m_nextProgressTime(0)
103 , m_documentOrderIndex(0)
104 , m_cachedDur(invalidCachedTime)
105 , m_cachedRepeatDur(invalidCachedTime)
106 , m_cachedRepeatCount(invalidCachedTime)
107 , m_cachedMin(invalidCachedTime)
108 , m_cachedMax(invalidCachedTime)
112 SVGSMILElement::~SVGSMILElement()
114 disconnectConditions();
116 m_timeContainer->unschedule(
this);
119 void SVGSMILElement::insertedIntoDocument()
121 SVGElement::insertedIntoDocument();
124 for (Node* n =
this; n; n = n->parent())
125 ASSERT(!n->isShadowNode());
127 SVGSVGElement* owner = ownerSVGElement();
130 m_timeContainer = owner->timeContainer();
131 ASSERT(m_timeContainer);
132 m_timeContainer->setDocumentOrderIndexesDirty();
136 void SVGSMILElement::removedFromDocument()
138 if (m_timeContainer) {
139 m_timeContainer->unschedule(
this);
144 RefPtr<SVGSMILElement> keepAlive(
this);
145 disconnectConditions();
146 SVGElement::removedFromDocument();
149 void SVGSMILElement::finishParsingChildren()
151 SVGElement::finishParsingChildren();
155 m_beginTimes.append(0);
157 if (m_isWaitingForFirstInterval) {
158 resolveFirstInterval();
163 SMILTime SVGSMILElement::parseOffsetValue(
const String& data)
168 if (parse.endsWith(
"h"))
169 result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60;
170 else if (parse.endsWith(
"min"))
171 result = parse.left(parse.length() - 3).toDouble(&ok) * 60;
172 else if (parse.endsWith(
"ms"))
173 result = parse.left(parse.length() - 2).toDouble(&ok) / 1000;
174 else if (parse.endsWith(
"s"))
175 result = parse.left(parse.length() - 1).toDouble(&ok);
177 result = parse.toDouble(&ok);
179 return SMILTime::unresolved();
183 SMILTime SVGSMILElement::parseClockValue(
const String& data)
186 return SMILTime::unresolved();
188 String parse = data.stripWhiteSpace();
190 static const AtomicString indefiniteValue(
"indefinite");
191 if (parse == indefiniteValue)
192 return SMILTime::indefinite();
196 int doublePointOne = parse.find(
':');
197 int doublePointTwo = parse.find(
':', doublePointOne + 1);
198 if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) {
199 result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60;
201 return SMILTime::unresolved();
202 result += parse.substring(3, 2).toUIntStrict(&ok) * 60;
204 return SMILTime::unresolved();
205 result += parse.substring(6).toDouble(&ok);
206 }
else if (doublePointOne == 2 && doublePointTwo == -1 && parse.length() >= 5) {
207 result += parse.substring(0, 2).toUIntStrict(&ok) * 60;
209 return SMILTime::unresolved();
210 result += parse.substring(3).toDouble(&ok);
212 return parseOffsetValue(parse);
215 return SMILTime::unresolved();
219 static void sortTimeList(Vector<SMILTime>& timeList)
221 std::sort(timeList.begin(), timeList.end());
224 bool SVGSMILElement::parseCondition(
const String& value, BeginOrEnd beginOrEnd)
226 String parseString = value.stripWhiteSpace();
230 int pos = parseString.find(
'+');
232 pos = parseString.find(
'-');
239 conditionString = parseString;
241 conditionString = parseString.left(pos).stripWhiteSpace();
242 String offsetString = parseString.
substring(pos + 1).stripWhiteSpace();
243 offset = parseOffsetValue(offsetString);
244 if (offset.isUnresolved())
246 offset = offset * sign;
248 if (conditionString.isEmpty())
250 pos = conditionString.find(
'.');
255 nameString = conditionString;
257 baseID = conditionString.left(pos);
258 nameString = conditionString.
substring(pos + 1);
260 if (nameString.isEmpty())
263 Condition::Type type;
265 if (nameString.startsWith(
"repeat(") && nameString.endsWith(
")")) {
268 repeats = nameString.
substring(7, nameString.length() - 8).toUIntStrict(&ok);
271 nameString =
"repeat";
272 type = Condition::EventBase;
273 }
else if (nameString ==
"begin" || nameString ==
"end") {
274 if (baseID.isEmpty())
276 type = Condition::Syncbase;
277 }
else if (nameString.startsWith(
"accesskey(")) {
279 type = Condition::AccessKey;
281 type = Condition::EventBase;
283 m_conditions.append(Condition(type, beginOrEnd, baseID, nameString, offset, repeats));
285 if (type == Condition::EventBase && beginOrEnd == End)
286 m_hasEndEventConditions =
true;
291 bool SVGSMILElement::isSMILElement(Node* node)
299 void SVGSMILElement::parseBeginOrEnd(
const String& parseString, BeginOrEnd beginOrEnd)
301 Vector<SMILTime>& timeList = beginOrEnd ==
Begin ? m_beginTimes : m_endTimes;
302 if (beginOrEnd == End)
303 m_hasEndEventConditions =
false;
304 HashSet<double> existing;
305 for (
unsigned n = 0; n < timeList.size(); ++n)
306 existing.add(timeList[n].value());
307 Vector<String> splitString;
308 parseString.split(
';', splitString);
309 for (
unsigned n = 0; n < splitString.size(); ++n) {
310 SMILTime value = parseClockValue(splitString[n]);
311 if (value.isUnresolved())
312 parseCondition(splitString[n], beginOrEnd);
313 else if (!existing.contains(value.value()))
314 timeList.append(value);
316 sortTimeList(timeList);
319 void SVGSMILElement::parseMappedAttribute(MappedAttribute* attr)
322 if (!m_conditions.isEmpty()) {
323 disconnectConditions();
324 m_conditions.clear();
327 parseBeginOrEnd(attr->value().string(),
Begin);
331 if (!m_conditions.isEmpty()) {
332 disconnectConditions();
333 m_conditions.clear();
336 parseBeginOrEnd(attr->value().string(),
End);
340 SVGElement::parseMappedAttribute(attr);
343 void SVGSMILElement::attributeChanged(Attribute* attr,
bool preserveDecls)
345 SVGElement::attributeChanged(attr, preserveDecls);
347 const QualifiedName& attrName = attr->name();
349 m_cachedDur = invalidCachedTime;
351 m_cachedRepeatDur = invalidCachedTime;
353 m_cachedRepeatCount = invalidCachedTime;
355 m_cachedMin = invalidCachedTime;
357 m_cachedMax = invalidCachedTime;
367 void SVGSMILElement::connectConditions()
369 if (m_conditionsConnected)
370 disconnectConditions();
371 m_conditionsConnected =
true;
372 for (
unsigned n = 0; n < m_conditions.size(); ++n) {
373 Condition& condition = m_conditions[n];
374 if (condition.m_type == Condition::EventBase) {
375 ASSERT(!condition.m_syncbase);
376 Element* eventBase = condition.m_baseID.isEmpty() ? targetElement() : document()->getElementById(condition.m_baseID);
379 ASSERT(!condition.m_eventListener);
380 condition.m_eventListener =
new ConditionEventListener(
this, eventBase, &condition);
381 }
else if (condition.m_type == Condition::Syncbase) {
382 ASSERT(!condition.m_baseID.isEmpty());
383 condition.m_syncbase = document()->getElementById(condition.m_baseID);
384 if (!isSMILElement(condition.m_syncbase.get())) {
385 condition.m_syncbase = 0;
388 SVGSMILElement* syncbase =
static_cast<SVGSMILElement*
>(condition.m_syncbase.get());
389 syncbase->addTimeDependent(
this);
394 void SVGSMILElement::disconnectConditions()
396 if (!m_conditionsConnected)
398 m_conditionsConnected =
false;
399 for (
unsigned n = 0; n < m_conditions.size(); ++n) {
400 Condition& condition = m_conditions[n];
401 if (condition.m_type == Condition::EventBase) {
402 ASSERT(!condition.m_syncbase);
403 if (condition.m_eventListener) {
404 condition.m_eventListener->unregister();
405 condition.m_eventListener = 0;
407 }
else if (condition.m_type == Condition::Syncbase) {
408 if (condition.m_syncbase) {
409 ASSERT(isSMILElement(condition.m_syncbase.get()));
410 static_cast<SVGSMILElement*
>(condition.m_syncbase.get())->removeTimeDependent(
this);
413 condition.m_syncbase = 0;
417 void SVGSMILElement::reschedule()
420 m_timeContainer->schedule(
this);
423 SVGElement* SVGSMILElement::targetElement()
const
425 String href = xlinkHref();
426 Node* target = href.isEmpty() ? parentNode() : document()->getElementById(SVGURIReference::getTarget(href));
427 if (target && target->isSVGElement())
428 return static_cast<SVGElement*>(target);
432 String SVGSMILElement::attributeName()
const
437 SMILTime SVGSMILElement::elapsed()
const
439 return m_timeContainer ? m_timeContainer->elapsed() : 0;
442 bool SVGSMILElement::isInactive()
const
444 return m_activeState == Inactive;
447 bool SVGSMILElement::isFrozen()
const
449 return m_activeState == Frozen;
452 SVGSMILElement::Restart SVGSMILElement::restart()
const
454 static const AtomicString never(
"never");
455 static const AtomicString whenNotActive(
"whenNotActive");
459 if (value == whenNotActive)
460 return RestartWhenNotActive;
461 return RestartAlways;
464 SVGSMILElement::FillMode SVGSMILElement::fill()
const
466 static const AtomicString freeze(
"freeze");
468 return value == freeze ? FillFreeze : FillRemove;
471 String SVGSMILElement::xlinkHref()
const
476 SMILTime SVGSMILElement::dur()
const
478 if (m_cachedDur != invalidCachedTime)
481 SMILTime clockValue = parseClockValue(value);
482 return m_cachedDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue;
485 SMILTime SVGSMILElement::repeatDur()
const
487 if (m_cachedRepeatDur != invalidCachedTime)
488 return m_cachedRepeatDur;
490 SMILTime clockValue = parseClockValue(value);
491 return m_cachedRepeatDur = clockValue < 0 ? SMILTime::unresolved() : clockValue;
495 SMILTime SVGSMILElement::repeatCount()
const
497 if (m_cachedRepeatCount != invalidCachedTime)
498 return m_cachedRepeatCount;
501 return SMILTime::unresolved();
503 static const AtomicString indefiniteValue(
"indefinite");
504 if (value == indefiniteValue)
505 return SMILTime::indefinite();
507 double result = value.string().toDouble(&ok);
508 return m_cachedRepeatCount = ok && result > 0 ? result : SMILTime::unresolved();
511 SMILTime SVGSMILElement::maxValue()
const
513 if (m_cachedMax != invalidCachedTime)
516 SMILTime result = parseClockValue(value);
517 return m_cachedMax = (result.isUnresolved() || result < 0) ? SMILTime::indefinite() : result;
520 SMILTime SVGSMILElement::minValue()
const
522 if (m_cachedMin != invalidCachedTime)
525 SMILTime result = parseClockValue(value);
526 return m_cachedMin = (result.isUnresolved() || result < 0) ? 0 : result;
529 SMILTime SVGSMILElement::simpleDuration()
const
531 return min(dur(), SMILTime::indefinite());
534 void SVGSMILElement::addBeginTime(SMILTime time)
536 m_beginTimes.append(time);
537 sortTimeList(m_beginTimes);
541 void SVGSMILElement::addEndTime(SMILTime time)
543 m_endTimes.append(time);
544 sortTimeList(m_endTimes);
548 SMILTime SVGSMILElement::findInstanceTime(BeginOrEnd beginOrEnd, SMILTime minimumTime,
bool equalsMinimumOK)
const
552 const Vector<SMILTime>&
list = beginOrEnd ==
Begin ? m_beginTimes : m_endTimes;
553 for (
unsigned n = 0; n < list.size(); ++n) {
554 SMILTime time = list[n];
555 ASSERT(!time.isUnresolved());
556 if (time.isIndefinite() && beginOrEnd ==
Begin) {
560 if (equalsMinimumOK) {
561 if (time >= minimumTime)
563 }
else if (time > minimumTime)
566 return SMILTime::unresolved();
569 SMILTime SVGSMILElement::repeatingDuration()
const
573 SMILTime repeatCount = this->repeatCount();
574 SMILTime repeatDur = this->repeatDur();
575 SMILTime simpleDuration = this->simpleDuration();
576 if (simpleDuration == 0 || (repeatDur.isUnresolved() && repeatCount.isUnresolved()))
577 return simpleDuration;
578 SMILTime repeatCountDuration = simpleDuration * repeatCount;
579 return min(repeatCountDuration, min(repeatDur, SMILTime::indefinite()));
582 SMILTime SVGSMILElement::resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd)
const
586 SMILTime preliminaryActiveDuration;
587 if (!resolvedEnd.isUnresolved() && dur().isUnresolved() && repeatDur().isUnresolved() && repeatCount().isUnresolved())
588 preliminaryActiveDuration = resolvedEnd - resolvedBegin;
589 else if (!resolvedEnd.isFinite())
590 preliminaryActiveDuration = repeatingDuration();
592 preliminaryActiveDuration = min(repeatingDuration(), resolvedEnd - resolvedBegin);
594 SMILTime minValue = this->minValue();
595 SMILTime maxValue = this->maxValue();
596 if (minValue > maxValue) {
600 maxValue = SMILTime::indefinite();
602 return resolvedBegin + min(maxValue, max(minValue, preliminaryActiveDuration));
605 void SVGSMILElement::resolveInterval(
bool first, SMILTime& beginResult, SMILTime& endResult)
const
609 SMILTime beginAfter = first ? -numeric_limits<double>::infinity() : m_intervalEnd;
610 SMILTime lastIntervalTempEnd = numeric_limits<double>::infinity();
612 SMILTime tempBegin = findInstanceTime(Begin, beginAfter,
true);
613 if (tempBegin.isUnresolved())
616 if (m_endTimes.isEmpty())
617 tempEnd = resolveActiveEnd(tempBegin, SMILTime::indefinite());
619 tempEnd = findInstanceTime(End, tempBegin,
true);
620 if ((first && tempBegin == tempEnd && tempEnd == lastIntervalTempEnd) || (!first && tempEnd == m_intervalEnd))
621 tempEnd = findInstanceTime(End, tempBegin,
false);
622 if (tempEnd.isUnresolved()) {
623 if (!m_endTimes.isEmpty() && !m_hasEndEventConditions)
626 tempEnd = resolveActiveEnd(tempBegin, tempEnd);
628 if (tempEnd > 0 || !first) {
629 beginResult = tempBegin;
632 }
else if (restart() == RestartNever)
635 beginAfter = tempEnd;
636 lastIntervalTempEnd = tempEnd;
638 beginResult = SMILTime::unresolved();
639 endResult = SMILTime::unresolved();
642 void SVGSMILElement::resolveFirstInterval()
646 resolveInterval(
true, begin, end);
647 ASSERT(!begin.isIndefinite());
649 if (!begin.isUnresolved() && (begin != m_intervalBegin || end != m_intervalEnd)) {
650 bool wasUnresolved = m_intervalBegin.isUnresolved();
651 m_intervalBegin = begin;
653 notifyDependentsIntervalChanged(wasUnresolved ? NewInterval : ExistingInterval);
654 m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
659 void SVGSMILElement::resolveNextInterval()
663 resolveInterval(
false, begin, end);
664 ASSERT(!begin.isIndefinite());
666 if (!begin.isUnresolved() && begin != m_intervalBegin) {
667 m_intervalBegin = begin;
669 notifyDependentsIntervalChanged(NewInterval);
670 m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
674 SMILTime SVGSMILElement::nextProgressTime()
const
676 return m_nextProgressTime;
679 void SVGSMILElement::beginListChanged()
681 SMILTime elapsed = this->elapsed();
682 if (m_isWaitingForFirstInterval)
683 resolveFirstInterval();
684 else if (elapsed < m_intervalBegin) {
685 SMILTime newBegin = findInstanceTime(Begin, elapsed,
false);
686 if (newBegin < m_intervalBegin) {
688 SMILTime oldBegin = m_intervalBegin;
689 m_intervalBegin = elapsed;
690 resolveInterval(
false, m_intervalBegin, m_intervalEnd);
691 ASSERT(!m_intervalBegin.isUnresolved());
692 if (m_intervalBegin != oldBegin)
693 notifyDependentsIntervalChanged(ExistingInterval);
696 m_nextProgressTime = elapsed;
700 void SVGSMILElement::endListChanged()
702 SMILTime elapsed = this->elapsed();
703 if (m_isWaitingForFirstInterval)
704 resolveFirstInterval();
705 else if (elapsed < m_intervalEnd && m_intervalBegin.isFinite()) {
706 SMILTime newEnd = findInstanceTime(End, m_intervalBegin,
false);
707 if (newEnd < m_intervalEnd) {
708 newEnd = resolveActiveEnd(m_intervalBegin, newEnd);
709 if (newEnd != m_intervalEnd) {
710 m_intervalEnd = newEnd;
711 notifyDependentsIntervalChanged(ExistingInterval);
715 m_nextProgressTime = elapsed;
719 void SVGSMILElement::checkRestart(SMILTime elapsed)
721 ASSERT(!m_isWaitingForFirstInterval);
722 ASSERT(elapsed >= m_intervalBegin);
724 Restart restart = this->restart();
725 if (restart == RestartNever)
728 if (elapsed < m_intervalEnd) {
729 if (restart != RestartAlways)
731 SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin,
false);
732 if (nextBegin < m_intervalEnd) {
733 m_intervalEnd = nextBegin;
734 notifyDependentsIntervalChanged(ExistingInterval);
737 if (elapsed >= m_intervalEnd)
738 resolveNextInterval();
741 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed,
unsigned& repeat)
const
743 SMILTime simpleDuration = this->simpleDuration();
745 if (simpleDuration.isIndefinite()) {
749 if (simpleDuration == 0) {
753 ASSERT(m_intervalBegin.isFinite());
754 ASSERT(simpleDuration.isFinite());
755 SMILTime activeTime = elapsed - m_intervalBegin;
756 SMILTime repeatingDuration = this->repeatingDuration();
757 if (elapsed >= m_intervalEnd || activeTime > repeatingDuration) {
758 repeat =
static_cast<unsigned>(repeatingDuration.value() / simpleDuration.value());
759 if (fmod(repeatingDuration.value(), simpleDuration.value() == 0.))
763 repeat =
static_cast<unsigned>(activeTime.value() / simpleDuration.value());
764 SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value());
768 SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed)
const
770 if (m_activeState == Active) {
772 SMILTime simpleDuration = this->simpleDuration();
774 SMILTime repeatCount = this->repeatCount();
775 SMILTime repeatingDurationEnd = m_intervalBegin + repeatingDuration();
778 if (elapsed < repeatingDurationEnd && repeatingDurationEnd < m_intervalEnd && repeatingDurationEnd.isFinite())
779 return repeatingDurationEnd;
780 return m_intervalEnd;
782 return elapsed + 0.025;
784 return m_intervalBegin >= elapsed ? m_intervalBegin : SMILTime::unresolved();
787 SVGSMILElement::ActiveState SVGSMILElement::determineActiveState(SMILTime elapsed)
const
789 if (elapsed >= m_intervalBegin && elapsed < m_intervalEnd)
792 if (m_activeState == Active)
793 return fill() == FillFreeze ? Frozen : Inactive;
795 return m_activeState;
798 bool SVGSMILElement::isContributing(SMILTime elapsed)
const
801 return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_intervalBegin + repeatingDuration())) || m_activeState == Frozen;
804 void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement)
806 ASSERT(m_timeContainer);
807 ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
809 if (!m_conditionsConnected)
812 if (!m_intervalBegin.isFinite()) {
813 ASSERT(m_activeState == Inactive);
814 m_nextProgressTime = SMILTime::unresolved();
818 if (elapsed < m_intervalBegin) {
819 ASSERT(m_activeState != Active);
820 if (m_activeState == Frozen && resultElement)
821 updateAnimation(m_lastPercent, m_lastRepeat, resultElement);
822 m_nextProgressTime = m_intervalBegin;
826 m_previousIntervalBegin = m_intervalBegin;
828 if (m_activeState == Inactive) {
829 m_isWaitingForFirstInterval =
false;
830 m_activeState = Active;
831 startedActiveInterval();
835 float percent = calculateAnimationPercentAndRepeat(elapsed, repeat);
837 checkRestart(elapsed);
839 ActiveState oldActiveState = m_activeState;
840 m_activeState = determineActiveState(elapsed);
842 if (isContributing(elapsed)) {
844 updateAnimation(percent, repeat, resultElement);
845 m_lastPercent = percent;
846 m_lastRepeat = repeat;
849 if (oldActiveState == Active && m_activeState != Active)
850 endedActiveInterval();
852 m_nextProgressTime = calculateNextProgressTime(elapsed);
855 void SVGSMILElement::notifyDependentsIntervalChanged(NewOrExistingInterval newOrExisting)
857 ASSERT(m_intervalBegin.isFinite());
858 static HashSet<SVGSMILElement*> loopBreaker;
859 if (loopBreaker.contains(
this))
861 loopBreaker.add(
this);
863 TimeDependentSet::iterator end = m_timeDependents.end();
864 for (TimeDependentSet::iterator it = m_timeDependents.begin(); it != end; ++it) {
865 SVGSMILElement* dependent = *it;
866 dependent->createInstanceTimesFromSyncbase(
this, newOrExisting);
869 loopBreaker.remove(
this);
872 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval newOrExisting)
876 for (
unsigned n = 0; n < m_conditions.size(); ++n) {
877 Condition& condition = m_conditions[n];
878 if (condition.m_type == Condition::Syncbase && condition.m_syncbase == syncbase) {
879 ASSERT(condition.m_name ==
"begin" || condition.m_name ==
"end");
882 if (condition.m_name ==
"begin")
883 time = syncbase->m_intervalBegin + condition.m_offset;
885 time = syncbase->m_intervalEnd + condition.m_offset;
886 ASSERT(time.isFinite());
887 if (condition.m_beginOrEnd == Begin)
895 void SVGSMILElement::addTimeDependent(SVGSMILElement* animation)
897 m_timeDependents.add(animation);
898 if (m_intervalBegin.isFinite())
899 animation->createInstanceTimesFromSyncbase(
this, NewInterval);
902 void SVGSMILElement::removeTimeDependent(SVGSMILElement* animation)
904 m_timeDependents.remove(animation);
907 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition)
909 if (condition->m_beginOrEnd == Begin)
910 addBeginTime(elapsed() + condition->m_offset);
912 addEndTime(elapsed() + condition->m_offset);
915 void SVGSMILElement::beginByLinkActivation()
917 addBeginTime(elapsed());
DOM::QualifiedName minAttr
DOM::QualifiedName attributeNameAttr
DOM::QualifiedName animateTransformTag
DOM::QualifiedName repeatCountAttr
DOM::QualifiedName hrefAttr
DOM::QualifiedName repeatDurAttr
DOM::QualifiedName maxAttr
DOM::QualifiedName beginAttr
float narrowPrecisionToFloat(T)
QString stripWhiteSpace() const
DOM::QualifiedName animateColorTag
DOM::QualifiedName endAttr
DOM::QualifiedName fillAttr
DOM::QualifiedName setTag
DOM::QualifiedName animateTag
DOM::QualifiedName durAttr
DOMString substring(unsigned pos, unsigned len=UINT_MAX) const
QList< Action > parse(QSettings &ini)
DOM::QualifiedName restartAttr
DOM::QualifiedName animateMotionTag
const KShortcut & begin()
QStringList list(const QString &fileClass)