00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #if ENABLE(SVG_ANIMATION)
00028 #include "SVGSMILElement.h"
00029
00030 #include "CSSPropertyNames.h"
00031 #include "Document.h"
00032 #include "Event.h"
00033 #include "EventListener.h"
00034 #include "FloatConversion.h"
00035 #include "FrameView.h"
00036 #include "HTMLNames.h"
00037 #include "SVGNames.h"
00038 #include "SVGParserUtilities.h"
00039 #include "SVGSVGElement.h"
00040 #include "SVGURIReference.h"
00041 #include "SMILTimeContainer.h"
00042 #include "XLinkNames.h"
00043 #include <math.h>
00044 #include <wtf/MathExtras.h>
00045 #include <wtf/Vector.h>
00046
00047 using namespace std;
00048
00049 namespace WebCore {
00050
00051
00052 static const double invalidCachedTime = -1.;
00053
00054 class ConditionEventListener : public EventListener {
00055 public:
00056 ConditionEventListener(SVGSMILElement* animation, Element* eventBase, SVGSMILElement::Condition* condition)
00057 : m_animation(animation)
00058 , m_condition(condition)
00059 , m_eventBase(eventBase)
00060 {
00061 m_eventBase->addEventListener(m_condition->m_name, this, false);
00062 }
00063
00064 void unregister()
00065 {
00066
00067 if (!hasOneRef())
00068 m_eventBase->removeEventListener(m_condition->m_name, this, false);
00069 }
00070
00071 virtual void handleEvent(Event* event, bool isWindowEvent)
00072 {
00073 m_animation->handleConditionEvent(event, m_condition);
00074 }
00075 private:
00076 SVGSMILElement* m_animation;
00077 SVGSMILElement::Condition* m_condition;
00078 Element* m_eventBase;
00079 };
00080
00081 SVGSMILElement::Condition::Condition(Type type, BeginOrEnd beginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeats)
00082 : m_type(type)
00083 , m_beginOrEnd(beginOrEnd)
00084 , m_baseID(baseID)
00085 , m_name(name)
00086 , m_offset(offset)
00087 , m_repeats(repeats)
00088 {
00089 }
00090
00091 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document* doc)
00092 : SVGElement(tagName, doc)
00093 , m_conditionsConnected(false)
00094 , m_hasEndEventConditions(false)
00095 , m_intervalBegin(SMILTime::unresolved())
00096 , m_intervalEnd(SMILTime::unresolved())
00097 , m_previousIntervalBegin(SMILTime::unresolved())
00098 , m_isWaitingForFirstInterval(true)
00099 , m_activeState(Inactive)
00100 , m_lastPercent(0)
00101 , m_lastRepeat(0)
00102 , m_nextProgressTime(0)
00103 , m_documentOrderIndex(0)
00104 , m_cachedDur(invalidCachedTime)
00105 , m_cachedRepeatDur(invalidCachedTime)
00106 , m_cachedRepeatCount(invalidCachedTime)
00107 , m_cachedMin(invalidCachedTime)
00108 , m_cachedMax(invalidCachedTime)
00109 {
00110 }
00111
00112 SVGSMILElement::~SVGSMILElement()
00113 {
00114 disconnectConditions();
00115 if (m_timeContainer)
00116 m_timeContainer->unschedule(this);
00117 }
00118
00119 void SVGSMILElement::insertedIntoDocument()
00120 {
00121 SVGElement::insertedIntoDocument();
00122 #ifndef NDEBUG
00123
00124 for (Node* n = this; n; n = n->parent())
00125 ASSERT(!n->isShadowNode());
00126 #endif
00127 SVGSVGElement* owner = ownerSVGElement();
00128 if (!owner)
00129 return;
00130 m_timeContainer = owner->timeContainer();
00131 ASSERT(m_timeContainer);
00132 m_timeContainer->setDocumentOrderIndexesDirty();
00133 reschedule();
00134 }
00135
00136 void SVGSMILElement::removedFromDocument()
00137 {
00138 if (m_timeContainer) {
00139 m_timeContainer->unschedule(this);
00140 m_timeContainer = 0;
00141 }
00142
00143
00144 RefPtr<SVGSMILElement> keepAlive(this);
00145 disconnectConditions();
00146 SVGElement::removedFromDocument();
00147 }
00148
00149 void SVGSMILElement::finishParsingChildren()
00150 {
00151 SVGElement::finishParsingChildren();
00152
00153
00154 if (!hasAttribute(SVGNames::beginAttr))
00155 m_beginTimes.append(0);
00156
00157 if (m_isWaitingForFirstInterval) {
00158 resolveFirstInterval();
00159 reschedule();
00160 }
00161 }
00162
00163 SMILTime SVGSMILElement::parseOffsetValue(const String& data)
00164 {
00165 bool ok;
00166 double result = 0;
00167 String parse = data.stripWhiteSpace();
00168 if (parse.endsWith("h"))
00169 result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60;
00170 else if (parse.endsWith("min"))
00171 result = parse.left(parse.length() - 3).toDouble(&ok) * 60;
00172 else if (parse.endsWith("ms"))
00173 result = parse.left(parse.length() - 2).toDouble(&ok) / 1000;
00174 else if (parse.endsWith("s"))
00175 result = parse.left(parse.length() - 1).toDouble(&ok);
00176 else
00177 result = parse.toDouble(&ok);
00178 if (!ok)
00179 return SMILTime::unresolved();
00180 return result;
00181 }
00182
00183 SMILTime SVGSMILElement::parseClockValue(const String& data)
00184 {
00185 if (data.isNull())
00186 return SMILTime::unresolved();
00187
00188 String parse = data.stripWhiteSpace();
00189
00190 static const AtomicString indefiniteValue("indefinite");
00191 if (parse == indefiniteValue)
00192 return SMILTime::indefinite();
00193
00194 double result = 0;
00195 bool ok;
00196 int doublePointOne = parse.find(':');
00197 int doublePointTwo = parse.find(':', doublePointOne + 1);
00198 if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) {
00199 result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60;
00200 if (!ok)
00201 return SMILTime::unresolved();
00202 result += parse.substring(3, 2).toUIntStrict(&ok) * 60;
00203 if (!ok)
00204 return SMILTime::unresolved();
00205 result += parse.substring(6).toDouble(&ok);
00206 } else if (doublePointOne == 2 && doublePointTwo == -1 && parse.length() >= 5) {
00207 result += parse.substring(0, 2).toUIntStrict(&ok) * 60;
00208 if (!ok)
00209 return SMILTime::unresolved();
00210 result += parse.substring(3).toDouble(&ok);
00211 } else
00212 return parseOffsetValue(parse);
00213
00214 if (!ok)
00215 return SMILTime::unresolved();
00216 return result;
00217 }
00218
00219 static void sortTimeList(Vector<SMILTime>& timeList)
00220 {
00221 std::sort(timeList.begin(), timeList.end());
00222 }
00223
00224 bool SVGSMILElement::parseCondition(const String& value, BeginOrEnd beginOrEnd)
00225 {
00226 String parseString = value.stripWhiteSpace();
00227
00228 double sign = 1.;
00229 bool ok;
00230 int pos = parseString.find('+');
00231 if (pos == -1) {
00232 pos = parseString.find('-');
00233 if (pos != -1)
00234 sign = -1.;
00235 }
00236 String conditionString;
00237 SMILTime offset = 0;
00238 if (pos == -1)
00239 conditionString = parseString;
00240 else {
00241 conditionString = parseString.left(pos).stripWhiteSpace();
00242 String offsetString = parseString.substring(pos + 1).stripWhiteSpace();
00243 offset = parseOffsetValue(offsetString);
00244 if (offset.isUnresolved())
00245 return false;
00246 offset = offset * sign;
00247 }
00248 if (conditionString.isEmpty())
00249 return false;
00250 pos = conditionString.find('.');
00251
00252 String baseID;
00253 String nameString;
00254 if (pos == -1)
00255 nameString = conditionString;
00256 else {
00257 baseID = conditionString.left(pos);
00258 nameString = conditionString.substring(pos + 1);
00259 }
00260 if (nameString.isEmpty())
00261 return false;
00262
00263 Condition::Type type;
00264 int repeats = -1;
00265 if (nameString.startsWith("repeat(") && nameString.endsWith(")")) {
00266
00267
00268 repeats = nameString.substring(7, nameString.length() - 8).toUIntStrict(&ok);
00269 if (!ok)
00270 return false;
00271 nameString = "repeat";
00272 type = Condition::EventBase;
00273 } else if (nameString == "begin" || nameString == "end") {
00274 if (baseID.isEmpty())
00275 return false;
00276 type = Condition::Syncbase;
00277 } else if (nameString.startsWith("accesskey(")) {
00278
00279 type = Condition::AccessKey;
00280 } else
00281 type = Condition::EventBase;
00282
00283 m_conditions.append(Condition(type, beginOrEnd, baseID, nameString, offset, repeats));
00284
00285 if (type == Condition::EventBase && beginOrEnd == End)
00286 m_hasEndEventConditions = true;
00287
00288 return true;
00289 }
00290
00291 bool SVGSMILElement::isSMILElement(Node* node)
00292 {
00293 if (!node)
00294 return false;
00295 return node->hasTagName(SVGNames::setTag) || node->hasTagName(SVGNames::animateTag) || node->hasTagName(SVGNames::animateMotionTag)
00296 || node->hasTagName(SVGNames::animateTransformTag) || node->hasTagName(SVGNames::animateColorTag);
00297 }
00298
00299 void SVGSMILElement::parseBeginOrEnd(const String& parseString, BeginOrEnd beginOrEnd)
00300 {
00301 Vector<SMILTime>& timeList = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
00302 if (beginOrEnd == End)
00303 m_hasEndEventConditions = false;
00304 HashSet<double> existing;
00305 for (unsigned n = 0; n < timeList.size(); ++n)
00306 existing.add(timeList[n].value());
00307 Vector<String> splitString;
00308 parseString.split(';', splitString);
00309 for (unsigned n = 0; n < splitString.size(); ++n) {
00310 SMILTime value = parseClockValue(splitString[n]);
00311 if (value.isUnresolved())
00312 parseCondition(splitString[n], beginOrEnd);
00313 else if (!existing.contains(value.value()))
00314 timeList.append(value);
00315 }
00316 sortTimeList(timeList);
00317 }
00318
00319 void SVGSMILElement::parseMappedAttribute(MappedAttribute* attr)
00320 {
00321 if (attr->name() == SVGNames::beginAttr) {
00322 if (!m_conditions.isEmpty()) {
00323 disconnectConditions();
00324 m_conditions.clear();
00325 parseBeginOrEnd(getAttribute(SVGNames::endAttr), End);
00326 }
00327 parseBeginOrEnd(attr->value().string(), Begin);
00328 if (inDocument())
00329 connectConditions();
00330 } else if (attr->name() == SVGNames::endAttr) {
00331 if (!m_conditions.isEmpty()) {
00332 disconnectConditions();
00333 m_conditions.clear();
00334 parseBeginOrEnd(getAttribute(SVGNames::beginAttr), Begin);
00335 }
00336 parseBeginOrEnd(attr->value().string(), End);
00337 if (inDocument())
00338 connectConditions();
00339 } else
00340 SVGElement::parseMappedAttribute(attr);
00341 }
00342
00343 void SVGSMILElement::attributeChanged(Attribute* attr, bool preserveDecls)
00344 {
00345 SVGElement::attributeChanged(attr, preserveDecls);
00346
00347 const QualifiedName& attrName = attr->name();
00348 if (attrName == SVGNames::durAttr)
00349 m_cachedDur = invalidCachedTime;
00350 else if (attrName == SVGNames::repeatDurAttr)
00351 m_cachedRepeatDur = invalidCachedTime;
00352 else if (attrName == SVGNames::repeatCountAttr)
00353 m_cachedRepeatCount = invalidCachedTime;
00354 else if (attrName == SVGNames::minAttr)
00355 m_cachedMin = invalidCachedTime;
00356 else if (attrName == SVGNames::maxAttr)
00357 m_cachedMax = invalidCachedTime;
00358
00359 if (inDocument()) {
00360 if (attrName == SVGNames::beginAttr)
00361 beginListChanged();
00362 else if (attrName == SVGNames::endAttr)
00363 endListChanged();
00364 }
00365 }
00366
00367 void SVGSMILElement::connectConditions()
00368 {
00369 if (m_conditionsConnected)
00370 disconnectConditions();
00371 m_conditionsConnected = true;
00372 for (unsigned n = 0; n < m_conditions.size(); ++n) {
00373 Condition& condition = m_conditions[n];
00374 if (condition.m_type == Condition::EventBase) {
00375 ASSERT(!condition.m_syncbase);
00376 Element* eventBase = condition.m_baseID.isEmpty() ? targetElement() : document()->getElementById(condition.m_baseID);
00377 if (!eventBase)
00378 continue;
00379 ASSERT(!condition.m_eventListener);
00380 condition.m_eventListener = new ConditionEventListener(this, eventBase, &condition);
00381 } else if (condition.m_type == Condition::Syncbase) {
00382 ASSERT(!condition.m_baseID.isEmpty());
00383 condition.m_syncbase = document()->getElementById(condition.m_baseID);
00384 if (!isSMILElement(condition.m_syncbase.get())) {
00385 condition.m_syncbase = 0;
00386 continue;
00387 }
00388 SVGSMILElement* syncbase = static_cast<SVGSMILElement*>(condition.m_syncbase.get());
00389 syncbase->addTimeDependent(this);
00390 }
00391 }
00392 }
00393
00394 void SVGSMILElement::disconnectConditions()
00395 {
00396 if (!m_conditionsConnected)
00397 return;
00398 m_conditionsConnected = false;
00399 for (unsigned n = 0; n < m_conditions.size(); ++n) {
00400 Condition& condition = m_conditions[n];
00401 if (condition.m_type == Condition::EventBase) {
00402 ASSERT(!condition.m_syncbase);
00403 if (condition.m_eventListener) {
00404 condition.m_eventListener->unregister();
00405 condition.m_eventListener = 0;
00406 }
00407 } else if (condition.m_type == Condition::Syncbase) {
00408 if (condition.m_syncbase) {
00409 ASSERT(isSMILElement(condition.m_syncbase.get()));
00410 static_cast<SVGSMILElement*>(condition.m_syncbase.get())->removeTimeDependent(this);
00411 }
00412 }
00413 condition.m_syncbase = 0;
00414 }
00415 }
00416
00417 void SVGSMILElement::reschedule()
00418 {
00419 if (m_timeContainer)
00420 m_timeContainer->schedule(this);
00421 }
00422
00423 SVGElement* SVGSMILElement::targetElement() const
00424 {
00425 String href = xlinkHref();
00426 Node* target = href.isEmpty() ? parentNode() : document()->getElementById(SVGURIReference::getTarget(href));
00427 if (target && target->isSVGElement())
00428 return static_cast<SVGElement*>(target);
00429 return 0;
00430 }
00431
00432 String SVGSMILElement::attributeName() const
00433 {
00434 return getAttribute(SVGNames::attributeNameAttr).string().stripWhiteSpace();
00435 }
00436
00437 SMILTime SVGSMILElement::elapsed() const
00438 {
00439 return m_timeContainer ? m_timeContainer->elapsed() : 0;
00440 }
00441
00442 bool SVGSMILElement::isInactive() const
00443 {
00444 return m_activeState == Inactive;
00445 }
00446
00447 bool SVGSMILElement::isFrozen() const
00448 {
00449 return m_activeState == Frozen;
00450 }
00451
00452 SVGSMILElement::Restart SVGSMILElement::restart() const
00453 {
00454 static const AtomicString never("never");
00455 static const AtomicString whenNotActive("whenNotActive");
00456 const AtomicString& value = getAttribute(SVGNames::restartAttr);
00457 if (value == never)
00458 return RestartNever;
00459 if (value == whenNotActive)
00460 return RestartWhenNotActive;
00461 return RestartAlways;
00462 }
00463
00464 SVGSMILElement::FillMode SVGSMILElement::fill() const
00465 {
00466 static const AtomicString freeze("freeze");
00467 const AtomicString& value = getAttribute(SVGNames::fillAttr);
00468 return value == freeze ? FillFreeze : FillRemove;
00469 }
00470
00471 String SVGSMILElement::xlinkHref() const
00472 {
00473 return getAttribute(XLinkNames::hrefAttr);
00474 }
00475
00476 SMILTime SVGSMILElement::dur() const
00477 {
00478 if (m_cachedDur != invalidCachedTime)
00479 return m_cachedDur;
00480 const AtomicString& value = getAttribute(SVGNames::durAttr);
00481 SMILTime clockValue = parseClockValue(value);
00482 return m_cachedDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue;
00483 }
00484
00485 SMILTime SVGSMILElement::repeatDur() const
00486 {
00487 if (m_cachedRepeatDur != invalidCachedTime)
00488 return m_cachedRepeatDur;
00489 const AtomicString& value = getAttribute(SVGNames::repeatDurAttr);
00490 SMILTime clockValue = parseClockValue(value);
00491 return m_cachedRepeatDur = clockValue < 0 ? SMILTime::unresolved() : clockValue;
00492 }
00493
00494
00495 SMILTime SVGSMILElement::repeatCount() const
00496 {
00497 if (m_cachedRepeatCount != invalidCachedTime)
00498 return m_cachedRepeatCount;
00499 const AtomicString& value = getAttribute(SVGNames::repeatCountAttr);
00500 if (value.isNull())
00501 return SMILTime::unresolved();
00502
00503 static const AtomicString indefiniteValue("indefinite");
00504 if (value == indefiniteValue)
00505 return SMILTime::indefinite();
00506 bool ok;
00507 double result = value.string().toDouble(&ok);
00508 return m_cachedRepeatCount = ok && result > 0 ? result : SMILTime::unresolved();
00509 }
00510
00511 SMILTime SVGSMILElement::maxValue() const
00512 {
00513 if (m_cachedMax != invalidCachedTime)
00514 return m_cachedMax;
00515 const AtomicString& value = getAttribute(SVGNames::maxAttr);
00516 SMILTime result = parseClockValue(value);
00517 return m_cachedMax = (result.isUnresolved() || result < 0) ? SMILTime::indefinite() : result;
00518 }
00519
00520 SMILTime SVGSMILElement::minValue() const
00521 {
00522 if (m_cachedMin != invalidCachedTime)
00523 return m_cachedMin;
00524 const AtomicString& value = getAttribute(SVGNames::minAttr);
00525 SMILTime result = parseClockValue(value);
00526 return m_cachedMin = (result.isUnresolved() || result < 0) ? 0 : result;
00527 }
00528
00529 SMILTime SVGSMILElement::simpleDuration() const
00530 {
00531 return min(dur(), SMILTime::indefinite());
00532 }
00533
00534 void SVGSMILElement::addBeginTime(SMILTime time)
00535 {
00536 m_beginTimes.append(time);
00537 sortTimeList(m_beginTimes);
00538 beginListChanged();
00539 }
00540
00541 void SVGSMILElement::addEndTime(SMILTime time)
00542 {
00543 m_endTimes.append(time);
00544 sortTimeList(m_endTimes);
00545 endListChanged();
00546 }
00547
00548 SMILTime SVGSMILElement::findInstanceTime(BeginOrEnd beginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const
00549 {
00550
00551
00552 const Vector<SMILTime>& list = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
00553 for (unsigned n = 0; n < list.size(); ++n) {
00554 SMILTime time = list[n];
00555 ASSERT(!time.isUnresolved());
00556 if (time.isIndefinite() && beginOrEnd == Begin) {
00557
00558 continue;
00559 }
00560 if (equalsMinimumOK) {
00561 if (time >= minimumTime)
00562 return time;
00563 } else if (time > minimumTime)
00564 return time;
00565 }
00566 return SMILTime::unresolved();
00567 }
00568
00569 SMILTime SVGSMILElement::repeatingDuration() const
00570 {
00571
00572
00573 SMILTime repeatCount = this->repeatCount();
00574 SMILTime repeatDur = this->repeatDur();
00575 SMILTime simpleDuration = this->simpleDuration();
00576 if (simpleDuration == 0 || (repeatDur.isUnresolved() && repeatCount.isUnresolved()))
00577 return simpleDuration;
00578 SMILTime repeatCountDuration = simpleDuration * repeatCount;
00579 return min(repeatCountDuration, min(repeatDur, SMILTime::indefinite()));
00580 }
00581
00582 SMILTime SVGSMILElement::resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const
00583 {
00584
00585
00586 SMILTime preliminaryActiveDuration;
00587 if (!resolvedEnd.isUnresolved() && dur().isUnresolved() && repeatDur().isUnresolved() && repeatCount().isUnresolved())
00588 preliminaryActiveDuration = resolvedEnd - resolvedBegin;
00589 else if (!resolvedEnd.isFinite())
00590 preliminaryActiveDuration = repeatingDuration();
00591 else
00592 preliminaryActiveDuration = min(repeatingDuration(), resolvedEnd - resolvedBegin);
00593
00594 SMILTime minValue = this->minValue();
00595 SMILTime maxValue = this->maxValue();
00596 if (minValue > maxValue) {
00597
00598
00599 minValue = 0;
00600 maxValue = SMILTime::indefinite();
00601 }
00602 return resolvedBegin + min(maxValue, max(minValue, preliminaryActiveDuration));
00603 }
00604
00605 void SVGSMILElement::resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const
00606 {
00607
00608
00609 SMILTime beginAfter = first ? -numeric_limits<double>::infinity() : m_intervalEnd;
00610 SMILTime lastIntervalTempEnd = numeric_limits<double>::infinity();
00611 while (true) {
00612 SMILTime tempBegin = findInstanceTime(Begin, beginAfter, true);
00613 if (tempBegin.isUnresolved())
00614 break;
00615 SMILTime tempEnd;
00616 if (m_endTimes.isEmpty())
00617 tempEnd = resolveActiveEnd(tempBegin, SMILTime::indefinite());
00618 else {
00619 tempEnd = findInstanceTime(End, tempBegin, true);
00620 if ((first && tempBegin == tempEnd && tempEnd == lastIntervalTempEnd) || (!first && tempEnd == m_intervalEnd))
00621 tempEnd = findInstanceTime(End, tempBegin, false);
00622 if (tempEnd.isUnresolved()) {
00623 if (!m_endTimes.isEmpty() && !m_hasEndEventConditions)
00624 break;
00625 }
00626 tempEnd = resolveActiveEnd(tempBegin, tempEnd);
00627 }
00628 if (tempEnd > 0 || !first) {
00629 beginResult = tempBegin;
00630 endResult = tempEnd;
00631 return;
00632 } else if (restart() == RestartNever)
00633 break;
00634 else
00635 beginAfter = tempEnd;
00636 lastIntervalTempEnd = tempEnd;
00637 }
00638 beginResult = SMILTime::unresolved();
00639 endResult = SMILTime::unresolved();
00640 }
00641
00642 void SVGSMILElement::resolveFirstInterval()
00643 {
00644 SMILTime begin;
00645 SMILTime end;
00646 resolveInterval(true, begin, end);
00647 ASSERT(!begin.isIndefinite());
00648
00649 if (!begin.isUnresolved() && (begin != m_intervalBegin || end != m_intervalEnd)) {
00650 bool wasUnresolved = m_intervalBegin.isUnresolved();
00651 m_intervalBegin = begin;
00652 m_intervalEnd = end;
00653 notifyDependentsIntervalChanged(wasUnresolved ? NewInterval : ExistingInterval);
00654 m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
00655 reschedule();
00656 }
00657 }
00658
00659 void SVGSMILElement::resolveNextInterval()
00660 {
00661 SMILTime begin;
00662 SMILTime end;
00663 resolveInterval(false, begin, end);
00664 ASSERT(!begin.isIndefinite());
00665
00666 if (!begin.isUnresolved() && begin != m_intervalBegin) {
00667 m_intervalBegin = begin;
00668 m_intervalEnd = end;
00669 notifyDependentsIntervalChanged(NewInterval);
00670 m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
00671 }
00672 }
00673
00674 SMILTime SVGSMILElement::nextProgressTime() const
00675 {
00676 return m_nextProgressTime;
00677 }
00678
00679 void SVGSMILElement::beginListChanged()
00680 {
00681 SMILTime elapsed = this->elapsed();
00682 if (m_isWaitingForFirstInterval)
00683 resolveFirstInterval();
00684 else if (elapsed < m_intervalBegin) {
00685 SMILTime newBegin = findInstanceTime(Begin, elapsed, false);
00686 if (newBegin < m_intervalBegin) {
00687
00688 SMILTime oldBegin = m_intervalBegin;
00689 m_intervalBegin = elapsed;
00690 resolveInterval(false, m_intervalBegin, m_intervalEnd);
00691 ASSERT(!m_intervalBegin.isUnresolved());
00692 if (m_intervalBegin != oldBegin)
00693 notifyDependentsIntervalChanged(ExistingInterval);
00694 }
00695 }
00696 m_nextProgressTime = elapsed;
00697 reschedule();
00698 }
00699
00700 void SVGSMILElement::endListChanged()
00701 {
00702 SMILTime elapsed = this->elapsed();
00703 if (m_isWaitingForFirstInterval)
00704 resolveFirstInterval();
00705 else if (elapsed < m_intervalEnd && m_intervalBegin.isFinite()) {
00706 SMILTime newEnd = findInstanceTime(End, m_intervalBegin, false);
00707 if (newEnd < m_intervalEnd) {
00708 newEnd = resolveActiveEnd(m_intervalBegin, newEnd);
00709 if (newEnd != m_intervalEnd) {
00710 m_intervalEnd = newEnd;
00711 notifyDependentsIntervalChanged(ExistingInterval);
00712 }
00713 }
00714 }
00715 m_nextProgressTime = elapsed;
00716 reschedule();
00717 }
00718
00719 void SVGSMILElement::checkRestart(SMILTime elapsed)
00720 {
00721 ASSERT(!m_isWaitingForFirstInterval);
00722 ASSERT(elapsed >= m_intervalBegin);
00723
00724 Restart restart = this->restart();
00725 if (restart == RestartNever)
00726 return;
00727
00728 if (elapsed < m_intervalEnd) {
00729 if (restart != RestartAlways)
00730 return;
00731 SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin, false);
00732 if (nextBegin < m_intervalEnd) {
00733 m_intervalEnd = nextBegin;
00734 notifyDependentsIntervalChanged(ExistingInterval);
00735 }
00736 }
00737 if (elapsed >= m_intervalEnd)
00738 resolveNextInterval();
00739 }
00740
00741 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const
00742 {
00743 SMILTime simpleDuration = this->simpleDuration();
00744 repeat = 0;
00745 if (simpleDuration.isIndefinite()) {
00746 repeat = 0;
00747 return 0.f;
00748 }
00749 if (simpleDuration == 0) {
00750 repeat = 0;
00751 return 1.f;
00752 }
00753 ASSERT(m_intervalBegin.isFinite());
00754 ASSERT(simpleDuration.isFinite());
00755 SMILTime activeTime = elapsed - m_intervalBegin;
00756 SMILTime repeatingDuration = this->repeatingDuration();
00757 if (elapsed >= m_intervalEnd || activeTime > repeatingDuration) {
00758 repeat = static_cast<unsigned>(repeatingDuration.value() / simpleDuration.value());
00759 if (fmod(repeatingDuration.value(), simpleDuration.value() == 0.))
00760 repeat--;
00761 return 1.f;
00762 }
00763 repeat = static_cast<unsigned>(activeTime.value() / simpleDuration.value());
00764 SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value());
00765 return narrowPrecisionToFloat(simpleTime.value() / simpleDuration.value());
00766 }
00767
00768 SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed) const
00769 {
00770 if (m_activeState == Active) {
00771
00772 SMILTime simpleDuration = this->simpleDuration();
00773 if (simpleDuration.isIndefinite() || hasTagName(SVGNames::setTag)) {
00774 SMILTime repeatCount = this->repeatCount();
00775 SMILTime repeatingDurationEnd = m_intervalBegin + repeatingDuration();
00776
00777
00778 if (elapsed < repeatingDurationEnd && repeatingDurationEnd < m_intervalEnd && repeatingDurationEnd.isFinite())
00779 return repeatingDurationEnd;
00780 return m_intervalEnd;
00781 }
00782 return elapsed + 0.025;
00783 }
00784 return m_intervalBegin >= elapsed ? m_intervalBegin : SMILTime::unresolved();
00785 }
00786
00787 SVGSMILElement::ActiveState SVGSMILElement::determineActiveState(SMILTime elapsed) const
00788 {
00789 if (elapsed >= m_intervalBegin && elapsed < m_intervalEnd)
00790 return Active;
00791
00792 if (m_activeState == Active)
00793 return fill() == FillFreeze ? Frozen : Inactive;
00794
00795 return m_activeState;
00796 }
00797
00798 bool SVGSMILElement::isContributing(SMILTime elapsed) const
00799 {
00800
00801 return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_intervalBegin + repeatingDuration())) || m_activeState == Frozen;
00802 }
00803
00804 void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement)
00805 {
00806 ASSERT(m_timeContainer);
00807 ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
00808
00809 if (!m_conditionsConnected)
00810 connectConditions();
00811
00812 if (!m_intervalBegin.isFinite()) {
00813 ASSERT(m_activeState == Inactive);
00814 m_nextProgressTime = SMILTime::unresolved();
00815 return;
00816 }
00817
00818 if (elapsed < m_intervalBegin) {
00819 ASSERT(m_activeState != Active);
00820 if (m_activeState == Frozen && resultElement)
00821 updateAnimation(m_lastPercent, m_lastRepeat, resultElement);
00822 m_nextProgressTime = m_intervalBegin;
00823 return;
00824 }
00825
00826 m_previousIntervalBegin = m_intervalBegin;
00827
00828 if (m_activeState == Inactive) {
00829 m_isWaitingForFirstInterval = false;
00830 m_activeState = Active;
00831 startedActiveInterval();
00832 }
00833
00834 unsigned repeat;
00835 float percent = calculateAnimationPercentAndRepeat(elapsed, repeat);
00836
00837 checkRestart(elapsed);
00838
00839 ActiveState oldActiveState = m_activeState;
00840 m_activeState = determineActiveState(elapsed);
00841
00842 if (isContributing(elapsed)) {
00843 if (resultElement)
00844 updateAnimation(percent, repeat, resultElement);
00845 m_lastPercent = percent;
00846 m_lastRepeat = repeat;
00847 }
00848
00849 if (oldActiveState == Active && m_activeState != Active)
00850 endedActiveInterval();
00851
00852 m_nextProgressTime = calculateNextProgressTime(elapsed);
00853 }
00854
00855 void SVGSMILElement::notifyDependentsIntervalChanged(NewOrExistingInterval newOrExisting)
00856 {
00857 ASSERT(m_intervalBegin.isFinite());
00858 static HashSet<SVGSMILElement*> loopBreaker;
00859 if (loopBreaker.contains(this))
00860 return;
00861 loopBreaker.add(this);
00862
00863 TimeDependentSet::iterator end = m_timeDependents.end();
00864 for (TimeDependentSet::iterator it = m_timeDependents.begin(); it != end; ++it) {
00865 SVGSMILElement* dependent = *it;
00866 dependent->createInstanceTimesFromSyncbase(this, newOrExisting);
00867 }
00868
00869 loopBreaker.remove(this);
00870 }
00871
00872 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval newOrExisting)
00873 {
00874
00875
00876 for (unsigned n = 0; n < m_conditions.size(); ++n) {
00877 Condition& condition = m_conditions[n];
00878 if (condition.m_type == Condition::Syncbase && condition.m_syncbase == syncbase) {
00879 ASSERT(condition.m_name == "begin" || condition.m_name == "end");
00880
00881 SMILTime time = 0;
00882 if (condition.m_name == "begin")
00883 time = syncbase->m_intervalBegin + condition.m_offset;
00884 else
00885 time = syncbase->m_intervalEnd + condition.m_offset;
00886 ASSERT(time.isFinite());
00887 if (condition.m_beginOrEnd == Begin)
00888 addBeginTime(time);
00889 else
00890 addEndTime(time);
00891 }
00892 }
00893 }
00894
00895 void SVGSMILElement::addTimeDependent(SVGSMILElement* animation)
00896 {
00897 m_timeDependents.add(animation);
00898 if (m_intervalBegin.isFinite())
00899 animation->createInstanceTimesFromSyncbase(this, NewInterval);
00900 }
00901
00902 void SVGSMILElement::removeTimeDependent(SVGSMILElement* animation)
00903 {
00904 m_timeDependents.remove(animation);
00905 }
00906
00907 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition)
00908 {
00909 if (condition->m_beginOrEnd == Begin)
00910 addBeginTime(elapsed() + condition->m_offset);
00911 else
00912 addEndTime(elapsed() + condition->m_offset);
00913 }
00914
00915 void SVGSMILElement::beginByLinkActivation()
00916 {
00917 addBeginTime(elapsed());
00918 }
00919
00920 }
00921
00922 #endif
00923