| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 m_condition == conditionEventListener->m_condition; | 117 m_condition == conditionEventListener->m_condition; |
| 118 return false; | 118 return false; |
| 119 } | 119 } |
| 120 | 120 |
| 121 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event) { | 121 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event) { |
| 122 if (!m_animation) | 122 if (!m_animation) |
| 123 return; | 123 return; |
| 124 m_animation->handleConditionEvent(event, m_condition); | 124 m_animation->handleConditionEvent(event, m_condition); |
| 125 } | 125 } |
| 126 | 126 |
| 127 void SVGSMILElement::Condition::setEventListener( | |
| 128 ConditionEventListener* eventListener) { | |
| 129 m_eventListener = eventListener; | |
| 130 } | |
| 131 | |
| 132 SVGSMILElement::Condition::Condition(Type type, | 127 SVGSMILElement::Condition::Condition(Type type, |
| 133 BeginOrEnd beginOrEnd, | 128 BeginOrEnd beginOrEnd, |
| 134 const String& baseID, | 129 const AtomicString& baseID, |
| 135 const String& name, | 130 const AtomicString& name, |
| 136 SMILTime offset, | 131 SMILTime offset, |
| 137 int repeat) | 132 int repeat) |
| 138 : m_type(type), | 133 : m_type(type), |
| 139 m_beginOrEnd(beginOrEnd), | 134 m_beginOrEnd(beginOrEnd), |
| 140 m_baseID(baseID), | 135 m_baseID(baseID), |
| 141 m_name(name), | 136 m_name(name), |
| 142 m_offset(offset), | 137 m_offset(offset), |
| 143 m_repeat(repeat) {} | 138 m_repeat(repeat) {} |
| 144 | 139 |
| 140 SVGSMILElement::Condition::~Condition() = default; |
| 141 |
| 142 DEFINE_TRACE(SVGSMILElement::Condition) { |
| 143 visitor->trace(m_syncBase); |
| 144 visitor->trace(m_eventListener); |
| 145 } |
| 146 |
| 147 void SVGSMILElement::Condition::connectSyncBase(SVGSMILElement& timedElement) { |
| 148 DCHECK(!m_baseID.isEmpty()); |
| 149 Element* element = timedElement.treeScope().getElementById(m_baseID); |
| 150 if (!element || !isSVGSMILElement(*element)) { |
| 151 m_syncBase = nullptr; |
| 152 return; |
| 153 } |
| 154 m_syncBase = toSVGSMILElement(element); |
| 155 m_syncBase->addSyncBaseDependent(timedElement); |
| 156 } |
| 157 |
| 158 void SVGSMILElement::Condition::disconnectSyncBase( |
| 159 SVGSMILElement& timedElement) { |
| 160 if (!m_syncBase) |
| 161 return; |
| 162 m_syncBase->removeSyncBaseDependent(timedElement); |
| 163 m_syncBase = nullptr; |
| 164 } |
| 165 |
| 166 SVGElement* SVGSMILElement::Condition::lookupEventBase( |
| 167 SVGSMILElement& timedElement) const { |
| 168 Element* eventBase = m_baseID.isEmpty() |
| 169 ? timedElement.targetElement() |
| 170 : timedElement.treeScope().getElementById(m_baseID); |
| 171 if (!eventBase || !eventBase->isSVGElement()) |
| 172 return nullptr; |
| 173 return toSVGElement(eventBase); |
| 174 } |
| 175 |
| 176 void SVGSMILElement::Condition::connectEventBase(SVGSMILElement& timedElement) { |
| 177 DCHECK(!m_syncBase); |
| 178 SVGElement* eventBase = lookupEventBase(timedElement); |
| 179 if (!eventBase) { |
| 180 if (m_baseID.isEmpty()) |
| 181 return; |
| 182 SVGTreeScopeResources& treeScopeResources = |
| 183 timedElement.treeScope().ensureSVGTreeScopedResources(); |
| 184 if (!treeScopeResources.isElementPendingResource(timedElement, m_baseID)) |
| 185 treeScopeResources.addPendingResource(m_baseID, timedElement); |
| 186 return; |
| 187 } |
| 188 DCHECK(!m_eventListener); |
| 189 m_eventListener = ConditionEventListener::create(&timedElement, this); |
| 190 eventBase->addEventListener(m_name, m_eventListener, false); |
| 191 timedElement.addReferenceTo(eventBase); |
| 192 } |
| 193 |
| 194 void SVGSMILElement::Condition::disconnectEventBase( |
| 195 SVGSMILElement& timedElement) { |
| 196 DCHECK(!m_syncBase); |
| 197 if (!m_eventListener) |
| 198 return; |
| 199 // Note: It's a memory optimization to try to remove our condition event |
| 200 // listener, but it's not guaranteed to work, since we have no guarantee that |
| 201 // we will be able to find our condition's original eventBase. So, we also |
| 202 // have to disconnect ourselves from our condition event listener, in case it |
| 203 // later fires. |
| 204 if (SVGElement* eventBase = lookupEventBase(timedElement)) |
| 205 eventBase->removeEventListener(m_name, m_eventListener, false); |
| 206 m_eventListener->disconnectAnimation(); |
| 207 m_eventListener = nullptr; |
| 208 } |
| 209 |
| 145 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document& doc) | 210 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document& doc) |
| 146 : SVGElement(tagName, doc), | 211 : SVGElement(tagName, doc), |
| 147 SVGTests(this), | 212 SVGTests(this), |
| 148 m_attributeName(anyQName()), | 213 m_attributeName(anyQName()), |
| 149 m_targetElement(nullptr), | 214 m_targetElement(nullptr), |
| 150 m_syncBaseConditionsConnected(false), | 215 m_syncBaseConditionsConnected(false), |
| 151 m_hasEndEventConditions(false), | 216 m_hasEndEventConditions(false), |
| 152 m_isWaitingForFirstInterval(true), | 217 m_isWaitingForFirstInterval(true), |
| 153 m_isScheduled(false), | 218 m_isScheduled(false), |
| 154 m_interval(SMILInterval(SMILTime::unresolved(), SMILTime::unresolved())), | 219 m_interval(SMILInterval(SMILTime::unresolved(), SMILTime::unresolved())), |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 type = Condition::Syncbase; | 471 type = Condition::Syncbase; |
| 407 } else if (nameString.startsWith("accesskey(")) { | 472 } else if (nameString.startsWith("accesskey(")) { |
| 408 // FIXME: accesskey() support. | 473 // FIXME: accesskey() support. |
| 409 type = Condition::AccessKey; | 474 type = Condition::AccessKey; |
| 410 } else { | 475 } else { |
| 411 UseCounter::count(&document(), UseCounter::SVGSMILBeginOrEndEventValue); | 476 UseCounter::count(&document(), UseCounter::SVGSMILBeginOrEndEventValue); |
| 412 type = Condition::EventBase; | 477 type = Condition::EventBase; |
| 413 } | 478 } |
| 414 | 479 |
| 415 m_conditions.push_back( | 480 m_conditions.push_back( |
| 416 Condition::create(type, beginOrEnd, baseID, nameString, offset, repeat)); | 481 Condition::create(type, beginOrEnd, AtomicString(baseID), |
| 482 AtomicString(nameString), offset, repeat)); |
| 417 | 483 |
| 418 if (type == Condition::EventBase && beginOrEnd == End) | 484 if (type == Condition::EventBase && beginOrEnd == End) |
| 419 m_hasEndEventConditions = true; | 485 m_hasEndEventConditions = true; |
| 420 | 486 |
| 421 return true; | 487 return true; |
| 422 } | 488 } |
| 423 | 489 |
| 424 void SVGSMILElement::parseBeginOrEnd(const String& parseString, | 490 void SVGSMILElement::parseBeginOrEnd(const String& parseString, |
| 425 BeginOrEnd beginOrEnd) { | 491 BeginOrEnd beginOrEnd) { |
| 426 Vector<SMILTimeWithOrigin>& timeList = | 492 Vector<SMILTimeWithOrigin>& timeList = |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 endListChanged(elapsed()); | 575 endListChanged(elapsed()); |
| 510 } | 576 } |
| 511 } else { | 577 } else { |
| 512 SVGElement::svgAttributeChanged(attrName); | 578 SVGElement::svgAttributeChanged(attrName); |
| 513 return; | 579 return; |
| 514 } | 580 } |
| 515 | 581 |
| 516 animationAttributeChanged(); | 582 animationAttributeChanged(); |
| 517 } | 583 } |
| 518 | 584 |
| 519 inline SVGElement* SVGSMILElement::eventBaseFor(const Condition& condition) { | |
| 520 Element* eventBase = | |
| 521 condition.baseID().isEmpty() | |
| 522 ? targetElement() | |
| 523 : treeScope().getElementById(AtomicString(condition.baseID())); | |
| 524 if (eventBase && eventBase->isSVGElement()) | |
| 525 return toSVGElement(eventBase); | |
| 526 return nullptr; | |
| 527 } | |
| 528 | |
| 529 void SVGSMILElement::connectSyncBaseConditions() { | 585 void SVGSMILElement::connectSyncBaseConditions() { |
| 530 if (m_syncBaseConditionsConnected) | 586 if (m_syncBaseConditionsConnected) |
| 531 disconnectSyncBaseConditions(); | 587 disconnectSyncBaseConditions(); |
| 532 m_syncBaseConditionsConnected = true; | 588 m_syncBaseConditionsConnected = true; |
| 533 for (unsigned n = 0; n < m_conditions.size(); ++n) { | 589 for (Condition* condition : m_conditions) { |
| 534 Condition* condition = m_conditions[n].get(); | 590 if (condition->getType() == Condition::Syncbase) |
| 535 if (condition->getType() == Condition::Syncbase) { | 591 condition->connectSyncBase(*this); |
| 536 ASSERT(!condition->baseID().isEmpty()); | |
| 537 Element* element = | |
| 538 treeScope().getElementById(AtomicString(condition->baseID())); | |
| 539 if (!element || !isSVGSMILElement(*element)) { | |
| 540 condition->setSyncBase(0); | |
| 541 continue; | |
| 542 } | |
| 543 SVGSMILElement* svgSMILElement = toSVGSMILElement(element); | |
| 544 condition->setSyncBase(svgSMILElement); | |
| 545 svgSMILElement->addSyncBaseDependent(this); | |
| 546 } | |
| 547 } | 592 } |
| 548 } | 593 } |
| 549 | 594 |
| 550 void SVGSMILElement::disconnectSyncBaseConditions() { | 595 void SVGSMILElement::disconnectSyncBaseConditions() { |
| 551 if (!m_syncBaseConditionsConnected) | 596 if (!m_syncBaseConditionsConnected) |
| 552 return; | 597 return; |
| 553 m_syncBaseConditionsConnected = false; | 598 m_syncBaseConditionsConnected = false; |
| 554 for (unsigned n = 0; n < m_conditions.size(); ++n) { | 599 for (Condition* condition : m_conditions) { |
| 555 Condition* condition = m_conditions[n].get(); | 600 if (condition->getType() == Condition::Syncbase) |
| 556 if (condition->getType() == Condition::Syncbase) { | 601 condition->disconnectSyncBase(*this); |
| 557 if (condition->syncBase()) | |
| 558 condition->syncBase()->removeSyncBaseDependent(this); | |
| 559 condition->setSyncBase(0); | |
| 560 } | |
| 561 } | 602 } |
| 562 } | 603 } |
| 563 | 604 |
| 564 void SVGSMILElement::connectEventBaseConditions() { | 605 void SVGSMILElement::connectEventBaseConditions() { |
| 565 disconnectEventBaseConditions(); | 606 disconnectEventBaseConditions(); |
| 566 for (unsigned n = 0; n < m_conditions.size(); ++n) { | 607 for (Condition* condition : m_conditions) { |
| 567 Condition* condition = m_conditions[n].get(); | 608 if (condition->getType() == Condition::EventBase) |
| 568 if (condition->getType() == Condition::EventBase) { | 609 condition->connectEventBase(*this); |
| 569 ASSERT(!condition->syncBase()); | |
| 570 SVGElement* eventBase = eventBaseFor(*condition); | |
| 571 if (!eventBase) { | |
| 572 if (!condition->baseID().isEmpty() && | |
| 573 !treeScope() | |
| 574 .ensureSVGTreeScopedResources() | |
| 575 .isElementPendingResource(*this, | |
| 576 AtomicString(condition->baseID()))) { | |
| 577 treeScope().ensureSVGTreeScopedResources().addPendingResource( | |
| 578 AtomicString(condition->baseID()), *this); | |
| 579 } | |
| 580 continue; | |
| 581 } | |
| 582 ASSERT(!condition->eventListener()); | |
| 583 condition->setEventListener( | |
| 584 ConditionEventListener::create(this, condition)); | |
| 585 eventBase->addEventListener(AtomicString(condition->name()), | |
| 586 condition->eventListener(), false); | |
| 587 addReferenceTo(eventBase); | |
| 588 } | |
| 589 } | 610 } |
| 590 } | 611 } |
| 591 | 612 |
| 592 void SVGSMILElement::disconnectEventBaseConditions() { | 613 void SVGSMILElement::disconnectEventBaseConditions() { |
| 593 for (unsigned n = 0; n < m_conditions.size(); ++n) { | 614 for (Condition* condition : m_conditions) { |
| 594 Condition* condition = m_conditions[n].get(); | 615 if (condition->getType() == Condition::EventBase) |
| 595 if (condition->getType() == Condition::EventBase) { | 616 condition->disconnectEventBase(*this); |
| 596 ASSERT(!condition->syncBase()); | |
| 597 if (!condition->eventListener()) | |
| 598 continue; | |
| 599 // Note: It's a memory optimization to try to remove our condition | |
| 600 // event listener, but it's not guaranteed to work, since we have | |
| 601 // no guarantee that eventBaseFor() will be able to find our condition's | |
| 602 // original eventBase. So, we also have to disconnect ourselves from | |
| 603 // our condition event listener, in case it later fires. | |
| 604 SVGElement* eventBase = eventBaseFor(*condition); | |
| 605 if (eventBase) | |
| 606 eventBase->removeEventListener(AtomicString(condition->name()), | |
| 607 condition->eventListener(), false); | |
| 608 condition->eventListener()->disconnectAnimation(); | |
| 609 condition->setEventListener(nullptr); | |
| 610 } | |
| 611 } | 617 } |
| 612 } | 618 } |
| 613 | 619 |
| 614 void SVGSMILElement::setTargetElement(SVGElement* target) { | 620 void SVGSMILElement::setTargetElement(SVGElement* target) { |
| 615 unscheduleIfScheduled(); | 621 unscheduleIfScheduled(); |
| 616 | 622 |
| 617 if (m_targetElement) { | 623 if (m_targetElement) { |
| 618 // Clear values that may depend on the previous target. | 624 // Clear values that may depend on the previous target. |
| 619 clearAnimatedType(); | 625 clearAnimatedType(); |
| 620 disconnectSyncBaseConditions(); | 626 disconnectSyncBaseConditions(); |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 // |notifyDependentsIntervalChanged| | 1182 // |notifyDependentsIntervalChanged| |
| 1177 // | 1183 // |
| 1178 // As the set here records SVGSMILElements on the stack, it is acceptable to | 1184 // As the set here records SVGSMILElements on the stack, it is acceptable to |
| 1179 // use a HashSet of untraced heap references -- any conservative GC which | 1185 // use a HashSet of untraced heap references -- any conservative GC which |
| 1180 // strikes before unwinding will find these elements on the stack. | 1186 // strikes before unwinding will find these elements on the stack. |
| 1181 DEFINE_STATIC_LOCAL(HashSet<UntracedMember<SVGSMILElement>>, loopBreaker, ()); | 1187 DEFINE_STATIC_LOCAL(HashSet<UntracedMember<SVGSMILElement>>, loopBreaker, ()); |
| 1182 if (!loopBreaker.insert(this).isNewEntry) | 1188 if (!loopBreaker.insert(this).isNewEntry) |
| 1183 return; | 1189 return; |
| 1184 | 1190 |
| 1185 for (SVGSMILElement* element : m_syncBaseDependents) | 1191 for (SVGSMILElement* element : m_syncBaseDependents) |
| 1186 element->createInstanceTimesFromSyncbase(this); | 1192 element->createInstanceTimesFromSyncbase(*this); |
| 1187 | 1193 |
| 1188 loopBreaker.erase(this); | 1194 loopBreaker.erase(this); |
| 1189 } | 1195 } |
| 1190 | 1196 |
| 1191 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncBase) { | 1197 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement& syncBase) { |
| 1192 // FIXME: To be really correct, this should handle updating exising interval | 1198 // FIXME: To be really correct, this should handle updating exising interval |
| 1193 // by changing the associated times instead of creating new ones. | 1199 // by changing the associated times instead of creating new ones. |
| 1194 for (unsigned n = 0; n < m_conditions.size(); ++n) { | 1200 for (Condition* condition : m_conditions) { |
| 1195 Condition* condition = m_conditions[n].get(); | |
| 1196 if (condition->getType() == Condition::Syncbase && | 1201 if (condition->getType() == Condition::Syncbase && |
| 1197 condition->syncBase() == syncBase) { | 1202 condition->syncBaseEquals(syncBase)) { |
| 1198 ASSERT(condition->name() == "begin" || condition->name() == "end"); | 1203 ASSERT(condition->name() == "begin" || condition->name() == "end"); |
| 1199 // No nested time containers in SVG, no need for crazy time space | 1204 // No nested time containers in SVG, no need for crazy time space |
| 1200 // conversions. Phew! | 1205 // conversions. Phew! |
| 1201 SMILTime time = 0; | 1206 SMILTime time = 0; |
| 1202 if (condition->name() == "begin") | 1207 if (condition->name() == "begin") |
| 1203 time = syncBase->m_interval.begin + condition->offset(); | 1208 time = syncBase.m_interval.begin + condition->offset(); |
| 1204 else | 1209 else |
| 1205 time = syncBase->m_interval.end + condition->offset(); | 1210 time = syncBase.m_interval.end + condition->offset(); |
| 1206 if (!time.isFinite()) | 1211 if (!time.isFinite()) |
| 1207 continue; | 1212 continue; |
| 1208 SMILTime elapsed = this->elapsed(); | 1213 SMILTime elapsed = this->elapsed(); |
| 1209 if (elapsed.isUnresolved()) | 1214 if (elapsed.isUnresolved()) |
| 1210 continue; | 1215 continue; |
| 1211 if (condition->getBeginOrEnd() == Begin) | 1216 if (condition->getBeginOrEnd() == Begin) |
| 1212 addBeginTime(elapsed, time); | 1217 addBeginTime(elapsed, time); |
| 1213 else | 1218 else |
| 1214 addEndTime(elapsed, time); | 1219 addEndTime(elapsed, time); |
| 1215 } | 1220 } |
| 1216 } | 1221 } |
| 1217 } | 1222 } |
| 1218 | 1223 |
| 1219 void SVGSMILElement::addSyncBaseDependent(SVGSMILElement* animation) { | 1224 void SVGSMILElement::addSyncBaseDependent(SVGSMILElement& animation) { |
| 1220 m_syncBaseDependents.insert(animation); | 1225 m_syncBaseDependents.insert(&animation); |
| 1221 if (m_interval.begin.isFinite()) | 1226 if (m_interval.begin.isFinite()) |
| 1222 animation->createInstanceTimesFromSyncbase(this); | 1227 animation.createInstanceTimesFromSyncbase(*this); |
| 1223 } | 1228 } |
| 1224 | 1229 |
| 1225 void SVGSMILElement::removeSyncBaseDependent(SVGSMILElement* animation) { | 1230 void SVGSMILElement::removeSyncBaseDependent(SVGSMILElement& animation) { |
| 1226 m_syncBaseDependents.erase(animation); | 1231 m_syncBaseDependents.erase(&animation); |
| 1227 } | 1232 } |
| 1228 | 1233 |
| 1229 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition) { | 1234 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition) { |
| 1230 if (event->type() == "repeatn" && | 1235 if (event->type() == "repeatn" && |
| 1231 toRepeatEvent(event)->repeat() != condition->repeat()) | 1236 toRepeatEvent(event)->repeat() != condition->repeat()) |
| 1232 return; | 1237 return; |
| 1233 | 1238 |
| 1234 SMILTime elapsed = this->elapsed(); | 1239 SMILTime elapsed = this->elapsed(); |
| 1235 if (elapsed.isUnresolved()) | 1240 if (elapsed.isUnresolved()) |
| 1236 return; | 1241 return; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 void SVGSMILElement::unscheduleIfScheduled() { | 1300 void SVGSMILElement::unscheduleIfScheduled() { |
| 1296 if (!m_isScheduled) | 1301 if (!m_isScheduled) |
| 1297 return; | 1302 return; |
| 1298 | 1303 |
| 1299 DCHECK(m_timeContainer); | 1304 DCHECK(m_timeContainer); |
| 1300 DCHECK(m_targetElement); | 1305 DCHECK(m_targetElement); |
| 1301 m_timeContainer->unschedule(this, m_targetElement, m_attributeName); | 1306 m_timeContainer->unschedule(this, m_targetElement, m_attributeName); |
| 1302 m_isScheduled = false; | 1307 m_isScheduled = false; |
| 1303 } | 1308 } |
| 1304 | 1309 |
| 1305 SVGSMILElement::Condition::~Condition() {} | |
| 1306 | |
| 1307 DEFINE_TRACE(SVGSMILElement::Condition) { | |
| 1308 visitor->trace(m_syncBase); | |
| 1309 visitor->trace(m_eventListener); | |
| 1310 } | |
| 1311 | |
| 1312 DEFINE_TRACE(SVGSMILElement) { | 1310 DEFINE_TRACE(SVGSMILElement) { |
| 1313 visitor->trace(m_targetElement); | 1311 visitor->trace(m_targetElement); |
| 1314 visitor->trace(m_timeContainer); | 1312 visitor->trace(m_timeContainer); |
| 1315 visitor->trace(m_conditions); | 1313 visitor->trace(m_conditions); |
| 1316 visitor->trace(m_syncBaseDependents); | 1314 visitor->trace(m_syncBaseDependents); |
| 1317 SVGElement::trace(visitor); | 1315 SVGElement::trace(visitor); |
| 1318 SVGTests::trace(visitor); | 1316 SVGTests::trace(visitor); |
| 1319 } | 1317 } |
| 1320 | 1318 |
| 1321 } // namespace blink | 1319 } // namespace blink |
| OLD | NEW |