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 #include "config.h" 27 #include "core/svg/animation/SVGSMILElement.h" 28 29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 30 #include "bindings/core/v8/ScriptEventListener.h" 31 #include "core/XLinkNames.h" 32 #include "core/dom/Document.h" 33 #include "core/events/Event.h" 34 #include "core/events/EventListener.h" 35 #include "core/events/EventSender.h" 36 #include "core/frame/UseCounter.h" 37 #include "core/svg/SVGDocumentExtensions.h" 38 #include "core/svg/SVGSVGElement.h" 39 #include "core/svg/SVGURIReference.h" 40 #include "core/svg/animation/SMILTimeContainer.h" 41 #include "platform/FloatConversion.h" 42 #include "wtf/MathExtras.h" 43 #include "wtf/StdLibExtras.h" 44 #include "wtf/Vector.h" 45 46 namespace blink { 47 48 class RepeatEvent FINAL : public Event { 49 public: 50 static PassRefPtrWillBeRawPtr<RepeatEvent> create(const AtomicString& type, int repeat) 51 { 52 return adoptRefWillBeNoop(new RepeatEvent(type, false, false, repeat)); 53 } 54 55 virtual ~RepeatEvent() { } 56 57 int repeat() const { return m_repeat; } 58 59 virtual void trace(Visitor* visitor) OVERRIDE 60 { 61 Event::trace(visitor); 62 } 63 64 protected: 65 RepeatEvent(const AtomicString& type, bool canBubble, bool cancelable, int repeat = -1) 66 : Event(type, canBubble, cancelable) 67 , m_repeat(repeat) 68 { 69 } 70 71 private: 72 int m_repeat; 73 }; 74 75 inline RepeatEvent* toRepeatEvent(Event* event) 76 { 77 ASSERT_WITH_SECURITY_IMPLICATION(!event || event->type() == "repeatn"); 78 return static_cast<RepeatEvent*>(event); 79 } 80 81 static SMILEventSender& smilEndEventSender() 82 { 83 DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::endEvent)); 84 return sender; 85 } 86 87 static SMILEventSender& smilBeginEventSender() 88 { 89 DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::beginEvent)); 90 return sender; 91 } 92 93 static SMILEventSender& smilRepeatEventSender() 94 { 95 DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::repeatEvent)); 96 return sender; 97 } 98 99 static SMILEventSender& smilRepeatNEventSender() 100 { 101 DEFINE_STATIC_LOCAL(SMILEventSender, sender, (AtomicString("repeatn", AtomicString::ConstructFromLiteral))); 102 return sender; 103 } 104 105 // This is used for duration type time values that can't be negative. 106 static const double invalidCachedTime = -1.; 107 108 class ConditionEventListener FINAL : public EventListener { 109 public: 110 static PassRefPtr<ConditionEventListener> create(SVGSMILElement* animation, SVGSMILElement::Condition* condition) 111 { 112 return adoptRef(new ConditionEventListener(animation, condition)); 113 } 114 115 static const ConditionEventListener* cast(const EventListener* listener) 116 { 117 return listener->type() == ConditionEventListenerType 118 ? static_cast<const ConditionEventListener*>(listener) 119 : 0; 120 } 121 122 virtual bool operator==(const EventListener& other) OVERRIDE; 123 124 void disconnectAnimation() 125 { 126 m_animation = 0; 127 } 128 129 private: 130 ConditionEventListener(SVGSMILElement* animation, SVGSMILElement::Condition* condition) 131 : EventListener(ConditionEventListenerType) 132 , m_animation(animation) 133 , m_condition(condition) 134 { 135 } 136 137 virtual void handleEvent(ExecutionContext*, Event*) OVERRIDE; 138 139 SVGSMILElement* m_animation; 140 SVGSMILElement::Condition* m_condition; 141 }; 142 143 bool ConditionEventListener::operator==(const EventListener& listener) 144 { 145 if (const ConditionEventListener* conditionEventListener = ConditionEventListener::cast(&listener)) 146 return m_animation == conditionEventListener->m_animation && m_condition == conditionEventListener->m_condition; 147 return false; 148 } 149 150 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event) 151 { 152 if (!m_animation) 153 return; 154 m_animation->handleConditionEvent(event, m_condition); 155 } 156 157 void SVGSMILElement::Condition::setEventListener(PassRefPtr<ConditionEventListener> eventListener) 158 { 159 m_eventListener = eventListener; 160 } 161 162 SVGSMILElement::Condition::Condition(Type type, BeginOrEnd beginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeat) 163 : m_type(type) 164 , m_beginOrEnd(beginOrEnd) 165 , m_baseID(baseID) 166 , m_name(name) 167 , m_offset(offset) 168 , m_repeat(repeat) 169 { 170 } 171 172 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document& doc) 173 : SVGElement(tagName, doc) 174 , SVGTests(this) 175 , m_attributeName(anyQName()) 176 , m_targetElement(nullptr) 177 , m_syncBaseConditionsConnected(false) 178 , m_hasEndEventConditions(false) 179 , m_isWaitingForFirstInterval(true) 180 , m_interval(SMILInterval(SMILTime::unresolved(), SMILTime::unresolved())) 181 , m_previousIntervalBegin(SMILTime::unresolved()) 182 , m_activeState(Inactive) 183 , m_lastPercent(0) 184 , m_lastRepeat(0) 185 , m_nextProgressTime(0) 186 , m_documentOrderIndex(0) 187 , m_cachedDur(invalidCachedTime) 188 , m_cachedRepeatDur(invalidCachedTime) 189 , m_cachedRepeatCount(invalidCachedTime) 190 , m_cachedMin(invalidCachedTime) 191 , m_cachedMax(invalidCachedTime) 192 { 193 resolveFirstInterval(); 194 } 195 196 SVGSMILElement::~SVGSMILElement() 197 { 198 #if !ENABLE(OILPAN) 199 clearResourceAndEventBaseReferences(); 200 #endif 201 smilEndEventSender().cancelEvent(this); 202 smilBeginEventSender().cancelEvent(this); 203 smilRepeatEventSender().cancelEvent(this); 204 smilRepeatNEventSender().cancelEvent(this); 205 #if !ENABLE(OILPAN) 206 clearConditions(); 207 208 if (m_timeContainer && m_targetElement && hasValidAttributeName()) 209 m_timeContainer->unschedule(this, m_targetElement, m_attributeName); 210 #endif 211 } 212 213 void SVGSMILElement::clearResourceAndEventBaseReferences() 214 { 215 removeAllOutgoingReferences(); 216 } 217 218 void SVGSMILElement::clearConditions() 219 { 220 disconnectSyncBaseConditions(); 221 disconnectEventBaseConditions(); 222 m_conditions.clear(); 223 } 224 225 void SVGSMILElement::buildPendingResource() 226 { 227 clearResourceAndEventBaseReferences(); 228 229 if (!inDocument()) { 230 // Reset the target element if we are no longer in the document. 231 setTargetElement(0); 232 return; 233 } 234 235 AtomicString id; 236 AtomicString href = getAttribute(XLinkNames::hrefAttr); 237 Element* target; 238 if (href.isEmpty()) 239 target = parentNode() && parentNode()->isElementNode() ? toElement(parentNode()) : 0; 240 else 241 target = SVGURIReference::targetElementFromIRIString(href, treeScope(), &id); 242 SVGElement* svgTarget = target && target->isSVGElement() ? toSVGElement(target) : 0; 243 244 if (svgTarget && !svgTarget->inDocument()) 245 svgTarget = 0; 246 247 if (svgTarget != targetElement()) 248 setTargetElement(svgTarget); 249 250 if (!svgTarget) { 251 // Do not register as pending if we are already pending this resource. 252 if (document().accessSVGExtensions().isElementPendingResource(this, id)) 253 return; 254 255 if (!id.isEmpty()) { 256 document().accessSVGExtensions().addPendingResource(id, this); 257 ASSERT(hasPendingResources()); 258 } 259 } else { 260 // Register us with the target in the dependencies map. Any change of hrefElement 261 // that leads to relayout/repainting now informs us, so we can react to it. 262 addReferenceTo(svgTarget); 263 } 264 connectEventBaseConditions(); 265 } 266 267 static inline QualifiedName constructQualifiedName(const SVGElement* svgElement, const AtomicString& attributeName) 268 { 269 ASSERT(svgElement); 270 if (attributeName.isEmpty()) 271 return anyQName(); 272 if (!attributeName.contains(':')) 273 return QualifiedName(nullAtom, attributeName, nullAtom); 274 275 AtomicString prefix; 276 AtomicString localName; 277 if (!Document::parseQualifiedName(attributeName, prefix, localName, IGNORE_EXCEPTION)) 278 return anyQName(); 279 280 const AtomicString& namespaceURI = svgElement->lookupNamespaceURI(prefix); 281 if (namespaceURI.isEmpty()) 282 return anyQName(); 283 284 return QualifiedName(nullAtom, localName, namespaceURI); 285 } 286 287 static inline void clearTimesWithDynamicOrigins(Vector<SMILTimeWithOrigin>& timeList) 288 { 289 for (int i = timeList.size() - 1; i >= 0; --i) { 290 if (timeList[i].originIsScript()) 291 timeList.remove(i); 292 } 293 } 294 295 void SVGSMILElement::reset() 296 { 297 clearAnimatedType(m_targetElement); 298 299 m_activeState = Inactive; 300 m_isWaitingForFirstInterval = true; 301 m_interval.begin = SMILTime::unresolved(); 302 m_interval.end = SMILTime::unresolved(); 303 m_previousIntervalBegin = SMILTime::unresolved(); 304 m_lastPercent = 0; 305 m_lastRepeat = 0; 306 m_nextProgressTime = 0; 307 resolveFirstInterval(); 308 } 309 310 Node::InsertionNotificationRequest SVGSMILElement::insertedInto(ContainerNode* rootParent) 311 { 312 SVGElement::insertedInto(rootParent); 313 314 if (!rootParent->inDocument()) 315 return InsertionDone; 316 317 UseCounter::count(document(), UseCounter::SVGSMILElementInDocument); 318 319 setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr))); 320 SVGSVGElement* owner = ownerSVGElement(); 321 if (!owner) 322 return InsertionDone; 323 324 m_timeContainer = owner->timeContainer(); 325 ASSERT(m_timeContainer); 326 m_timeContainer->setDocumentOrderIndexesDirty(); 327 328 // "If no attribute is present, the default begin value (an offset-value of 0) must be evaluated." 329 if (!fastHasAttribute(SVGNames::beginAttr)) 330 m_beginTimes.append(SMILTimeWithOrigin()); 331 332 if (m_isWaitingForFirstInterval) 333 resolveFirstInterval(); 334 335 if (m_timeContainer) 336 m_timeContainer->notifyIntervalsChanged(); 337 338 buildPendingResource(); 339 340 return InsertionDone; 341 } 342 343 void SVGSMILElement::removedFrom(ContainerNode* rootParent) 344 { 345 if (rootParent->inDocument()) { 346 clearResourceAndEventBaseReferences(); 347 clearConditions(); 348 setTargetElement(0); 349 setAttributeName(anyQName()); 350 animationAttributeChanged(); 351 m_timeContainer = nullptr; 352 } 353 354 SVGElement::removedFrom(rootParent); 355 } 356 357 bool SVGSMILElement::hasValidAttributeName() 358 { 359 return attributeName() != anyQName(); 360 } 361 362 SMILTime SVGSMILElement::parseOffsetValue(const String& data) 363 { 364 bool ok; 365 double result = 0; 366 String parse = data.stripWhiteSpace(); 367 if (parse.endsWith('h')) 368 result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60; 369 else if (parse.endsWith("min")) 370 result = parse.left(parse.length() - 3).toDouble(&ok) * 60; 371 else if (parse.endsWith("ms")) 372 result = parse.left(parse.length() - 2).toDouble(&ok) / 1000; 373 else if (parse.endsWith('s')) 374 result = parse.left(parse.length() - 1).toDouble(&ok); 375 else 376 result = parse.toDouble(&ok); 377 if (!ok || !SMILTime(result).isFinite()) 378 return SMILTime::unresolved(); 379 return result; 380 } 381 382 SMILTime SVGSMILElement::parseClockValue(const String& data) 383 { 384 if (data.isNull()) 385 return SMILTime::unresolved(); 386 387 String parse = data.stripWhiteSpace(); 388 389 DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite", AtomicString::ConstructFromLiteral)); 390 if (parse == indefiniteValue) 391 return SMILTime::indefinite(); 392 393 double result = 0; 394 bool ok; 395 size_t doublePointOne = parse.find(':'); 396 size_t doublePointTwo = parse.find(':', doublePointOne + 1); 397 if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) { 398 result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60; 399 if (!ok) 400 return SMILTime::unresolved(); 401 result += parse.substring(3, 2).toUIntStrict(&ok) * 60; 402 if (!ok) 403 return SMILTime::unresolved(); 404 result += parse.substring(6).toDouble(&ok); 405 } else if (doublePointOne == 2 && doublePointTwo == kNotFound && parse.length() >= 5) { 406 result += parse.substring(0, 2).toUIntStrict(&ok) * 60; 407 if (!ok) 408 return SMILTime::unresolved(); 409 result += parse.substring(3).toDouble(&ok); 410 } else 411 return parseOffsetValue(parse); 412 413 if (!ok || !SMILTime(result).isFinite()) 414 return SMILTime::unresolved(); 415 return result; 416 } 417 418 static void sortTimeList(Vector<SMILTimeWithOrigin>& timeList) 419 { 420 std::sort(timeList.begin(), timeList.end()); 421 } 422 423 bool SVGSMILElement::parseCondition(const String& value, BeginOrEnd beginOrEnd) 424 { 425 String parseString = value.stripWhiteSpace(); 426 427 double sign = 1.; 428 bool ok; 429 size_t pos = parseString.find('+'); 430 if (pos == kNotFound) { 431 pos = parseString.find('-'); 432 if (pos != kNotFound) 433 sign = -1.; 434 } 435 String conditionString; 436 SMILTime offset = 0; 437 if (pos == kNotFound) 438 conditionString = parseString; 439 else { 440 conditionString = parseString.left(pos).stripWhiteSpace(); 441 String offsetString = parseString.substring(pos + 1).stripWhiteSpace(); 442 offset = parseOffsetValue(offsetString); 443 if (offset.isUnresolved()) 444 return false; 445 offset = offset * sign; 446 } 447 if (conditionString.isEmpty()) 448 return false; 449 pos = conditionString.find('.'); 450 451 String baseID; 452 String nameString; 453 if (pos == kNotFound) 454 nameString = conditionString; 455 else { 456 baseID = conditionString.left(pos); 457 nameString = conditionString.substring(pos + 1); 458 } 459 if (nameString.isEmpty()) 460 return false; 461 462 Condition::Type type; 463 int repeat = -1; 464 if (nameString.startsWith("repeat(") && nameString.endsWith(')')) { 465 repeat = nameString.substring(7, nameString.length() - 8).toUIntStrict(&ok); 466 if (!ok) 467 return false; 468 nameString = "repeatn"; 469 type = Condition::EventBase; 470 } else if (nameString == "begin" || nameString == "end") { 471 if (baseID.isEmpty()) 472 return false; 473 type = Condition::Syncbase; 474 } else if (nameString.startsWith("accesskey(")) { 475 // FIXME: accesskey() support. 476 type = Condition::AccessKey; 477 } else 478 type = Condition::EventBase; 479 480 m_conditions.append(Condition::create(type, beginOrEnd, baseID, nameString, offset, repeat)); 481 482 if (type == Condition::EventBase && beginOrEnd == End) 483 m_hasEndEventConditions = true; 484 485 return true; 486 } 487 488 void SVGSMILElement::parseBeginOrEnd(const String& parseString, BeginOrEnd beginOrEnd) 489 { 490 Vector<SMILTimeWithOrigin>& timeList = beginOrEnd == Begin ? m_beginTimes : m_endTimes; 491 if (beginOrEnd == End) 492 m_hasEndEventConditions = false; 493 HashSet<SMILTime> existing; 494 for (unsigned n = 0; n < timeList.size(); ++n) { 495 if (!timeList[n].time().isUnresolved()) 496 existing.add(timeList[n].time().value()); 497 } 498 Vector<String> splitString; 499 parseString.split(';', splitString); 500 for (unsigned n = 0; n < splitString.size(); ++n) { 501 SMILTime value = parseClockValue(splitString[n]); 502 if (value.isUnresolved()) 503 parseCondition(splitString[n], beginOrEnd); 504 else if (!existing.contains(value.value())) 505 timeList.append(SMILTimeWithOrigin(value, SMILTimeWithOrigin::ParserOrigin)); 506 } 507 sortTimeList(timeList); 508 } 509 510 bool SVGSMILElement::isSupportedAttribute(const QualifiedName& attrName) 511 { 512 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 513 if (supportedAttributes.isEmpty()) { 514 SVGTests::addSupportedAttributes(supportedAttributes); 515 supportedAttributes.add(SVGNames::beginAttr); 516 supportedAttributes.add(SVGNames::endAttr); 517 supportedAttributes.add(SVGNames::durAttr); 518 supportedAttributes.add(SVGNames::repeatDurAttr); 519 supportedAttributes.add(SVGNames::repeatCountAttr); 520 supportedAttributes.add(SVGNames::minAttr); 521 supportedAttributes.add(SVGNames::maxAttr); 522 supportedAttributes.add(SVGNames::attributeNameAttr); 523 supportedAttributes.add(XLinkNames::hrefAttr); 524 } 525 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 526 } 527 528 void SVGSMILElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 529 { 530 if (name == SVGNames::beginAttr) { 531 if (!m_conditions.isEmpty()) { 532 clearConditions(); 533 parseBeginOrEnd(fastGetAttribute(SVGNames::endAttr), End); 534 } 535 parseBeginOrEnd(value.string(), Begin); 536 if (inDocument()) 537 connectSyncBaseConditions(); 538 } else if (name == SVGNames::endAttr) { 539 if (!m_conditions.isEmpty()) { 540 clearConditions(); 541 parseBeginOrEnd(fastGetAttribute(SVGNames::beginAttr), Begin); 542 } 543 parseBeginOrEnd(value.string(), End); 544 if (inDocument()) 545 connectSyncBaseConditions(); 546 } else if (name == SVGNames::onbeginAttr) { 547 setAttributeEventListener(EventTypeNames::beginEvent, createAttributeEventListener(this, name, value, eventParameterName())); 548 } else if (name == SVGNames::onendAttr) { 549 setAttributeEventListener(EventTypeNames::endEvent, createAttributeEventListener(this, name, value, eventParameterName())); 550 } else if (name == SVGNames::onrepeatAttr) { 551 setAttributeEventListener(EventTypeNames::repeatEvent, createAttributeEventListener(this, name, value, eventParameterName())); 552 } else { 553 SVGElement::parseAttributeNew(name, value); 554 } 555 } 556 557 void SVGSMILElement::svgAttributeChanged(const QualifiedName& attrName) 558 { 559 if (!isSupportedAttribute(attrName)) { 560 SVGElement::svgAttributeChanged(attrName); 561 return; 562 } 563 564 if (attrName == SVGNames::durAttr) 565 m_cachedDur = invalidCachedTime; 566 else if (attrName == SVGNames::repeatDurAttr) 567 m_cachedRepeatDur = invalidCachedTime; 568 else if (attrName == SVGNames::repeatCountAttr) 569 m_cachedRepeatCount = invalidCachedTime; 570 else if (attrName == SVGNames::minAttr) 571 m_cachedMin = invalidCachedTime; 572 else if (attrName == SVGNames::maxAttr) 573 m_cachedMax = invalidCachedTime; 574 else if (attrName == SVGNames::attributeNameAttr) 575 setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr))); 576 else if (attrName.matches(XLinkNames::hrefAttr)) { 577 SVGElement::InvalidationGuard invalidationGuard(this); 578 buildPendingResource(); 579 if (m_targetElement) 580 clearAnimatedType(m_targetElement); 581 } else if (inDocument()) { 582 if (attrName == SVGNames::beginAttr) 583 beginListChanged(elapsed()); 584 else if (attrName == SVGNames::endAttr) 585 endListChanged(elapsed()); 586 } 587 588 animationAttributeChanged(); 589 } 590 591 inline SVGElement* SVGSMILElement::eventBaseFor(const Condition& condition) 592 { 593 Element* eventBase = condition.baseID().isEmpty() ? targetElement() : treeScope().getElementById(AtomicString(condition.baseID())); 594 if (eventBase && eventBase->isSVGElement()) 595 return toSVGElement(eventBase); 596 return 0; 597 } 598 599 void SVGSMILElement::connectSyncBaseConditions() 600 { 601 if (m_syncBaseConditionsConnected) 602 disconnectSyncBaseConditions(); 603 m_syncBaseConditionsConnected = true; 604 for (unsigned n = 0; n < m_conditions.size(); ++n) { 605 Condition* condition = m_conditions[n].get(); 606 if (condition->type() == Condition::Syncbase) { 607 ASSERT(!condition->baseID().isEmpty()); 608 Element* element = treeScope().getElementById(AtomicString(condition->baseID())); 609 if (!element || !isSVGSMILElement(*element)) { 610 condition->setSyncBase(0); 611 continue; 612 } 613 SVGSMILElement* svgSMILElement = toSVGSMILElement(element); 614 condition->setSyncBase(svgSMILElement); 615 svgSMILElement->addSyncBaseDependent(this); 616 } 617 } 618 } 619 620 void SVGSMILElement::disconnectSyncBaseConditions() 621 { 622 if (!m_syncBaseConditionsConnected) 623 return; 624 m_syncBaseConditionsConnected = false; 625 for (unsigned n = 0; n < m_conditions.size(); ++n) { 626 Condition* condition = m_conditions[n].get(); 627 if (condition->type() == Condition::Syncbase) { 628 if (condition->syncBase()) 629 condition->syncBase()->removeSyncBaseDependent(this); 630 condition->setSyncBase(0); 631 } 632 } 633 } 634 635 void SVGSMILElement::connectEventBaseConditions() 636 { 637 disconnectEventBaseConditions(); 638 for (unsigned n = 0; n < m_conditions.size(); ++n) { 639 Condition* condition = m_conditions[n].get(); 640 if (condition->type() == Condition::EventBase) { 641 ASSERT(!condition->syncBase()); 642 SVGElement* eventBase = eventBaseFor(*condition); 643 if (!eventBase) { 644 if (!condition->baseID().isEmpty() && !document().accessSVGExtensions().isElementPendingResource(this, AtomicString(condition->baseID()))) 645 document().accessSVGExtensions().addPendingResource(AtomicString(condition->baseID()), this); 646 continue; 647 } 648 ASSERT(!condition->eventListener()); 649 condition->setEventListener(ConditionEventListener::create(this, condition)); 650 eventBase->addEventListener(AtomicString(condition->name()), condition->eventListener(), false); 651 addReferenceTo(eventBase); 652 } 653 } 654 } 655 656 void SVGSMILElement::disconnectEventBaseConditions() 657 { 658 for (unsigned n = 0; n < m_conditions.size(); ++n) { 659 Condition* condition = m_conditions[n].get(); 660 if (condition->type() == Condition::EventBase) { 661 ASSERT(!condition->syncBase()); 662 if (!condition->eventListener()) 663 continue; 664 // Note: It's a memory optimization to try to remove our condition 665 // event listener, but it's not guaranteed to work, since we have 666 // no guarantee that eventBaseFor() will be able to find our condition's 667 // original eventBase. So, we also have to disconnect ourselves from 668 // our condition event listener, in case it later fires. 669 SVGElement* eventBase = eventBaseFor(*condition); 670 if (eventBase) 671 eventBase->removeEventListener(AtomicString(condition->name()), condition->eventListener(), false); 672 condition->eventListener()->disconnectAnimation(); 673 condition->setEventListener(nullptr); 674 } 675 } 676 } 677 678 void SVGSMILElement::setAttributeName(const QualifiedName& attributeName) 679 { 680 if (m_timeContainer && m_targetElement && m_attributeName != attributeName) { 681 if (hasValidAttributeName()) 682 m_timeContainer->unschedule(this, m_targetElement, m_attributeName); 683 m_attributeName = attributeName; 684 if (hasValidAttributeName()) 685 m_timeContainer->schedule(this, m_targetElement, m_attributeName); 686 } else 687 m_attributeName = attributeName; 688 689 // Only clear the animated type, if we had a target before. 690 if (m_targetElement) 691 clearAnimatedType(m_targetElement); 692 } 693 694 void SVGSMILElement::setTargetElement(SVGElement* target) 695 { 696 if (m_timeContainer && hasValidAttributeName()) { 697 if (m_targetElement) 698 m_timeContainer->unschedule(this, m_targetElement, m_attributeName); 699 if (target) 700 m_timeContainer->schedule(this, target, m_attributeName); 701 } 702 703 if (m_targetElement) { 704 // Clear values that may depend on the previous target. 705 clearAnimatedType(m_targetElement); 706 disconnectSyncBaseConditions(); 707 } 708 709 // If the animation state is not Inactive, always reset to a clear state before leaving the old target element. 710 if (m_activeState != Inactive) 711 endedActiveInterval(); 712 713 m_targetElement = target; 714 } 715 716 SMILTime SVGSMILElement::elapsed() const 717 { 718 return m_timeContainer ? m_timeContainer->elapsed() : 0; 719 } 720 721 bool SVGSMILElement::isFrozen() const 722 { 723 return m_activeState == Frozen; 724 } 725 726 SVGSMILElement::Restart SVGSMILElement::restart() const 727 { 728 DEFINE_STATIC_LOCAL(const AtomicString, never, ("never", AtomicString::ConstructFromLiteral)); 729 DEFINE_STATIC_LOCAL(const AtomicString, whenNotActive, ("whenNotActive", AtomicString::ConstructFromLiteral)); 730 const AtomicString& value = fastGetAttribute(SVGNames::restartAttr); 731 if (value == never) 732 return RestartNever; 733 if (value == whenNotActive) 734 return RestartWhenNotActive; 735 return RestartAlways; 736 } 737 738 SVGSMILElement::FillMode SVGSMILElement::fill() const 739 { 740 DEFINE_STATIC_LOCAL(const AtomicString, freeze, ("freeze", AtomicString::ConstructFromLiteral)); 741 const AtomicString& value = fastGetAttribute(SVGNames::fillAttr); 742 return value == freeze ? FillFreeze : FillRemove; 743 } 744 745 SMILTime SVGSMILElement::dur() const 746 { 747 if (m_cachedDur != invalidCachedTime) 748 return m_cachedDur; 749 const AtomicString& value = fastGetAttribute(SVGNames::durAttr); 750 SMILTime clockValue = parseClockValue(value); 751 return m_cachedDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue; 752 } 753 754 SMILTime SVGSMILElement::repeatDur() const 755 { 756 if (m_cachedRepeatDur != invalidCachedTime) 757 return m_cachedRepeatDur; 758 const AtomicString& value = fastGetAttribute(SVGNames::repeatDurAttr); 759 SMILTime clockValue = parseClockValue(value); 760 m_cachedRepeatDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue; 761 return m_cachedRepeatDur; 762 } 763 764 // So a count is not really a time but let just all pretend we did not notice. 765 SMILTime SVGSMILElement::repeatCount() const 766 { 767 if (m_cachedRepeatCount != invalidCachedTime) 768 return m_cachedRepeatCount; 769 SMILTime computedRepeatCount = SMILTime::unresolved(); 770 const AtomicString& value = fastGetAttribute(SVGNames::repeatCountAttr); 771 if (!value.isNull()) { 772 DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite", AtomicString::ConstructFromLiteral)); 773 if (value == indefiniteValue) { 774 computedRepeatCount = SMILTime::indefinite(); 775 } else { 776 bool ok; 777 double result = value.toDouble(&ok); 778 if (ok && result > 0) 779 computedRepeatCount = result; 780 } 781 } 782 m_cachedRepeatCount = computedRepeatCount; 783 return m_cachedRepeatCount; 784 } 785 786 SMILTime SVGSMILElement::maxValue() const 787 { 788 if (m_cachedMax != invalidCachedTime) 789 return m_cachedMax; 790 const AtomicString& value = fastGetAttribute(SVGNames::maxAttr); 791 SMILTime result = parseClockValue(value); 792 return m_cachedMax = (result.isUnresolved() || result <= 0) ? SMILTime::indefinite() : result; 793 } 794 795 SMILTime SVGSMILElement::minValue() const 796 { 797 if (m_cachedMin != invalidCachedTime) 798 return m_cachedMin; 799 const AtomicString& value = fastGetAttribute(SVGNames::minAttr); 800 SMILTime result = parseClockValue(value); 801 return m_cachedMin = (result.isUnresolved() || result < 0) ? 0 : result; 802 } 803 804 SMILTime SVGSMILElement::simpleDuration() const 805 { 806 return std::min(dur(), SMILTime::indefinite()); 807 } 808 809 void SVGSMILElement::addBeginTime(SMILTime eventTime, SMILTime beginTime, SMILTimeWithOrigin::Origin origin) 810 { 811 m_beginTimes.append(SMILTimeWithOrigin(beginTime, origin)); 812 sortTimeList(m_beginTimes); 813 beginListChanged(eventTime); 814 } 815 816 void SVGSMILElement::addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin origin) 817 { 818 m_endTimes.append(SMILTimeWithOrigin(endTime, origin)); 819 sortTimeList(m_endTimes); 820 endListChanged(eventTime); 821 } 822 823 inline bool compareTimes(const SMILTimeWithOrigin& left, const SMILTimeWithOrigin& right) 824 { 825 return left.time() < right.time(); 826 } 827 828 SMILTime SVGSMILElement::findInstanceTime(BeginOrEnd beginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const 829 { 830 const Vector<SMILTimeWithOrigin>& list = beginOrEnd == Begin ? m_beginTimes : m_endTimes; 831 int sizeOfList = list.size(); 832 833 if (!sizeOfList) 834 return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite(); 835 836 const SMILTimeWithOrigin dummyTimeWithOrigin(minimumTime, SMILTimeWithOrigin::ParserOrigin); 837 const SMILTimeWithOrigin* result = std::lower_bound(list.begin(), list.end(), dummyTimeWithOrigin, compareTimes); 838 int indexOfResult = result - list.begin(); 839 if (indexOfResult == sizeOfList) 840 return SMILTime::unresolved(); 841 const SMILTime& currentTime = list[indexOfResult].time(); 842 843 // The special value "indefinite" does not yield an instance time in the begin list. 844 if (currentTime.isIndefinite() && beginOrEnd == Begin) 845 return SMILTime::unresolved(); 846 847 if (currentTime > minimumTime) 848 return currentTime; 849 850 ASSERT(currentTime == minimumTime); 851 if (equalsMinimumOK) 852 return currentTime; 853 854 // If the equals is not accepted, return the next bigger item in the list. 855 SMILTime nextTime = currentTime; 856 while (indexOfResult < sizeOfList - 1) { 857 nextTime = list[indexOfResult + 1].time(); 858 if (nextTime > minimumTime) 859 return nextTime; 860 ++indexOfResult; 861 } 862 863 return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite(); 864 } 865 866 SMILTime SVGSMILElement::repeatingDuration() const 867 { 868 // Computing the active duration 869 // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur 870 SMILTime repeatCount = this->repeatCount(); 871 SMILTime repeatDur = this->repeatDur(); 872 SMILTime simpleDuration = this->simpleDuration(); 873 if (!simpleDuration || (repeatDur.isUnresolved() && repeatCount.isUnresolved())) 874 return simpleDuration; 875 repeatDur = std::min(repeatDur, SMILTime::indefinite()); 876 SMILTime repeatCountDuration = simpleDuration * repeatCount; 877 if (!repeatCountDuration.isUnresolved()) 878 return std::min(repeatDur, repeatCountDuration); 879 return repeatDur; 880 } 881 882 SMILTime SVGSMILElement::resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const 883 { 884 // Computing the active duration 885 // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur 886 SMILTime preliminaryActiveDuration; 887 if (!resolvedEnd.isUnresolved() && dur().isUnresolved() && repeatDur().isUnresolved() && repeatCount().isUnresolved()) 888 preliminaryActiveDuration = resolvedEnd - resolvedBegin; 889 else if (!resolvedEnd.isFinite()) 890 preliminaryActiveDuration = repeatingDuration(); 891 else 892 preliminaryActiveDuration = std::min(repeatingDuration(), resolvedEnd - resolvedBegin); 893 894 SMILTime minValue = this->minValue(); 895 SMILTime maxValue = this->maxValue(); 896 if (minValue > maxValue) { 897 // Ignore both. 898 // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#MinMax 899 minValue = 0; 900 maxValue = SMILTime::indefinite(); 901 } 902 return resolvedBegin + std::min(maxValue, std::max(minValue, preliminaryActiveDuration)); 903 } 904 905 SMILInterval SVGSMILElement::resolveInterval(ResolveInterval resolveIntervalType) const 906 { 907 bool first = resolveIntervalType == FirstInterval; 908 // See the pseudocode in http://www.w3.org/TR/SMIL3/smil-timing.html#q90. 909 SMILTime beginAfter = first ? -std::numeric_limits<double>::infinity() : m_interval.end; 910 SMILTime lastIntervalTempEnd = std::numeric_limits<double>::infinity(); 911 while (true) { 912 bool equalsMinimumOK = !first || m_interval.end > m_interval.begin; 913 SMILTime tempBegin = findInstanceTime(Begin, beginAfter, equalsMinimumOK); 914 if (tempBegin.isUnresolved()) 915 break; 916 SMILTime tempEnd; 917 if (m_endTimes.isEmpty()) 918 tempEnd = resolveActiveEnd(tempBegin, SMILTime::indefinite()); 919 else { 920 tempEnd = findInstanceTime(End, tempBegin, true); 921 if ((first && tempBegin == tempEnd && tempEnd == lastIntervalTempEnd) || (!first && tempEnd == m_interval.end)) 922 tempEnd = findInstanceTime(End, tempBegin, false); 923 if (tempEnd.isUnresolved()) { 924 if (!m_endTimes.isEmpty() && !m_hasEndEventConditions) 925 break; 926 } 927 tempEnd = resolveActiveEnd(tempBegin, tempEnd); 928 } 929 if (!first || (tempEnd > 0 || (!tempBegin.value() && !tempEnd.value()))) 930 return SMILInterval(tempBegin, tempEnd); 931 932 beginAfter = tempEnd; 933 lastIntervalTempEnd = tempEnd; 934 } 935 return SMILInterval(SMILTime::unresolved(), SMILTime::unresolved()); 936 } 937 938 void SVGSMILElement::resolveFirstInterval() 939 { 940 SMILInterval firstInterval = resolveInterval(FirstInterval); 941 ASSERT(!firstInterval.begin.isIndefinite()); 942 943 if (!firstInterval.begin.isUnresolved() && firstInterval != m_interval) { 944 m_interval = firstInterval; 945 notifyDependentsIntervalChanged(); 946 m_nextProgressTime = m_nextProgressTime.isUnresolved() ? m_interval.begin : std::min(m_nextProgressTime, m_interval.begin); 947 948 if (m_timeContainer) 949 m_timeContainer->notifyIntervalsChanged(); 950 } 951 } 952 953 bool SVGSMILElement::resolveNextInterval() 954 { 955 SMILInterval nextInterval = resolveInterval(NextInterval); 956 ASSERT(!nextInterval.begin.isIndefinite()); 957 958 if (!nextInterval.begin.isUnresolved() && nextInterval.begin != m_interval.begin) { 959 m_interval = nextInterval; 960 notifyDependentsIntervalChanged(); 961 m_nextProgressTime = m_nextProgressTime.isUnresolved() ? m_interval.begin : std::min(m_nextProgressTime, m_interval.begin); 962 return true; 963 } 964 965 return false; 966 } 967 968 SMILTime SVGSMILElement::nextProgressTime() const 969 { 970 return m_nextProgressTime; 971 } 972 973 void SVGSMILElement::beginListChanged(SMILTime eventTime) 974 { 975 if (m_isWaitingForFirstInterval) 976 resolveFirstInterval(); 977 else { 978 SMILTime newBegin = findInstanceTime(Begin, eventTime, true); 979 if (newBegin.isFinite() && (m_interval.end <= eventTime || newBegin < m_interval.begin)) { 980 // Begin time changed, re-resolve the interval. 981 SMILTime oldBegin = m_interval.begin; 982 m_interval.end = eventTime; 983 m_interval = resolveInterval(NextInterval); 984 ASSERT(!m_interval.begin.isUnresolved()); 985 if (m_interval.begin != oldBegin) { 986 if (m_activeState == Active && m_interval.begin > eventTime) { 987 m_activeState = determineActiveState(eventTime); 988 if (m_activeState != Active) 989 endedActiveInterval(); 990 } 991 notifyDependentsIntervalChanged(); 992 } 993 } 994 } 995 m_nextProgressTime = elapsed(); 996 997 if (m_timeContainer) 998 m_timeContainer->notifyIntervalsChanged(); 999 } 1000 1001 void SVGSMILElement::endListChanged(SMILTime) 1002 { 1003 SMILTime elapsed = this->elapsed(); 1004 if (m_isWaitingForFirstInterval) { 1005 resolveFirstInterval(); 1006 } else if (elapsed < m_interval.end && m_interval.begin.isFinite()) { 1007 SMILTime newEnd = findInstanceTime(End, m_interval.begin, false); 1008 if (newEnd < m_interval.end) { 1009 newEnd = resolveActiveEnd(m_interval.begin, newEnd); 1010 if (newEnd != m_interval.end) { 1011 m_interval.end = newEnd; 1012 notifyDependentsIntervalChanged(); 1013 } 1014 } 1015 } 1016 m_nextProgressTime = elapsed; 1017 1018 if (m_timeContainer) 1019 m_timeContainer->notifyIntervalsChanged(); 1020 } 1021 1022 SVGSMILElement::RestartedInterval SVGSMILElement::maybeRestartInterval(SMILTime elapsed) 1023 { 1024 ASSERT(!m_isWaitingForFirstInterval); 1025 ASSERT(elapsed >= m_interval.begin); 1026 1027 Restart restart = this->restart(); 1028 if (restart == RestartNever) 1029 return DidNotRestartInterval; 1030 1031 if (elapsed < m_interval.end) { 1032 if (restart != RestartAlways) 1033 return DidNotRestartInterval; 1034 SMILTime nextBegin = findInstanceTime(Begin, m_interval.begin, false); 1035 if (nextBegin < m_interval.end) { 1036 m_interval.end = nextBegin; 1037 notifyDependentsIntervalChanged(); 1038 } 1039 } 1040 1041 if (elapsed >= m_interval.end) { 1042 if (resolveNextInterval() && elapsed >= m_interval.begin) 1043 return DidRestartInterval; 1044 } 1045 return DidNotRestartInterval; 1046 } 1047 1048 void SVGSMILElement::seekToIntervalCorrespondingToTime(SMILTime elapsed) 1049 { 1050 ASSERT(!m_isWaitingForFirstInterval); 1051 ASSERT(elapsed >= m_interval.begin); 1052 1053 // Manually seek from interval to interval, just as if the animation would run regulary. 1054 while (true) { 1055 // Figure out the next value in the begin time list after the current interval begin. 1056 SMILTime nextBegin = findInstanceTime(Begin, m_interval.begin, false); 1057 1058 // If the 'nextBegin' time is unresolved (eg. just one defined interval), we're done seeking. 1059 if (nextBegin.isUnresolved()) 1060 return; 1061 1062 // If the 'nextBegin' time is larger than or equal to the current interval end time, we're done seeking. 1063 // If the 'elapsed' time is smaller than the next begin interval time, we're done seeking. 1064 if (nextBegin < m_interval.end && elapsed >= nextBegin) { 1065 // End current interval, and start a new interval from the 'nextBegin' time. 1066 m_interval.end = nextBegin; 1067 if (!resolveNextInterval()) 1068 break; 1069 continue; 1070 } 1071 1072 // If the desired 'elapsed' time is past the current interval, advance to the next. 1073 if (elapsed >= m_interval.end) { 1074 if (!resolveNextInterval()) 1075 break; 1076 continue; 1077 } 1078 1079 return; 1080 } 1081 } 1082 1083 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const 1084 { 1085 SMILTime simpleDuration = this->simpleDuration(); 1086 repeat = 0; 1087 if (simpleDuration.isIndefinite()) { 1088 repeat = 0; 1089 return 0.f; 1090 } 1091 if (!simpleDuration) { 1092 repeat = 0; 1093 return 1.f; 1094 } 1095 ASSERT(m_interval.begin.isFinite()); 1096 ASSERT(simpleDuration.isFinite()); 1097 SMILTime activeTime = elapsed - m_interval.begin; 1098 SMILTime repeatingDuration = this->repeatingDuration(); 1099 if (elapsed >= m_interval.end || activeTime > repeatingDuration) { 1100 repeat = static_cast<unsigned>(repeatingDuration.value() / simpleDuration.value()); 1101 if (!fmod(repeatingDuration.value(), simpleDuration.value())) 1102 repeat--; 1103 1104 double percent = (m_interval.end.value() - m_interval.begin.value()) / simpleDuration.value(); 1105 percent = percent - floor(percent); 1106 if (percent < std::numeric_limits<float>::epsilon() || 1 - percent < std::numeric_limits<float>::epsilon()) 1107 return 1.0f; 1108 return narrowPrecisionToFloat(percent); 1109 } 1110 repeat = static_cast<unsigned>(activeTime.value() / simpleDuration.value()); 1111 SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value()); 1112 return narrowPrecisionToFloat(simpleTime.value() / simpleDuration.value()); 1113 } 1114 1115 SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed) const 1116 { 1117 if (m_activeState == Active) { 1118 // If duration is indefinite the value does not actually change over time. Same is true for <set>. 1119 SMILTime simpleDuration = this->simpleDuration(); 1120 if (simpleDuration.isIndefinite() || isSVGSetElement(*this)) { 1121 SMILTime repeatingDurationEnd = m_interval.begin + repeatingDuration(); 1122 // We are supposed to do freeze semantics when repeating ends, even if the element is still active. 1123 // Take care that we get a timer callback at that point. 1124 if (elapsed < repeatingDurationEnd && repeatingDurationEnd < m_interval.end && repeatingDurationEnd.isFinite()) 1125 return repeatingDurationEnd; 1126 return m_interval.end; 1127 } 1128 return elapsed + 0.025; 1129 } 1130 return m_interval.begin >= elapsed ? m_interval.begin : SMILTime::unresolved(); 1131 } 1132 1133 SVGSMILElement::ActiveState SVGSMILElement::determineActiveState(SMILTime elapsed) const 1134 { 1135 if (elapsed >= m_interval.begin && elapsed < m_interval.end) 1136 return Active; 1137 1138 return fill() == FillFreeze ? Frozen : Inactive; 1139 } 1140 1141 bool SVGSMILElement::isContributing(SMILTime elapsed) const 1142 { 1143 // Animation does not contribute during the active time if it is past its repeating duration and has fill=remove. 1144 return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_interval.begin + repeatingDuration())) || m_activeState == Frozen; 1145 } 1146 1147 bool SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement, bool seekToTime) 1148 { 1149 ASSERT(resultElement); 1150 ASSERT(m_timeContainer); 1151 ASSERT(m_isWaitingForFirstInterval || m_interval.begin.isFinite()); 1152 1153 if (!m_syncBaseConditionsConnected) 1154 connectSyncBaseConditions(); 1155 1156 if (!m_interval.begin.isFinite()) { 1157 ASSERT(m_activeState == Inactive); 1158 m_nextProgressTime = SMILTime::unresolved(); 1159 return false; 1160 } 1161 1162 if (elapsed < m_interval.begin) { 1163 ASSERT(m_activeState != Active); 1164 bool isFrozen = (m_activeState == Frozen); 1165 if (isFrozen) { 1166 if (this == resultElement) 1167 resetAnimatedType(); 1168 updateAnimation(m_lastPercent, m_lastRepeat, resultElement); 1169 } 1170 m_nextProgressTime = m_interval.begin; 1171 // If the animation is frozen, it's still contributing. 1172 return isFrozen; 1173 } 1174 1175 m_previousIntervalBegin = m_interval.begin; 1176 1177 if (m_isWaitingForFirstInterval) { 1178 m_isWaitingForFirstInterval = false; 1179 resolveFirstInterval(); 1180 } 1181 1182 // This call may obtain a new interval -- never call calculateAnimationPercentAndRepeat() before! 1183 if (seekToTime) { 1184 seekToIntervalCorrespondingToTime(elapsed); 1185 if (elapsed < m_interval.begin) { 1186 // elapsed is not within an interval. 1187 m_nextProgressTime = m_interval.begin; 1188 return false; 1189 } 1190 } 1191 1192 unsigned repeat = 0; 1193 float percent = calculateAnimationPercentAndRepeat(elapsed, repeat); 1194 RestartedInterval restartedInterval = maybeRestartInterval(elapsed); 1195 1196 ActiveState oldActiveState = m_activeState; 1197 m_activeState = determineActiveState(elapsed); 1198 bool animationIsContributing = isContributing(elapsed); 1199 1200 // Only reset the animated type to the base value once for the lowest priority animation that animates and contributes to a particular element/attribute pair. 1201 if (this == resultElement && animationIsContributing) 1202 resetAnimatedType(); 1203 1204 if (animationIsContributing) { 1205 if (oldActiveState == Inactive || restartedInterval == DidRestartInterval) { 1206 smilBeginEventSender().dispatchEventSoon(this); 1207 startedActiveInterval(); 1208 } 1209 1210 if (repeat && repeat != m_lastRepeat) 1211 dispatchRepeatEvents(repeat); 1212 1213 updateAnimation(percent, repeat, resultElement); 1214 m_lastPercent = percent; 1215 m_lastRepeat = repeat; 1216 } 1217 1218 if ((oldActiveState == Active && m_activeState != Active) || restartedInterval == DidRestartInterval) { 1219 smilEndEventSender().dispatchEventSoon(this); 1220 endedActiveInterval(); 1221 if (!animationIsContributing && this == resultElement) 1222 clearAnimatedType(m_targetElement); 1223 } 1224 1225 // Triggering all the pending events if the animation timeline is changed. 1226 if (seekToTime) { 1227 if (m_activeState == Inactive) 1228 smilBeginEventSender().dispatchEventSoon(this); 1229 1230 if (repeat) { 1231 for (unsigned repeatEventCount = 1; repeatEventCount < repeat; repeatEventCount++) 1232 dispatchRepeatEvents(repeatEventCount); 1233 if (m_activeState == Inactive) 1234 dispatchRepeatEvents(repeat); 1235 } 1236 1237 if (m_activeState == Inactive || m_activeState == Frozen) 1238 smilEndEventSender().dispatchEventSoon(this); 1239 } 1240 1241 m_nextProgressTime = calculateNextProgressTime(elapsed); 1242 return animationIsContributing; 1243 } 1244 1245 void SVGSMILElement::notifyDependentsIntervalChanged() 1246 { 1247 ASSERT(m_interval.begin.isFinite()); 1248 // |loopBreaker| is used to avoid infinite recursions which may be caused from: 1249 // |notifyDependentsIntervalChanged| -> |createInstanceTimesFromSyncbase| -> |add{Begin,End}Time| -> |{begin,end}TimeChanged| -> |notifyDependentsIntervalChanged| 1250 // |loopBreaker| is defined as a Persistent<HeapHashSet<Member<SVGSMILElement> > >. This won't cause leaks because it is guaranteed to be empty after the root |notifyDependentsIntervalChanged| has exited. 1251 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashSet<RawPtrWillBeMember<SVGSMILElement> > >, loopBreaker, (adoptPtrWillBeNoop(new WillBeHeapHashSet<RawPtrWillBeMember<SVGSMILElement> >()))); 1252 if (!loopBreaker->add(this).isNewEntry) 1253 return; 1254 1255 TimeDependentSet::iterator end = m_syncBaseDependents.end(); 1256 for (TimeDependentSet::iterator it = m_syncBaseDependents.begin(); it != end; ++it) { 1257 SVGSMILElement* dependent = *it; 1258 dependent->createInstanceTimesFromSyncbase(this); 1259 } 1260 1261 loopBreaker->remove(this); 1262 } 1263 1264 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncBase) 1265 { 1266 // FIXME: To be really correct, this should handle updating exising interval by changing 1267 // the associated times instead of creating new ones. 1268 for (unsigned n = 0; n < m_conditions.size(); ++n) { 1269 Condition* condition = m_conditions[n].get(); 1270 if (condition->type() == Condition::Syncbase && condition->syncBase() == syncBase) { 1271 ASSERT(condition->name() == "begin" || condition->name() == "end"); 1272 // No nested time containers in SVG, no need for crazy time space conversions. Phew! 1273 SMILTime time = 0; 1274 if (condition->name() == "begin") 1275 time = syncBase->m_interval.begin + condition->offset(); 1276 else 1277 time = syncBase->m_interval.end + condition->offset(); 1278 if (!time.isFinite()) 1279 continue; 1280 SMILTime elapsed = this->elapsed(); 1281 if (elapsed.isUnresolved()) 1282 continue; 1283 if (condition->beginOrEnd() == Begin) 1284 addBeginTime(elapsed, time); 1285 else 1286 addEndTime(elapsed, time); 1287 } 1288 } 1289 } 1290 1291 void SVGSMILElement::addSyncBaseDependent(SVGSMILElement* animation) 1292 { 1293 m_syncBaseDependents.add(animation); 1294 if (m_interval.begin.isFinite()) 1295 animation->createInstanceTimesFromSyncbase(this); 1296 } 1297 1298 void SVGSMILElement::removeSyncBaseDependent(SVGSMILElement* animation) 1299 { 1300 m_syncBaseDependents.remove(animation); 1301 } 1302 1303 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition) 1304 { 1305 if (event->type() == "repeatn" && toRepeatEvent(event)->repeat() != condition->repeat()) 1306 return; 1307 1308 SMILTime elapsed = this->elapsed(); 1309 if (elapsed.isUnresolved()) 1310 return; 1311 if (condition->beginOrEnd() == Begin) 1312 addBeginTime(elapsed, elapsed + condition->offset()); 1313 else 1314 addEndTime(elapsed, elapsed + condition->offset()); 1315 } 1316 1317 void SVGSMILElement::beginByLinkActivation() 1318 { 1319 SMILTime elapsed = this->elapsed(); 1320 if (elapsed.isUnresolved()) 1321 return; 1322 addBeginTime(elapsed, elapsed); 1323 } 1324 1325 void SVGSMILElement::endedActiveInterval() 1326 { 1327 clearTimesWithDynamicOrigins(m_beginTimes); 1328 clearTimesWithDynamicOrigins(m_endTimes); 1329 } 1330 1331 void SVGSMILElement::dispatchRepeatEvents(unsigned count) 1332 { 1333 m_repeatEventCountList.append(count); 1334 smilRepeatEventSender().dispatchEventSoon(this); 1335 smilRepeatNEventSender().dispatchEventSoon(this); 1336 } 1337 1338 void SVGSMILElement::dispatchPendingEvent(SMILEventSender* eventSender) 1339 { 1340 ASSERT(eventSender == &smilEndEventSender() || eventSender == &smilBeginEventSender() || eventSender == &smilRepeatEventSender() || eventSender == &smilRepeatNEventSender()); 1341 const AtomicString& eventType = eventSender->eventType(); 1342 if (eventType == "repeatn") { 1343 unsigned repeatEventCount = m_repeatEventCountList.first(); 1344 m_repeatEventCountList.remove(0); 1345 dispatchEvent(RepeatEvent::create(eventType, repeatEventCount)); 1346 } else { 1347 dispatchEvent(Event::create(eventType)); 1348 } 1349 } 1350 1351 SVGSMILElement::Condition::~Condition() 1352 { 1353 } 1354 1355 void SVGSMILElement::Condition::trace(Visitor* visitor) 1356 { 1357 visitor->trace(m_syncBase); 1358 } 1359 1360 void SVGSMILElement::trace(Visitor* visitor) 1361 { 1362 #if ENABLE(OILPAN) 1363 visitor->trace(m_targetElement); 1364 visitor->trace(m_timeContainer); 1365 visitor->trace(m_conditions); 1366 visitor->trace(m_syncBaseDependents); 1367 #endif 1368 SVGElement::trace(visitor); 1369 } 1370 1371 } 1372