1/* 2 * Copyright (c) 2013, Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "core/animation/TimedItem.h" 33 34#include <gtest/gtest.h> 35 36using namespace WebCore; 37 38namespace { 39 40class TestTimedItemEventDelegate : public TimedItemEventDelegate { 41public: 42 void onEventCondition(bool wasInPlay, bool isInPlay, double previousIteration, double currentIteration) OVERRIDE 43 { 44 m_eventTriggered = true; 45 m_playStateChanged = wasInPlay != isInPlay; 46 m_iterationChanged = isInPlay && previousIteration != currentIteration; 47 if (isInPlay) 48 ASSERT(!isNull(currentIteration)); 49 50 } 51 void reset() 52 { 53 m_eventTriggered = false; 54 m_playStateChanged = false; 55 m_iterationChanged = false; 56 } 57 bool eventTriggered() { return m_eventTriggered; } 58 bool playStateChanged() { return m_playStateChanged; } 59 bool iterationChanged() { return m_iterationChanged; } 60 61private: 62 bool m_eventTriggered; 63 bool m_playStateChanged; 64 bool m_iterationChanged; 65}; 66 67class TestTimedItem : public TimedItem { 68public: 69 static PassRefPtr<TestTimedItem> create(const Timing& specified) 70 { 71 return adoptRef(new TestTimedItem(specified, new TestTimedItemEventDelegate())); 72 } 73 74 void updateInheritedTime(double time) 75 { 76 m_eventDelegate->reset(); 77 TimedItem::updateInheritedTime(time); 78 } 79 80 void updateChildrenAndEffects(bool wasActiveOrInEffect) const FINAL OVERRIDE { 81 } 82 83 void willDetach() { } 84 85 TestTimedItemEventDelegate* eventDelegate() { return m_eventDelegate; } 86 87private: 88 TestTimedItem(const Timing& specified, TestTimedItemEventDelegate* eventDelegate) 89 : TimedItem(specified, adoptPtr(eventDelegate)) 90 , m_eventDelegate(eventDelegate) 91 { 92 } 93 94 TestTimedItemEventDelegate* m_eventDelegate; 95}; 96 97TEST(TimedItem, Sanity) 98{ 99 Timing timing; 100 timing.hasIterationDuration = true; 101 timing.iterationDuration = 2; 102 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 103 104 ASSERT_FALSE(timedItem->isCurrent()); 105 ASSERT_FALSE(timedItem->isInEffect()); 106 ASSERT_FALSE(timedItem->isInPlay()); 107 ASSERT_TRUE(isNull(timedItem->currentIteration())); 108 ASSERT_EQ(0, timedItem->startTime()); 109 ASSERT_TRUE(isNull(timedItem->activeDuration())); 110 ASSERT_TRUE(isNull(timedItem->timeFraction())); 111 112 timedItem->updateInheritedTime(0); 113 114 ASSERT_TRUE(timedItem->isInPlay()); 115 ASSERT_TRUE(timedItem->isCurrent()); 116 ASSERT_TRUE(timedItem->isInEffect()); 117 ASSERT_EQ(0, timedItem->currentIteration()); 118 ASSERT_EQ(0, timedItem->startTime()); 119 ASSERT_EQ(2, timedItem->activeDuration()); 120 ASSERT_EQ(0, timedItem->timeFraction()); 121 122 timedItem->updateInheritedTime(1); 123 124 ASSERT_TRUE(timedItem->isInPlay()); 125 ASSERT_TRUE(timedItem->isCurrent()); 126 ASSERT_TRUE(timedItem->isInEffect()); 127 ASSERT_EQ(0, timedItem->currentIteration()); 128 ASSERT_EQ(0, timedItem->startTime()); 129 ASSERT_EQ(2, timedItem->activeDuration()); 130 ASSERT_EQ(0.5, timedItem->timeFraction()); 131 132 timedItem->updateInheritedTime(2); 133 134 ASSERT_FALSE(timedItem->isInPlay()); 135 ASSERT_FALSE(timedItem->isCurrent()); 136 ASSERT_TRUE(timedItem->isInEffect()); 137 ASSERT_EQ(0, timedItem->currentIteration()); 138 ASSERT_EQ(0, timedItem->startTime()); 139 ASSERT_EQ(2, timedItem->activeDuration()); 140 ASSERT_EQ(1, timedItem->timeFraction()); 141 142 timedItem->updateInheritedTime(3); 143 144 ASSERT_FALSE(timedItem->isInPlay()); 145 ASSERT_FALSE(timedItem->isCurrent()); 146 ASSERT_TRUE(timedItem->isInEffect()); 147 ASSERT_EQ(0, timedItem->currentIteration()); 148 ASSERT_EQ(0, timedItem->startTime()); 149 ASSERT_EQ(2, timedItem->activeDuration()); 150 ASSERT_EQ(1, timedItem->timeFraction()); 151} 152 153TEST(TimedItem, FillForwards) 154{ 155 Timing timing; 156 timing.hasIterationDuration = true; 157 timing.iterationDuration = 1; 158 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 159 160 timedItem->updateInheritedTime(-1); 161 ASSERT_TRUE(isNull(timedItem->timeFraction())); 162 163 timedItem->updateInheritedTime(2); 164 ASSERT_EQ(1, timedItem->timeFraction()); 165} 166 167TEST(TimedItem, FillBackwards) 168{ 169 Timing timing; 170 timing.hasIterationDuration = true; 171 timing.iterationDuration = 1; 172 timing.fillMode = Timing::FillModeBackwards; 173 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 174 175 timedItem->updateInheritedTime(-1); 176 ASSERT_EQ(0, timedItem->timeFraction()); 177 178 timedItem->updateInheritedTime(2); 179 ASSERT_TRUE(isNull(timedItem->timeFraction())); 180} 181 182TEST(TimedItem, FillBoth) 183{ 184 Timing timing; 185 timing.hasIterationDuration = true; 186 timing.iterationDuration = 1; 187 timing.fillMode = Timing::FillModeBoth; 188 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 189 190 timedItem->updateInheritedTime(-1); 191 ASSERT_EQ(0, timedItem->timeFraction()); 192 193 timedItem->updateInheritedTime(2); 194 ASSERT_EQ(1, timedItem->timeFraction()); 195} 196 197TEST(TimedItem, StartDelay) 198{ 199 Timing timing; 200 timing.hasIterationDuration = true; 201 timing.iterationDuration = 1; 202 timing.startDelay = 0.5; 203 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 204 205 timedItem->updateInheritedTime(0); 206 ASSERT_TRUE(isNull(timedItem->timeFraction())); 207 208 timedItem->updateInheritedTime(0.5); 209 ASSERT_EQ(0, timedItem->timeFraction()); 210 211 timedItem->updateInheritedTime(1.5); 212 ASSERT_EQ(1, timedItem->timeFraction()); 213} 214 215TEST(TimedItem, InfiniteIteration) 216{ 217 Timing timing; 218 timing.hasIterationDuration = true; 219 timing.iterationDuration = 1; 220 timing.iterationCount = std::numeric_limits<double>::infinity(); 221 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 222 223 timedItem->updateInheritedTime(-1); 224 ASSERT_TRUE(isNull(timedItem->currentIteration())); 225 ASSERT_TRUE(isNull(timedItem->timeFraction())); 226 227 ASSERT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration()); 228 229 timedItem->updateInheritedTime(0); 230 ASSERT_EQ(0, timedItem->currentIteration()); 231 ASSERT_EQ(0, timedItem->timeFraction()); 232} 233 234TEST(TimedItem, Iteration) 235{ 236 Timing timing; 237 timing.iterationCount = 2; 238 timing.hasIterationDuration = true; 239 timing.iterationDuration = 2; 240 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 241 242 timedItem->updateInheritedTime(0); 243 ASSERT_EQ(0, timedItem->currentIteration()); 244 ASSERT_EQ(0, timedItem->timeFraction()); 245 246 timedItem->updateInheritedTime(1); 247 ASSERT_EQ(0, timedItem->currentIteration()); 248 ASSERT_EQ(0.5, timedItem->timeFraction()); 249 250 timedItem->updateInheritedTime(2); 251 ASSERT_EQ(1, timedItem->currentIteration()); 252 ASSERT_EQ(0, timedItem->timeFraction()); 253 254 timedItem->updateInheritedTime(2); 255 ASSERT_EQ(1, timedItem->currentIteration()); 256 ASSERT_EQ(0, timedItem->timeFraction()); 257 258 timedItem->updateInheritedTime(5); 259 ASSERT_EQ(1, timedItem->currentIteration()); 260 ASSERT_EQ(1, timedItem->timeFraction()); 261} 262 263TEST(TimedItem, IterationStart) 264{ 265 Timing timing; 266 timing.iterationStart = 1.2; 267 timing.iterationCount = 2.2; 268 timing.hasIterationDuration = true; 269 timing.iterationDuration = 1; 270 timing.fillMode = Timing::FillModeBoth; 271 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 272 273 timedItem->updateInheritedTime(-1); 274 ASSERT_EQ(1, timedItem->currentIteration()); 275 ASSERT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001); 276 277 timedItem->updateInheritedTime(0); 278 ASSERT_EQ(1, timedItem->currentIteration()); 279 ASSERT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001); 280 281 timedItem->updateInheritedTime(10); 282 ASSERT_EQ(3, timedItem->currentIteration()); 283 ASSERT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001); 284} 285 286TEST(TimedItem, IterationAlternate) 287{ 288 Timing timing; 289 timing.iterationCount = 10; 290 timing.hasIterationDuration = true; 291 timing.iterationDuration = 1; 292 timing.direction = Timing::PlaybackDirectionAlternate; 293 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 294 295 timedItem->updateInheritedTime(0.75); 296 ASSERT_EQ(0, timedItem->currentIteration()); 297 ASSERT_EQ(0.75, timedItem->timeFraction()); 298 299 timedItem->updateInheritedTime(1.75); 300 ASSERT_EQ(1, timedItem->currentIteration()); 301 ASSERT_EQ(0.25, timedItem->timeFraction()); 302 303 timedItem->updateInheritedTime(2.75); 304 ASSERT_EQ(2, timedItem->currentIteration()); 305 ASSERT_EQ(0.75, timedItem->timeFraction()); 306} 307 308TEST(TimedItem, IterationAlternateReverse) 309{ 310 Timing timing; 311 timing.iterationCount = 10; 312 timing.hasIterationDuration = true; 313 timing.iterationDuration = 1; 314 timing.direction = Timing::PlaybackDirectionAlternateReverse; 315 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 316 317 timedItem->updateInheritedTime(0.75); 318 ASSERT_EQ(0, timedItem->currentIteration()); 319 ASSERT_EQ(0.25, timedItem->timeFraction()); 320 321 timedItem->updateInheritedTime(1.75); 322 ASSERT_EQ(1, timedItem->currentIteration()); 323 ASSERT_EQ(0.75, timedItem->timeFraction()); 324 325 timedItem->updateInheritedTime(2.75); 326 ASSERT_EQ(2, timedItem->currentIteration()); 327 ASSERT_EQ(0.25, timedItem->timeFraction()); 328} 329 330TEST(TimedItem, ZeroDurationSanity) 331{ 332 Timing timing; 333 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 334 335 ASSERT_FALSE(timedItem->isInPlay()); 336 ASSERT_FALSE(timedItem->isCurrent()); 337 ASSERT_FALSE(timedItem->isInEffect()); 338 ASSERT_TRUE(isNull(timedItem->currentIteration())); 339 ASSERT_EQ(0, timedItem->startTime()); 340 ASSERT_TRUE(isNull(timedItem->activeDuration())); 341 ASSERT_TRUE(isNull(timedItem->timeFraction())); 342 343 timedItem->updateInheritedTime(0); 344 345 ASSERT_FALSE(timedItem->isInPlay()); 346 ASSERT_FALSE(timedItem->isCurrent()); 347 ASSERT_TRUE(timedItem->isInEffect()); 348 ASSERT_EQ(0, timedItem->currentIteration()); 349 ASSERT_EQ(0, timedItem->startTime()); 350 ASSERT_EQ(0, timedItem->activeDuration()); 351 ASSERT_EQ(1, timedItem->timeFraction()); 352 353 timedItem->updateInheritedTime(1); 354 355 ASSERT_FALSE(timedItem->isInPlay()); 356 ASSERT_FALSE(timedItem->isCurrent()); 357 ASSERT_TRUE(timedItem->isInEffect()); 358 ASSERT_EQ(0, timedItem->currentIteration()); 359 ASSERT_EQ(0, timedItem->startTime()); 360 ASSERT_EQ(0, timedItem->activeDuration()); 361 ASSERT_EQ(1, timedItem->timeFraction()); 362} 363 364TEST(TimedItem, ZeroDurationFillForwards) 365{ 366 Timing timing; 367 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 368 369 timedItem->updateInheritedTime(-1); 370 ASSERT_TRUE(isNull(timedItem->timeFraction())); 371 372 timedItem->updateInheritedTime(0); 373 ASSERT_EQ(1, timedItem->timeFraction()); 374 375 timedItem->updateInheritedTime(1); 376 ASSERT_EQ(1, timedItem->timeFraction()); 377} 378 379TEST(TimedItem, ZeroDurationFillBackwards) 380{ 381 Timing timing; 382 timing.fillMode = Timing::FillModeBackwards; 383 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 384 385 timedItem->updateInheritedTime(-1); 386 ASSERT_EQ(0, timedItem->timeFraction()); 387 388 timedItem->updateInheritedTime(0); 389 ASSERT_TRUE(isNull(timedItem->timeFraction())); 390 391 timedItem->updateInheritedTime(1); 392 ASSERT_TRUE(isNull(timedItem->timeFraction())); 393} 394 395TEST(TimedItem, ZeroDurationFillBoth) 396{ 397 Timing timing; 398 timing.fillMode = Timing::FillModeBoth; 399 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 400 401 timedItem->updateInheritedTime(-1); 402 ASSERT_EQ(0, timedItem->timeFraction()); 403 404 timedItem->updateInheritedTime(0); 405 ASSERT_EQ(1, timedItem->timeFraction()); 406 407 timedItem->updateInheritedTime(1); 408 ASSERT_EQ(1, timedItem->timeFraction()); 409} 410 411TEST(TimedItem, ZeroDurationStartDelay) 412{ 413 Timing timing; 414 timing.startDelay = 0.5; 415 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 416 417 timedItem->updateInheritedTime(0); 418 ASSERT_TRUE(isNull(timedItem->timeFraction())); 419 420 timedItem->updateInheritedTime(0.5); 421 ASSERT_EQ(1, timedItem->timeFraction()); 422 423 timedItem->updateInheritedTime(1.5); 424 ASSERT_EQ(1, timedItem->timeFraction()); 425} 426 427TEST(TimedItem, ZeroDurationIterationStartAndCount) 428{ 429 Timing timing; 430 timing.iterationStart = 0.1; 431 timing.iterationCount = 0.2; 432 timing.fillMode = Timing::FillModeBoth; 433 timing.startDelay = 0.3; 434 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 435 436 timedItem->updateInheritedTime(0); 437 ASSERT_EQ(0.1, timedItem->timeFraction()); 438 439 timedItem->updateInheritedTime(0.3); 440 ASSERT_DOUBLE_EQ(0.3, timedItem->timeFraction()); 441 442 timedItem->updateInheritedTime(1); 443 ASSERT_DOUBLE_EQ(0.3, timedItem->timeFraction()); 444} 445 446// FIXME: Needs specification work -- ASSERTION FAILED: activeDuration >= 0 447TEST(TimedItem, DISABLED_ZeroDurationInfiniteIteration) 448{ 449 Timing timing; 450 timing.iterationCount = std::numeric_limits<double>::infinity(); 451 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 452 453 timedItem->updateInheritedTime(-1); 454 ASSERT_TRUE(isNull(timedItem->currentIteration())); 455 ASSERT_TRUE(isNull(timedItem->timeFraction())); 456 ASSERT_TRUE(isNull(timedItem->activeDuration())); 457 458 timedItem->updateInheritedTime(0); 459 ASSERT_EQ(std::numeric_limits<double>::infinity(), timedItem->currentIteration()); 460 ASSERT_EQ(1, timedItem->timeFraction()); 461} 462 463TEST(TimedItem, ZeroDurationIteration) 464{ 465 Timing timing; 466 timing.iterationCount = 2; 467 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 468 469 timedItem->updateInheritedTime(-1); 470 ASSERT_TRUE(isNull(timedItem->currentIteration())); 471 ASSERT_TRUE(isNull(timedItem->timeFraction())); 472 473 timedItem->updateInheritedTime(0); 474 ASSERT_EQ(1, timedItem->currentIteration()); 475 ASSERT_EQ(1, timedItem->timeFraction()); 476 477 timedItem->updateInheritedTime(1); 478 ASSERT_EQ(1, timedItem->currentIteration()); 479 ASSERT_EQ(1, timedItem->timeFraction()); 480} 481 482TEST(TimedItem, ZeroDurationIterationStart) 483{ 484 Timing timing; 485 timing.iterationStart = 1.2; 486 timing.iterationCount = 2.2; 487 timing.fillMode = Timing::FillModeBoth; 488 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 489 490 timedItem->updateInheritedTime(-1); 491 ASSERT_EQ(1, timedItem->currentIteration()); 492 ASSERT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001); 493 494 timedItem->updateInheritedTime(0); 495 ASSERT_EQ(3, timedItem->currentIteration()); 496 ASSERT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001); 497 498 timedItem->updateInheritedTime(10); 499 ASSERT_EQ(3, timedItem->currentIteration()); 500 ASSERT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001); 501} 502 503TEST(TimedItem, ZeroDurationIterationAlternate) 504{ 505 Timing timing; 506 timing.iterationCount = 2; 507 timing.direction = Timing::PlaybackDirectionAlternate; 508 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 509 510 timedItem->updateInheritedTime(-1); 511 ASSERT_TRUE(isNull(timedItem->currentIteration())); 512 ASSERT_TRUE(isNull(timedItem->timeFraction())); 513 514 timedItem->updateInheritedTime(0); 515 ASSERT_EQ(1, timedItem->currentIteration()); 516 ASSERT_EQ(0, timedItem->timeFraction()); 517 518 timedItem->updateInheritedTime(1); 519 ASSERT_EQ(1, timedItem->currentIteration()); 520 ASSERT_EQ(0, timedItem->timeFraction()); 521} 522 523TEST(TimedItem, ZeroDurationIterationAlternateReverse) 524{ 525 Timing timing; 526 timing.iterationCount = 2; 527 timing.direction = Timing::PlaybackDirectionAlternateReverse; 528 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 529 530 timedItem->updateInheritedTime(-1); 531 ASSERT_TRUE(isNull(timedItem->currentIteration())); 532 ASSERT_TRUE(isNull(timedItem->timeFraction())); 533 534 timedItem->updateInheritedTime(0); 535 ASSERT_EQ(1, timedItem->currentIteration()); 536 ASSERT_EQ(1, timedItem->timeFraction()); 537 538 timedItem->updateInheritedTime(1); 539 ASSERT_EQ(1, timedItem->currentIteration()); 540 ASSERT_EQ(1, timedItem->timeFraction()); 541} 542 543TEST(TimedItem, Events) 544{ 545 Timing timing; 546 timing.hasIterationDuration = true; 547 timing.iterationDuration = 1; 548 timing.iterationCount = 2; 549 RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing); 550 551 timedItem->updateInheritedTime(0.3); 552 ASSERT_TRUE(timedItem->eventDelegate()->eventTriggered()); 553 EXPECT_TRUE(timedItem->eventDelegate()->playStateChanged()); 554 EXPECT_TRUE(timedItem->eventDelegate()->iterationChanged()); 555 556 timedItem->updateInheritedTime(0.6); 557 ASSERT_FALSE(timedItem->eventDelegate()->eventTriggered()); 558 559 timedItem->updateInheritedTime(1.5); 560 ASSERT_TRUE(timedItem->eventDelegate()->eventTriggered()); 561 EXPECT_TRUE(timedItem->eventDelegate()->iterationChanged()); 562 EXPECT_FALSE(timedItem->eventDelegate()->playStateChanged()); 563 564 timedItem->updateInheritedTime(2.5); 565 ASSERT_TRUE(timedItem->eventDelegate()->eventTriggered()); 566 EXPECT_FALSE(timedItem->eventDelegate()->iterationChanged()); 567 EXPECT_TRUE(timedItem->eventDelegate()->playStateChanged()); 568 569 timedItem->updateInheritedTime(3); 570 ASSERT_FALSE(timedItem->eventDelegate()->eventTriggered()); 571 572 timedItem->updateInheritedTime(1.5); 573 ASSERT_TRUE(timedItem->eventDelegate()->eventTriggered()); 574 EXPECT_FALSE(timedItem->eventDelegate()->iterationChanged()); 575 EXPECT_TRUE(timedItem->eventDelegate()->playStateChanged()); 576} 577} 578