| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 | 6 |
| 7 #include "cc/test/layer_tree_test_common.h" | 7 #include "cc/test/layer_tree_test_common.h" |
| 8 | 8 |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "cc/active_animation.h" | 10 #include "cc/active_animation.h" |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 bool TestHooks::prepareToDrawOnThread(cc::LayerTreeHostImpl*) | 82 bool TestHooks::prepareToDrawOnThread(cc::LayerTreeHostImpl*) |
| 83 { | 83 { |
| 84 return true; | 84 return true; |
| 85 } | 85 } |
| 86 | 86 |
| 87 scoped_ptr<WebCompositorOutputSurface> TestHooks::createOutputSurface() | 87 scoped_ptr<WebCompositorOutputSurface> TestHooks::createOutputSurface() |
| 88 { | 88 { |
| 89 return FakeWebCompositorOutputSurface::create(CompositorFakeWebGraphicsConte
xt3DWithTextureTracking::create(WebGraphicsContext3D::Attributes()).PassAs<WebKi
t::WebGraphicsContext3D>()).PassAs<WebKit::WebCompositorOutputSurface>(); | 89 return FakeWebCompositorOutputSurface::create(CompositorFakeWebGraphicsConte
xt3DWithTextureTracking::create(WebGraphicsContext3D::Attributes()).PassAs<WebKi
t::WebGraphicsContext3D>()).PassAs<WebKit::WebCompositorOutputSurface>(); |
| 90 } | 90 } |
| 91 | 91 |
| 92 scoped_ptr<MockLayerTreeHostImpl> MockLayerTreeHostImpl::create(TestHooks* testH
ooks, const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy*
proxy) | 92 scoped_ptr<MockLayerTreeHostImpl> MockLayerTreeHostImpl::create(TestHooks* testH
ooks, const LayerTreeSettings& settings, LayerTreeHostImplClient* client) |
| 93 { | 93 { |
| 94 return make_scoped_ptr(new MockLayerTreeHostImpl(testHooks, settings, client
, proxy)); | 94 return make_scoped_ptr(new MockLayerTreeHostImpl(testHooks, settings, client
)); |
| 95 } | 95 } |
| 96 | 96 |
| 97 void MockLayerTreeHostImpl::beginCommit() | 97 void MockLayerTreeHostImpl::beginCommit() |
| 98 { | 98 { |
| 99 LayerTreeHostImpl::beginCommit(); | 99 LayerTreeHostImpl::beginCommit(); |
| 100 m_testHooks->beginCommitOnThread(this); | 100 m_testHooks->beginCommitOnThread(this); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void MockLayerTreeHostImpl::commitComplete() | 103 void MockLayerTreeHostImpl::commitComplete() |
| 104 { | 104 { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 125 m_testHooks->willAnimateLayers(this, monotonicTime); | 125 m_testHooks->willAnimateLayers(this, monotonicTime); |
| 126 LayerTreeHostImpl::animateLayers(monotonicTime, wallClockTime); | 126 LayerTreeHostImpl::animateLayers(monotonicTime, wallClockTime); |
| 127 m_testHooks->animateLayers(this, monotonicTime); | 127 m_testHooks->animateLayers(this, monotonicTime); |
| 128 } | 128 } |
| 129 | 129 |
| 130 base::TimeDelta MockLayerTreeHostImpl::lowFrequencyAnimationInterval() const | 130 base::TimeDelta MockLayerTreeHostImpl::lowFrequencyAnimationInterval() const |
| 131 { | 131 { |
| 132 return base::TimeDelta::FromMilliseconds(16); | 132 return base::TimeDelta::FromMilliseconds(16); |
| 133 } | 133 } |
| 134 | 134 |
| 135 MockLayerTreeHostImpl::MockLayerTreeHostImpl(TestHooks* testHooks, const LayerTr
eeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy) | 135 MockLayerTreeHostImpl::MockLayerTreeHostImpl(TestHooks* testHooks, const LayerTr
eeSettings& settings, LayerTreeHostImplClient* client) |
| 136 : LayerTreeHostImpl(settings, client, proxy) | 136 : LayerTreeHostImpl(settings, client) |
| 137 , m_testHooks(testHooks) | 137 , m_testHooks(testHooks) |
| 138 { | 138 { |
| 139 } | 139 } |
| 140 | 140 |
| 141 // Adapts LayerTreeHost for test. Injects MockLayerTreeHostImpl. | 141 // Adapts LayerTreeHost for test. Injects MockLayerTreeHostImpl. |
| 142 class MockLayerTreeHost : public cc::LayerTreeHost { | 142 class MockLayerTreeHost : public cc::LayerTreeHost { |
| 143 public: | 143 public: |
| 144 static scoped_ptr<MockLayerTreeHost> create(TestHooks* testHooks, cc::LayerT
reeHostClient* client, scoped_refptr<cc::Layer> rootLayer, const cc::LayerTreeSe
ttings& settings, scoped_ptr<cc::Thread> implThread) | 144 static scoped_ptr<MockLayerTreeHost> create(TestHooks* testHooks, cc::LayerT
reeHostClient* client, scoped_refptr<cc::Layer> rootLayer, const cc::LayerTreeSe
ttings& settings) |
| 145 { | 145 { |
| 146 scoped_ptr<MockLayerTreeHost> layerTreeHost(new MockLayerTreeHost(testHo
oks, client, settings)); | 146 scoped_ptr<MockLayerTreeHost> layerTreeHost(new MockLayerTreeHost(testHo
oks, client, settings)); |
| 147 bool success = layerTreeHost->initialize(implThread.Pass()); | 147 bool success = layerTreeHost->initialize(); |
| 148 EXPECT_TRUE(success); | 148 EXPECT_TRUE(success); |
| 149 layerTreeHost->setRootLayer(rootLayer); | 149 layerTreeHost->setRootLayer(rootLayer); |
| 150 | 150 |
| 151 // LayerTreeHostImpl won't draw if it has 1x1 viewport. | 151 // LayerTreeHostImpl won't draw if it has 1x1 viewport. |
| 152 layerTreeHost->setViewportSize(gfx::Size(1, 1), gfx::Size(1, 1)); | 152 layerTreeHost->setViewportSize(gfx::Size(1, 1), gfx::Size(1, 1)); |
| 153 | 153 |
| 154 layerTreeHost->rootLayer()->setLayerAnimationDelegate(testHooks); | 154 layerTreeHost->rootLayer()->setLayerAnimationDelegate(testHooks); |
| 155 | 155 |
| 156 return layerTreeHost.Pass(); | 156 return layerTreeHost.Pass(); |
| 157 } | 157 } |
| 158 | 158 |
| 159 virtual scoped_ptr<cc::LayerTreeHostImpl> createLayerTreeHostImpl(cc::LayerT
reeHostImplClient* client) | 159 virtual scoped_ptr<cc::LayerTreeHostImpl> createLayerTreeHostImpl(cc::LayerT
reeHostImplClient* client) |
| 160 { | 160 { |
| 161 return MockLayerTreeHostImpl::create(m_testHooks, settings(), client, pr
oxy()).PassAs<cc::LayerTreeHostImpl>(); | 161 return MockLayerTreeHostImpl::create(m_testHooks, settings(), client).Pa
ssAs<cc::LayerTreeHostImpl>(); |
| 162 } | 162 } |
| 163 | 163 |
| 164 virtual void didAddAnimation() OVERRIDE | 164 virtual void didAddAnimation() OVERRIDE |
| 165 { | 165 { |
| 166 LayerTreeHost::didAddAnimation(); | 166 LayerTreeHost::didAddAnimation(); |
| 167 m_testHooks->didAddAnimation(); | 167 m_testHooks->didAddAnimation(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 virtual void setNeedsCommit() OVERRIDE | 170 virtual void setNeedsCommit() OVERRIDE |
| 171 { | 171 { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 TestHooks* m_testHooks; | 268 TestHooks* m_testHooks; |
| 269 }; | 269 }; |
| 270 | 270 |
| 271 ThreadedTest::ThreadedTest() | 271 ThreadedTest::ThreadedTest() |
| 272 : m_beginning(false) | 272 : m_beginning(false) |
| 273 , m_endWhenBeginReturns(false) | 273 , m_endWhenBeginReturns(false) |
| 274 , m_timedOut(false) | 274 , m_timedOut(false) |
| 275 , m_finished(false) | 275 , m_finished(false) |
| 276 , m_scheduled(false) | 276 , m_scheduled(false) |
| 277 , m_started(false) | 277 , m_started(false) |
| 278 , m_implThread(0) | |
| 279 { | 278 { |
| 280 } | 279 } |
| 281 | 280 |
| 282 ThreadedTest::~ThreadedTest() | 281 ThreadedTest::~ThreadedTest() |
| 283 { | 282 { |
| 284 } | 283 } |
| 285 | 284 |
| 286 void ThreadedTest::endTest() | 285 void ThreadedTest::endTest() |
| 287 { | 286 { |
| 288 m_finished = true; | 287 m_finished = true; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchSet
Visible, base::Unretained(this), visible)); | 339 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchSet
Visible, base::Unretained(this), visible)); |
| 341 } | 340 } |
| 342 | 341 |
| 343 void ThreadedTest::postDidAddAnimationToMainThread() | 342 void ThreadedTest::postDidAddAnimationToMainThread() |
| 344 { | 343 { |
| 345 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchDid
AddAnimation, base::Unretained(this))); | 344 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchDid
AddAnimation, base::Unretained(this))); |
| 346 } | 345 } |
| 347 | 346 |
| 348 void ThreadedTest::doBeginTest() | 347 void ThreadedTest::doBeginTest() |
| 349 { | 348 { |
| 349 DCHECK(Proxy::isMainThread()); |
| 350 m_client = ThreadedMockLayerTreeHostClient::create(this); | 350 m_client = ThreadedMockLayerTreeHostClient::create(this); |
| 351 | 351 |
| 352 scoped_refptr<Layer> rootLayer = Layer::create(); | 352 scoped_refptr<Layer> rootLayer = Layer::create(); |
| 353 scoped_ptr<cc::Thread> implCCThread(NULL); | 353 m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer,
m_settings); |
| 354 if (m_implThread) | |
| 355 implCCThread = cc::ThreadImpl::createForDifferentThread(m_implThread->me
ssage_loop_proxy()); | |
| 356 m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer,
m_settings, implCCThread.Pass()); | |
| 357 ASSERT_TRUE(m_layerTreeHost.get()); | 354 ASSERT_TRUE(m_layerTreeHost.get()); |
| 358 rootLayer->setLayerTreeHost(m_layerTreeHost.get()); | 355 rootLayer->setLayerTreeHost(m_layerTreeHost.get()); |
| 359 m_layerTreeHost->setSurfaceReady(); | 356 m_layerTreeHost->setSurfaceReady(); |
| 360 | 357 |
| 361 m_started = true; | 358 m_started = true; |
| 362 m_beginning = true; | 359 m_beginning = true; |
| 363 beginTest(); | 360 beginTest(); |
| 364 m_beginning = false; | 361 m_beginning = false; |
| 365 if (m_endWhenBeginReturns) | 362 if (m_endWhenBeginReturns) |
| 366 realEndTest(); | 363 realEndTest(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 380 void ThreadedTest::scheduleComposite() | 377 void ThreadedTest::scheduleComposite() |
| 381 { | 378 { |
| 382 if (!m_started || m_scheduled || m_finished) | 379 if (!m_started || m_scheduled || m_finished) |
| 383 return; | 380 return; |
| 384 m_scheduled = true; | 381 m_scheduled = true; |
| 385 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchCom
posite, base::Unretained(this))); | 382 m_mainThreadProxy->postTask(FROM_HERE, base::Bind(&ThreadedTest::dispatchCom
posite, base::Unretained(this))); |
| 386 } | 383 } |
| 387 | 384 |
| 388 void ThreadedTest::realEndTest() | 385 void ThreadedTest::realEndTest() |
| 389 { | 386 { |
| 387 DCHECK(Proxy::isMainThread()); |
| 390 MessageLoop::current()->Quit(); | 388 MessageLoop::current()->Quit(); |
| 391 } | 389 } |
| 392 | 390 |
| 393 void ThreadedTest::dispatchSetNeedsAnimate() | 391 void ThreadedTest::dispatchSetNeedsAnimate() |
| 394 { | 392 { |
| 395 DCHECK(!proxy() || proxy()->isMainThread()); | 393 DCHECK(Proxy::isMainThread()); |
| 396 | 394 |
| 397 if (m_finished) | 395 if (m_finished) |
| 398 return; | 396 return; |
| 399 | 397 |
| 400 if (m_layerTreeHost.get()) | 398 if (m_layerTreeHost.get()) |
| 401 m_layerTreeHost->setNeedsAnimate(); | 399 m_layerTreeHost->setNeedsAnimate(); |
| 402 } | 400 } |
| 403 | 401 |
| 404 void ThreadedTest::dispatchAddInstantAnimation() | 402 void ThreadedTest::dispatchAddInstantAnimation() |
| 405 { | 403 { |
| 406 DCHECK(!proxy() || proxy()->isMainThread()); | 404 DCHECK(Proxy::isMainThread()); |
| 407 | 405 |
| 408 if (m_finished) | 406 if (m_finished) |
| 409 return; | 407 return; |
| 410 | 408 |
| 411 if (m_layerTreeHost.get() && m_layerTreeHost->rootLayer()) | 409 if (m_layerTreeHost.get() && m_layerTreeHost->rootLayer()) |
| 412 addOpacityTransitionToLayer(*m_layerTreeHost->rootLayer(), 0, 0, 0.5, fa
lse); | 410 addOpacityTransitionToLayer(*m_layerTreeHost->rootLayer(), 0, 0, 0.5, fa
lse); |
| 413 } | 411 } |
| 414 | 412 |
| 415 void ThreadedTest::dispatchAddAnimation(Layer* layerToReceiveAnimation) | 413 void ThreadedTest::dispatchAddAnimation(Layer* layerToReceiveAnimation) |
| 416 { | 414 { |
| 417 DCHECK(!proxy() || proxy()->isMainThread()); | 415 DCHECK(Proxy::isMainThread()); |
| 418 | 416 |
| 419 if (m_finished) | 417 if (m_finished) |
| 420 return; | 418 return; |
| 421 | 419 |
| 422 if (layerToReceiveAnimation) | 420 if (layerToReceiveAnimation) |
| 423 addOpacityTransitionToLayer(*layerToReceiveAnimation, 10, 0, 0.5, true); | 421 addOpacityTransitionToLayer(*layerToReceiveAnimation, 10, 0, 0.5, true); |
| 424 } | 422 } |
| 425 | 423 |
| 426 void ThreadedTest::dispatchSetNeedsAnimateAndCommit() | 424 void ThreadedTest::dispatchSetNeedsAnimateAndCommit() |
| 427 { | 425 { |
| 428 DCHECK(!proxy() || proxy()->isMainThread()); | 426 DCHECK(Proxy::isMainThread()); |
| 429 | 427 |
| 430 if (m_finished) | 428 if (m_finished) |
| 431 return; | 429 return; |
| 432 | 430 |
| 433 if (m_layerTreeHost.get()) { | 431 if (m_layerTreeHost.get()) { |
| 434 m_layerTreeHost->setNeedsAnimate(); | 432 m_layerTreeHost->setNeedsAnimate(); |
| 435 m_layerTreeHost->setNeedsCommit(); | 433 m_layerTreeHost->setNeedsCommit(); |
| 436 } | 434 } |
| 437 } | 435 } |
| 438 | 436 |
| 439 void ThreadedTest::dispatchSetNeedsCommit() | 437 void ThreadedTest::dispatchSetNeedsCommit() |
| 440 { | 438 { |
| 441 DCHECK(!proxy() || proxy()->isMainThread()); | 439 DCHECK(Proxy::isMainThread()); |
| 442 | 440 |
| 443 if (m_finished) | 441 if (m_finished) |
| 444 return; | 442 return; |
| 445 | 443 |
| 446 if (m_layerTreeHost.get()) | 444 if (m_layerTreeHost.get()) |
| 447 m_layerTreeHost->setNeedsCommit(); | 445 m_layerTreeHost->setNeedsCommit(); |
| 448 } | 446 } |
| 449 | 447 |
| 450 void ThreadedTest::dispatchAcquireLayerTextures() | 448 void ThreadedTest::dispatchAcquireLayerTextures() |
| 451 { | 449 { |
| 452 DCHECK(!proxy() || proxy()->isMainThread()); | 450 DCHECK(Proxy::isMainThread()); |
| 453 | 451 |
| 454 if (m_finished) | 452 if (m_finished) |
| 455 return; | 453 return; |
| 456 | 454 |
| 457 if (m_layerTreeHost.get()) | 455 if (m_layerTreeHost.get()) |
| 458 m_layerTreeHost->acquireLayerTextures(); | 456 m_layerTreeHost->acquireLayerTextures(); |
| 459 } | 457 } |
| 460 | 458 |
| 461 void ThreadedTest::dispatchSetNeedsRedraw() | 459 void ThreadedTest::dispatchSetNeedsRedraw() |
| 462 { | 460 { |
| 463 DCHECK(!proxy() || proxy()->isMainThread()); | 461 DCHECK(Proxy::isMainThread()); |
| 464 | 462 |
| 465 if (m_finished) | 463 if (m_finished) |
| 466 return; | 464 return; |
| 467 | 465 |
| 468 if (m_layerTreeHost.get()) | 466 if (m_layerTreeHost.get()) |
| 469 m_layerTreeHost->setNeedsRedraw(); | 467 m_layerTreeHost->setNeedsRedraw(); |
| 470 } | 468 } |
| 471 | 469 |
| 472 void ThreadedTest::dispatchSetVisible(bool visible) | 470 void ThreadedTest::dispatchSetVisible(bool visible) |
| 473 { | 471 { |
| 474 DCHECK(!proxy() || proxy()->isMainThread()); | 472 DCHECK(Proxy::isMainThread()); |
| 475 | 473 |
| 476 if (m_finished) | 474 if (m_finished) |
| 477 return; | 475 return; |
| 478 | 476 |
| 479 if (m_layerTreeHost.get()) | 477 if (m_layerTreeHost.get()) |
| 480 m_layerTreeHost->setVisible(visible); | 478 m_layerTreeHost->setVisible(visible); |
| 481 } | 479 } |
| 482 | 480 |
| 483 void ThreadedTest::dispatchComposite() | 481 void ThreadedTest::dispatchComposite() |
| 484 { | 482 { |
| 485 m_scheduled = false; | 483 m_scheduled = false; |
| 486 if (m_layerTreeHost.get() && !m_finished) | 484 if (m_layerTreeHost.get() && !m_finished) |
| 487 m_layerTreeHost->composite(); | 485 m_layerTreeHost->composite(); |
| 488 } | 486 } |
| 489 | 487 |
| 490 void ThreadedTest::dispatchDidAddAnimation() | 488 void ThreadedTest::dispatchDidAddAnimation() |
| 491 { | 489 { |
| 492 DCHECK(!proxy() || proxy()->isMainThread()); | 490 DCHECK(Proxy::isMainThread()); |
| 493 | 491 |
| 494 if (m_finished) | 492 if (m_finished) |
| 495 return; | 493 return; |
| 496 | 494 |
| 497 if (m_layerTreeHost.get()) | 495 if (m_layerTreeHost.get()) |
| 498 m_layerTreeHost->didAddAnimation(); | 496 m_layerTreeHost->didAddAnimation(); |
| 499 } | 497 } |
| 500 | 498 |
| 501 void ThreadedTest::runTest(bool threaded) | 499 void ThreadedTest::runTest(bool threaded) |
| 502 { | 500 { |
| 503 // For these tests, we will enable threaded animations. | 501 // For these tests, we will enable threaded animations. |
| 504 ScopedSettings scopedSettings; | 502 ScopedSettings scopedSettings; |
| 505 Settings::setAcceleratedAnimationEnabled(true); | 503 Settings::setAcceleratedAnimationEnabled(true); |
| 506 | 504 |
| 507 if (threaded) { | 505 if (threaded) { |
| 508 m_implThread.reset(new base::Thread("ThreadedTest")); | 506 m_implThread.reset(new base::Thread("ThreadedTest")); |
| 509 ASSERT_TRUE(m_implThread->Start()); | 507 ASSERT_TRUE(m_implThread->Start()); |
| 508 m_implCCThread = cc::ThreadImpl::createForDifferentThread(m_implThread->
message_loop_proxy()); |
| 509 cc::Proxy::setImplThread(m_implCCThread.get()); |
| 510 } | 510 } |
| 511 | 511 |
| 512 m_mainCCThread = cc::ThreadImpl::createForCurrentThread(); | 512 DCHECK(Proxy::isMainThread()); |
| 513 m_mainThreadProxy = ScopedThreadProxy::create(m_mainCCThread.get()); | 513 m_mainThreadProxy = ScopedThreadProxy::create(Proxy::mainThread()); |
| 514 | 514 |
| 515 initializeSettings(m_settings); | 515 initializeSettings(m_settings); |
| 516 | 516 |
| 517 m_mainCCThread->postTask(base::Bind(&ThreadedTest::doBeginTest, base::Unreta
ined(this))); | 517 cc::Proxy::mainThread()->postTask(base::Bind(&ThreadedTest::doBeginTest, bas
e::Unretained(this))); |
| 518 m_timeout.Reset(base::Bind(&ThreadedTest::timeout, base::Unretained(this))); | 518 m_timeout.Reset(base::Bind(&ThreadedTest::timeout, base::Unretained(this))); |
| 519 m_mainCCThread->postDelayedTask(m_timeout.callback(), 5000); | 519 cc::Proxy::mainThread()->postDelayedTask(m_timeout.callback(), 5000); |
| 520 MessageLoop::current()->Run(); | 520 MessageLoop::current()->Run(); |
| 521 if (m_layerTreeHost.get() && m_layerTreeHost->rootLayer()) | 521 if (m_layerTreeHost.get() && m_layerTreeHost->rootLayer()) |
| 522 m_layerTreeHost->rootLayer()->setLayerTreeHost(0); | 522 m_layerTreeHost->rootLayer()->setLayerTreeHost(0); |
| 523 m_layerTreeHost.reset(); | 523 m_layerTreeHost.reset(); |
| 524 | 524 |
| 525 cc::Proxy::setImplThread(0); |
| 526 |
| 525 m_timeout.Cancel(); | 527 m_timeout.Cancel(); |
| 526 | 528 |
| 527 ASSERT_FALSE(m_layerTreeHost.get()); | 529 ASSERT_FALSE(m_layerTreeHost.get()); |
| 528 m_client.reset(); | 530 m_client.reset(); |
| 529 if (m_timedOut) { | 531 if (m_timedOut) { |
| 530 FAIL() << "Test timed out"; | 532 FAIL() << "Test timed out"; |
| 531 return; | 533 return; |
| 532 } | 534 } |
| 533 afterTest(); | 535 afterTest(); |
| 534 } | 536 } |
| 535 | 537 |
| 536 } // namespace WebKitTests | 538 } // namespace WebKitTests |
| OLD | NEW |