0

Enable webkit_compositor_unittests

These are unit tests of the webkit compositor bindings that bind the
WebKit Platform Web*Layer* family of APIs to cc. They currently depend
on some test utilities in cc.

Also updates snapshot to WebKit r127194

BUG=

Review URL: https://chromiumcodereview.appspot.com/10909020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154307 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
jamesr@chromium.org
2012-08-30 23:25:27 +00:00
parent ce71608c07
commit c0dd24c4c6
34 changed files with 5810 additions and 191 deletions

@ -749,6 +749,8 @@ void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor)
if (deviceScaleFactor == m_deviceScaleFactor)
return;
m_deviceScaleFactor = deviceScaleFactor;
updateMaxScrollPosition();
}

@ -380,6 +380,24 @@ TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
}
TEST_F(CCLayerTreeHostImplTest, maxScrollPositionChangedByDeviceScaleFactor)
{
setupScrollAndContentsLayers(IntSize(100, 100));
float deviceScaleFactor = 2;
IntSize layoutViewport(25, 25);
IntSize deviceViewport(layoutViewport);
deviceViewport.scale(deviceScaleFactor);
m_hostImpl->setViewportSize(layoutViewport, deviceViewport);
m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(25, 25));
deviceScaleFactor = 1;
m_hostImpl->setViewportSize(layoutViewport, layoutViewport);
m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(75, 75));
}
TEST_F(CCLayerTreeHostImplTest, pinchGesture)
{
setupScrollAndContentsLayers(IntSize(100, 100));

@ -497,6 +497,63 @@ TEST_F(CCLayerTreeHostTestAbortFrameWhenInvisible, runMultiThread)
runTest(true);
}
// Makes sure that setNedsAnimate does not cause the commitRequested() state to be set.
class CCLayerTreeHostTestSetNeedsAnimateShouldNotSetCommitRequested : public CCLayerTreeHostTest {
public:
CCLayerTreeHostTestSetNeedsAnimateShouldNotSetCommitRequested()
: m_numCommits(0)
{
}
virtual void beginTest() OVERRIDE
{
// The tests start up with a commit pending because we give them a root layer.
// We need to wait for the commit to happen before doing anything.
EXPECT_TRUE(m_layerTreeHost->commitRequested());
}
virtual void animate(double monotonicTime) OVERRIDE
{
// We skip the first commit becasue its the commit that populates the
// impl thread with a tree.
if (!m_numCommits)
return;
m_layerTreeHost->setNeedsAnimate();
// Right now, commitRequested is going to be true, because during
// beginFrame, we force commitRequested to true to prevent requests from
// hitting the impl thread. But, when the next didCommit happens, we should
// verify that commitRequested has gone back to false.
}
virtual void didCommit() OVERRIDE
{
if (!m_numCommits) {
EXPECT_FALSE(m_layerTreeHost->commitRequested());
m_layerTreeHost->setNeedsAnimate();
EXPECT_FALSE(m_layerTreeHost->commitRequested());
m_numCommits++;
}
// Verifies that the setNeedsAnimate we made in ::animate did not
// trigger commitRequested.
EXPECT_FALSE(m_layerTreeHost->commitRequested());
endTest();
}
virtual void afterTest() OVERRIDE
{
}
private:
int m_numCommits;
};
TEST_F(CCLayerTreeHostTestSetNeedsAnimateShouldNotSetCommitRequested, runMultiThread)
{
runTest(true);
}
// Trigger a frame with setNeedsCommit. Then, inside the resulting animate
// callback, requet another frame using setNeedsAnimate. End the test when
@ -891,7 +948,7 @@ private:
int m_scrolls;
};
TEST_F(CCLayerTreeHostTestScrollSimple, DISABLED_runMultiThread)
TEST_F(CCLayerTreeHostTestScrollSimple, runMultiThread)
{
runTest(true);
}
@ -2218,8 +2275,7 @@ private:
RefPtr<LayerChromium> m_rootScrollLayer;
};
// https://bugs.webkit.org/show_bug.cgi?id=95358
TEST_F(CCLayerTreeHostTestScrollChildLayer, DISABLED_runMultiThread)
TEST_F(CCLayerTreeHostTestScrollChildLayer, runMultiThread)
{
runTest(true);
}

@ -13,7 +13,6 @@ namespace WebCore {
CCScheduler::CCScheduler(CCSchedulerClient* client, PassOwnPtr<CCFrameRateController> frameRateController)
: m_client(client)
, m_frameRateController(frameRateController)
, m_hasMoreResourceUpdates(false)
, m_updateMoreResourcesPending(false)
{
ASSERT(m_client);
@ -68,10 +67,9 @@ void CCScheduler::setMainThreadNeedsLayerTextures()
processScheduledActions();
}
void CCScheduler::beginFrameComplete(bool hasResourceUpdates)
void CCScheduler::beginFrameComplete()
{
TRACE_EVENT0("cc", "CCScheduler::beginFrameComplete");
m_hasMoreResourceUpdates = hasResourceUpdates;
m_stateMachine.beginFrameComplete();
processScheduledActions();
}
@ -118,8 +116,7 @@ void CCScheduler::vsyncTick()
{
if (m_updateMoreResourcesPending) {
m_updateMoreResourcesPending = false;
ASSERT(m_hasMoreResourceUpdates);
m_stateMachine.beginUpdateMoreResourcesComplete(true);
m_stateMachine.beginUpdateMoreResourcesComplete(m_client->hasMoreResourceUpdates());
}
TRACE_EVENT0("cc", "CCScheduler::vsyncTick");
@ -128,17 +125,6 @@ void CCScheduler::vsyncTick()
m_stateMachine.didLeaveVSync();
}
void CCScheduler::updateResourcesComplete()
{
TRACE_EVENT0("cc", "CCScheduler::updateResourcesComplete");
if (m_updateMoreResourcesPending) {
m_updateMoreResourcesPending = false;
m_stateMachine.beginUpdateMoreResourcesComplete(false);
}
m_hasMoreResourceUpdates = false;
processScheduledActions();
}
CCSchedulerStateMachine::Action CCScheduler::nextAction()
{
m_stateMachine.setCanDraw(m_client->canDraw());
@ -168,7 +154,7 @@ void CCScheduler::processScheduledActions()
m_client->scheduledActionBeginFrame();
break;
case CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES:
if (m_hasMoreResourceUpdates) {
if (m_client->hasMoreResourceUpdates()) {
m_client->scheduledActionUpdateMoreResources(m_frameRateController->nextTickTimeIfActivated());
m_updateMoreResourcesPending = true;
} else

@ -33,6 +33,7 @@ struct CCScheduledActionDrawAndSwapResult {
class CCSchedulerClient {
public:
virtual bool canDraw() = 0;
virtual bool hasMoreResourceUpdates() const = 0;
virtual void scheduledActionBeginFrame() = 0;
virtual CCScheduledActionDrawAndSwapResult scheduledActionDrawAndSwapIfPossible() = 0;
@ -72,7 +73,7 @@ public:
// Like setNeedsRedraw(), but ensures the draw will definitely happen even if we are not visible.
void setNeedsForcedRedraw();
void beginFrameComplete(bool hasResourceUpdates);
void beginFrameComplete();
void beginFrameAborted();
void setMaxFramesPending(int);
@ -89,8 +90,6 @@ public:
// CCFrameRateControllerClient implementation
virtual void vsyncTick() OVERRIDE;
void updateResourcesComplete();
private:
CCScheduler(CCSchedulerClient*, PassOwnPtr<CCFrameRateController>);
@ -100,7 +99,6 @@ private:
CCSchedulerClient* m_client;
OwnPtr<CCFrameRateController> m_frameRateController;
CCSchedulerStateMachine m_stateMachine;
bool m_hasMoreResourceUpdates;
bool m_updateMoreResourcesPending;
};

@ -23,12 +23,14 @@ public:
void reset()
{
m_actions.clear();
m_hasMoreResourceUpdates = false;
m_canDraw = true;
m_drawWillHappen = true;
m_swapWillHappenIfDrawHappens = true;
m_numDraws = 0;
}
void setHasMoreResourceUpdates(bool b) { m_hasMoreResourceUpdates = b; }
void setCanDraw(bool b) { m_canDraw = b; }
int numDraws() const { return m_numDraws; }
@ -44,6 +46,7 @@ public:
}
virtual bool canDraw() OVERRIDE { return m_canDraw; }
virtual bool hasMoreResourceUpdates() const OVERRIDE { return m_hasMoreResourceUpdates; }
virtual void scheduledActionBeginFrame() OVERRIDE { m_actions.push_back("scheduledActionBeginFrame"); }
virtual CCScheduledActionDrawAndSwapResult scheduledActionDrawAndSwapIfPossible() OVERRIDE
{
@ -90,9 +93,9 @@ TEST(CCSchedulerTest, RequestCommit)
EXPECT_FALSE(timeSource->active());
client.reset();
// Since, hasResourceUpdates is false,
// Since, hasMoreResourceUpdates is set to false,
// beginFrameComplete should commit
scheduler->beginFrameComplete(false);
scheduler->beginFrameComplete();
EXPECT_EQ(1, client.numActions());
EXPECT_STREQ("scheduledActionCommit", client.action(0));
EXPECT_TRUE(timeSource->active());
@ -126,9 +129,9 @@ TEST(CCSchedulerTest, RequestCommitAfterBeginFrame)
// Now setNeedsCommit again. Calling here means we need a second frame.
scheduler->setNeedsCommit();
// Since, hasResourceUpdates is false, and another commit is
// Since, hasMoreResourceUpdates is set to false, and another commit is
// needed, beginFrameComplete should commit, then begin another frame.
scheduler->beginFrameComplete(false);
scheduler->beginFrameComplete();
EXPECT_EQ(1, client.numActions());
EXPECT_STREQ("scheduledActionCommit", client.action(0));
client.reset();
@ -161,7 +164,7 @@ TEST(CCSchedulerTest, TextureAcquisitionCollision)
EXPECT_FALSE(timeSource->active());
// Trigger the commit
scheduler->beginFrameComplete(false);
scheduler->beginFrameComplete();
EXPECT_TRUE(timeSource->active());
client.reset();
@ -189,7 +192,7 @@ TEST(CCSchedulerTest, VisibilitySwitchWithTextureAcquisition)
scheduler->setVisible(true);
scheduler->setNeedsCommit();
scheduler->beginFrameComplete(false);
scheduler->beginFrameComplete();
scheduler->setMainThreadNeedsLayerTextures();
client.reset();
// Verify that pending texture acquisition fires when visibility
@ -358,7 +361,7 @@ TEST(CCSchedulerTest, RequestCommitInsideDraw)
EXPECT_FALSE(timeSource->active());
EXPECT_EQ(1, client.numDraws());
EXPECT_TRUE(scheduler->commitPending());
scheduler->beginFrameComplete(false);
scheduler->beginFrameComplete();
timeSource->tick();
EXPECT_EQ(2, client.numDraws());

@ -92,9 +92,8 @@ void CCTextureUpdateController::updateTextures(CCResourceProvider* resourceProvi
copier->flush();
}
CCTextureUpdateController::CCTextureUpdateController(CCTextureUpdateControllerClient* client, CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
: m_client(client)
, m_timer(adoptPtr(new CCTimer(thread, this)))
CCTextureUpdateController::CCTextureUpdateController(CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
: m_timer(adoptPtr(new CCTimer(thread, this)))
, m_queue(queue)
, m_resourceProvider(resourceProvider)
, m_copier(copier)
@ -108,40 +107,34 @@ CCTextureUpdateController::~CCTextureUpdateController()
{
}
bool CCTextureUpdateController::hasMoreUpdates() const
{
return m_queue->hasMoreUpdates();
}
void CCTextureUpdateController::updateMoreTextures(double monotonicTimeLimit)
{
ASSERT(monotonicTimeLimit >= m_monotonicTimeLimit);
m_monotonicTimeLimit = monotonicTimeLimit;
// Update already in progress.
if (m_timer->isActive())
if (!m_queue->hasMoreUpdates())
return;
// Call updateMoreTexturesNow() directly unless it's the first update
// attempt. This ensures that we empty the update queue in a finite
// amount of time.
if (m_firstUpdateAttempt) {
// Post a 0-delay task when no updates were left. When it runs,
// updateTexturesCompleted() will be called.
if (!updateMoreTexturesIfEnoughTimeRemaining())
m_timer->startOneShot(0);
updateMoreTexturesIfEnoughTimeRemaining();
m_firstUpdateAttempt = false;
} else
updateMoreTexturesNow();
}
void CCTextureUpdateController::discardUploads()
{
// CCTextureUpdateControllerClient::updateTexturesCompleted will be
// called when all remaining texture copies are done.
m_queue->clearUploads();
}
void CCTextureUpdateController::onTimerFired()
{
if (!updateMoreTexturesIfEnoughTimeRemaining())
m_client->updateTexturesCompleted();
if (!m_queue->hasMoreUpdates())
return;
updateMoreTexturesIfEnoughTimeRemaining();
}
double CCTextureUpdateController::monotonicTimeNow() const
@ -159,16 +152,11 @@ size_t CCTextureUpdateController::updateMoreTexturesSize() const
return textureUpdatesPerTick;
}
bool CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
void CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
{
if (!m_queue->hasMoreUpdates())
return false;
bool hasTimeRemaining = monotonicTimeNow() < m_monotonicTimeLimit - updateMoreTexturesTime();
if (hasTimeRemaining)
updateMoreTexturesNow();
return true;
}
void CCTextureUpdateController::updateMoreTexturesNow()

@ -15,31 +15,21 @@ namespace WebCore {
class TextureCopier;
class TextureUploader;
class CCTextureUpdateControllerClient {
public:
virtual void updateTexturesCompleted() = 0;
protected:
virtual ~CCTextureUpdateControllerClient() { }
};
class CCTextureUpdateController : public CCTimerClient {
WTF_MAKE_NONCOPYABLE(CCTextureUpdateController);
public:
static PassOwnPtr<CCTextureUpdateController> create(CCTextureUpdateControllerClient* client, CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
static PassOwnPtr<CCTextureUpdateController> create(CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
{
return adoptPtr(new CCTextureUpdateController(client, thread, queue, resourceProvider, copier, uploader));
return adoptPtr(new CCTextureUpdateController(thread, queue, resourceProvider, copier, uploader));
}
static size_t maxPartialTextureUpdates();
static void updateTextures(CCResourceProvider*, TextureCopier*, TextureUploader*, CCTextureUpdateQueue*, size_t count);
virtual ~CCTextureUpdateController();
bool hasMoreUpdates() const;
void updateMoreTextures(double monotonicTimeLimit);
// Discard all remaining uploads.
void discardUploads();
// CCTimerClient implementation.
virtual void onTimerFired() OVERRIDE;
@ -49,13 +39,11 @@ public:
virtual size_t updateMoreTexturesSize() const;
protected:
CCTextureUpdateController(CCTextureUpdateControllerClient*, CCThread*, PassOwnPtr<CCTextureUpdateQueue>, CCResourceProvider*, TextureCopier*, TextureUploader*);
CCTextureUpdateController(CCThread*, PassOwnPtr<CCTextureUpdateQueue>, CCResourceProvider*, TextureCopier*, TextureUploader*);
// This returns true when there were textures left to update.
bool updateMoreTexturesIfEnoughTimeRemaining();
void updateMoreTexturesIfEnoughTimeRemaining();
void updateMoreTexturesNow();
CCTextureUpdateControllerClient* m_client;
OwnPtr<CCTimer> m_timer;
OwnPtr<CCTextureUpdateQueue> m_queue;
bool m_contentsTexturesPurged;

@ -521,23 +521,11 @@ TEST_F(CCTextureUpdateControllerTest, TripleUpdateFinalUpdateAllPartial)
EXPECT_EQ(kFullUploads + kPartialUploads, m_numTotalUploads);
}
class FakeCCTextureUpdateControllerClient : public WebCore::CCTextureUpdateControllerClient {
public:
FakeCCTextureUpdateControllerClient() { reset(); }
void reset() { m_completedCalled = false; }
bool completedCalled() const { return m_completedCalled; }
virtual void updateTexturesCompleted() OVERRIDE { m_completedCalled = true; }
protected:
bool m_completedCalled;
};
class FakeCCTextureUpdateController : public WebCore::CCTextureUpdateController {
public:
static PassOwnPtr<FakeCCTextureUpdateController> create(WebCore::CCTextureUpdateControllerClient* client, WebCore::CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
static PassOwnPtr<FakeCCTextureUpdateController> create(WebCore::CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
{
return adoptPtr(new FakeCCTextureUpdateController(client, thread, queue, resourceProvider, copier, uploader));
return adoptPtr(new FakeCCTextureUpdateController(thread, queue, resourceProvider, copier, uploader));
}
void setMonotonicTimeNow(double time) { m_monotonicTimeNow = time; }
@ -548,8 +536,8 @@ public:
virtual size_t updateMoreTexturesSize() const OVERRIDE { return m_updateMoreTexturesSize; }
protected:
FakeCCTextureUpdateController(WebCore::CCTextureUpdateControllerClient* client, WebCore::CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
: WebCore::CCTextureUpdateController(client, thread, queue, resourceProvider, copier, uploader)
FakeCCTextureUpdateController(WebCore::CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader)
: WebCore::CCTextureUpdateController(thread, queue, resourceProvider, copier, uploader)
, m_monotonicTimeNow(0)
, m_updateMoreTexturesTime(0)
, m_updateMoreTexturesSize(0) { }
@ -559,17 +547,8 @@ protected:
size_t m_updateMoreTexturesSize;
};
static void runPendingTasks(FakeCCThread* thread, FakeCCTextureUpdateController* controller)
{
while (thread->hasPendingTask()) {
controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread->pendingDelayMs() / 1000.0);
thread->runPendingTask();
}
}
TEST_F(CCTextureUpdateControllerTest, UpdateMoreTextures)
{
FakeCCTextureUpdateControllerClient client;
FakeCCThread thread;
setMaxUploadCountPerUpdate(1);
@ -577,34 +556,39 @@ TEST_F(CCTextureUpdateControllerTest, UpdateMoreTextures)
appendPartialUploadsToUpdateQueue(0);
DebugScopedSetImplThread implThread;
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.1);
controller->setUpdateMoreTexturesSize(1);
// Not enough time for any updates.
controller->updateMoreTextures(0.09);
runPendingTasks(&thread, controller.get());
EXPECT_FALSE(thread.hasPendingTask());
EXPECT_EQ(0, m_numBeginUploads);
EXPECT_EQ(0, m_numEndUploads);
thread.reset();
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.1);
controller->setUpdateMoreTexturesSize(1);
// Only enough time for 1 update.
controller->updateMoreTextures(0.12);
runPendingTasks(&thread, controller.get());
EXPECT_TRUE(thread.hasPendingTask());
controller->setMonotonicTimeNow(thread.pendingDelayMs() / 1000.0);
thread.runPendingTask();
EXPECT_EQ(1, m_numBeginUploads);
EXPECT_EQ(1, m_numEndUploads);
EXPECT_EQ(1, m_numTotalUploads);
thread.reset();
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.1);
controller->setUpdateMoreTexturesSize(1);
// Enough time for 2 updates.
controller->updateMoreTextures(0.22);
runPendingTasks(&thread, controller.get());
EXPECT_TRUE(client.completedCalled());
EXPECT_TRUE(thread.hasPendingTask());
controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread.pendingDelayMs() / 1000.0);
thread.runPendingTask();
EXPECT_EQ(3, m_numBeginUploads);
EXPECT_EQ(3, m_numEndUploads);
EXPECT_EQ(3, m_numTotalUploads);
@ -612,7 +596,6 @@ TEST_F(CCTextureUpdateControllerTest, UpdateMoreTextures)
TEST_F(CCTextureUpdateControllerTest, NoMoreUpdates)
{
FakeCCTextureUpdateControllerClient client;
FakeCCThread thread;
setMaxUploadCountPerUpdate(1);
@ -620,26 +603,30 @@ TEST_F(CCTextureUpdateControllerTest, NoMoreUpdates)
appendPartialUploadsToUpdateQueue(0);
DebugScopedSetImplThread implThread;
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.1);
controller->setUpdateMoreTexturesSize(1);
// Enough time for 3 updates but only 2 necessary.
controller->updateMoreTextures(0.31);
runPendingTasks(&thread, controller.get());
EXPECT_TRUE(client.completedCalled());
EXPECT_TRUE(thread.hasPendingTask());
controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread.pendingDelayMs() / 1000.0);
thread.runPendingTask();
EXPECT_TRUE(thread.hasPendingTask());
controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread.pendingDelayMs() / 1000.0);
thread.runPendingTask();
EXPECT_EQ(2, m_numBeginUploads);
EXPECT_EQ(2, m_numEndUploads);
EXPECT_EQ(2, m_numTotalUploads);
thread.reset();
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.1);
controller->setUpdateMoreTexturesSize(1);
// Enough time for updates but no more updates left.
controller->updateMoreTextures(0.31);
runPendingTasks(&thread, controller.get());
EXPECT_TRUE(client.completedCalled());
EXPECT_FALSE(thread.hasPendingTask());
EXPECT_EQ(2, m_numBeginUploads);
EXPECT_EQ(2, m_numEndUploads);
EXPECT_EQ(2, m_numTotalUploads);
@ -647,7 +634,6 @@ TEST_F(CCTextureUpdateControllerTest, NoMoreUpdates)
TEST_F(CCTextureUpdateControllerTest, UpdatesCompleteInFiniteTime)
{
FakeCCTextureUpdateControllerClient client;
FakeCCThread thread;
setMaxUploadCountPerUpdate(1);
@ -655,22 +641,25 @@ TEST_F(CCTextureUpdateControllerTest, UpdatesCompleteInFiniteTime)
appendPartialUploadsToUpdateQueue(0);
DebugScopedSetImplThread implThread;
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
OwnPtr<FakeCCTextureUpdateController> controller(FakeCCTextureUpdateController::create(&thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader));
controller->setMonotonicTimeNow(0);
controller->setUpdateMoreTexturesTime(0.5);
controller->setUpdateMoreTexturesSize(1);
for (int i = 0; i < 100; i++) {
if (client.completedCalled())
if (!controller->hasMoreUpdates())
break;
// Not enough time for any updates.
controller->updateMoreTextures(0.4);
runPendingTasks(&thread, controller.get());
if (thread.hasPendingTask()) {
controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread.pendingDelayMs() / 1000.0);
thread.runPendingTask();
}
}
EXPECT_TRUE(client.completedCalled());
EXPECT_EQ(2, m_numBeginUploads);
EXPECT_EQ(2, m_numEndUploads);
EXPECT_EQ(2, m_numTotalUploads);

@ -14,6 +14,7 @@
#include "CCLayerTreeHost.h"
#include "CCScheduler.h"
#include "CCScopedThreadProxy.h"
#include "CCTextureUpdateController.h"
#include "CCThreadTask.h"
#include "TraceEvent.h"
#include <public/WebSharedGraphicsContext3D.h>
@ -47,6 +48,7 @@ PassOwnPtr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost)
CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
: m_animateRequested(false)
, m_commitRequested(false)
, m_commitRequestSentToImplThread(false)
, m_forcedCommitRequested(false)
, m_layerTreeHost(layerTreeHost)
, m_compositorIdentifier(-1)
@ -275,7 +277,11 @@ void CCThreadProxy::setNeedsAnimate()
TRACE_EVENT0("cc", "CCThreadProxy::setNeedsAnimate");
m_animateRequested = true;
setNeedsCommit();
if (m_commitRequestSentToImplThread)
return;
m_commitRequestSentToImplThread = true;
CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnImplThread));
}
void CCThreadProxy::setNeedsCommit()
@ -283,9 +289,12 @@ void CCThreadProxy::setNeedsCommit()
ASSERT(isMainThread());
if (m_commitRequested)
return;
TRACE_EVENT0("cc", "CCThreadProxy::setNeedsCommit");
m_commitRequested = true;
if (m_commitRequestSentToImplThread)
return;
m_commitRequestSentToImplThread = true;
CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnImplThread));
}
@ -293,8 +302,7 @@ void CCThreadProxy::didLoseContextOnImplThread()
{
ASSERT(isImplThread());
TRACE_EVENT0("cc", "CCThreadProxy::didLoseContextOnImplThread");
if (m_currentTextureUpdateControllerOnImplThread)
m_currentTextureUpdateControllerOnImplThread->discardUploads();
m_currentTextureUpdateControllerOnImplThread.clear();
m_schedulerOnImplThread->didLoseContext();
}
@ -468,6 +476,7 @@ void CCThreadProxy::beginFrame()
// the paint, m_commitRequested will be set to false to allow new commit
// requests to be scheduled.
m_commitRequested = true;
m_commitRequestSentToImplThread = true;
// On the other hand, the animationRequested flag needs to be cleared
// here so that any animation requests generated by the apply or animate
@ -480,6 +489,7 @@ void CCThreadProxy::beginFrame()
if (!m_inCompositeAndReadback && !m_layerTreeHost->visible()) {
m_commitRequested = false;
m_commitRequestSentToImplThread = false;
m_forcedCommitRequested = false;
TRACE_EVENT0("cc", "EarlyOut_NotVisible");
@ -496,6 +506,7 @@ void CCThreadProxy::beginFrame()
// layout when painted will trigger another setNeedsCommit inside
// updateLayers.
m_commitRequested = false;
m_commitRequestSentToImplThread = false;
m_forcedCommitRequested = false;
if (!m_layerTreeHost->initializeRendererIfNeeded())
@ -512,11 +523,16 @@ void CCThreadProxy::beginFrame()
m_texturesAcquired = false;
m_layerTreeHost->willCommit();
// Before applying scrolls and calling animate, we set m_animateRequested to false.
// If it is true now, it means setNeedAnimate was called again. Call setNeedsCommit
// now so that we get begin frame when this one is done.
if (m_animateRequested)
setNeedsCommit();
// Before applying scrolls and calling animate, we set m_animateRequested to
// false. If it is true now, it means setNeedAnimate was called again, but
// during a state when m_commitRequestSentToImplThread = true. We need to
// force that call to happen again now so that the commit request is sent to
// the impl thread.
if (m_animateRequested) {
// Forces setNeedsAnimate to consider posting a commit task.
m_animateRequested = false;
setNeedsAnimate();
}
// Notify the impl thread that the beginFrame has completed. This will
// begin the commit process, which is blocking from the main thread's
@ -558,12 +574,10 @@ void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion
} else
m_resetContentsTexturesPurgedAfterCommitOnImplThread = true;
bool hasResourceUpdates = queue->hasMoreUpdates();
if (hasResourceUpdates)
m_currentTextureUpdateControllerOnImplThread = CCTextureUpdateController::create(this, CCProxy::implThread(), queue, m_layerTreeHostImpl->resourceProvider(), m_layerTreeHostImpl->renderer()->textureCopier(), m_layerTreeHostImpl->renderer()->textureUploader());
m_currentTextureUpdateControllerOnImplThread = CCTextureUpdateController::create(CCProxy::implThread(), queue, m_layerTreeHostImpl->resourceProvider(), m_layerTreeHostImpl->renderer()->textureCopier(), m_layerTreeHostImpl->renderer()->textureUploader());
m_commitCompletionEventOnImplThread = completion;
m_schedulerOnImplThread->beginFrameComplete(hasResourceUpdates);
m_schedulerOnImplThread->beginFrameComplete();
}
void CCThreadProxy::beginFrameAbortedOnImplThread()
@ -576,6 +590,13 @@ void CCThreadProxy::beginFrameAbortedOnImplThread()
m_schedulerOnImplThread->beginFrameAborted();
}
bool CCThreadProxy::hasMoreResourceUpdates() const
{
if (!m_currentTextureUpdateControllerOnImplThread)
return false;
return m_currentTextureUpdateControllerOnImplThread->hasMoreUpdates();
}
bool CCThreadProxy::canDraw()
{
ASSERT(isImplThread());
@ -595,6 +616,7 @@ void CCThreadProxy::scheduledActionCommit()
{
TRACE_EVENT0("cc", "CCThreadProxy::scheduledActionCommit");
ASSERT(isImplThread());
ASSERT(!hasMoreResourceUpdates());
ASSERT(m_commitCompletionEventOnImplThread);
m_currentTextureUpdateControllerOnImplThread.clear();
@ -732,12 +754,6 @@ CCScheduledActionDrawAndSwapResult CCThreadProxy::scheduledActionDrawAndSwapForc
return scheduledActionDrawAndSwapInternal(true);
}
void CCThreadProxy::updateTexturesCompleted()
{
ASSERT(isImplThread());
m_schedulerOnImplThread->updateResourcesComplete();
}
void CCThreadProxy::didCommitAndDrawFrame()
{
ASSERT(isMainThread());

@ -10,7 +10,6 @@
#include "CCLayerTreeHostImpl.h"
#include "CCProxy.h"
#include "CCScheduler.h"
#include "CCTextureUpdateController.h"
#include <wtf/OwnPtr.h>
namespace WebCore {
@ -20,10 +19,11 @@ class CCLayerTreeHost;
class CCScheduler;
class CCScopedThreadProxy;
class CCTextureUpdateQueue;
class CCTextureUpdateController;
class CCThread;
class CCThreadProxyContextRecreationTimer;
class CCThreadProxy : public CCProxy, CCLayerTreeHostImplClient, CCSchedulerClient, CCTextureUpdateControllerClient {
class CCThreadProxy : public CCProxy, CCLayerTreeHostImplClient, CCSchedulerClient {
public:
static PassOwnPtr<CCProxy> create(CCLayerTreeHost*);
@ -64,6 +64,7 @@ public:
// CCSchedulerClient implementation
virtual bool canDraw() OVERRIDE;
virtual bool hasMoreResourceUpdates() const OVERRIDE;
virtual void scheduledActionBeginFrame() OVERRIDE;
virtual CCScheduledActionDrawAndSwapResult scheduledActionDrawAndSwapIfPossible() OVERRIDE;
virtual CCScheduledActionDrawAndSwapResult scheduledActionDrawAndSwapForced() OVERRIDE;
@ -72,9 +73,6 @@ public:
virtual void scheduledActionBeginContextRecreation() OVERRIDE;
virtual void scheduledActionAcquireLayerTexturesForMainThread() OVERRIDE;
// CCTextureUpdateControllerClient implementation
virtual void updateTexturesCompleted() OVERRIDE;
private:
explicit CCThreadProxy(CCLayerTreeHost*);
friend class CCThreadProxyContextRecreationTimer;
@ -129,8 +127,9 @@ private:
void setNeedsForcedCommitOnImplThread();
// Accessed on main thread only.
bool m_animateRequested;
bool m_commitRequested;
bool m_animateRequested; // Set only when setNeedsAnimate is called.
bool m_commitRequested; // Set only when setNeedsCommit is called.
bool m_commitRequestSentToImplThread; // Set by setNeedsCommit and setNeedsAnimate.
bool m_forcedCommitRequested;
OwnPtr<CCThreadProxyContextRecreationTimer> m_contextRecreationTimer;
CCLayerTreeHost* m_layerTreeHost;

@ -40,6 +40,8 @@
'CCThreadedTest.h',
'CCTiledLayerImplTest.cpp',
'CCTimerTest.cpp',
],
'cc_tests_support_files': [
'test/CCAnimationTestCommon.cpp',
'test/CCAnimationTestCommon.h',
'test/CCLayerTestCommon.cpp',
@ -60,7 +62,7 @@
'test/FakeWebGraphicsContext3D.h',
'test/FakeWebScrollbarThemeGeometry.h',
'test/MockCCQuadCuller.h',
]
],
},
'conditions': [
['use_libcc_for_compositor==1 and component!="shared_library"', {
@ -69,15 +71,16 @@
'target_name': 'cc_unittests',
'type': 'executable',
'dependencies': [
'<(DEPTH)/base/base.gyp:test_support_base',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(DEPTH)/webkit/support/webkit_support.gyp:webkit_support',
'<(DEPTH)/skia/skia.gyp:skia',
'../base/base.gyp:test_support_base',
'../testing/gtest.gyp:gtest',
'../testing/gmock.gyp:gmock',
'../webkit/support/webkit_support.gyp:webkit_support',
'../skia/skia.gyp:skia',
# We have to depend on WTF directly to pick up the correct defines for WTF headers - for instance USE_SYSTEM_MALLOC.
'<(DEPTH)/third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'<(DEPTH)/third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
'../third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'../third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
'cc.gyp:cc',
'cc_test_support',
],
'defines': [
'WTF_USE_ACCELERATED_COMPOSITING=1',
@ -92,6 +95,30 @@
'test/run_all_unittests.cc',
],
},
{
'target_name': 'cc_test_support',
'type': 'static_library',
'defines': [
'WTF_USE_ACCELERATED_COMPOSITING=1',
],
'include_dirs': [
'stubs',
'test',
'.',
'..',
],
'dependencies': [
'../ui/gl/gl.gyp:gl',
'../testing/gtest.gyp:gtest',
'../testing/gmock.gyp:gmock',
'../skia/skia.gyp:skia',
'../third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'../third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
],
'sources': [
'<@(cc_tests_support_files)',
],
},
],
}, {
'targets': [

@ -61,16 +61,15 @@ def Readfile(gypfile):
obj = eval(cc_gyp.read())
return obj
def Main():
files = Readfile("cc.gyp")['variables']['cc_source_files']
def CopyFiles(files):
for f in files:
dst = Copy(f)
FixCopyrightHeader(dst)
files = Readfile("cc_tests.gyp")['variables']['cc_tests_source_files']
for f in files:
dst = Copy(f)
FixCopyrightHeader(dst)
def Main():
CopyFiles(Readfile("cc.gyp")['variables']['cc_source_files'])
CopyFiles(Readfile("cc_tests.gyp")['variables']['cc_tests_source_files'])
CopyFiles(Readfile("cc_tests.gyp")['variables']['cc_tests_support_files'])
if __name__ == '__main__':
import sys

@ -65,6 +65,16 @@ FakeFloatAnimationCurve::~FakeFloatAnimationCurve()
{
}
double FakeFloatAnimationCurve::duration() const
{
return 1;
}
float FakeFloatAnimationCurve::getValue(double now) const
{
return 0;
}
PassOwnPtr<WebCore::CCAnimationCurve> FakeFloatAnimationCurve::clone() const
{
return adoptPtr(new FakeFloatAnimationCurve);
@ -79,6 +89,11 @@ FakeTransformTransition::~FakeTransformTransition()
{
}
double FakeTransformTransition::duration() const
{
return m_duration;
}
WebKit::WebTransformationMatrix FakeTransformTransition::getValue(double time) const
{
return WebKit::WebTransformationMatrix();
@ -101,6 +116,11 @@ FakeFloatTransition::~FakeFloatTransition()
{
}
double FakeFloatTransition::duration() const
{
return m_duration;
}
float FakeFloatTransition::getValue(double time) const
{
time /= m_duration;
@ -118,6 +138,31 @@ FakeLayerAnimationControllerClient::~FakeLayerAnimationControllerClient()
{
}
int FakeLayerAnimationControllerClient::id() const
{
return 0;
}
void FakeLayerAnimationControllerClient::setOpacityFromAnimation(float opacity)
{
m_opacity = opacity;
}
float FakeLayerAnimationControllerClient::opacity() const
{
return m_opacity;
}
void FakeLayerAnimationControllerClient::setTransformFromAnimation(const WebKit::WebTransformationMatrix& transform)
{
m_transform = transform;
}
const WebKit::WebTransformationMatrix& FakeLayerAnimationControllerClient::transform() const
{
return m_transform;
}
PassOwnPtr<WebCore::CCAnimationCurve> FakeFloatTransition::clone() const
{
return adoptPtr(new FakeFloatTransition(*this));

@ -24,8 +24,8 @@ public:
FakeFloatAnimationCurve();
virtual ~FakeFloatAnimationCurve();
virtual double duration() const OVERRIDE { return 1; }
virtual float getValue(double now) const OVERRIDE { return 0; }
virtual double duration() const OVERRIDE;
virtual float getValue(double now) const OVERRIDE;
virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const OVERRIDE;
};
@ -34,7 +34,7 @@ public:
FakeTransformTransition(double duration);
virtual ~FakeTransformTransition();
virtual double duration() const OVERRIDE { return m_duration; }
virtual double duration() const OVERRIDE;
virtual WebKit::WebTransformationMatrix getValue(double time) const OVERRIDE;
virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const OVERRIDE;
@ -48,7 +48,7 @@ public:
FakeFloatTransition(double duration, float from, float to);
virtual ~FakeFloatTransition();
virtual double duration() const OVERRIDE { return m_duration; }
virtual double duration() const OVERRIDE;
virtual float getValue(double time) const OVERRIDE;
virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const OVERRIDE;
@ -65,11 +65,11 @@ public:
virtual ~FakeLayerAnimationControllerClient();
// CCLayerAnimationControllerClient implementation
virtual int id() const OVERRIDE { return 0; }
virtual void setOpacityFromAnimation(float opacity) OVERRIDE { m_opacity = opacity; }
virtual float opacity() const OVERRIDE { return m_opacity; }
virtual void setTransformFromAnimation(const WebKit::WebTransformationMatrix& transform) OVERRIDE { m_transform = transform; }
virtual const WebKit::WebTransformationMatrix& transform() const OVERRIDE { return m_transform; }
virtual int id() const OVERRIDE;
virtual void setOpacityFromAnimation(float) OVERRIDE;
virtual float opacity() const OVERRIDE;
virtual void setTransformFromAnimation(const WebKit::WebTransformationMatrix&) OVERRIDE;
virtual const WebKit::WebTransformationMatrix& transform() const OVERRIDE;
private:
float m_opacity;

@ -65,6 +65,11 @@ PassOwnPtr<LayerTextureUpdater::Texture> FakeLayerTextureUpdater::createTexture(
return adoptPtr(new Texture(this, CCPrioritizedTexture::create(manager)));
}
LayerTextureUpdater::SampledTexelFormat FakeLayerTextureUpdater::sampledTexelFormat(GC3Denum)
{
return SampledTexelFormatRGBA;
}
FakeCCTiledLayerImpl::FakeCCTiledLayerImpl(int id)
: CCTiledLayerImpl(id)
{
@ -85,6 +90,11 @@ FakeTiledLayerChromium::FakeTiledLayerChromium(CCPrioritizedTextureManager* text
setIsDrawable(true); // So that we don't get false positives if any of these tests expect to return false from drawsContent() for other reasons.
}
FakeTiledLayerWithScaledBounds::FakeTiledLayerWithScaledBounds(CCPrioritizedTextureManager* textureManager)
: FakeTiledLayerChromium(textureManager)
{
}
FakeTiledLayerChromium::~FakeTiledLayerChromium()
{
}
@ -112,9 +122,29 @@ void FakeTiledLayerChromium::setTexturePriorities(const CCPriorityCalculator& ca
}
}
FakeTiledLayerWithScaledBounds::FakeTiledLayerWithScaledBounds(CCPrioritizedTextureManager* textureManager)
: FakeTiledLayerChromium(textureManager)
WebCore::CCPrioritizedTextureManager* FakeTiledLayerChromium::textureManager() const
{
return m_textureManager;
}
WebCore::LayerTextureUpdater* FakeTiledLayerChromium::textureUpdater() const
{
return m_fakeTextureUpdater.get();
}
WebCore::IntSize FakeTiledLayerWithScaledBounds::contentBounds() const
{
return m_forcedContentBounds;
}
bool FakeTextureUploader::isBusy()
{
return false;
}
void FakeTextureUploader::uploadTexture(WebCore::CCResourceProvider* resourceProvider, Parameters upload)
{
upload.texture->updateRect(resourceProvider, upload.sourceRect, upload.destOffset);
}
} // namespace

@ -40,7 +40,7 @@ public:
virtual ~FakeLayerTextureUpdater();
virtual PassOwnPtr<WebCore::LayerTextureUpdater::Texture> createTexture(WebCore::CCPrioritizedTextureManager*) OVERRIDE;
virtual SampledTexelFormat sampledTexelFormat(GC3Denum) OVERRIDE { return SampledTexelFormatRGBA; }
virtual SampledTexelFormat sampledTexelFormat(GC3Denum) OVERRIDE;
virtual void prepareToUpdate(const WebCore::IntRect& contentRect, const WebCore::IntSize&, float, float, WebCore::IntRect& resultingOpaqueRect, WebCore::CCRenderingStats&) OVERRIDE;
// Sets the rect to invalidate during the next call to prepareToUpdate(). After the next
@ -102,12 +102,12 @@ public:
virtual void setTexturePriorities(const WebCore::CCPriorityCalculator&) OVERRIDE;
virtual WebCore::CCPrioritizedTextureManager* textureManager() const OVERRIDE { return m_textureManager; }
virtual WebCore::CCPrioritizedTextureManager* textureManager() const OVERRIDE;
FakeLayerTextureUpdater* fakeLayerTextureUpdater() { return m_fakeTextureUpdater.get(); }
WebCore::FloatRect updateRect() { return m_updateRect; }
protected:
virtual WebCore::LayerTextureUpdater* textureUpdater() const OVERRIDE { return m_fakeTextureUpdater.get(); }
virtual WebCore::LayerTextureUpdater* textureUpdater() const OVERRIDE;
virtual void createTextureUpdaterIfNeeded() OVERRIDE { }
private:
@ -121,7 +121,7 @@ public:
explicit FakeTiledLayerWithScaledBounds(WebCore::CCPrioritizedTextureManager*);
void setContentBounds(const WebCore::IntSize& contentBounds) { m_forcedContentBounds = contentBounds; }
virtual WebCore::IntSize contentBounds() const OVERRIDE { return m_forcedContentBounds; }
virtual WebCore::IntSize contentBounds() const OVERRIDE;
protected:
WebCore::IntSize m_forcedContentBounds;
@ -129,16 +129,16 @@ protected:
class FakeTextureCopier : public WebCore::TextureCopier {
public:
virtual void copyTexture(Parameters) { }
virtual void flush() { }
virtual void copyTexture(Parameters) OVERRIDE { }
virtual void flush() OVERRIDE { }
};
class FakeTextureUploader : public WebCore::TextureUploader {
public:
virtual bool isBusy() { return false; }
virtual void beginUploads() { }
virtual void endUploads() { }
virtual void uploadTexture(WebCore::CCResourceProvider* resourceProvider, Parameters upload) { upload.texture->updateRect(resourceProvider, upload.sourceRect, upload.destOffset); }
virtual bool isBusy() OVERRIDE;
virtual void beginUploads() OVERRIDE { }
virtual void endUploads() OVERRIDE { }
virtual void uploadTexture(WebCore::CCResourceProvider*, Parameters upload) OVERRIDE;
};
}

@ -7,6 +7,8 @@
#include <public/WebCompositorOutputSurface.h>
#include <public/WebGraphicsContext3D.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
namespace WebKit {

@ -0,0 +1,814 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "LayerChromium.h"
#include "CCLayerImpl.h"
#include "CCLayerTreeHost.h"
#include "CCLayerTreeTestCommon.h"
#include "CCSingleThreadProxy.h"
#include "FakeCCLayerTreeHostClient.h"
#include "LayerPainterChromium.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <public/WebCompositor.h>
#include <public/WebTransformationMatrix.h>
using namespace WebCore;
using namespace WebKitTests;
using WebKit::WebTransformationMatrix;
using ::testing::Mock;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AnyNumber;
#define EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(numTimesExpectedSetNeedsCommit, codeToTest) do { \
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times((numTimesExpectedSetNeedsCommit)); \
codeToTest; \
Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); \
} while (0)
namespace {
class MockCCLayerTreeHost : public CCLayerTreeHost {
public:
MockCCLayerTreeHost()
: CCLayerTreeHost(&m_fakeClient, CCLayerTreeSettings())
{
initialize();
}
MOCK_METHOD0(setNeedsCommit, void());
private:
FakeCCLayerTreeHostClient m_fakeClient;
};
class MockLayerPainterChromium : public LayerPainterChromium {
public:
virtual void paint(SkCanvas*, const IntRect&, FloatRect&) OVERRIDE { }
};
class LayerChromiumTest : public testing::Test {
protected:
virtual void SetUp()
{
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
m_layerTreeHost = adoptPtr(new MockCCLayerTreeHost);
}
virtual void TearDown()
{
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_parent.clear();
m_child1.clear();
m_child2.clear();
m_child3.clear();
m_grandChild1.clear();
m_grandChild2.clear();
m_grandChild3.clear();
m_layerTreeHost->setRootLayer(0);
m_layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
void verifyTestTreeInitialState() const
{
ASSERT_EQ(static_cast<size_t>(3), m_parent->children().size());
EXPECT_EQ(m_child1, m_parent->children()[0]);
EXPECT_EQ(m_child2, m_parent->children()[1]);
EXPECT_EQ(m_child3, m_parent->children()[2]);
EXPECT_EQ(m_parent.get(), m_child1->parent());
EXPECT_EQ(m_parent.get(), m_child2->parent());
EXPECT_EQ(m_parent.get(), m_child3->parent());
ASSERT_EQ(static_cast<size_t>(2), m_child1->children().size());
EXPECT_EQ(m_grandChild1, m_child1->children()[0]);
EXPECT_EQ(m_grandChild2, m_child1->children()[1]);
EXPECT_EQ(m_child1.get(), m_grandChild1->parent());
EXPECT_EQ(m_child1.get(), m_grandChild2->parent());
ASSERT_EQ(static_cast<size_t>(1), m_child2->children().size());
EXPECT_EQ(m_grandChild3, m_child2->children()[0]);
EXPECT_EQ(m_child2.get(), m_grandChild3->parent());
ASSERT_EQ(static_cast<size_t>(0), m_child3->children().size());
}
void createSimpleTestTree()
{
m_parent = LayerChromium::create();
m_child1 = LayerChromium::create();
m_child2 = LayerChromium::create();
m_child3 = LayerChromium::create();
m_grandChild1 = LayerChromium::create();
m_grandChild2 = LayerChromium::create();
m_grandChild3 = LayerChromium::create();
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(m_parent);
m_parent->addChild(m_child1);
m_parent->addChild(m_child2);
m_parent->addChild(m_child3);
m_child1->addChild(m_grandChild1);
m_child1->addChild(m_grandChild2);
m_child2->addChild(m_grandChild3);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
verifyTestTreeInitialState();
}
OwnPtr<MockCCLayerTreeHost> m_layerTreeHost;
RefPtr<LayerChromium> m_parent, m_child1, m_child2, m_child3, m_grandChild1, m_grandChild2, m_grandChild3;
};
TEST_F(LayerChromiumTest, basicCreateAndDestroy)
{
RefPtr<LayerChromium> testLayer = LayerChromium::create();
ASSERT_TRUE(testLayer);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(0);
testLayer->setLayerTreeHost(m_layerTreeHost.get());
}
TEST_F(LayerChromiumTest, addAndRemoveChild)
{
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
// Upon creation, layers should not have children or parent.
ASSERT_EQ(static_cast<size_t>(0), parent->children().size());
EXPECT_FALSE(child->parent());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, m_layerTreeHost->setRootLayer(parent));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->addChild(child));
ASSERT_EQ(static_cast<size_t>(1), parent->children().size());
EXPECT_EQ(child.get(), parent->children()[0]);
EXPECT_EQ(parent.get(), child->parent());
EXPECT_EQ(parent.get(), child->rootLayer());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(1), child->removeFromParent());
}
TEST_F(LayerChromiumTest, insertChild)
{
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child1 = LayerChromium::create();
RefPtr<LayerChromium> child2 = LayerChromium::create();
RefPtr<LayerChromium> child3 = LayerChromium::create();
RefPtr<LayerChromium> child4 = LayerChromium::create();
parent->setLayerTreeHost(m_layerTreeHost.get());
ASSERT_EQ(static_cast<size_t>(0), parent->children().size());
// Case 1: inserting to empty list.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child3, 0));
ASSERT_EQ(static_cast<size_t>(1), parent->children().size());
EXPECT_EQ(child3, parent->children()[0]);
EXPECT_EQ(parent.get(), child3->parent());
// Case 2: inserting to beginning of list
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child1, 0));
ASSERT_EQ(static_cast<size_t>(2), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
EXPECT_EQ(child3, parent->children()[1]);
EXPECT_EQ(parent.get(), child1->parent());
// Case 3: inserting to middle of list
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child2, 1));
ASSERT_EQ(static_cast<size_t>(3), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
EXPECT_EQ(child2, parent->children()[1]);
EXPECT_EQ(child3, parent->children()[2]);
EXPECT_EQ(parent.get(), child2->parent());
// Case 4: inserting to end of list
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child4, 3));
ASSERT_EQ(static_cast<size_t>(4), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
EXPECT_EQ(child2, parent->children()[1]);
EXPECT_EQ(child3, parent->children()[2]);
EXPECT_EQ(child4, parent->children()[3]);
EXPECT_EQ(parent.get(), child4->parent());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
}
TEST_F(LayerChromiumTest, insertChildPastEndOfList)
{
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child1 = LayerChromium::create();
RefPtr<LayerChromium> child2 = LayerChromium::create();
ASSERT_EQ(static_cast<size_t>(0), parent->children().size());
// insert to an out-of-bounds index
parent->insertChild(child1, 53);
ASSERT_EQ(static_cast<size_t>(1), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
// insert another child to out-of-bounds, when list is not already empty.
parent->insertChild(child2, 2459);
ASSERT_EQ(static_cast<size_t>(2), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
EXPECT_EQ(child2, parent->children()[1]);
}
TEST_F(LayerChromiumTest, insertSameChildTwice)
{
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child1 = LayerChromium::create();
RefPtr<LayerChromium> child2 = LayerChromium::create();
parent->setLayerTreeHost(m_layerTreeHost.get());
ASSERT_EQ(static_cast<size_t>(0), parent->children().size());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child1, 0));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, parent->insertChild(child2, 1));
ASSERT_EQ(static_cast<size_t>(2), parent->children().size());
EXPECT_EQ(child1, parent->children()[0]);
EXPECT_EQ(child2, parent->children()[1]);
// Inserting the same child again should cause the child to be removed and re-inserted at the new location.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(1), parent->insertChild(child1, 1));
// child1 should now be at the end of the list.
ASSERT_EQ(static_cast<size_t>(2), parent->children().size());
EXPECT_EQ(child2, parent->children()[0]);
EXPECT_EQ(child1, parent->children()[1]);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
}
TEST_F(LayerChromiumTest, replaceChildWithNewChild)
{
createSimpleTestTree();
RefPtr<LayerChromium> child4 = LayerChromium::create();
EXPECT_FALSE(child4->parent());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(1), m_parent->replaceChild(m_child2.get(), child4));
ASSERT_EQ(static_cast<size_t>(3), m_parent->children().size());
EXPECT_EQ(m_child1, m_parent->children()[0]);
EXPECT_EQ(child4, m_parent->children()[1]);
EXPECT_EQ(m_child3, m_parent->children()[2]);
EXPECT_EQ(m_parent.get(), child4->parent());
EXPECT_FALSE(m_child2->parent());
}
TEST_F(LayerChromiumTest, replaceChildWithNewChildThatHasOtherParent)
{
createSimpleTestTree();
// create another simple tree with testLayer and child4.
RefPtr<LayerChromium> testLayer = LayerChromium::create();
RefPtr<LayerChromium> child4 = LayerChromium::create();
testLayer->addChild(child4);
ASSERT_EQ(static_cast<size_t>(1), testLayer->children().size());
EXPECT_EQ(child4, testLayer->children()[0]);
EXPECT_EQ(testLayer.get(), child4->parent());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(1), m_parent->replaceChild(m_child2.get(), child4));
ASSERT_EQ(static_cast<size_t>(3), m_parent->children().size());
EXPECT_EQ(m_child1, m_parent->children()[0]);
EXPECT_EQ(child4, m_parent->children()[1]);
EXPECT_EQ(m_child3, m_parent->children()[2]);
EXPECT_EQ(m_parent.get(), child4->parent());
// testLayer should no longer have child4,
// and child2 should no longer have a parent.
ASSERT_EQ(static_cast<size_t>(0), testLayer->children().size());
EXPECT_FALSE(m_child2->parent());
}
TEST_F(LayerChromiumTest, replaceChildWithSameChild)
{
createSimpleTestTree();
// setNeedsCommit should not be called because its the same child
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, m_parent->replaceChild(m_child2.get(), m_child2));
verifyTestTreeInitialState();
}
TEST_F(LayerChromiumTest, removeAllChildren)
{
createSimpleTestTree();
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(3), m_parent->removeAllChildren());
ASSERT_EQ(static_cast<size_t>(0), m_parent->children().size());
EXPECT_FALSE(m_child1->parent());
EXPECT_FALSE(m_child2->parent());
EXPECT_FALSE(m_child3->parent());
}
TEST_F(LayerChromiumTest, setChildren)
{
RefPtr<LayerChromium> oldParent = LayerChromium::create();
RefPtr<LayerChromium> newParent = LayerChromium::create();
RefPtr<LayerChromium> child1 = LayerChromium::create();
RefPtr<LayerChromium> child2 = LayerChromium::create();
Vector<RefPtr<LayerChromium> > newChildren;
newChildren.append(child1);
newChildren.append(child2);
// Set up and verify initial test conditions: child1 has a parent, child2 has no parent.
oldParent->addChild(child1);
ASSERT_EQ(static_cast<size_t>(0), newParent->children().size());
EXPECT_EQ(oldParent.get(), child1->parent());
EXPECT_FALSE(child2->parent());
newParent->setLayerTreeHost(m_layerTreeHost.get());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(AtLeast(1), newParent->setChildren(newChildren));
ASSERT_EQ(static_cast<size_t>(2), newParent->children().size());
EXPECT_EQ(newParent.get(), child1->parent());
EXPECT_EQ(newParent.get(), child2->parent());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
}
TEST_F(LayerChromiumTest, getRootLayerAfterTreeManipulations)
{
createSimpleTestTree();
// For this test we don't care about setNeedsCommit calls.
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
RefPtr<LayerChromium> child4 = LayerChromium::create();
EXPECT_EQ(m_parent.get(), m_parent->rootLayer());
EXPECT_EQ(m_parent.get(), m_child1->rootLayer());
EXPECT_EQ(m_parent.get(), m_child2->rootLayer());
EXPECT_EQ(m_parent.get(), m_child3->rootLayer());
EXPECT_EQ(child4.get(), child4->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild1->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild2->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild3->rootLayer());
m_child1->removeFromParent();
// child1 and its children, grandChild1 and grandChild2 are now on a separate subtree.
EXPECT_EQ(m_parent.get(), m_parent->rootLayer());
EXPECT_EQ(m_child1.get(), m_child1->rootLayer());
EXPECT_EQ(m_parent.get(), m_child2->rootLayer());
EXPECT_EQ(m_parent.get(), m_child3->rootLayer());
EXPECT_EQ(child4.get(), child4->rootLayer());
EXPECT_EQ(m_child1.get(), m_grandChild1->rootLayer());
EXPECT_EQ(m_child1.get(), m_grandChild2->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild3->rootLayer());
m_grandChild3->addChild(child4);
EXPECT_EQ(m_parent.get(), m_parent->rootLayer());
EXPECT_EQ(m_child1.get(), m_child1->rootLayer());
EXPECT_EQ(m_parent.get(), m_child2->rootLayer());
EXPECT_EQ(m_parent.get(), m_child3->rootLayer());
EXPECT_EQ(m_parent.get(), child4->rootLayer());
EXPECT_EQ(m_child1.get(), m_grandChild1->rootLayer());
EXPECT_EQ(m_child1.get(), m_grandChild2->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild3->rootLayer());
m_child2->replaceChild(m_grandChild3.get(), m_child1);
// grandChild3 gets orphaned and the child1 subtree gets planted back into the tree under child2.
EXPECT_EQ(m_parent.get(), m_parent->rootLayer());
EXPECT_EQ(m_parent.get(), m_child1->rootLayer());
EXPECT_EQ(m_parent.get(), m_child2->rootLayer());
EXPECT_EQ(m_parent.get(), m_child3->rootLayer());
EXPECT_EQ(m_grandChild3.get(), child4->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild1->rootLayer());
EXPECT_EQ(m_parent.get(), m_grandChild2->rootLayer());
EXPECT_EQ(m_grandChild3.get(), m_grandChild3->rootLayer());
}
TEST_F(LayerChromiumTest, checkSetNeedsDisplayCausesCorrectBehavior)
{
// The semantics for setNeedsDisplay which are tested here:
// 1. sets needsDisplay flag appropriately.
// 2. indirectly calls setNeedsCommit, exactly once for each call to setNeedsDisplay.
RefPtr<LayerChromium> testLayer = LayerChromium::create();
testLayer->setLayerTreeHost(m_layerTreeHost.get());
IntSize testBounds = IntSize(501, 508);
FloatRect dirty1 = FloatRect(10, 15, 1, 2);
FloatRect dirty2 = FloatRect(20, 25, 3, 4);
FloatRect emptyDirtyRect = FloatRect(40, 45, 0, 0);
FloatRect outOfBoundsDirtyRect = FloatRect(400, 405, 500, 502);
// Before anything, testLayer should not be dirty.
EXPECT_FALSE(testLayer->needsDisplay());
// This is just initialization, but setNeedsCommit behavior is verified anyway to avoid warnings.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(testBounds));
testLayer = LayerChromium::create();
testLayer->setLayerTreeHost(m_layerTreeHost.get());
EXPECT_FALSE(testLayer->needsDisplay());
// The real test begins here.
// Case 1: needsDisplay flag should not change because of an empty dirty rect.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNeedsDisplayRect(emptyDirtyRect));
EXPECT_FALSE(testLayer->needsDisplay());
// Case 2: basic.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNeedsDisplayRect(dirty1));
EXPECT_TRUE(testLayer->needsDisplay());
// Case 3: a second dirty rect.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNeedsDisplayRect(dirty2));
EXPECT_TRUE(testLayer->needsDisplay());
// Case 4: LayerChromium should accept dirty rects that go beyond its bounds.
testLayer = LayerChromium::create();
testLayer->setLayerTreeHost(m_layerTreeHost.get());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(testBounds));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNeedsDisplayRect(outOfBoundsDirtyRect));
EXPECT_TRUE(testLayer->needsDisplay());
// Case 5: setNeedsDisplay() without the dirty rect arg.
testLayer = LayerChromium::create();
testLayer->setLayerTreeHost(m_layerTreeHost.get());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(testBounds));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNeedsDisplay());
EXPECT_TRUE(testLayer->needsDisplay());
}
TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior)
{
RefPtr<LayerChromium> testLayer = LayerChromium::create();
testLayer->setLayerTreeHost(m_layerTreeHost.get());
RefPtr<LayerChromium> dummyLayer = LayerChromium::create(); // just a dummy layer for this test case.
// sanity check of initial test condition
EXPECT_FALSE(testLayer->needsDisplay());
// Test properties that should not call needsDisplay and needsCommit when changed.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setVisibleContentRect(IntRect(0, 0, 40, 50)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setUseLCDText(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setDrawOpacity(0.5));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setRenderTarget(0));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setDrawTransform(WebTransformationMatrix()));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setScreenSpaceTransform(WebTransformationMatrix()));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(0, testLayer->setDrawableContentRect(IntRect(4, 5, 6, 7)));
EXPECT_FALSE(testLayer->needsDisplay());
// Next, test properties that should call setNeedsCommit (but not setNeedsDisplay)
// All properties need to be set to new values in order for setNeedsCommit to be called.
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setAnchorPoint(FloatPoint(1.23f, 4.56f)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setAnchorPointZ(0.7f));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBackgroundColor(SK_ColorLTGRAY));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setMasksToBounds(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setMaskLayer(dummyLayer.get()));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setOpacity(0.5));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setOpaque(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setPosition(FloatPoint(4, 9)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setReplicaLayer(dummyLayer.get()));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setSublayerTransform(WebTransformationMatrix(0, 0, 0, 0, 0, 0)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setScrollable(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setShouldScrollOnMainThread(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setNonFastScrollableRegion(Region(IntRect(1, 1, 2, 2))));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setHaveWheelEventHandlers(true));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setScrollPosition(IntPoint(10, 10)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setTransform(WebTransformationMatrix(0, 0, 0, 0, 0, 0)));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDoubleSided(false));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDebugName("Test Layer"));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDrawCheckerboardForMissingTiles(!testLayer->drawCheckerboardForMissingTiles()));
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setForceRenderSurface(true));
// The above tests should not have caused a change to the needsDisplay flag.
EXPECT_FALSE(testLayer->needsDisplay());
// Test properties that should call setNeedsDisplay and setNeedsCommit
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(IntSize(5, 10)));
EXPECT_TRUE(testLayer->needsDisplay());
}
TEST_F(LayerChromiumTest, verifyPushPropertiesAccumulatesUpdateRect)
{
DebugScopedSetImplThread setImplThread;
RefPtr<LayerChromium> testLayer = LayerChromium::create();
OwnPtr<CCLayerImpl> implLayer = CCLayerImpl::create(1);
testLayer->setNeedsDisplayRect(FloatRect(FloatPoint::zero(), FloatSize(5, 5)));
testLayer->pushPropertiesTo(implLayer.get());
EXPECT_FLOAT_RECT_EQ(FloatRect(FloatPoint::zero(), FloatSize(5, 5)), implLayer->updateRect());
// The CCLayerImpl's updateRect should be accumulated here, since we did not do anything to clear it.
testLayer->setNeedsDisplayRect(FloatRect(FloatPoint(10, 10), FloatSize(5, 5)));
testLayer->pushPropertiesTo(implLayer.get());
EXPECT_FLOAT_RECT_EQ(FloatRect(FloatPoint::zero(), FloatSize(15, 15)), implLayer->updateRect());
// If we do clear the CCLayerImpl side, then the next updateRect should be fresh without accumulation.
implLayer->resetAllChangeTrackingForSubtree();
testLayer->setNeedsDisplayRect(FloatRect(FloatPoint(10, 10), FloatSize(5, 5)));
testLayer->pushPropertiesTo(implLayer.get());
EXPECT_FLOAT_RECT_EQ(FloatRect(FloatPoint(10, 10), FloatSize(5, 5)), implLayer->updateRect());
}
class LayerChromiumWithContentScaling : public LayerChromium {
public:
explicit LayerChromiumWithContentScaling()
: LayerChromium()
{
}
virtual bool needsContentsScale() const OVERRIDE
{
return true;
}
virtual void setNeedsDisplayRect(const FloatRect& dirtyRect) OVERRIDE
{
m_lastNeedsDisplayRect = dirtyRect;
LayerChromium::setNeedsDisplayRect(dirtyRect);
}
void resetNeedsDisplay()
{
m_needsDisplay = false;
}
const FloatRect& lastNeedsDisplayRect() const { return m_lastNeedsDisplayRect; }
private:
FloatRect m_lastNeedsDisplayRect;
};
TEST_F(LayerChromiumTest, checkContentsScaleChangeTriggersNeedsDisplay)
{
RefPtr<LayerChromiumWithContentScaling> testLayer = adoptRef(new LayerChromiumWithContentScaling());
testLayer->setLayerTreeHost(m_layerTreeHost.get());
IntSize testBounds = IntSize(320, 240);
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(testBounds));
testLayer->resetNeedsDisplay();
EXPECT_FALSE(testLayer->needsDisplay());
EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setContentsScale(testLayer->contentsScale() + 1.f));
EXPECT_TRUE(testLayer->needsDisplay());
EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 320, 240), testLayer->lastNeedsDisplayRect());
}
class FakeCCLayerTreeHost : public CCLayerTreeHost {
public:
static PassOwnPtr<FakeCCLayerTreeHost> create()
{
OwnPtr<FakeCCLayerTreeHost> host(adoptPtr(new FakeCCLayerTreeHost));
// The initialize call will fail, since our client doesn't provide a valid GraphicsContext3D, but it doesn't matter in the tests that use this fake so ignore the return value.
host->initialize();
return host.release();
}
private:
FakeCCLayerTreeHost()
: CCLayerTreeHost(&m_client, CCLayerTreeSettings())
{
}
FakeCCLayerTreeHostClient m_client;
};
void assertLayerTreeHostMatchesForSubtree(LayerChromium* layer, CCLayerTreeHost* host)
{
EXPECT_EQ(host, layer->layerTreeHost());
for (size_t i = 0; i < layer->children().size(); ++i)
assertLayerTreeHostMatchesForSubtree(layer->children()[i].get(), host);
if (layer->maskLayer())
assertLayerTreeHostMatchesForSubtree(layer->maskLayer(), host);
if (layer->replicaLayer())
assertLayerTreeHostMatchesForSubtree(layer->replicaLayer(), host);
}
TEST(LayerChromiumLayerTreeHostTest, enteringTree)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
RefPtr<LayerChromium> replica = LayerChromium::create();
RefPtr<LayerChromium> replicaMask = LayerChromium::create();
// Set up a detached tree of layers. The host pointer should be nil for these layers.
parent->addChild(child);
child->setMaskLayer(mask.get());
child->setReplicaLayer(replica.get());
replica->setMaskLayer(mask.get());
assertLayerTreeHostMatchesForSubtree(parent.get(), 0);
OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
// Setting the root layer should set the host pointer for all layers in the tree.
layerTreeHost->setRootLayer(parent.get());
assertLayerTreeHostMatchesForSubtree(parent.get(), layerTreeHost.get());
// Clearing the root layer should also clear out the host pointers for all layers in the tree.
layerTreeHost->setRootLayer(0);
assertLayerTreeHostMatchesForSubtree(parent.get(), 0);
layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> parent = LayerChromium::create();
OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
layerTreeHost->setRootLayer(parent.get());
EXPECT_EQ(parent->layerTreeHost(), layerTreeHost.get());
// Adding a subtree to a layer already associated with a host should set the host pointer on all layers in that subtree.
RefPtr<LayerChromium> child = LayerChromium::create();
RefPtr<LayerChromium> grandChild = LayerChromium::create();
child->addChild(grandChild);
// Masks, replicas, and replica masks should pick up the new host too.
RefPtr<LayerChromium> childMask = LayerChromium::create();
child->setMaskLayer(childMask.get());
RefPtr<LayerChromium> childReplica = LayerChromium::create();
child->setReplicaLayer(childReplica.get());
RefPtr<LayerChromium> childReplicaMask = LayerChromium::create();
childReplica->setMaskLayer(childReplicaMask.get());
parent->addChild(child);
assertLayerTreeHostMatchesForSubtree(parent.get(), layerTreeHost.get());
layerTreeHost->setRootLayer(0);
layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
TEST(LayerChromiumLayerTreeHostTest, changeHost)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
RefPtr<LayerChromium> replica = LayerChromium::create();
RefPtr<LayerChromium> replicaMask = LayerChromium::create();
// Same setup as the previous test.
parent->addChild(child);
child->setMaskLayer(mask.get());
child->setReplicaLayer(replica.get());
replica->setMaskLayer(mask.get());
OwnPtr<FakeCCLayerTreeHost> firstLayerTreeHost(FakeCCLayerTreeHost::create());
firstLayerTreeHost->setRootLayer(parent.get());
assertLayerTreeHostMatchesForSubtree(parent.get(), firstLayerTreeHost.get());
// Now re-root the tree to a new host (simulating what we do on a context lost event).
// This should update the host pointers for all layers in the tree.
OwnPtr<FakeCCLayerTreeHost> secondLayerTreeHost(FakeCCLayerTreeHost::create());
secondLayerTreeHost->setRootLayer(parent.get());
assertLayerTreeHostMatchesForSubtree(parent.get(), secondLayerTreeHost.get());
secondLayerTreeHost->setRootLayer(0);
firstLayerTreeHost.clear();
secondLayerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
TEST(LayerChromiumLayerTreeHostTest, changeHostInSubtree)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> firstParent = LayerChromium::create();
RefPtr<LayerChromium> firstChild = LayerChromium::create();
RefPtr<LayerChromium> secondParent = LayerChromium::create();
RefPtr<LayerChromium> secondChild = LayerChromium::create();
RefPtr<LayerChromium> secondGrandChild = LayerChromium::create();
// First put all children under the first parent and set the first host.
firstParent->addChild(firstChild);
secondChild->addChild(secondGrandChild);
firstParent->addChild(secondChild);
OwnPtr<FakeCCLayerTreeHost> firstLayerTreeHost(FakeCCLayerTreeHost::create());
firstLayerTreeHost->setRootLayer(firstParent.get());
assertLayerTreeHostMatchesForSubtree(firstParent.get(), firstLayerTreeHost.get());
// Now reparent the subtree starting at secondChild to a layer in a different tree.
OwnPtr<FakeCCLayerTreeHost> secondLayerTreeHost(FakeCCLayerTreeHost::create());
secondLayerTreeHost->setRootLayer(secondParent.get());
secondParent->addChild(secondChild);
// The moved layer and its children should point to the new host.
EXPECT_EQ(secondLayerTreeHost.get(), secondChild->layerTreeHost());
EXPECT_EQ(secondLayerTreeHost.get(), secondGrandChild->layerTreeHost());
// Test over, cleanup time.
firstLayerTreeHost->setRootLayer(0);
secondLayerTreeHost->setRootLayer(0);
firstLayerTreeHost.clear();
secondLayerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
TEST(LayerChromiumLayerTreeHostTest, replaceMaskAndReplicaLayer)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
RefPtr<LayerChromium> replica = LayerChromium::create();
RefPtr<LayerChromium> maskChild = LayerChromium::create();
RefPtr<LayerChromium> replicaChild = LayerChromium::create();
RefPtr<LayerChromium> maskReplacement = LayerChromium::create();
RefPtr<LayerChromium> replicaReplacement = LayerChromium::create();
parent->setMaskLayer(mask.get());
parent->setReplicaLayer(replica.get());
mask->addChild(maskChild);
replica->addChild(replicaChild);
OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
layerTreeHost->setRootLayer(parent.get());
assertLayerTreeHostMatchesForSubtree(parent.get(), layerTreeHost.get());
// Replacing the mask should clear out the old mask's subtree's host pointers.
parent->setMaskLayer(maskReplacement.get());
EXPECT_EQ(0, mask->layerTreeHost());
EXPECT_EQ(0, maskChild->layerTreeHost());
// Same for replacing a replica layer.
parent->setReplicaLayer(replicaReplacement.get());
EXPECT_EQ(0, replica->layerTreeHost());
EXPECT_EQ(0, replicaChild->layerTreeHost());
// Test over, cleanup time.
layerTreeHost->setRootLayer(0);
layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
TEST(LayerChromiumLayerTreeHostTest, destroyHostWithNonNullRootLayer)
{
WebKit::WebCompositor::initialize(0);
RefPtr<LayerChromium> root = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
root->addChild(child);
OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
layerTreeHost->setRootLayer(root);
layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
class MockLayerChromium : public LayerChromium {
public:
bool needsDisplay() const { return m_needsDisplay; }
};
TEST(LayerChromiumTestWithoutFixture, setBoundsTriggersSetNeedsRedrawAfterGettingNonEmptyBounds)
{
RefPtr<MockLayerChromium> layer(adoptRef(new MockLayerChromium));
EXPECT_FALSE(layer->needsDisplay());
layer->setBounds(IntSize(0, 10));
EXPECT_FALSE(layer->needsDisplay());
layer->setBounds(IntSize(10, 10));
EXPECT_TRUE(layer->needsDisplay());
}
} // namespace

@ -0,0 +1,59 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "TextureCopier.h"
#include "FakeWebGraphicsContext3D.h"
#include "GraphicsContext3D.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <wtf/RefPtr.h>
using namespace WebCore;
using namespace WebKit;
using testing::InSequence;
using testing::Test;
using testing::_;
class MockContext : public FakeWebGraphicsContext3D {
public:
MOCK_METHOD2(bindFramebuffer, void(WGC3Denum, WebGLId));
MOCK_METHOD3(texParameteri, void(WGC3Denum target, WGC3Denum pname, WGC3Dint param));
MOCK_METHOD3(drawArrays, void(WGC3Denum mode, WGC3Dint first, WGC3Dsizei count));
};
TEST(TextureCopierTest, testDrawArraysCopy)
{
OwnPtr<MockContext> mockContext = adoptPtr(new MockContext);
{
InSequence sequence;
// Here we check just some essential properties of copyTexture() to avoid mirroring the full implementation.
EXPECT_CALL(*mockContext, bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, _));
// Make sure linear filtering is disabled during the copy.
EXPECT_CALL(*mockContext, texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST));
EXPECT_CALL(*mockContext, texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST));
EXPECT_CALL(*mockContext, drawArrays(_, _, _));
// Linear filtering should be restored.
EXPECT_CALL(*mockContext, texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
EXPECT_CALL(*mockContext, texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
// Default framebuffer should be restored
EXPECT_CALL(*mockContext, bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
}
int sourceTextureId = 1;
int destTextureId = 2;
IntSize size(256, 128);
OwnPtr<AcceleratedTextureCopier> copier(AcceleratedTextureCopier::create(mockContext.get(), false));
TextureCopier::Parameters copy = { sourceTextureId, destTextureId, size };
copier->copyTexture(copy);
}

@ -0,0 +1,116 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "TextureLayerChromium.h"
#include "CCLayerTreeHost.h"
#include "FakeCCLayerTreeHostClient.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <public/WebCompositor.h>
using namespace WebCore;
using ::testing::Mock;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AnyNumber;
namespace {
class MockCCLayerTreeHost : public CCLayerTreeHost {
public:
MockCCLayerTreeHost()
: CCLayerTreeHost(&m_fakeClient, CCLayerTreeSettings())
{
initialize();
}
MOCK_METHOD0(acquireLayerTextures, void());
private:
FakeCCLayerTreeHostClient m_fakeClient;
};
class TextureLayerChromiumTest : public testing::Test {
protected:
virtual void SetUp()
{
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
m_layerTreeHost = adoptPtr(new MockCCLayerTreeHost);
}
virtual void TearDown()
{
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(0);
m_layerTreeHost.clear();
WebKit::WebCompositor::shutdown();
}
OwnPtr<MockCCLayerTreeHost> m_layerTreeHost;
};
TEST_F(TextureLayerChromiumTest, syncImplWhenChangingTextureId)
{
RefPtr<TextureLayerChromium> testLayer = TextureLayerChromium::create(0);
ASSERT_TRUE(testLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(testLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_EQ(testLayer->layerTreeHost(), m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
testLayer->setTextureId(1);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
testLayer->setTextureId(2);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
testLayer->setTextureId(0);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
}
TEST_F(TextureLayerChromiumTest, syncImplWhenRemovingFromTree)
{
RefPtr<LayerChromium> rootLayer = LayerChromium::create();
ASSERT_TRUE(rootLayer);
RefPtr<LayerChromium> childLayer = LayerChromium::create();
ASSERT_TRUE(childLayer);
rootLayer->addChild(childLayer);
RefPtr<TextureLayerChromium> testLayer = TextureLayerChromium::create(0);
ASSERT_TRUE(testLayer);
testLayer->setTextureId(0);
childLayer->addChild(testLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(rootLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
testLayer->removeFromParent();
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
childLayer->addChild(testLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
testLayer->setTextureId(1);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
testLayer->removeFromParent();
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
}
} // anonymous namespace

@ -0,0 +1,72 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "ThrottledTextureUploader.h"
#include "Extensions3DChromium.h"
#include "FakeWebGraphicsContext3D.h"
#include "GraphicsContext3D.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <wtf/RefPtr.h>
using namespace WebCore;
using namespace WebKit;
namespace {
class FakeWebGraphicsContext3DWithQueryTesting : public FakeWebGraphicsContext3D {
public:
FakeWebGraphicsContext3DWithQueryTesting() : m_resultAvailable(0)
{
}
virtual void getQueryObjectuivEXT(WebGLId, GC3Denum type, GC3Duint* value)
{
switch (type) {
case Extensions3DChromium::QUERY_RESULT_AVAILABLE_EXT:
*value = m_resultAvailable;
break;
default:
*value = 0;
break;
}
}
void setResultAvailable(unsigned resultAvailable) { m_resultAvailable = resultAvailable; }
private:
unsigned m_resultAvailable;
};
TEST(ThrottledTextureUploaderTest, IsBusy)
{
OwnPtr<FakeWebGraphicsContext3DWithQueryTesting> fakeContext(adoptPtr(new FakeWebGraphicsContext3DWithQueryTesting));
OwnPtr<ThrottledTextureUploader> uploader = ThrottledTextureUploader::create(fakeContext.get(), 2);
fakeContext->setResultAvailable(0);
EXPECT_FALSE(uploader->isBusy());
uploader->beginUploads();
uploader->endUploads();
EXPECT_FALSE(uploader->isBusy());
uploader->beginUploads();
uploader->endUploads();
EXPECT_TRUE(uploader->isBusy());
fakeContext->setResultAvailable(1);
EXPECT_FALSE(uploader->isBusy());
uploader->beginUploads();
uploader->endUploads();
EXPECT_FALSE(uploader->isBusy());
uploader->beginUploads();
uploader->endUploads();
EXPECT_FALSE(uploader->isBusy());
uploader->beginUploads();
uploader->endUploads();
}
} // namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,405 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "TreeSynchronizer.h"
#include "CCAnimationTestCommon.h"
#include "CCLayerAnimationController.h"
#include "CCLayerImpl.h"
#include "CCProxy.h"
#include "CCSingleThreadProxy.h"
#include "LayerChromium.h"
#include "Region.h"
#include <gtest/gtest.h>
using namespace WebCore;
using namespace WebKitTests;
namespace {
class MockCCLayerImpl : public CCLayerImpl {
public:
static PassOwnPtr<MockCCLayerImpl> create(int layerId)
{
return adoptPtr(new MockCCLayerImpl(layerId));
}
virtual ~MockCCLayerImpl()
{
if (m_ccLayerDestructionList)
m_ccLayerDestructionList->append(id());
}
void setCCLayerDestructionList(Vector<int>* list) { m_ccLayerDestructionList = list; }
private:
MockCCLayerImpl(int layerId)
: CCLayerImpl(layerId)
, m_ccLayerDestructionList(0)
{
}
Vector<int>* m_ccLayerDestructionList;
};
class MockLayerChromium : public LayerChromium {
public:
static PassRefPtr<MockLayerChromium> create(Vector<int>* ccLayerDestructionList)
{
return adoptRef(new MockLayerChromium(ccLayerDestructionList));
}
virtual ~MockLayerChromium() { }
virtual PassOwnPtr<CCLayerImpl> createCCLayerImpl() OVERRIDE
{
return MockCCLayerImpl::create(m_layerId);
}
virtual void pushPropertiesTo(CCLayerImpl* ccLayer) OVERRIDE
{
LayerChromium::pushPropertiesTo(ccLayer);
MockCCLayerImpl* mockCCLayer = static_cast<MockCCLayerImpl*>(ccLayer);
mockCCLayer->setCCLayerDestructionList(m_ccLayerDestructionList);
}
private:
MockLayerChromium(Vector<int>* ccLayerDestructionList)
: LayerChromium()
, m_ccLayerDestructionList(ccLayerDestructionList)
{
}
Vector<int>* m_ccLayerDestructionList;
};
class FakeLayerAnimationController : public CCLayerAnimationController {
public:
static PassOwnPtr<FakeLayerAnimationController> create(CCLayerAnimationControllerClient* client)
{
return adoptPtr(new FakeLayerAnimationController(client));
}
bool synchronizedAnimations() const { return m_synchronizedAnimations; }
private:
explicit FakeLayerAnimationController(CCLayerAnimationControllerClient* client)
: CCLayerAnimationController(client)
, m_synchronizedAnimations(false)
{
}
virtual void pushAnimationUpdatesTo(CCLayerAnimationController* controllerImpl)
{
CCLayerAnimationController::pushAnimationUpdatesTo(controllerImpl);
m_synchronizedAnimations = true;
}
bool m_synchronizedAnimations;
};
void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer, CCLayerTreeHostImpl* hostImpl)
{
ASSERT_TRUE(layer);
ASSERT_TRUE(ccLayer);
EXPECT_EQ(layer->id(), ccLayer->id());
EXPECT_EQ(ccLayer->layerTreeHostImpl(), hostImpl);
EXPECT_EQ(layer->nonFastScrollableRegion(), ccLayer->nonFastScrollableRegion());
ASSERT_EQ(!!layer->maskLayer(), !!ccLayer->maskLayer());
if (layer->maskLayer())
expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer(), hostImpl);
ASSERT_EQ(!!layer->replicaLayer(), !!ccLayer->replicaLayer());
if (layer->replicaLayer())
expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer(), hostImpl);
const Vector<RefPtr<LayerChromium> >& layerChildren = layer->children();
const Vector<OwnPtr<CCLayerImpl> >& ccLayerChildren = ccLayer->children();
ASSERT_EQ(layerChildren.size(), ccLayerChildren.size());
for (size_t i = 0; i < layerChildren.size(); ++i)
expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get(), hostImpl);
}
// Attempts to synchronizes a null tree. This should not crash, and should
// return a null tree.
TEST(TreeSynchronizerTest, syncNullTree)
{
DebugScopedSetImplThread impl;
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(0, nullptr, 0);
EXPECT_TRUE(!ccLayerTreeRoot.get());
}
// Constructs a very simple tree and synchronizes it without trying to reuse any preexisting layers.
TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
{
DebugScopedSetImplThread impl;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
}
// Constructs a very simple tree and synchronizes it attempting to reuse some layers
TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Add a new layer to the LayerChromium side
layerTreeRoot->children()[0]->addChild(MockLayerChromium::create(&ccLayerDestructionList));
// Remove one.
layerTreeRoot->children()[1]->removeFromParent();
int secondCCLayerId = ccLayerTreeRoot->children()[1]->id();
// Synchronize again. After the sync the trees should be equivalent and we should have created and destroyed one CCLayerImpl.
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ASSERT_EQ(1u, ccLayerDestructionList.size());
EXPECT_EQ(secondCCLayerId, ccLayerDestructionList[0]);
}
// Constructs a very simple tree and checks that a stacking-order change is tracked properly.
TEST(TreeSynchronizerTest, syncSimpleTreeAndTrackStackingOrderChange)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
// Set up the tree and sync once. child2 needs to be synced here, too, even though we
// remove it to set up the intended scenario.
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
RefPtr<LayerChromium> child2 = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(child2);
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ccLayerTreeRoot->resetAllChangeTrackingForSubtree();
// re-insert the layer and sync again.
child2->removeFromParent();
layerTreeRoot->addChild(child2);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Check that the impl thread properly tracked the change.
EXPECT_FALSE(ccLayerTreeRoot->layerPropertyChanged());
EXPECT_FALSE(ccLayerTreeRoot->children()[0]->layerPropertyChanged());
EXPECT_TRUE(ccLayerTreeRoot->children()[1]->layerPropertyChanged());
}
TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
{
DebugScopedSetImplThread impl;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
// Pick some random properties to set. The values are not important, we're just testing that at least some properties are making it through.
FloatPoint rootPosition = FloatPoint(2.3f, 7.4f);
layerTreeRoot->setPosition(rootPosition);
float firstChildOpacity = 0.25f;
layerTreeRoot->children()[0]->setOpacity(firstChildOpacity);
IntSize secondChildBounds = IntSize(25, 53);
layerTreeRoot->children()[1]->setBounds(secondChildBounds);
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Check that the property values we set on the LayerChromium tree are reflected in the CCLayerImpl tree.
FloatPoint rootCCLayerPosition = ccLayerTreeRoot->position();
EXPECT_EQ(rootPosition.x(), rootCCLayerPosition.x());
EXPECT_EQ(rootPosition.y(), rootCCLayerPosition.y());
EXPECT_EQ(firstChildOpacity, ccLayerTreeRoot->children()[0]->opacity());
IntSize secondCCLayerChildBounds = ccLayerTreeRoot->children()[1]->bounds();
EXPECT_EQ(secondChildBounds.width(), secondCCLayerChildBounds.width());
EXPECT_EQ(secondChildBounds.height(), secondCCLayerChildBounds.height());
}
TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
// Set up a tree with this sort of structure:
// root --- A --- B ---+--- C
// |
// +--- D
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerA = layerTreeRoot->children()[0].get();
layerA->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerB = layerA->children()[0].get();
layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerC = layerB->children()[0].get();
layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerD = layerB->children()[1].get();
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Now restructure the tree to look like this:
// root --- D ---+--- A
// |
// +--- C --- B
layerTreeRoot->removeAllChildren();
layerD->removeAllChildren();
layerTreeRoot->addChild(layerD);
layerA->removeAllChildren();
layerD->addChild(layerA);
layerC->removeAllChildren();
layerD->addChild(layerC);
layerB->removeAllChildren();
layerC->addChild(layerB);
// After another synchronize our trees should match and we should not have destroyed any CCLayerImpls
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
EXPECT_EQ(0u, ccLayerDestructionList.size());
}
// Constructs a very simple tree, synchronizes it, then synchronizes to a totally new tree. All layers from the old tree should be deleted.
TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
{
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
int oldTreeRootLayerId = oldLayerTreeRoot->id();
int oldTreeFirstChildLayerId = oldLayerTreeRoot->children()[0]->id();
int oldTreeSecondChildLayerId = oldLayerTreeRoot->children()[1]->id();
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove all children on the LayerChromium side.
oldLayerTreeRoot->removeAllChildren();
// Synchronize again. After the sync all CCLayerImpls from the old tree should be deleted.
RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create();
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ASSERT_EQ(3u, ccLayerDestructionList.size());
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeRootLayerId));
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeFirstChildLayerId));
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeSecondChildLayerId));
}
// Constructs+syncs a tree with mask, replica, and replica mask layers.
TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
{
DebugScopedSetImplThread impl;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
// First child gets a mask layer.
RefPtr<LayerChromium> maskLayer = LayerChromium::create();
layerTreeRoot->children()[0]->setMaskLayer(maskLayer.get());
// Second child gets a replica layer.
RefPtr<LayerChromium> replicaLayer = LayerChromium::create();
layerTreeRoot->children()[1]->setReplicaLayer(replicaLayer.get());
// Third child gets a replica layer with a mask layer.
RefPtr<LayerChromium> replicaLayerWithMask = LayerChromium::create();
RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create();
replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get());
layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the mask layer.
layerTreeRoot->children()[0]->setMaskLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the replica layer.
layerTreeRoot->children()[1]->setReplicaLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the replica mask.
replicaLayerWithMask->setMaskLayer(0);
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
}
TEST(TreeSynchronizerTest, synchronizeAnimations)
{
DebugScopedSetImplThread impl;
CCLayerTreeSettings settings;
OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
FakeLayerAnimationControllerClient dummy;
layerTreeRoot->setLayerAnimationController(FakeLayerAnimationController::create(&dummy));
EXPECT_FALSE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
EXPECT_TRUE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
}
} // namespace

@ -0,0 +1,63 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include <public/WebAnimation.h>
#include <gtest/gtest.h>
#include <public/WebFloatAnimationCurve.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
using namespace WebKit;
namespace {
// Linux/Win bots failed on this test.
// https://bugs.webkit.org/show_bug.cgi?id=90651
#if OS(WINDOWS)
#define MAYBE_DefaultSettings DISABLED_DefaultSettings
#elif OS(LINUX)
#define MAYBE_DefaultSettings DISABLED_DefaultSettings
#else
#define MAYBE_DefaultSettings DefaultSettings
#endif
TEST(WebAnimationTest, MAYBE_DefaultSettings)
{
OwnPtr<WebAnimationCurve> curve = adoptPtr(WebFloatAnimationCurve::create());
OwnPtr<WebAnimation> animation = adoptPtr(WebAnimation::create(*curve, WebAnimation::TargetPropertyOpacity));
// Ensure that the defaults are correct.
EXPECT_EQ(1, animation->iterations());
EXPECT_EQ(0, animation->startTime());
EXPECT_EQ(0, animation->timeOffset());
EXPECT_FALSE(animation->alternatesDirection());
}
// Linux/Win bots failed on this test.
// https://bugs.webkit.org/show_bug.cgi?id=90651
#if OS(WINDOWS)
#define MAYBE_ModifiedSettings DISABLED_ModifiedSettings
#elif OS(LINUX)
#define MAYBE_ModifiedSettings DISABLED_ModifiedSettings
#else
#define MAYBE_ModifiedSettings ModifiedSettings
#endif
TEST(WebAnimationTest, MAYBE_ModifiedSettings)
{
OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(WebFloatAnimationCurve::create());
OwnPtr<WebAnimation> animation = adoptPtr(WebAnimation::create(*curve, WebAnimation::TargetPropertyOpacity));
animation->setIterations(2);
animation->setStartTime(2);
animation->setTimeOffset(2);
animation->setAlternatesDirection(true);
EXPECT_EQ(2, animation->iterations());
EXPECT_EQ(2, animation->startTime());
EXPECT_EQ(2, animation->timeOffset());
EXPECT_TRUE(animation->alternatesDirection());
}
} // namespace

@ -0,0 +1,155 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include <public/WebLayer.h>
#include "CompositorFakeWebGraphicsContext3D.h"
#include "WebLayerImpl.h"
#include "WebLayerTreeViewTestCommon.h"
#include <public/WebCompositor.h>
#include <public/WebContentLayer.h>
#include <public/WebContentLayerClient.h>
#include <public/WebExternalTextureLayer.h>
#include <public/WebFloatPoint.h>
#include <public/WebFloatRect.h>
#include <public/WebLayerTreeView.h>
#include <public/WebLayerTreeViewClient.h>
#include <public/WebRect.h>
#include <public/WebSize.h>
#include <gmock/gmock.h>
using namespace WebKit;
using testing::AnyNumber;
using testing::AtLeast;
using testing::Mock;
using testing::Test;
using testing::_;
namespace {
class MockWebContentLayerClient : public WebContentLayerClient {
public:
MOCK_METHOD3(paintContents, void(WebCanvas*, const WebRect& clip, WebFloatRect& opaque));
};
class WebLayerTest : public Test {
public:
virtual void SetUp()
{
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
m_rootLayer = adoptPtr(WebLayer::create());
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
EXPECT_TRUE(m_view = adoptPtr(WebLayerTreeView::create(&m_client, *m_rootLayer, WebLayerTreeView::Settings())));
Mock::VerifyAndClearExpectations(&m_client);
}
virtual void TearDown()
{
// We may get any number of scheduleComposite calls during shutdown.
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
m_rootLayer.clear();
m_view.clear();
WebKit::WebCompositor::shutdown();
}
protected:
MockWebLayerTreeViewClient m_client;
OwnPtr<WebLayer> m_rootLayer;
OwnPtr<WebLayerTreeView> m_view;
};
// Tests that the client gets called to ask for a composite if we change the
// fields.
TEST_F(WebLayerTest, Client)
{
// Base layer.
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
OwnPtr<WebLayer> layer = adoptPtr(WebLayer::create());
m_rootLayer->addChild(layer.get());
Mock::VerifyAndClearExpectations(&m_client);
WebFloatPoint point(3, 4);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setAnchorPoint(point);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_EQ(point, layer->anchorPoint());
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
float anchorZ = 5;
layer->setAnchorPointZ(anchorZ);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_EQ(anchorZ, layer->anchorPointZ());
WebSize size(7, 8);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setBounds(size);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_EQ(size, layer->bounds());
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setMasksToBounds(true);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_TRUE(layer->masksToBounds());
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
OwnPtr<WebLayer> otherLayer = adoptPtr(WebLayer::create());
m_rootLayer->addChild(otherLayer.get());
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setMaskLayer(otherLayer.get());
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
float opacity = 0.123f;
layer->setOpacity(opacity);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_EQ(opacity, layer->opacity());
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setOpaque(true);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_TRUE(layer->opaque());
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
layer->setPosition(point);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_EQ(point, layer->position());
// Texture layer.
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
OwnPtr<WebExternalTextureLayer> textureLayer = adoptPtr(WebExternalTextureLayer::create());
m_rootLayer->addChild(textureLayer->layer());
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
textureLayer->setTextureId(3);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
textureLayer->setFlipped(true);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
WebFloatRect uvRect(0.1f, 0.1f, 0.9f, 0.9f);
textureLayer->setUVRect(uvRect);
Mock::VerifyAndClearExpectations(&m_client);
// Content layer.
MockWebContentLayerClient contentClient;
EXPECT_CALL(contentClient, paintContents(_, _, _)).Times(AnyNumber());
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
OwnPtr<WebContentLayer> contentLayer = adoptPtr(WebContentLayer::create(&contentClient));
m_rootLayer->addChild(contentLayer->layer());
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_CALL(m_client, scheduleComposite()).Times(AtLeast(1));
contentLayer->layer()->setDrawsContent(false);
Mock::VerifyAndClearExpectations(&m_client);
EXPECT_FALSE(contentLayer->layer()->drawsContent());
}
}

@ -0,0 +1,187 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include <public/WebLayerTreeView.h>
#include "CompositorFakeWebGraphicsContext3D.h"
#include "FakeWebCompositorOutputSurface.h"
#include "WebLayerTreeViewTestCommon.h"
#include <gmock/gmock.h>
#include <public/Platform.h>
#include <public/WebCompositor.h>
#include <public/WebLayer.h>
#include <public/WebLayerTreeViewClient.h>
#include <public/WebThread.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
using namespace WebKit;
using testing::Mock;
using testing::Test;
namespace {
class MockWebLayerTreeViewClientForThreadedTests : public MockWebLayerTreeViewClient {
public:
virtual void didBeginFrame() OVERRIDE
{
WebKit::Platform::current()->currentThread()->exitRunLoop();
MockWebLayerTreeViewClient::didBeginFrame();
}
};
class WebLayerTreeViewTestBase : public Test {
protected:
virtual void initializeCompositor() = 0;
virtual WebLayerTreeViewClient* client() = 0;
public:
virtual void SetUp()
{
initializeCompositor();
m_rootLayer = adoptPtr(WebLayer::create());
ASSERT_TRUE(m_view = adoptPtr(WebLayerTreeView::create(client(), *m_rootLayer, WebLayerTreeView::Settings())));
m_view->setSurfaceReady();
}
virtual void TearDown()
{
Mock::VerifyAndClearExpectations(client());
m_rootLayer.clear();
m_view.clear();
WebKit::WebCompositor::shutdown();
}
protected:
OwnPtr<WebLayer> m_rootLayer;
OwnPtr<WebLayerTreeView> m_view;
};
class WebLayerTreeViewSingleThreadTest : public WebLayerTreeViewTestBase {
protected:
void composite()
{
m_view->composite();
}
virtual void initializeCompositor() OVERRIDE
{
WebKit::WebCompositor::initialize(0);
}
virtual WebLayerTreeViewClient* client() OVERRIDE
{
return &m_client;
}
MockWebLayerTreeViewClient m_client;
};
class CancelableTaskWrapper : public RefCounted<CancelableTaskWrapper> {
class Task : public WebThread::Task {
public:
Task(CancelableTaskWrapper* cancelableTask)
: m_cancelableTask(cancelableTask)
{
}
private:
virtual void run() OVERRIDE
{
m_cancelableTask->runIfNotCanceled();
}
RefPtr<CancelableTaskWrapper> m_cancelableTask;
};
public:
CancelableTaskWrapper(PassOwnPtr<WebThread::Task> task)
: m_task(task)
{
}
void cancel()
{
m_task.clear();
}
WebThread::Task* createTask()
{
ASSERT(m_task);
return new Task(this);
}
void runIfNotCanceled()
{
if (!m_task)
return;
m_task->run();
m_task.clear();
}
private:
OwnPtr<WebThread::Task> m_task;
};
class WebLayerTreeViewThreadedTest : public WebLayerTreeViewTestBase {
protected:
class TimeoutTask : public WebThread::Task {
virtual void run() OVERRIDE
{
WebKit::Platform::current()->currentThread()->exitRunLoop();
}
};
void composite()
{
m_view->setNeedsRedraw();
RefPtr<CancelableTaskWrapper> timeoutTask = adoptRef(new CancelableTaskWrapper(adoptPtr(new TimeoutTask())));
WebKit::Platform::current()->currentThread()->postDelayedTask(timeoutTask->createTask(), 5000);
WebKit::Platform::current()->currentThread()->enterRunLoop();
timeoutTask->cancel();
m_view->finishAllRendering();
}
virtual void initializeCompositor() OVERRIDE
{
m_webThread = adoptPtr(WebKit::Platform::current()->createThread("WebLayerTreeViewTest"));
WebCompositor::initialize(m_webThread.get());
}
virtual WebLayerTreeViewClient* client() OVERRIDE
{
return &m_client;
}
MockWebLayerTreeViewClientForThreadedTests m_client;
OwnPtr<WebThread> m_webThread;
};
TEST_F(WebLayerTreeViewSingleThreadTest, InstrumentationCallbacks)
{
::testing::InSequence dummy;
EXPECT_CALL(m_client, willCommit());
EXPECT_CALL(m_client, didCommit());
EXPECT_CALL(m_client, didBeginFrame());
composite();
}
TEST_F(WebLayerTreeViewThreadedTest, InstrumentationCallbacks)
{
::testing::InSequence dummy;
EXPECT_CALL(m_client, willBeginFrame());
EXPECT_CALL(m_client, willCommit());
EXPECT_CALL(m_client, didCommit());
EXPECT_CALL(m_client, didBeginFrame());
composite();
}
} // namespace

@ -0,0 +1,619 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include <public/WebTransformOperations.h>
#include <public/WebTransformationMatrix.h>
#include "CCLayerTreeTestCommon.h"
#include <gtest/gtest.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
using namespace std;
using namespace WebKit;
TEST(WebTransformOperationTest, transformTypesAreUnique)
{
Vector<OwnPtr<WebTransformOperations> > transforms;
WebTransformOperations* toAdd = new WebTransformOperations();
toAdd->appendTranslate(1, 0, 0);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendRotate(0, 0, 1, 2);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendScale(2, 2, 2);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendSkew(1, 0);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendPerspective(800);
transforms.append(adoptPtr(toAdd));
for (size_t i = 0; i < transforms.size(); ++i) {
for (size_t j = 0; j < transforms.size(); ++j) {
bool matchesType = transforms[i]->matchesTypes(*transforms[j]);
EXPECT_TRUE((i == j && matchesType) || !matchesType);
}
}
}
TEST(WebTransformOperationTest, matchTypesSameLength)
{
WebTransformOperations translates;
translates.appendTranslate(1, 0, 0);
translates.appendTranslate(1, 0, 0);
translates.appendTranslate(1, 0, 0);
WebTransformOperations skews;
skews.appendSkew(0, 2);
skews.appendSkew(0, 2);
skews.appendSkew(0, 2);
WebTransformOperations translates2;
translates2.appendTranslate(0, 2, 0);
translates2.appendTranslate(0, 2, 0);
translates2.appendTranslate(0, 2, 0);
WebTransformOperations translates3 = translates2;
EXPECT_FALSE(translates.matchesTypes(skews));
EXPECT_TRUE(translates.matchesTypes(translates2));
EXPECT_TRUE(translates.matchesTypes(translates3));
}
TEST(WebTransformOperationTest, matchTypesDifferentLength)
{
WebTransformOperations translates;
translates.appendTranslate(1, 0, 0);
translates.appendTranslate(1, 0, 0);
translates.appendTranslate(1, 0, 0);
WebTransformOperations skews;
skews.appendSkew(2, 0);
skews.appendSkew(2, 0);
WebTransformOperations translates2;
translates2.appendTranslate(0, 2, 0);
translates2.appendTranslate(0, 2, 0);
EXPECT_FALSE(translates.matchesTypes(skews));
EXPECT_FALSE(translates.matchesTypes(translates2));
}
void getIdentityOperations(Vector<OwnPtr<WebTransformOperations> >* operations)
{
WebTransformOperations* toAdd = new WebTransformOperations();
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendTranslate(0, 0, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendTranslate(0, 0, 0);
toAdd->appendTranslate(0, 0, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendScale(1, 1, 1);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendScale(1, 1, 1);
toAdd->appendScale(1, 1, 1);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendSkew(0, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendSkew(0, 0);
toAdd->appendSkew(0, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendRotate(0, 0, 1, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendRotate(0, 0, 1, 0);
toAdd->appendRotate(0, 0, 1, 0);
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendMatrix(WebTransformationMatrix());
operations->append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
toAdd->appendMatrix(WebTransformationMatrix());
toAdd->appendMatrix(WebTransformationMatrix());
operations->append(adoptPtr(toAdd));
}
TEST(WebTransformOperationTest, identityAlwaysMatches)
{
Vector<OwnPtr<WebTransformOperations> > operations;
getIdentityOperations(&operations);
for (size_t i = 0; i < operations.size(); ++i) {
for (size_t j = 0; j < operations.size(); ++j)
EXPECT_TRUE(operations[i]->matchesTypes(*operations[j]));
}
}
TEST(WebTransformOperationTest, applyTranslate)
{
double x = 1;
double y = 2;
double z = 3;
WebTransformOperations operations;
operations.appendTranslate(x, y, z);
WebTransformationMatrix expected;
expected.translate3d(x, y, z);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.apply());
}
TEST(WebTransformOperationTest, applyRotate)
{
double x = 1;
double y = 2;
double z = 3;
double degrees = 80;
WebTransformOperations operations;
operations.appendRotate(x, y, z, degrees);
WebTransformationMatrix expected;
expected.rotate3d(x, y, z, degrees);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.apply());
}
TEST(WebTransformOperationTest, applyScale)
{
double x = 1;
double y = 2;
double z = 3;
WebTransformOperations operations;
operations.appendScale(x, y, z);
WebTransformationMatrix expected;
expected.scale3d(x, y, z);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.apply());
}
TEST(WebTransformOperationTest, applySkew)
{
double x = 1;
double y = 2;
WebTransformOperations operations;
operations.appendSkew(x, y);
WebTransformationMatrix expected;
expected.skewX(x);
expected.skewY(y);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.apply());
}
TEST(WebTransformOperationTest, applyPerspective)
{
double depth = 800;
WebTransformOperations operations;
operations.appendPerspective(depth);
WebTransformationMatrix expected;
expected.applyPerspective(depth);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.apply());
}
TEST(WebTransformOperationTest, applyMatrix)
{
double dx = 1;
double dy = 2;
double dz = 3;
WebTransformationMatrix expectedMatrix;
expectedMatrix.translate3d(dx, dy, dz);
WebTransformOperations matrixTransform;
matrixTransform.appendMatrix(expectedMatrix);
EXPECT_TRANSFORMATION_MATRIX_EQ(expectedMatrix, matrixTransform.apply());
}
TEST(WebTransformOperationTest, applyOrder)
{
double sx = 2;
double sy = 4;
double sz = 8;
double dx = 1;
double dy = 2;
double dz = 3;
WebTransformOperations operations;
operations.appendScale(sx, sy, sz);
operations.appendTranslate(dx, dy, dz);
WebTransformationMatrix expectedScaleMatrix;
expectedScaleMatrix.scale3d(sx, sy, sz);
WebTransformationMatrix expectedTranslateMatrix;
expectedTranslateMatrix.translate3d(dx, dy, dz);
WebTransformationMatrix expectedCombinedMatrix = expectedScaleMatrix;
expectedCombinedMatrix.multiply(expectedTranslateMatrix);
EXPECT_TRANSFORMATION_MATRIX_EQ(expectedCombinedMatrix, operations.apply());
}
TEST(WebTransformOperationTest, blendOrder)
{
double sx1 = 2;
double sy1 = 4;
double sz1 = 8;
double dx1 = 1;
double dy1 = 2;
double dz1 = 3;
double sx2 = 4;
double sy2 = 8;
double sz2 = 16;
double dx2 = 10;
double dy2 = 20;
double dz2 = 30;
WebTransformOperations operationsFrom;
operationsFrom.appendScale(sx1, sy1, sz1);
operationsFrom.appendTranslate(dx1, dy1, dz1);
WebTransformOperations operationsTo;
operationsTo.appendScale(sx2, sy2, sz2);
operationsTo.appendTranslate(dx2, dy2, dz2);
WebTransformationMatrix scaleFrom;
scaleFrom.scale3d(sx1, sy1, sz1);
WebTransformationMatrix translateFrom;
translateFrom.translate3d(dx1, dy1, dz1);
WebTransformationMatrix scaleTo;
scaleTo.scale3d(sx2, sy2, sz2);
WebTransformationMatrix translateTo;
translateTo.translate3d(dx2, dy2, dz2);
double progress = 0.25;
WebTransformationMatrix blendedScale = scaleTo;
blendedScale.blend(scaleFrom, progress);
WebTransformationMatrix blendedTranslate = translateTo;
blendedTranslate.blend(translateFrom, progress);
WebTransformationMatrix expected = blendedScale;
expected.multiply(blendedTranslate);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
static void checkProgress(double progress,
const WebTransformationMatrix& fromMatrix,
const WebTransformationMatrix& toMatrix,
const WebTransformOperations& fromTransform,
const WebTransformOperations& toTransform)
{
WebTransformationMatrix expectedMatrix = toMatrix;
expectedMatrix.blend(fromMatrix, progress);
EXPECT_TRANSFORMATION_MATRIX_EQ(expectedMatrix, toTransform.blend(fromTransform, progress));
}
TEST(WebTransformOperationTest, blendProgress)
{
double sx = 2;
double sy = 4;
double sz = 8;
WebTransformOperations operationsFrom;
operationsFrom.appendScale(sx, sy, sz);
WebTransformationMatrix matrixFrom;
matrixFrom.scale3d(sx, sy, sz);
sx = 4;
sy = 8;
sz = 16;
WebTransformOperations operationsTo;
operationsTo.appendScale(sx, sy, sz);
WebTransformationMatrix matrixTo;
matrixTo.scale3d(sx, sy, sz);
checkProgress(-1, matrixFrom, matrixTo, operationsFrom, operationsTo);
checkProgress(0, matrixFrom, matrixTo, operationsFrom, operationsTo);
checkProgress(0.25, matrixFrom, matrixTo, operationsFrom, operationsTo);
checkProgress(0.5, matrixFrom, matrixTo, operationsFrom, operationsTo);
checkProgress(1, matrixFrom, matrixTo, operationsFrom, operationsTo);
checkProgress(2, matrixFrom, matrixTo, operationsFrom, operationsTo);
}
TEST(WebTransformOperationTest, blendWhenTypesDoNotMatch)
{
double sx1 = 2;
double sy1 = 4;
double sz1 = 8;
double dx1 = 1;
double dy1 = 2;
double dz1 = 3;
double sx2 = 4;
double sy2 = 8;
double sz2 = 16;
double dx2 = 10;
double dy2 = 20;
double dz2 = 30;
WebTransformOperations operationsFrom;
operationsFrom.appendScale(sx1, sy1, sz1);
operationsFrom.appendTranslate(dx1, dy1, dz1);
WebTransformOperations operationsTo;
operationsTo.appendTranslate(dx2, dy2, dz2);
operationsTo.appendScale(sx2, sy2, sz2);
WebTransformationMatrix from;
from.scale3d(sx1, sy1, sz1);
from.translate3d(dx1, dy1, dz1);
WebTransformationMatrix to;
to.translate3d(dx2, dy2, dz2);
to.scale3d(sx2, sy2, sz2);
double progress = 0.25;
WebTransformationMatrix expected = to;
expected.blend(from, progress);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
TEST(WebTransformOperationTest, largeRotationsWithSameAxis)
{
WebTransformOperations operationsFrom;
operationsFrom.appendRotate(0, 0, 1, 0);
WebTransformOperations operationsTo;
operationsTo.appendRotate(0, 0, 2, 360);
double progress = 0.5;
WebTransformationMatrix expected;
expected.rotate3d(0, 0, 1, 180);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
TEST(WebTransformOperationTest, largeRotationsWithSameAxisInDifferentDirection)
{
WebTransformOperations operationsFrom;
operationsFrom.appendRotate(0, 0, 1, 180);
WebTransformOperations operationsTo;
operationsTo.appendRotate(0, 0, -1, 180);
double progress = 0.5;
WebTransformationMatrix expected;
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
TEST(WebTransformOperationTest, largeRotationsWithDifferentAxes)
{
WebTransformOperations operationsFrom;
operationsFrom.appendRotate(0, 0, 1, 180);
WebTransformOperations operationsTo;
operationsTo.appendRotate(0, 1, 0, 180);
double progress = 0.5;
WebTransformationMatrix matrixFrom;
matrixFrom.rotate3d(0, 0, 1, 180);
WebTransformationMatrix matrixTo;
matrixTo.rotate3d(0, 1, 0, 180);
WebTransformationMatrix expected = matrixTo;
expected.blend(matrixFrom, progress);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
TEST(WebTransformOperationTest, blendRotationFromIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendRotate(0, 0, 1, 360);
double progress = 0.5;
WebTransformationMatrix expected;
expected.rotate3d(0, 0, 1, 180);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
}
}
TEST(WebTransformOperationTest, blendTranslationFromIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendTranslate(2, 2, 2);
double progress = 0.5;
WebTransformationMatrix expected;
expected.translate3d(1, 1, 1);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
}
}
TEST(WebTransformOperationTest, blendScaleFromIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendScale(3, 3, 3);
double progress = 0.5;
WebTransformationMatrix expected;
expected.scale3d(2, 2, 2);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
}
}
TEST(WebTransformOperationTest, blendSkewFromIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendSkew(2, 2);
double progress = 0.5;
WebTransformationMatrix expected;
expected.skewX(1);
expected.skewY(1);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
}
}
TEST(WebTransformOperationTest, blendPerspectiveFromIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendPerspective(1000);
double progress = 0.5;
WebTransformationMatrix expected;
expected.applyPerspective(500 + 0.5 * numeric_limits<double>::max());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
}
}
TEST(WebTransformOperationTest, blendRotationToIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendRotate(0, 0, 1, 360);
double progress = 0.5;
WebTransformationMatrix expected;
expected.rotate3d(0, 0, 1, 180);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
}
}
TEST(WebTransformOperationTest, blendTranslationToIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendTranslate(2, 2, 2);
double progress = 0.5;
WebTransformationMatrix expected;
expected.translate3d(1, 1, 1);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
}
}
TEST(WebTransformOperationTest, blendScaleToIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendScale(3, 3, 3);
double progress = 0.5;
WebTransformationMatrix expected;
expected.scale3d(2, 2, 2);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
}
}
TEST(WebTransformOperationTest, blendSkewToIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendSkew(2, 2);
double progress = 0.5;
WebTransformationMatrix expected;
expected.skewX(1);
expected.skewY(1);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
}
}
TEST(WebTransformOperationTest, blendPerspectiveToIdentity)
{
Vector<OwnPtr<WebTransformOperations> > identityOperations;
getIdentityOperations(&identityOperations);
for (size_t i = 0; i < identityOperations.size(); ++i) {
WebTransformOperations operations;
operations.appendPerspective(1000);
double progress = 0.5;
WebTransformationMatrix expected;
expected.applyPerspective(500 + 0.5 * numeric_limits<double>::max());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
}
}

File diff suppressed because it is too large Load Diff

@ -52,21 +52,21 @@
'target_name': 'webkit_compositor',
'type': 'static_library',
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/cc/cc.gyp:cc',
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
'../../base/base.gyp:base',
'../../cc/cc.gyp:cc',
'../../skia/skia.gyp:skia',
'../../third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
# We have to depend on WTF directly to pick up the correct defines for WTF headers - for instance USE_SYSTEM_MALLOC.
'<(DEPTH)/third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'../../third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
],
'defines': [
'WEBKIT_IMPLEMENTATION=1',
],
'include_dirs': [
'<(DEPTH)/cc',
'<(DEPTH)/cc/stubs',
'../../cc',
'../../cc/stubs',
'stubs',
'<(DEPTH)/third_party/WebKit/Source/WebKit/chromium/public',
'../../third_party/WebKit/Source/WebKit/chromium/public',
],
'sources': [
'<@(webkit_compositor_sources)',

@ -7,8 +7,23 @@
'chromium_code': 0,
'use_libcc_for_compositor%': 0,
'webkit_compositor_tests_sources': [
'LayerChromiumTest.cpp',
'TextureCopierTest.cpp',
'TextureLayerChromiumTest.cpp',
'ThrottledTextureUploaderTest.cpp',
'TiledLayerChromiumTest.cpp',
'TreeSynchronizerTest.cpp',
'WebAnimationTest.cpp',
'WebFloatAnimationCurveTest.cpp',
'WebFloatAnimationCurveTest.cpp',
'WebLayerTest.cpp',
'WebLayerTreeViewTest.cpp',
'WebTransformAnimationCurveTest.cpp',
'WebTransformAnimationCurveTest.cpp',
'WebTransformOperationsTest.cpp',
'WebTransformationMatrixTest.cpp',
'test/FakeWebScrollbarThemeGeometry.h',
'test/WebLayerTreeViewTestCommon.h',
],
},
'conditions': [
@ -18,19 +33,23 @@
'target_name': 'webkit_compositor_unittests',
'type' : 'executable',
'dependencies': [
'<(DEPTH)/base/base.gyp:test_support_base',
'<(DEPTH)/cc/cc.gyp:cc',
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
'<(DEPTH)/third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'<(DEPTH)/webkit/support/webkit_support.gyp:webkit_support',
'../../base/base.gyp:test_support_base',
'../../cc/cc.gyp:cc',
'../../cc/cc_tests.gyp:cc_test_support',
'../../skia/skia.gyp:skia',
'../../testing/gmock.gyp:gmock',
'../../testing/gtest.gyp:gtest',
'../../third_party/WebKit/Source/Platform/Platform.gyp/Platform.gyp:webkit_platform',
'../../third_party/WebKit/Source/WTF/WTF.gyp/WTF.gyp:wtf',
'../../webkit/support/webkit_support.gyp:webkit_support',
'compositor.gyp:webkit_compositor',
],
'include_dirs': [
'.',
'test',
'<(DEPTH)/cc',
'<(DEPTH)/cc/stubs',
'<(DEPTH)/cc/test',
],
'sources': [
'<@(webkit_compositor_tests_sources)',

@ -15,6 +15,8 @@ def Copy(name):
src = name
dst = name
fullsrc = ""
if name.startswith("test/"):
src = src[5:]
for prefix in prefixes:
candidate = "%s/%s" % (prefix, src)
if os.path.exists(candidate):

@ -0,0 +1,48 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FakeWebScrollbarThemeGeometry_h
#define FakeWebScrollbarThemeGeometry_h
#include <public/WebScrollbarThemeGeometry.h>
#include <wtf/PassOwnPtr.h>
namespace WebKit {
class FakeWebScrollbarThemeGeometry : public WebKit::WebScrollbarThemeGeometry {
public:
static PassOwnPtr<WebKit::WebScrollbarThemeGeometry> create() { return adoptPtr(new WebKit::FakeWebScrollbarThemeGeometry()); }
virtual WebKit::WebScrollbarThemeGeometry* clone() const OVERRIDE
{
return new FakeWebScrollbarThemeGeometry();
}
virtual int thumbPosition(WebScrollbar*) OVERRIDE { return 0; }
virtual int thumbLength(WebScrollbar*) OVERRIDE { return 0; }
virtual int trackPosition(WebScrollbar*) OVERRIDE { return 0; }
virtual int trackLength(WebScrollbar*) OVERRIDE { return 0; }
virtual bool hasButtons(WebScrollbar*) OVERRIDE { return false; }
virtual bool hasThumb(WebScrollbar*) OVERRIDE { return false; }
virtual WebRect trackRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual WebRect thumbRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual int minimumThumbLength(WebScrollbar*) OVERRIDE { return 0; }
virtual int scrollbarThickness(WebScrollbar*) OVERRIDE { return 0; }
virtual WebRect backButtonStartRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual WebRect backButtonEndRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual WebRect forwardButtonStartRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual WebRect forwardButtonEndRect(WebScrollbar*) OVERRIDE { return WebRect(); }
virtual WebRect constrainTrackRectToTrackPieces(WebScrollbar*, const WebRect&) OVERRIDE { return WebRect(); }
virtual void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startTrack, WebRect& thumb, WebRect& endTrack) OVERRIDE
{
startTrack = WebRect();
thumb = WebRect();
endTrack = WebRect();
}
};
} // namespace WebKit
#endif // FakeWebScrollbarThemeGeometry_h

@ -0,0 +1,38 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebLayerTreeViewTestCommon_h
#define WebLayerTreeViewTestCommon_h
#include "CompositorFakeWebGraphicsContext3D.h"
#include "FakeWebCompositorOutputSurface.h"
#include <gmock/gmock.h>
#include <public/WebLayerTreeViewClient.h>
namespace WebKit {
class MockWebLayerTreeViewClient : public WebLayerTreeViewClient {
public:
MOCK_METHOD0(scheduleComposite, void());
virtual void updateAnimations(double frameBeginTime) OVERRIDE { }
MOCK_METHOD0(willBeginFrame, void());
MOCK_METHOD0(didBeginFrame, void());
virtual void layout() OVERRIDE { }
virtual void applyScrollAndScale(const WebSize& scrollDelta, float scaleFactor) OVERRIDE { }
virtual WebCompositorOutputSurface* createOutputSurface() OVERRIDE
{
return FakeWebCompositorOutputSurface::create(CompositorFakeWebGraphicsContext3D::create(WebGraphicsContext3D::Attributes())).leakPtr();
}
virtual void didRecreateOutputSurface(bool) OVERRIDE { }
MOCK_METHOD0(willCommit, void());
MOCK_METHOD0(didCommit, void());
virtual void didCommitAndDrawFrame() OVERRIDE { }
virtual void didCompleteSwapBuffers() OVERRIDE { }
};
}
#endif // WebLayerTreeViewTestCommon_h