diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/WebKit/chromium/tests | |
parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
download | qtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz |
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Source/WebKit/chromium/tests')
34 files changed, 3772 insertions, 298 deletions
diff --git a/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp b/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp index 62d12b400..677865ac0 100644 --- a/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp +++ b/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp @@ -40,6 +40,7 @@ #include "platform/WebURLLoaderClient.h" #include "platform/WebURLRequest.h" #include "platform/WebURLResponse.h" +#include <wtf/text/WTFString.h> #include <googleurl/src/gurl.h> #include <gtest/gtest.h> @@ -137,6 +138,7 @@ public: void didReceiveResponse(WebURLLoader* loader, const WebURLResponse& response) { m_didReceiveResponse = true; + m_actualResponse = WebURLResponse(response); EXPECT_EQ(m_expectedLoader, loader); EXPECT_EQ(m_expectedResponse.url(), response.url()); EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode()); @@ -220,12 +222,49 @@ public: EXPECT_FALSE(m_didReceiveResponse); } + bool CheckAccessControlHeaders(const char* headerName, bool exposed) + { + std::string id("http://www.other.com/CheckAccessControlExposeHeaders_"); + id.append(headerName); + if (exposed) + id.append("-Exposed"); + id.append(".html"); + + GURL url = GURL(id); + WebURLRequest request; + request.initialize(); + request.setURL(url); + + WebString headerNameString(WebString::fromUTF8(headerName)); + m_expectedResponse = WebURLResponse(); + m_expectedResponse.initialize(); + m_expectedResponse.setMIMEType("text/html"); + m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); + if (exposed) + m_expectedResponse.addHTTPHeaderField("access-control-expose-header", headerNameString); + m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); + webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath); + + WebURLLoaderOptions options; + options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; + m_expectedLoader = createAssociatedURLLoader(options); + EXPECT_TRUE(m_expectedLoader); + m_expectedLoader->loadAsynchronously(request, this); + serveRequests(); + EXPECT_TRUE(m_didReceiveResponse); + EXPECT_TRUE(m_didReceiveData); + EXPECT_TRUE(m_didFinishLoading); + + return !m_actualResponse.httpHeaderField(headerNameString).isEmpty(); + } + protected: WebString m_frameFilePath; TestWebFrameClient m_webFrameClient; WebView* m_webView; WebURLLoader* m_expectedLoader; + WebURLResponse m_actualResponse; WebURLResponse m_expectedResponse; WebURLRequest m_expectedNewRequest; WebURLResponse m_expectedRedirectResponse; @@ -487,4 +526,29 @@ TEST_F(AssociatedURLLoaderTest, UntrustedCheckHeaders) CheckHeaderFails("foo", "bar\x0d\x0ax-csrf-token:\x20test1234"); } +// Test that the loader filters response headers according to the CORS standard. +TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting) +{ + // Test that whitelisted headers are returned without exposing them. + EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false)); + EXPECT_TRUE(CheckAccessControlHeaders("content-language", false)); + EXPECT_TRUE(CheckAccessControlHeaders("content-type", false)); + EXPECT_TRUE(CheckAccessControlHeaders("expires", false)); + EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false)); + EXPECT_TRUE(CheckAccessControlHeaders("pragma", false)); + + // Test that non-whitelisted headers aren't returned. + EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false)); + + // Test that Set-Cookie headers aren't returned. + EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false)); + EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false)); + + // Test that exposed headers that aren't whitelisted are returned. + EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true)); + + // Test that Set-Cookie headers aren't returned, even if exposed. + EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true)); +} + } diff --git a/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp b/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp new file mode 100644 index 000000000..3e93d95de --- /dev/null +++ b/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCActiveAnimation.h" + +#include "cc/CCAnimationCurve.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class FakeFloatAnimation : public CCFloatAnimationCurve { +public: + virtual double duration() const { return 1; } + virtual float getValue(double now) const { return 0; } +}; + +PassOwnPtr<CCActiveAnimation> createActiveAnimation(int iterations) +{ + OwnPtr<CCActiveAnimation> toReturn(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimation), 1, CCActiveAnimation::Opacity)); + toReturn->setIterations(iterations); + return toReturn.release(); +} + +TEST(CCActiveAnimationTest, TrimTimeZeroIterations) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(-1)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(1)); +} + +TEST(CCActiveAnimationTest, TrimTimeOneIteration) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(-1)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0)); + EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1)); + EXPECT_EQ(1, anim->trimTimeToCurrentIteration(2)); +} + +TEST(CCActiveAnimationTest, TrimTimeInfiniteIterations) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(-1)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0)); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(1)); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1.5)); +} + +TEST(CCActiveAnimationTest, TrimTimeStartTime) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1)); + anim->setStartTime(4); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0)); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(4)); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(4.5)); + EXPECT_EQ(1, anim->trimTimeToCurrentIteration(5)); + EXPECT_EQ(1, anim->trimTimeToCurrentIteration(6)); +} + +TEST(CCActiveAnimationTest, TrimTimePauseResume) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0)); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5)); + anim->setRunState(CCActiveAnimation::Paused, 0.5); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024)); + anim->setRunState(CCActiveAnimation::Running, 1024); + EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024)); + EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1024.5)); +} + +TEST(CCActiveAnimationTest, IsFinishedAtZeroIterations) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_FALSE(anim->isFinishedAt(-1)); + EXPECT_TRUE(anim->isFinishedAt(0)); + EXPECT_TRUE(anim->isFinishedAt(1)); +} + +TEST(CCActiveAnimationTest, IsFinishedAtOneIteration) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_FALSE(anim->isFinishedAt(-1)); + EXPECT_FALSE(anim->isFinishedAt(0)); + EXPECT_TRUE(anim->isFinishedAt(1)); + EXPECT_TRUE(anim->isFinishedAt(2)); +} + +TEST(CCActiveAnimationTest, IsFinishedAtInfiniteIterations) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(-1)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_FALSE(anim->isFinishedAt(0)); + EXPECT_FALSE(anim->isFinishedAt(0.5)); + EXPECT_FALSE(anim->isFinishedAt(1)); + EXPECT_FALSE(anim->isFinishedAt(1.5)); +} + +TEST(CCActiveAnimationTest, IsFinishedAtNotRunning) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_TRUE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::Paused, 0); + EXPECT_FALSE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::WaitingForNextTick, 0); + EXPECT_FALSE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0); + EXPECT_FALSE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::WaitingForStartTime, 0); + EXPECT_FALSE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::Finished, 0); + EXPECT_TRUE(anim->isFinishedAt(0)); + anim->setRunState(CCActiveAnimation::Aborted, 0); + EXPECT_TRUE(anim->isFinishedAt(0)); +} + +TEST(CCActiveAnimationTest, IsFinished) +{ + OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1)); + anim->setRunState(CCActiveAnimation::Running, 0); + EXPECT_FALSE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::Paused, 0); + EXPECT_FALSE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::WaitingForNextTick, 0); + EXPECT_FALSE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 0); + EXPECT_FALSE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::WaitingForStartTime, 0); + EXPECT_FALSE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::Finished, 0); + EXPECT_TRUE(anim->isFinished()); + anim->setRunState(CCActiveAnimation::Aborted, 0); + EXPECT_TRUE(anim->isFinished()); +} + +} // namespace WebCore diff --git a/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp b/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp index 41c9d119e..867d56ea8 100644 --- a/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp +++ b/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp @@ -46,10 +46,12 @@ TEST(CCDelayBasedTimeSourceTest, TaskPostedAndTickCalled) timer->setMonotonicallyIncreasingTimeMs(0); timer->setActive(true); + EXPECT_TRUE(timer->active()); EXPECT_TRUE(thread.hasPendingTask()); timer->setMonotonicallyIncreasingTimeMs(16); thread.runPendingTask(); + EXPECT_TRUE(timer->active()); EXPECT_TRUE(client.tickCalled()); } diff --git a/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp new file mode 100644 index 000000000..3d50d06e6 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCLayerAnimationControllerImpl.h" + +#include "TransformOperations.h" +#include "cc/CCAnimationCurve.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +using namespace WebCore; + +namespace { + +class FakeControllerClient : public CCLayerAnimationControllerImplClient { +public: + FakeControllerClient() : m_opacity(0) { } + virtual ~FakeControllerClient() { } + + virtual float opacity() const { return m_opacity; } + virtual void setOpacity(float opacity) { m_opacity = opacity; } + virtual const TransformationMatrix& transform() const { return m_transform; } + virtual void setTransform(const TransformationMatrix& transform) { m_transform = transform; } + virtual void animationControllerImplDidActivate(CCLayerAnimationControllerImpl* controller) + { + m_activeControllers.append(controller); + } + + Vector<CCLayerAnimationControllerImpl*>& activeControllers() { return m_activeControllers; } + +private: + float m_opacity; + TransformationMatrix m_transform; + Vector<CCLayerAnimationControllerImpl*> m_activeControllers; +}; + +class FakeTransformTransition : public CCTransformAnimationCurve { +public: + FakeTransformTransition(double duration) : m_duration(duration) { } + virtual double duration() const { return m_duration; } + virtual TransformOperations getValue(double time) const + { + return TransformOperations(); + } + +private: + double m_duration; +}; + +class FakeFloatTransition : public CCFloatAnimationCurve { +public: + FakeFloatTransition(double duration, float from, float to) + : m_duration(duration) + , m_from(from) + , m_to(to) + { + } + + virtual double duration() const { return m_duration; } + virtual float getValue(double time) const + { + time /= m_duration; + if (time >= 1) + time = 1; + return (1 - time) * m_from + time * m_to; + } + +private: + double m_duration; + float m_from; + float m_to; +}; + +// Tests that transitioning opacity from 0 to 1 works as expected. +TEST(CCLayerAnimationControllerImplTest, TrivialTransition) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + + controller->add(toAdd.release()); + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1); + EXPECT_EQ(1, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests that two queued animations affecting the same property run in sequence. +TEST(CCLayerAnimationControllerImplTest, TrivialQueuing) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); + controller->animate(2); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests interrupting a transition with another transition. +TEST(CCLayerAnimationControllerImplTest, Interrupt) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); + toAdd->setRunState(CCActiveAnimation::WaitingForNextTick, 0); + controller->add(toAdd.release()); + + controller->animate(0.5); // second anim starts NOW. + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); + controller->animate(1.5); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests scheduling two animations to run together when only one property is free. +TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWhenAPropertyIsBlocked) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), 1, CCActiveAnimation::Transform)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), 2, CCActiveAnimation::Transform)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 2, CCActiveAnimation::Opacity)); + + controller->animate(0); + EXPECT_EQ(0, dummy.opacity()); + EXPECT_TRUE(controller->hasActiveAnimation()); + controller->animate(1); + // Should not have started the float transition yet. + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + // The the float animation should have started at time 1 and should be done. + controller->animate(2); + EXPECT_EQ(1, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests scheduling two animations to run together with different lengths and another +// animation queued to start when the shorter animation finishes (should wait +// for both to finish). +TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWithAnAnimWaiting) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(2)), 1, CCActiveAnimation::Transform)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); + + // Anims with id 1 should both start now. + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + // The opacity animation should have finished at time 1, but the group + // of animations with id 1 don't finish until time 2 because of the length + // of the transform animation. + controller->animate(2); + // Should not have started the float transition yet. + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); + + // The the second opacity animation should start at time 2 and should be + // done by time 3 + controller->animate(3); + EXPECT_EQ(0.5f, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests scheduling an animation to start in the future. +TEST(CCLayerAnimationControllerImplTest, ScheduleAnimation) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0); + toAdd->setStartTime(1); + controller->add(toAdd.release()); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(2); + EXPECT_EQ(1, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests scheduling an animation to start in the future that's interrupting a running animation. +TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimation) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0.5f, 0)), 2, CCActiveAnimation::Opacity)); + toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0); + toAdd->setStartTime(1); + controller->add(toAdd.release()); + + // First 2s opacity transition should start immediately. + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(0.5); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + controller->animate(2); + EXPECT_EQ(0, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Tests scheduling an animation to start in the future that interrupts a running animation +// and there is yet another animation queued to start later. +TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0.5f, 0)), 2, CCActiveAnimation::Opacity)); + toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0); + toAdd->setStartTime(1); + controller->add(toAdd.release()); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 0.75f)), 3, CCActiveAnimation::Opacity)); + + // First 2s opacity transition should start immediately. + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(0.5); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + EXPECT_TRUE(controller->hasActiveAnimation()); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + controller->animate(3); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(4); + EXPECT_EQ(0.75f, dummy.opacity()); + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +// Test that a looping animation loops and for the correct number of iterations. +TEST(CCLayerAnimationControllerImplTest, TrivialLooping) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + toAdd->setIterations(3); + controller->add(toAdd.release()); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1.25); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->animate(1.75); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->animate(2.25); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->animate(2.75); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->animate(3); + EXPECT_FALSE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); + + // Just be extra sure. + controller->animate(4); + EXPECT_EQ(1, dummy.opacity()); +} + +// Test that an infinitely looping animation does indeed go until aborted. +TEST(CCLayerAnimationControllerImplTest, InfiniteLooping) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + const int id = 1; + OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity)); + toAdd->setIterations(-1); + controller->add(toAdd.release()); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1.25); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->animate(1.75); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + + controller->animate(1073741824.25); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.25f, dummy.opacity()); + controller->animate(1073741824.75); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + + EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity)); + controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Aborted, 0.75f); + EXPECT_FALSE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); +} + +// Test that pausing and resuming work as expected. +TEST(CCLayerAnimationControllerImplTest, PauseResume) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + const int id = 1; + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity)); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(0.5); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity)); + controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Paused, 0.5f); + + controller->animate(1024); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity)); + controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Running, 1024); + + controller->animate(1024.25); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); + controller->animate(1024.5); + EXPECT_FALSE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); +} + +TEST(CCLayerAnimationControllerImplTest, AbortAGroupedAnimation) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + const int id = 1; + controller->add(CCActiveAnimation::create(adoptPtr(new FakeTransformTransition(1)), id, CCActiveAnimation::Transform)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), id, CCActiveAnimation::Opacity)); + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.75f)), 2, CCActiveAnimation::Opacity)); + + controller->animate(0); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0, dummy.opacity()); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(0.5f, dummy.opacity()); + + EXPECT_TRUE(controller->getActiveAnimation(id, CCActiveAnimation::Opacity)); + controller->getActiveAnimation(id, CCActiveAnimation::Opacity)->setRunState(CCActiveAnimation::Aborted, 1); + controller->animate(1); + EXPECT_TRUE(controller->hasActiveAnimation()); + EXPECT_EQ(1, dummy.opacity()); + controller->animate(2); + EXPECT_TRUE(!controller->hasActiveAnimation()); + EXPECT_EQ(0.75f, dummy.opacity()); +} + +// Tests that adding an animation to the controller calls the appropriate callback on the controller client +// (in this case, adding the controller to the list of active controller). +TEST(CCLayerAnimationControllerImplTest, DidActivate) +{ + FakeControllerClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controller( + CCLayerAnimationControllerImpl::create(&dummy)); + + EXPECT_EQ(size_t(0), dummy.activeControllers().size()); + + controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + + EXPECT_EQ(size_t(1), dummy.activeControllers().size()); + EXPECT_EQ(controller.get(), dummy.activeControllers()[0]); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp index 165405d49..27728cbef 100644 --- a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp @@ -112,6 +112,7 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly) EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDebugBorderWidth(arbitraryNumber)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDrawsContent(true)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundColor(Color::gray)); + EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundCoversViewport(true)); // Special case: check that sublayer transform changes all layer's descendants, but not the layer itself. root->resetAllChangeTrackingForSubtree(); diff --git a/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp b/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp index 47a6fd4dc..bff7e1ba9 100644 --- a/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp @@ -52,7 +52,7 @@ public: private: TestLayerChromium() - : LayerChromium(0) + : LayerChromium() , m_drawsContent(true) { setBounds(IntSize(100, 100)); diff --git a/Source/WebKit/chromium/tests/CCLayerTestCommon.cpp b/Source/WebKit/chromium/tests/CCLayerTestCommon.cpp new file mode 100644 index 000000000..9fe377766 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCLayerTestCommon.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "CCLayerTestCommon.h" + +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +using namespace WebCore; + +namespace CCLayerTestCommon { + +// Align with expected and actual output +const char* quadString = " Quad: "; + +bool completelyContains(const Region& container, const IntRect& rect) +{ + Region tester(rect); + Vector<IntRect> rects = container.rects(); + for (size_t i = 0; i < rects.size(); ++i) + tester.subtract(rects[i]); + return tester.isEmpty(); +} + +void verifyQuadsExactlyCoverRect(const CCQuadList& quads, const IntRect& rect) +{ + Region remaining(rect); + + for (size_t i = 0; i < quads.size(); ++i) { + CCDrawQuad* quad = quads[i].get(); + + EXPECT_TRUE(rect.contains(quad->quadRect())) << quadString << i; + EXPECT_TRUE(completelyContains(remaining, quad->quadRect())) << quadString << i; + remaining.subtract(Region(quad->quadRect())); + } + + EXPECT_TRUE(remaining.isEmpty()); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerTestCommon.h b/Source/WebKit/chromium/tests/CCLayerTestCommon.h new file mode 100644 index 000000000..c5add93a9 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCLayerTestCommon.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCLayerTestCommon_h +#define CCLayerTestCommon_h + +#include "IntRect.h" +#include "Region.h" +#include "cc/CCRenderPass.h" + +namespace CCLayerTestCommon { + +extern const char* quadString; + +bool completelyContains(const WebCore::Region&, const WebCore::IntRect&); +void verifyQuadsExactlyCoverRect(const WebCore::CCQuadList&, const WebCore::IntRect&); + +} // namespace CCLayerTestCommon +#endif // CCLayerTestCommon_h diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp index a35d96522..b1fa72918 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp @@ -28,6 +28,7 @@ #include "CCLayerTreeTestCommon.h" #include "LayerChromium.h" +#include "Region.h" #include "TransformationMatrix.h" #include <gmock/gmock.h> @@ -35,6 +36,12 @@ using namespace WebCore; +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.width(), b.width()); \ + EXPECT_EQ(a.height(), b.height()); + namespace { void setLayerPropertiesForTesting(LayerChromium* layer, const TransformationMatrix& transform, const TransformationMatrix& sublayerTransform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool preserves3D) @@ -71,8 +78,8 @@ TransformationMatrix remove3DComponentOfMatrix(const TransformationMatrix& mat) class LayerChromiumWithForcedDrawsContent : public LayerChromium { public: - explicit LayerChromiumWithForcedDrawsContent(CCLayerDelegate* delegate) - : LayerChromium(delegate) + LayerChromiumWithForcedDrawsContent() + : LayerChromium() { } @@ -86,9 +93,9 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForNoOpLayer) // screenSpaceTransform, and the hierarchy passed on to children // layers should also be identity transforms. - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromium> grandChild = LayerChromium::create(0); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromium> grandChild = LayerChromium::create(); parent->createRenderSurface(); parent->addChild(child); child->addChild(grandChild); @@ -116,7 +123,7 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleLayer) // different position. When we initialize layers for testing here, we need to initialize that unintutive position value. TransformationMatrix identityMatrix; - RefPtr<LayerChromium> layer = LayerChromium::create(0); + RefPtr<LayerChromium> layer = LayerChromium::create(); layer->createRenderSurface(); // Case 1: setting the sublayer transform should not affect this layer's draw transform or screen-space transform. @@ -181,9 +188,9 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleLayer) TEST(CCLayerTreeHostCommonTest, verifyTransformsForSimpleHierarchy) { TransformationMatrix identityMatrix; - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromium> grandChild = LayerChromium::create(0); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromium> grandChild = LayerChromium::create(); parent->createRenderSurface(); parent->addChild(child); child->addChild(grandChild); @@ -263,9 +270,9 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSimpleHierarchy) TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleRenderSurface) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromiumWithForcedDrawsContent> grandChild = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> grandChild = adoptRef(new LayerChromiumWithForcedDrawsContent()); parent->createRenderSurface(); parent->addChild(child); child->addChild(grandChild); @@ -318,15 +325,15 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForRenderSurfaceHierarchy) // - Sanity check on recursion: verify transforms of layers described w.r.t. a render surface that is described w.r.t. an ancestor render surface. // - verifying that each layer has a reference to the correct renderSurface and targetRenderSurface values. - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(0); - RefPtr<LayerChromium> renderSurface2 = LayerChromium::create(0); - RefPtr<LayerChromium> childOfRoot = LayerChromium::create(0); - RefPtr<LayerChromium> childOfRS1 = LayerChromium::create(0); - RefPtr<LayerChromium> childOfRS2 = LayerChromium::create(0); - RefPtr<LayerChromium> grandChildOfRoot = LayerChromium::create(0); - RefPtr<LayerChromiumWithForcedDrawsContent> grandChildOfRS1 = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); - RefPtr<LayerChromiumWithForcedDrawsContent> grandChildOfRS2 = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(); + RefPtr<LayerChromium> renderSurface2 = LayerChromium::create(); + RefPtr<LayerChromium> childOfRoot = LayerChromium::create(); + RefPtr<LayerChromium> childOfRS1 = LayerChromium::create(); + RefPtr<LayerChromium> childOfRS2 = LayerChromium::create(); + RefPtr<LayerChromium> grandChildOfRoot = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> grandChildOfRS1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> grandChildOfRS2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); parent->createRenderSurface(); parent->addChild(renderSurface1); parent->addChild(childOfRoot); @@ -454,9 +461,9 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForRenderSurfaceHierarchy) TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForClipLayer) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(0); - RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent()); renderSurface1->setOpacity(0.9); const TransformationMatrix identityMatrix; @@ -483,9 +490,9 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForClipLayer) TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForTransparentChild) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(0); - RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent()); renderSurface1->setOpacity(0); const TransformationMatrix identityMatrix; @@ -526,12 +533,12 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces) // const TransformationMatrix identityMatrix; - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromium> grandChild = LayerChromium::create(0); - RefPtr<LayerChromium> greatGrandChild = LayerChromium::create(0); - RefPtr<LayerChromiumWithForcedDrawsContent> leafNode1 = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); - RefPtr<LayerChromiumWithForcedDrawsContent> leafNode2 = adoptRef(new LayerChromiumWithForcedDrawsContent(0)); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromium> grandChild = LayerChromium::create(); + RefPtr<LayerChromium> greatGrandChild = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> leafNode1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> leafNode2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); parent->createRenderSurface(); parent->addChild(child); child->addChild(grandChild); @@ -595,4 +602,174 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces) // - test the other functions in CCLayerTreeHostCommon // +TEST(CCLayerTreeHostCommonTest, layerAddsSelfToOccludedRegion) +{ + // This tests that the right transforms are being used. + Region occluded; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(layer); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + + layer->setOpaque(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + // FIXME: when we fix this "root-layer special case" behavior in CCLayerTreeHost, we will have to fix it here, too. + parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); +} + +TEST(CCLayerTreeHostCommonTest, layerAddsSelfToOccludedRegionWithRotation) +{ + // This tests that the right transforms are being used. + Region occluded; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(layer); + + TransformationMatrix layerTransform; + layerTransform.translate(250, 250); + layerTransform.rotate(90); + layerTransform.translate(-250, -250); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(layer.get(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + + layer->setOpaque(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + // FIXME: when we fix this "root-layer special case" behavior in CCLayerTreeHost, we will have to fix it here, too. + parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); +} + +TEST(CCLayerTreeHostCommonTest, layerAddsSelfToOccludedRegionWithTranslation) +{ + // This tests that the right transforms are being used. + Region occluded; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(layer); + + TransformationMatrix layerTransform; + layerTransform.translate(20, 20); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(layer.get(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + + layer->setOpaque(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + // FIXME: when we fix this "root-layer special case" behavior in CCLayerTreeHost, we will have to fix it here, too. + parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); +} + +TEST(CCLayerTreeHostCommonTest, layerAddsSelfToOccludedRegionWithRotatedSurface) +{ + // This tests that the right transforms are being used. + Region occluded; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child); + child->addChild(layer); + + TransformationMatrix childTransform; + childTransform.translate(250, 250); + childTransform.rotate(90); + childTransform.translate(-250, -250); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(child.get(), childTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), false); + + child->setMasksToBounds(true); + layer->setOpaque(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + // FIXME: when we fix this "root-layer special case" behavior in CCLayerTreeHost, we will have to fix it here, too. + parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + /* Justification for the above opaque rect from |layer|: + 100 + +---------------------+ +---------------------+ + | | | |30 Visible region of |layer|: ///// + | 30 | rotate(90) | | + | 30 + ---------------------------------+ | +---------------------------------+ + 100 | | 10 | | ==> | | |10 | + | |10+---------------------------------+ | +---------------------------------+ | + | | | | | | | | |///////////////| 420 | | + | | | | | | | | |///////////////|60 | | + | | | | | | | | |///////////////| | | + +----|--|-------------+ | | +--|--|---------------+ | | + | | | | 20|10| 70 | | + | | | | | | | | + | | | |500 | | | | + | | | | | | | | + | | | | | | | | + | | | | | | | | + | | | | | | |10| + +--|-------------------------------+ | | +------------------------------|--+ + | | | 490 | + +---------------------------------+ +---------------------------------+ + 500 500 + */ +} + } // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp index 9b87d00fa..f59893de9 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp @@ -31,6 +31,7 @@ #include "LayerRendererChromium.h" #include "cc/CCLayerImpl.h" #include "cc/CCSingleThreadProxy.h" +#include "cc/CCSolidColorDrawQuad.h" #include <gtest/gtest.h> using namespace WebCore; @@ -73,6 +74,20 @@ public: ASSERT_EQ(timesEncountered, 1); } + void setupScrollAndContentsLayers(const IntSize& contentSize) + { + RefPtr<CCLayerImpl> root = CCLayerImpl::create(0); + root->setScrollable(true); + root->setScrollPosition(IntPoint(0, 0)); + root->setMaxScrollPosition(contentSize); + RefPtr<CCLayerImpl> contents = CCLayerImpl::create(1); + contents->setDrawsContent(true); + contents->setBounds(contentSize); + contents->setContentBounds(contentSize); + root->addChild(contents); + m_hostImpl->setRootLayer(root); + } + protected: DebugScopedSetImplThread m_alwaysImplThread; OwnPtr<CCLayerTreeHostImpl> m_hostImpl; @@ -155,6 +170,112 @@ TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw) EXPECT_TRUE(m_didRequestCommit); } +TEST_F(CCLayerTreeHostImplTest, pinchGesture) +{ + setupScrollAndContentsLayers(IntSize(100, 100)); + m_hostImpl->setViewportSize(IntSize(50, 50)); + + CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer(); + ASSERT(scrollLayer); + + const float minPageScale = 0.5, maxPageScale = 4; + + // Basic pinch zoom in gesture + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + + float pageScaleDelta = 2; + m_hostImpl->pinchGestureBegin(); + m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); + m_hostImpl->pinchGestureEnd(); + EXPECT_TRUE(m_didRequestRedraw); + EXPECT_TRUE(m_didRequestCommit); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); + } + + // Zoom-in clamping + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + float pageScaleDelta = 10; + + m_hostImpl->pinchGestureBegin(); + m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); + m_hostImpl->pinchGestureEnd(); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale); + } + + // Zoom-out clamping + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollPosition(IntPoint(50, 50)); + + float pageScaleDelta = 0.1; + m_hostImpl->pinchGestureBegin(); + m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); + m_hostImpl->pinchGestureEnd(); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); + + // Pushed to (0,0) via clamping against contents layer size. + expectContains(*scrollInfo.get(), scrollLayer->id(), IntSize(-50, -50)); + } +} + +TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation) +{ + setupScrollAndContentsLayers(IntSize(100, 100)); + m_hostImpl->setViewportSize(IntSize(50, 50)); + + CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer(); + ASSERT(scrollLayer); + + const float minPageScale = 0.5, maxPageScale = 4; + const double startTimeMs = 1000; + const double durationMs = 100; + + // Non-anchor zoom-in + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollPosition(IntPoint(50, 50)); + + m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTimeMs, durationMs); + m_hostImpl->animate(startTimeMs + durationMs / 2); + EXPECT_TRUE(m_didRequestRedraw); + m_hostImpl->animate(startTimeMs + durationMs); + EXPECT_TRUE(m_didRequestCommit); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, 2); + expectContains(*scrollInfo.get(), scrollLayer->id(), IntSize(-50, -50)); + } + + // Anchor zoom-out + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollPosition(IntPoint(50, 50)); + + m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale, startTimeMs, durationMs); + m_hostImpl->animate(startTimeMs + durationMs); + EXPECT_TRUE(m_didRequestRedraw); + EXPECT_TRUE(m_didRequestCommit); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); + // Pushed to (0,0) via clamping against contents layer size. + expectContains(*scrollInfo.get(), scrollLayer->id(), IntSize(-50, -50)); + } +} + class BlendStateTrackerContext: public FakeWebGraphicsContext3D { public: BlendStateTrackerContext() : m_blend(false) { } @@ -183,11 +304,13 @@ class BlendStateCheckLayer : public CCLayerImpl { public: static PassRefPtr<BlendStateCheckLayer> create(int id) { return adoptRef(new BlendStateCheckLayer(id)); } - virtual void draw(LayerRendererChromium* renderer) + virtual void appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) { - m_drawn = true; - BlendStateTrackerContext* context = static_cast<BlendStateTrackerContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(renderer->context())); - EXPECT_EQ(m_blend, context->blend()); + m_quadsAppended = true; + + Color color = m_opaqueColor ? Color::white : Color(0, 0, 0, 0); + OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCSolidColorDrawQuad::create(sharedQuadState, IntRect(5, 5, 5, 5), color); + EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending()); EXPECT_EQ(m_hasRenderSurface, !!renderSurface()); } @@ -195,17 +318,20 @@ public: { m_blend = blend; m_hasRenderSurface = hasRenderSurface; - m_drawn = false; + m_quadsAppended = false; } - bool drawn() const { return m_drawn; } + bool quadsAppended() const { return m_quadsAppended; } + + void setOpaqueColor(bool opaqueColor) { m_opaqueColor = opaqueColor; } private: explicit BlendStateCheckLayer(int id) : CCLayerImpl(id) , m_blend(false) , m_hasRenderSurface(false) - , m_drawn(false) + , m_quadsAppended(false) + , m_opaqueColor(true) { setAnchorPoint(FloatPoint(0, 0)); setBounds(IntSize(10, 10)); @@ -214,7 +340,8 @@ private: bool m_blend; bool m_hasRenderSurface; - bool m_drawn; + bool m_quadsAppended; + bool m_opaqueColor; }; // https://bugs.webkit.org/show_bug.cgi?id=75783 @@ -236,45 +363,76 @@ TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) // Opaque layer, drawn without blending. layer1->setOpaque(true); + layer1->setOpaqueColor(true); layer1->setExpectation(false, false); m_hostImpl->drawLayers(); - EXPECT_TRUE(layer1->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); - // Layer with translucent content, drawn with blending. + // Layer with translucent content, but solid color is opaque, so drawn without blending. layer1->setOpaque(false); + layer1->setOpaqueColor(true); + layer1->setExpectation(false, false); + m_hostImpl->drawLayers(); + EXPECT_TRUE(layer1->quadsAppended()); + + // Layer with translucent content and painting, so drawn with blending. + layer1->setOpaque(false); + layer1->setOpaqueColor(false); layer1->setExpectation(true, false); m_hostImpl->drawLayers(); - EXPECT_TRUE(layer1->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); // Layer with translucent opacity, drawn with blending. layer1->setOpaque(true); + layer1->setOpaqueColor(true); + layer1->setOpacity(0.5); + layer1->setExpectation(true, false); + m_hostImpl->drawLayers(); + EXPECT_TRUE(layer1->quadsAppended()); + + // Layer with translucent opacity and painting, drawn with blending. + layer1->setOpaque(true); + layer1->setOpaqueColor(false); layer1->setOpacity(0.5); layer1->setExpectation(true, false); m_hostImpl->drawLayers(); - EXPECT_TRUE(layer1->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); RefPtr<BlendStateCheckLayer> layer2 = BlendStateCheckLayer::create(2); layer1->addChild(layer2); // 2 opaque layers, drawn without blending. layer1->setOpaque(true); + layer1->setOpaqueColor(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(true); + layer2->setOpaqueColor(true); layer2->setOpacity(1); layer2->setExpectation(false, false); m_hostImpl->drawLayers(); - EXPECT_FALSE(layer1->drawn()); - EXPECT_TRUE(layer2->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); // Parent layer with translucent content, drawn with blending. // Child layer with opaque content, drawn without blending. layer1->setOpaque(false); + layer1->setOpaqueColor(false); layer1->setExpectation(true, false); layer2->setExpectation(false, false); m_hostImpl->drawLayers(); - EXPECT_FALSE(layer1->drawn()); - EXPECT_TRUE(layer2->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); + + // Parent layer with translucent content but opaque painting, drawn without blending. + // Child layer with opaque content, drawn without blending. + layer1->setOpaque(false); + layer1->setOpaqueColor(true); + layer1->setExpectation(false, false); + layer2->setExpectation(false, false); + m_hostImpl->drawLayers(); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); // Parent layer with translucent opacity and opaque content. Since it has a // drawing child, it's drawn to a render surface which carries the opacity, @@ -282,35 +440,51 @@ TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) // Child layer with opaque content, drawn without blending (parent surface // carries the inherited opacity). layer1->setOpaque(true); + layer1->setOpaqueColor(true); layer1->setOpacity(0.5); layer1->setExpectation(false, true); layer2->setExpectation(false, false); m_hostImpl->drawLayers(); - EXPECT_FALSE(layer1->drawn()); - EXPECT_TRUE(layer2->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); // Draw again, but with child non-opaque, to make sure // layer1 not culled. layer1->setOpaque(true); + layer1->setOpaqueColor(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(true); + layer2->setOpaqueColor(true); layer2->setOpacity(0.5); layer2->setExpectation(true, false); m_hostImpl->drawLayers(); - EXPECT_TRUE(layer1->drawn()); - EXPECT_TRUE(layer2->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); // A second way of making the child non-opaque. layer1->setOpaque(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(false); + layer2->setOpaqueColor(false); layer2->setOpacity(1); layer2->setExpectation(true, false); m_hostImpl->drawLayers(); - EXPECT_TRUE(layer1->drawn()); - EXPECT_TRUE(layer2->drawn()); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); + + // And when the layer says its not opaque but is painted opaque, it is not blended. + layer1->setOpaque(true); + layer1->setOpacity(1); + layer1->setExpectation(false, false); + layer2->setOpaque(false); + layer2->setOpaqueColor(true); + layer2->setOpacity(1); + layer2->setExpectation(false, false); + m_hostImpl->drawLayers(); + EXPECT_TRUE(layer1->quadsAppended()); + EXPECT_TRUE(layer2->quadsAppended()); } class ReshapeTrackerContext: public FakeWebGraphicsContext3D { diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp index bfa1b0822..41fe4fb65 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp @@ -26,10 +26,11 @@ #include "cc/CCLayerTreeHost.h" -#include "CompositorFakeGraphicsContext3D.h" +#include "CompositorFakeWebGraphicsContext3D.h" #include "ContentLayerChromium.h" -#include "FakeWebGraphicsContext3D.h" +#include "GraphicsContext3DPrivate.h" #include "LayerChromium.h" +#include "Region.h" #include "TextureManager.h" #include "WebCompositor.h" #include "WebKit.h" @@ -40,8 +41,8 @@ #include "cc/CCThreadTask.h" #include "platform/WebKitPlatformSupport.h" #include "platform/WebThread.h" +#include <gmock/gmock.h> #include <gtest/gtest.h> -#include <webkit/support/webkit_support.h> #include <wtf/MainThread.h> #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> @@ -130,6 +131,52 @@ private: TestHooks* m_testHooks; }; +class CompositorFakeWebGraphicsContext3DWithTextureTracking : public CompositorFakeWebGraphicsContext3D { +public: + static PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> create(Attributes attrs) + { + return adoptPtr(new CompositorFakeWebGraphicsContext3DWithTextureTracking(attrs)); + } + + virtual WebGLId createTexture() + { + WebGLId texture = m_textures.size() + 1; + m_textures.append(texture); + return texture; + } + + virtual void deleteTexture(WebGLId texture) + { + for (size_t i = 0; i < m_textures.size(); i++) { + if (m_textures[i] == texture) { + m_textures.remove(i); + break; + } + } + } + + virtual void bindTexture(WGC3Denum /* target */, WebGLId texture) + { + m_usedTextures.add(texture); + } + + int numTextures() const { return static_cast<int>(m_textures.size()); } + int texture(int i) const { return m_textures[i]; } + void resetTextures() { m_textures.clear(); } + + int numUsedTextures() const { return static_cast<int>(m_usedTextures.size()); } + bool usedTexture(int texture) const { return m_usedTextures.find(texture) != m_usedTextures.end(); } + void resetUsedTextures() { m_usedTextures.clear(); } + +private: + explicit CompositorFakeWebGraphicsContext3DWithTextureTracking(Attributes attrs) : CompositorFakeWebGraphicsContext3D(attrs) + { + } + + Vector<WebGLId> m_textures; + HashSet<WebGLId> m_usedTextures; +}; + // Implementation of CCLayerTreeHost callback interface. class MockLayerTreeHostClient : public CCLayerTreeHostClient { public: @@ -155,7 +202,15 @@ public: virtual PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D() { - return createCompositorMockGraphicsContext3D(GraphicsContext3D::Attributes()); + GraphicsContext3D::Attributes attrs; + WebGraphicsContext3D::Attributes webAttrs; + webAttrs.alpha = attrs.alpha; + + OwnPtr<WebGraphicsContext3D> webContext = CompositorFakeWebGraphicsContext3DWithTextureTracking::create(webAttrs); + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext( + webContext.release(), attrs, 0, + GraphicsContext3D::RenderDirectlyToHostWindow, + GraphicsContext3DPrivate::ForUseOnAnotherThread); } virtual void didCommitAndDrawFrame() @@ -243,16 +298,10 @@ protected: void doBeginTest(); - static void onBeginTest(void* self) - { - static_cast<CCLayerTreeHostTest*>(self)->doBeginTest(); - } - static void onEndTest(void* self) { ASSERT(isMainThread()); - webkit_support::QuitMessageLoop(); - webkit_support::RunAllPendingMessages(); + webKitPlatformSupport()->currentThread()->exitRunLoop(); } static void dispatchSetNeedsAnimate(void* self) @@ -311,7 +360,7 @@ protected: test->m_layerTreeHost->setVisible(false); } - class TimeoutTask : public webkit_support::TaskAdaptor { + class TimeoutTask : public WebThread::Task { public: explicit TimeoutTask(CCLayerTreeHostTest* test) : m_test(test) @@ -329,7 +378,7 @@ protected: m_test->clearTimeout(); } - virtual void Run() + virtual void run() { if (m_test) m_test->timeout(); @@ -339,10 +388,24 @@ protected: CCLayerTreeHostTest* m_test; }; + class BeginTask : public WebThread::Task { + public: + explicit BeginTask(CCLayerTreeHostTest* test) + : m_test(test) + { + } + + virtual ~BeginTask() { } + virtual void run() + { + m_test->doBeginTest(); + } + private: + CCLayerTreeHostTest* m_test; + }; + virtual void runTest(bool threaded) { - m_settings.refreshRate = 100.0; - if (threaded) { m_webThread = adoptPtr(webKitPlatformSupport()->createThread("CCLayerTreeHostTest")); WebCompositor::initialize(m_webThread.get()); @@ -352,11 +415,11 @@ protected: ASSERT(CCProxy::isMainThread()); m_mainThreadProxy = CCScopedThreadProxy::create(CCProxy::mainThread()); - webkit_support::PostDelayedTask(CCLayerTreeHostTest::onBeginTest, static_cast<void*>(this), 0); + m_beginTask = new BeginTask(this); + webKitPlatformSupport()->currentThread()->postDelayedTask(m_beginTask, 0); // postDelayedTask takes ownership of the task m_timeoutTask = new TimeoutTask(this); - webkit_support::PostDelayedTask(m_timeoutTask, 5000); // webkit_support takes ownership of the task - webkit_support::RunMessageLoop(); - webkit_support::RunAllPendingMessages(); + webKitPlatformSupport()->currentThread()->postDelayedTask(m_timeoutTask, 5000); + webKitPlatformSupport()->currentThread()->enterRunLoop(); if (m_layerTreeHost && m_layerTreeHost->rootLayer()) m_layerTreeHost->rootLayer()->setLayerTreeHost(0); @@ -388,6 +451,7 @@ private: OwnPtr<WebThread> m_webThread; RefPtr<CCScopedThreadProxy> m_mainThreadProxy; TimeoutTask* m_timeoutTask; + BeginTask* m_beginTask; }; void CCLayerTreeHostTest::doBeginTest() @@ -395,7 +459,7 @@ void CCLayerTreeHostTest::doBeginTest() ASSERT(isMainThread()); m_client = MockLayerTreeHostClient::create(this); - RefPtr<LayerChromium> rootLayer = LayerChromium::create(0); + RefPtr<LayerChromium> rootLayer = LayerChromium::create(); m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings); ASSERT_TRUE(m_layerTreeHost); rootLayer->setLayerTreeHost(m_layerTreeHost.get()); @@ -912,7 +976,7 @@ TEST_F(CCLayerTreeHostTestSetVisible, runMultiThread) runTest(true); } -class TestOpacityChangeLayerDelegate : public CCLayerDelegate { +class TestOpacityChangeLayerDelegate : public ContentLayerDelegate { public: TestOpacityChangeLayerDelegate(CCLayerTreeHostTest* test) : m_test(test) @@ -933,7 +997,7 @@ private: class ContentLayerChromiumWithUpdateTracking : public ContentLayerChromium { public: - static PassRefPtr<ContentLayerChromiumWithUpdateTracking> create(CCLayerDelegate *delegate) { return adoptRef(new ContentLayerChromiumWithUpdateTracking(delegate)); } + static PassRefPtr<ContentLayerChromiumWithUpdateTracking> create(ContentLayerDelegate *delegate) { return adoptRef(new ContentLayerChromiumWithUpdateTracking(delegate)); } int paintContentsCount() { return m_paintContentsCount; } int idlePaintContentsCount() { return m_idlePaintContentsCount; } @@ -942,9 +1006,9 @@ public: int updateCount() { return m_updateCount; } void resetUpdateCount() { m_updateCount = 0; } - virtual void paintContentsIfDirty() + virtual void paintContentsIfDirty(const Region& occludedScreenSpace) { - ContentLayerChromium::paintContentsIfDirty(); + ContentLayerChromium::paintContentsIfDirty(occludedScreenSpace); m_paintContentsCount++; } @@ -961,7 +1025,7 @@ public: } private: - explicit ContentLayerChromiumWithUpdateTracking(CCLayerDelegate *delegate) + explicit ContentLayerChromiumWithUpdateTracking(ContentLayerDelegate* delegate) : ContentLayerChromium(delegate) , m_paintContentsCount(0) , m_idlePaintContentsCount(0) @@ -1068,4 +1132,341 @@ TEST_F(CCLayerTreeHostTestSetViewportSize, runSingleThread) runTest(false); } +class MockContentLayerDelegate : public ContentLayerDelegate { +public: + bool drawsContent() const { return true; } + MOCK_CONST_METHOD0(preserves3D, bool()); + void paintContents(GraphicsContext&, const IntRect&) { } + void notifySyncRequired() { } +}; + +// Verify atomicity of commits and reuse of textures. +class CCLayerTreeHostTestAtomicCommit : public CCLayerTreeHostTest { +public: + CCLayerTreeHostTestAtomicCommit() + : m_updateCheckLayer(ContentLayerChromiumWithUpdateTracking::create(&m_delegate)) + , m_numCommits(0) + { + // Make sure partial texture updates are turned off. + m_settings.partialTextureUpdates = false; + } + + virtual void beginTest() + { + m_layerTreeHost->setRootLayer(m_updateCheckLayer); + m_layerTreeHost->setViewportSize(IntSize(10, 10)); + + postSetNeedsCommitToMainThread(); + postSetNeedsRedrawToMainThread(); + } + + virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl) + { + CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context())); + + switch (impl->frameNumber()) { + case 0: + // Number of textures should be one. + EXPECT_EQ(1, context->numTextures()); + // Number of textures used for commit should be one. + EXPECT_EQ(1, context->numUsedTextures()); + // Verify used texture is correct. + EXPECT_TRUE(context->usedTexture(context->texture(0))); + + context->resetUsedTextures(); + break; + case 1: + // Number of textures should be two as the first texture + // is used by impl thread and cannot by used for update. + EXPECT_EQ(2, context->numTextures()); + // Number of textures used for commit should still be one. + EXPECT_EQ(1, context->numUsedTextures()); + // First texture should not have been used. + EXPECT_FALSE(context->usedTexture(context->texture(0))); + // New texture should have been used. + EXPECT_TRUE(context->usedTexture(context->texture(1))); + + context->resetUsedTextures(); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + } + + virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) + { + CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context())); + + // Number of textures used for draw should always be one. + EXPECT_EQ(1, context->numUsedTextures()); + + if (impl->frameNumber() < 2) { + context->resetUsedTextures(); + postSetNeedsAnimateAndCommitToMainThread(); + postSetNeedsRedrawToMainThread(); + } else + endTest(); + } + + virtual void layout() + { + m_updateCheckLayer->setNeedsDisplay(); + } + + virtual void afterTest() + { + } + +private: + MockContentLayerDelegate m_delegate; + RefPtr<ContentLayerChromiumWithUpdateTracking> m_updateCheckLayer; + int m_numCommits; +}; + +TEST_F(CCLayerTreeHostTestAtomicCommit, runMultiThread) +{ + runTest(true); +} + +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.width(), b.width()); \ + EXPECT_EQ(a.height(), b.height()); + +class TestLayerChromium : public LayerChromium { +public: + static PassRefPtr<TestLayerChromium> create() { return adoptRef(new TestLayerChromium()); } + + virtual void paintContentsIfDirty(const Region& occludedScreenSpace) + { + m_occludedScreenSpace = occludedScreenSpace; + } + + virtual bool drawsContent() const { return true; } + + const Region& occludedScreenSpace() const { return m_occludedScreenSpace; } + void clearOccludedScreenSpace() { m_occludedScreenSpace = Region(); } + +private: + TestLayerChromium() : LayerChromium() { } + + Region m_occludedScreenSpace; +}; + +static void setLayerPropertiesForTesting(TestLayerChromium* layer, LayerChromium* parent, const TransformationMatrix& transform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool opaque) +{ + layer->removeAllChildren(); + if (parent) + parent->addChild(layer); + layer->setTransform(transform); + layer->setAnchorPoint(anchor); + layer->setPosition(position); + layer->setBounds(bounds); + layer->setOpaque(opaque); + layer->clearOccludedScreenSpace(); +} + +class CCLayerTreeHostTestLayerOcclusion : public CCLayerTreeHostTest { +public: + CCLayerTreeHostTestLayerOcclusion() { } + + virtual void beginTest() + { + RefPtr<TestLayerChromium> rootLayer = TestLayerChromium::create(); + RefPtr<TestLayerChromium> child = TestLayerChromium::create(); + RefPtr<TestLayerChromium> child2 = TestLayerChromium::create(); + RefPtr<TestLayerChromium> grandChild = TestLayerChromium::create(); + RefPtr<TestLayerChromium> mask = TestLayerChromium::create(); + + TransformationMatrix identityMatrix; + TransformationMatrix childTransform; + childTransform.translate(250, 250); + childTransform.rotate(90); + childTransform.translate(-250, -250); + + child->setMasksToBounds(true); + + // See CCLayerTreeHostCommonTest.layerAddsSelfToOccludedRegionWithRotatedSurface for a nice visual of these layers and how they end up + // positioned on the screen. + + // The child layer is rotated and the grandChild is opaque, but clipped to the child and rootLayer + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // If the child layer is opaque, then it adds to the occlusion seen by the rootLayer. + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // Add a second child to the root layer and the regions should merge + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(70, 20), IntSize(500, 500), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 20, 70, 80), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(2u, rootLayer->occludedScreenSpace().rects().size()); + + // Move the second child to be sure. + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 30, 90, 70), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(2u, rootLayer->occludedScreenSpace().rects().size()); + + // If the child layer has a mask on it, then it shouldn't contribute to occlusion on stuff below it + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + child->setMaskLayer(mask.get()); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // If the child layer with a mask is below child2, then child2 should contribute to occlusion on everything, and child shouldn't contribute to the rootLayer + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); + + child->setMaskLayer(mask.get()); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 40, 90, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(2u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // If the child layer has a non-opaque drawOpacity, then it shouldn't contribute to occlusion on stuff below it + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + + child->setMaskLayer(0); + child->setOpacity(0.5); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // If the child layer with non-opaque drawOpacity is below child2, then child2 should contribute to occlusion on everything, and child shouldn't contribute to the rootLayer + setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true); + setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); + + child->setMaskLayer(0); + child->setOpacity(0.5); + + m_layerTreeHost->setRootLayer(rootLayer); + m_layerTreeHost->setViewportSize(rootLayer->bounds()); + m_layerTreeHost->updateLayers(); + m_layerTreeHost->commitComplete(); + + EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds()); + EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), grandChild->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, grandChild->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 40, 90, 60), child->occludedScreenSpace().bounds()); + EXPECT_EQ(2u, child->occludedScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds()); + EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size()); + + // Kill the layerTreeHost immediately. + m_layerTreeHost->setRootLayer(0); + m_layerTreeHost.clear(); + + endTest(); + } + + virtual void afterTest() + { + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestLayerOcclusion) + } // namespace diff --git a/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp b/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp index ed15e6c10..299e5c7e5 100644 --- a/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp +++ b/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp @@ -26,6 +26,7 @@ #include "cc/CCQuadCuller.h" +#include "cc/CCTileDrawQuad.h" #include <gmock/gmock.h> #include <gtest/gtest.h> @@ -36,37 +37,29 @@ namespace { class CCQuadCullerTest : public testing::Test { }; -class TestDrawQuad : public CCDrawQuad { -public: - TestDrawQuad(const CCSharedQuadState* state, Material m, const IntRect& rect) - : CCDrawQuad(state, m, rect) - { - } - - static PassOwnPtr<TestDrawQuad> create(const CCSharedQuadState* state, Material m, const IntRect& rect) - { - return adoptPtr(new TestDrawQuad(state, m, rect)); - } -}; +static PassOwnPtr<CCDrawQuad> MakeTileQuad(CCSharedQuadState* state, const IntRect& rect, const IntRect& opaqueRect = IntRect()) +{ + return CCTileDrawQuad::create(state, rect, intersection(rect, opaqueRect), 1, IntPoint(1, 1), IntSize(100, 100), 0, false, false, false, false, false); +} -void setQuads(CCSharedQuadState* rootState, CCSharedQuadState* childState, CCQuadList& quadList) +void setQuads(CCSharedQuadState* rootState, CCSharedQuadState* childState, CCQuadList& quadList, const IntRect& opaqueRect = IntRect()) { quadList.clear(); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 0), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 0), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 100), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 100), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 100), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 200), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 200), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 200), IntSize(100, 100)))); - - quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 0), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 100), IntSize(100, 100)))); - quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 100), IntSize(100, 100)))); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 0), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 0), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 100), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 100), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 100), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 200), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 200), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 200), IntSize(100, 100)), opaqueRect)); + + quadList.append(MakeTileQuad(childState, IntRect(IntPoint(), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 0), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(childState, IntRect(IntPoint(0, 100), IntSize(100, 100)), opaqueRect)); + quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 100), IntSize(100, 100)), opaqueRect)); } #define DECLARE_AND_INITIALIZE_TEST_QUADS \ @@ -129,6 +122,67 @@ TEST(CCQuadCullerTest, verifyCullCenterTileOnly) EXPECT_EQ(quadList.size(), 13u); CCQuadCuller::cullOccludedQuads(quadList); EXPECT_EQ(quadList.size(), 12u); + + IntRect quadVisibleRect1 = quadList[1].get()->quadVisibleRect(); + EXPECT_EQ(quadVisibleRect1.height(), 50); + + IntRect quadVisibleRect3 = quadList[3].get()->quadVisibleRect(); + EXPECT_EQ(quadVisibleRect3.width(), 50); + + // Next index is 4, not 5, since centre quad culled. + IntRect quadVisibleRect4 = quadList[4].get()->quadVisibleRect(); + EXPECT_EQ(quadVisibleRect4.width(), 50); + EXPECT_EQ(quadVisibleRect4.x(), 250); + + IntRect quadVisibleRect6 = quadList[6].get()->quadVisibleRect(); + EXPECT_EQ(quadVisibleRect6.height(), 50); + EXPECT_EQ(quadVisibleRect6.y(), 250); +} + +TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize1) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + childTransform.translate(100, 100); + + // Create root layer tile with extent (99.1, 99.1) -> (200.9, 200.9) to make + // sure it doesn't get culled due to transform rounding. + TransformationMatrix rootTransform; + rootTransform.translate(99.1, 99.1); + rootTransform.scale(1.018); + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100)))); + quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100)))); + + EXPECT_EQ(quadList.size(), 2u); + CCQuadCuller::cullOccludedQuads(quadList); + EXPECT_EQ(quadList.size(), 2u); +} + +TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize2) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + // Make the child quad slightly smaller than, and centred over, the root layer tile. + // Verify the child does not cause the quad below to be culled due to rounding. + childTransform.translate(100.1, 100.1); + childTransform.scale(0.982); + + TransformationMatrix rootTransform; + rootTransform.translate(100, 100); + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100)))); + quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100)))); + + EXPECT_EQ(quadList.size(), 2u); + CCQuadCuller::cullOccludedQuads(quadList); + EXPECT_EQ(quadList.size(), 2u); } TEST(CCQuadCullerTest, verifyCullChildLinesUpBottomRight) @@ -146,6 +200,54 @@ TEST(CCQuadCullerTest, verifyCullChildLinesUpBottomRight) EXPECT_EQ(quadList.size(), 9u); } +TEST(CCQuadCullerTest, verifyCullSubRegion) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + childTransform.translate(50, 50); + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false); + IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() / 2); + + setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList); + EXPECT_EQ(quadList.size(), 12u); +} + +TEST(CCQuadCullerTest, verifyCullSubRegion2) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + childTransform.translate(50, 10); + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false); + IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() * 3 / 4); + + setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList); + EXPECT_EQ(quadList.size(), 12u); +} + +TEST(CCQuadCullerTest, verifyCullSubRegionCheckOvercull) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + childTransform.translate(50, 49); + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false); + IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() / 2); + + setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList); + EXPECT_EQ(quadList.size(), 13u); +} + TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsDontOcclude) { DECLARE_AND_INITIALIZE_TEST_QUADS diff --git a/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp b/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp index 48a3fda1f..3908f40a9 100644 --- a/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp +++ b/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp @@ -77,8 +77,11 @@ TEST(CCSchedulerStateMachineTest, TestNextActionBeginsFrameIfNeeded) state.setUpdateMoreResourcesPending(false); state.setVisible(true); + EXPECT_FALSE(state.vsyncCallbackNeeded()); + state.didLeaveVSync(); EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction()); + EXPECT_FALSE(state.vsyncCallbackNeeded()); state.didEnterVSync(); EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction()); } @@ -91,6 +94,7 @@ TEST(CCSchedulerStateMachineTest, TestNextActionBeginsFrameIfNeeded) state.setNeedsCommit(true); state.setUpdateMoreResourcesPending(false); state.setVisible(true); + EXPECT_FALSE(state.vsyncCallbackNeeded()); } // Begin the frame, make sure needsCommit and commitState update correctly. @@ -100,6 +104,7 @@ TEST(CCSchedulerStateMachineTest, TestNextActionBeginsFrameIfNeeded) state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME); EXPECT_EQ(CCSchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS, state.commitState()); EXPECT_FALSE(state.needsCommit()); + EXPECT_FALSE(state.vsyncCallbackNeeded()); } } @@ -108,6 +113,7 @@ TEST(CCSchedulerStateMachineTest, TestSetForcedRedrawDoesNotSetsNormalRedraw) CCSchedulerStateMachine state; state.setNeedsForcedRedraw(); EXPECT_FALSE(state.redrawPending()); + EXPECT_TRUE(state.vsyncCallbackNeeded()); } TEST(CCSchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) @@ -115,6 +121,7 @@ TEST(CCSchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) CCSchedulerStateMachine state; state.setVisible(true); state.setNeedsRedraw(); + EXPECT_TRUE(state.vsyncCallbackNeeded()); state.didEnterVSync(); EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); state.updateState(CCSchedulerStateMachine::ACTION_DRAW); @@ -126,10 +133,12 @@ TEST(CCSchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) // Move to another frame. This should now draw. state.didLeaveVSync(); + EXPECT_TRUE(state.vsyncCallbackNeeded()); state.didEnterVSync(); EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); state.updateState(CCSchedulerStateMachine::ACTION_DRAW); + EXPECT_FALSE(state.vsyncCallbackNeeded()); } TEST(CCSchedulerStateMachineTest, TestNextActionDrawsOnVSync) @@ -140,34 +149,42 @@ TEST(CCSchedulerStateMachineTest, TestNextActionDrawsOnVSync) for (unsigned j = 0; j < 2; ++j) { StateMachine state; state.setCommitState(allCommitStates[i]); - if (!j) { + bool visible = j; + if (!visible) { state.didEnterVSync(); state.setVisible(false); - } + } else + state.setVisible(true); // Case 1: needsCommit=false updateMoreResourcesPending=false. state.setNeedsCommit(false); state.setUpdateMoreResourcesPending(false); + EXPECT_FALSE(state.vsyncCallbackNeeded()); EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); // Case 2: needsCommit=false updateMoreResourcesPending=true. state.setNeedsCommit(false); state.setUpdateMoreResourcesPending(true); + if (visible) + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); // Case 3: needsCommit=true updateMoreResourcesPending=false. state.setNeedsCommit(true); state.setUpdateMoreResourcesPending(false); + EXPECT_FALSE(state.vsyncCallbackNeeded()); EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); // Case 4: needsCommit=true updateMoreResourcesPending=true. state.setNeedsCommit(true); state.setUpdateMoreResourcesPending(true); + if (visible) + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_NE(CCSchedulerStateMachine::ACTION_DRAW, state.nextAction()); } } - // When on vsync, or not on vsync but needsForcedRedraw set, should always draw expect if you're ready to commit, in which case commit. + // When on vsync, or not on vsync but needsForcedRedraw set, should always draw except if you're ready to commit, in which case commit. for (size_t i = 0; i < numCommitStates; ++i) { for (unsigned j = 0; j < 2; ++j) { StateMachine state; @@ -188,21 +205,25 @@ TEST(CCSchedulerStateMachineTest, TestNextActionDrawsOnVSync) // Case 1: needsCommit=false updateMoreResourcesPending=false. state.setNeedsCommit(false); state.setUpdateMoreResourcesPending(false); + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_EQ(expectedAction, state.nextAction()); // Case 2: needsCommit=false updateMoreResourcesPending=true. state.setNeedsCommit(false); state.setUpdateMoreResourcesPending(true); + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_EQ(expectedAction, state.nextAction()); // Case 3: needsCommit=true updateMoreResourcesPending=false. state.setNeedsCommit(true); state.setUpdateMoreResourcesPending(false); + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_EQ(expectedAction, state.nextAction()); // Case 4: needsCommit=true updateMoreResourcesPending=true. state.setNeedsCommit(true); state.setUpdateMoreResourcesPending(true); + EXPECT_TRUE(state.vsyncCallbackNeeded()); EXPECT_EQ(expectedAction, state.nextAction()); } } diff --git a/Source/WebKit/chromium/tests/CCSchedulerTest.cpp b/Source/WebKit/chromium/tests/CCSchedulerTest.cpp index 0fe811d86..475987f13 100644 --- a/Source/WebKit/chromium/tests/CCSchedulerTest.cpp +++ b/Source/WebKit/chromium/tests/CCSchedulerTest.cpp @@ -77,6 +77,7 @@ TEST(CCSchedulerTest, RequestCommit) scheduler->setNeedsCommit(); EXPECT_EQ(1, client.numActions()); EXPECT_STREQ("scheduledActionBeginFrame", client.action(0)); + EXPECT_FALSE(timeSource->active()); client.reset(); // Since, hasMoreResourceUpdates is set to false, @@ -86,17 +87,18 @@ TEST(CCSchedulerTest, RequestCommit) EXPECT_EQ(2, client.numActions()); EXPECT_STREQ("scheduledActionUpdateMoreResources", client.action(0)); EXPECT_STREQ("scheduledActionCommit", client.action(1)); + EXPECT_TRUE(timeSource->active()); client.reset(); // Tick should draw. timeSource->tick(); EXPECT_EQ(1, client.numActions()); EXPECT_STREQ("scheduledActionDrawAndSwap", client.action(0)); + EXPECT_FALSE(timeSource->active()); client.reset(); - // Tick should do nothing. - timeSource->tick(); - EXPECT_EQ(0, client.numActions()); + // Timer should be off. + EXPECT_FALSE(timeSource->active()); } TEST(CCSchedulerTest, RequestCommitAfterBeginFrame) @@ -126,6 +128,7 @@ TEST(CCSchedulerTest, RequestCommitAfterBeginFrame) // Tick should draw but then begin another frame. timeSource->tick(); + EXPECT_FALSE(timeSource->active()); EXPECT_EQ(2, client.numActions()); EXPECT_STREQ("scheduledActionDrawAndSwap", client.action(0)); EXPECT_STREQ("scheduledActionBeginFrame", client.action(1)); @@ -175,15 +178,18 @@ TEST(CCSchedulerTest, RequestRedrawInsideDraw) scheduler->setNeedsRedraw(); EXPECT_TRUE(scheduler->redrawPending()); + EXPECT_TRUE(timeSource->active()); EXPECT_EQ(0, client.numDraws()); timeSource->tick(); EXPECT_EQ(1, client.numDraws()); EXPECT_TRUE(scheduler->redrawPending()); + EXPECT_TRUE(timeSource->active()); timeSource->tick(); EXPECT_EQ(2, client.numDraws()); EXPECT_FALSE(scheduler->redrawPending()); + EXPECT_FALSE(timeSource->active()); } class SchedulerClientThatSetNeedsCommitInsideDraw : public CCSchedulerClient { @@ -228,14 +234,17 @@ TEST(CCSchedulerTest, RequestCommitInsideDraw) scheduler->setNeedsRedraw(); EXPECT_TRUE(scheduler->redrawPending()); EXPECT_EQ(0, client.numDraws()); + EXPECT_TRUE(timeSource->active()); timeSource->tick(); + EXPECT_FALSE(timeSource->active()); EXPECT_EQ(1, client.numDraws()); EXPECT_TRUE(scheduler->commitPending()); scheduler->beginFrameComplete(); timeSource->tick(); EXPECT_EQ(2, client.numDraws()); + EXPECT_FALSE(timeSource->active()); EXPECT_FALSE(scheduler->redrawPending()); } diff --git a/Source/WebKit/chromium/tests/CCSchedulerTestCommon.h b/Source/WebKit/chromium/tests/CCSchedulerTestCommon.h index fcf703e51..9b5e0383e 100644 --- a/Source/WebKit/chromium/tests/CCSchedulerTestCommon.h +++ b/Source/WebKit/chromium/tests/CCSchedulerTestCommon.h @@ -91,6 +91,7 @@ public: virtual void setClient(WebCore::CCTimeSourceClient* client) { m_client = client; } virtual void setActive(bool b) { m_active = b; } + virtual bool active() const { return m_active; } void tick() { diff --git a/Source/WebKit/chromium/tests/CCSolidColorLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCSolidColorLayerImplTest.cpp new file mode 100644 index 000000000..059ef2adc --- /dev/null +++ b/Source/WebKit/chromium/tests/CCSolidColorLayerImplTest.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCSolidColorLayerImpl.h" + +#include "CCLayerTestCommon.h" +#include "cc/CCSingleThreadProxy.h" +#include "cc/CCSolidColorDrawQuad.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace WebCore; +using namespace CCLayerTestCommon; + +namespace { + +TEST(CCSolidColorLayerImplTest, verifyTilingCompleteAndNoOverlap) +{ + DebugScopedSetImplThread scopedImplThread; + + CCQuadList quadList; + IntSize layerSize = IntSize(800, 600); + IntRect visibleLayerRect = IntRect(IntPoint(), layerSize); + + RefPtr<CCSolidColorLayerImpl> layer = CCSolidColorLayerImpl::create(0); + layer->setVisibleLayerRect(visibleLayerRect); + layer->setBounds(layerSize); + + OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); + layer->appendQuads(quadList, sharedQuadState.get()); + + verifyQuadsExactlyCoverRect(quadList, visibleLayerRect); +} + +TEST(CCSolidColorLayerImplTest, verifyCorrectBackgroundColorInQuad) +{ + DebugScopedSetImplThread scopedImplThread; + + const Color testColor = 0xFFA55AFF; + + CCQuadList quadList; + IntSize layerSize = IntSize(100, 100); + IntRect visibleLayerRect = IntRect(IntPoint(), layerSize); + + RefPtr<CCSolidColorLayerImpl> layer = CCSolidColorLayerImpl::create(0); + layer->setVisibleLayerRect(visibleLayerRect); + layer->setBounds(layerSize); + layer->setBackgroundColor(testColor); + + OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); + layer->appendQuads(quadList, sharedQuadState.get()); + + ASSERT_EQ(quadList.size(), 1U); + EXPECT_EQ(quadList[0]->toSolidColorDrawQuad()->color(), testColor); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCTiledLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCTiledLayerImplTest.cpp index a2eea9440..d55c0bc16 100644 --- a/Source/WebKit/chromium/tests/CCTiledLayerImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCTiledLayerImplTest.cpp @@ -26,13 +26,14 @@ #include "cc/CCTiledLayerImpl.h" -#include "Region.h" +#include "CCLayerTestCommon.h" #include "cc/CCSingleThreadProxy.h" #include "cc/CCTileDrawQuad.h" #include <gmock/gmock.h> #include <gtest/gtest.h> using namespace WebCore; +using namespace CCLayerTestCommon; namespace { @@ -46,11 +47,12 @@ static PassRefPtr<CCTiledLayerImpl> createLayer(const IntSize& tileSize, const I layer->setTilingData(*tiler); layer->setSkipsDraw(false); layer->setVisibleLayerRect(IntRect(IntPoint(), layerSize)); + layer->setDrawOpacity(1); int textureId = 1; for (int i = 0; i < tiler->numTilesX(); ++i) for (int j = 0; j < tiler->numTilesY(); ++j) - layer->syncTextureId(i, j, static_cast<Platform3DObject>(textureId++)); + layer->pushTileProperties(i, j, static_cast<Platform3DObject>(textureId++), IntRect(0, 0, 1, 1)); return layer.release(); } @@ -134,7 +136,7 @@ TEST(CCTiledLayerImplTest, checkerboarding) for (int i = 0; i < numTilesX; ++i) for (int j = 0; j < numTilesY; ++j) - layer->syncTextureId(i, j, static_cast<Platform3DObject>(0)); + layer->pushTileProperties(i, j, static_cast<Platform3DObject>(0), IntRect()); // All checkerboarding { @@ -146,16 +148,7 @@ TEST(CCTiledLayerImplTest, checkerboarding) } } -static bool completelyContains(const Region& container, const IntRect& rect) -{ - Region tester(rect); - Vector<IntRect> rects = container.rects(); - for (size_t i = 0; i < rects.size(); ++i) - tester.subtract(rects[i]); - return tester.isEmpty(); -} - -static void getQuads(CCQuadList& quads, IntSize tileSize, const IntSize& layerSize, CCLayerTilingData::BorderTexelOption borderTexelOption, const IntRect& visibleLayerRect) +static PassOwnPtr<CCSharedQuadState> getQuads(CCQuadList& quads, IntSize tileSize, const IntSize& layerSize, CCLayerTilingData::BorderTexelOption borderTexelOption, const IntRect& visibleLayerRect) { RefPtr<CCTiledLayerImpl> layer = createLayer(tileSize, layerSize, borderTexelOption); layer->setVisibleLayerRect(visibleLayerRect); @@ -163,24 +156,7 @@ static void getQuads(CCQuadList& quads, IntSize tileSize, const IntSize& layerSi OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); layer->appendQuads(quads, sharedQuadState.get()); -} - -// Align with expected and actual output -static const char* quadString = " Quad: "; - -static void verifyQuadsExactlyCoverRect(const CCQuadList& quads, const IntRect& rect) -{ - Region remaining(rect); - - for (size_t i = 0; i < quads.size(); ++i) { - CCDrawQuad* quad = quads[i].get(); - - EXPECT_TRUE(rect.contains(quad->quadRect())) << quadString << i; - EXPECT_TRUE(completelyContains(remaining, quad->quadRect())) << quadString << i; - remaining.subtract(Region(quad->quadRect())); - } - - EXPECT_TRUE(remaining.isEmpty()); + return sharedQuadState.release(); // The shared data must be owned as long as the quad list exists. } // Test with both border texels and without. @@ -200,7 +176,8 @@ static void coverageVisibleRectOnTileBoundaries(CCLayerTilingData::BorderTexelOp IntSize layerSize(1000, 1000); CCQuadList quads; - getQuads(quads, IntSize(100, 100), layerSize, borders, IntRect(IntPoint(), layerSize)); + OwnPtr<CCSharedQuadState> sharedState; + sharedState = getQuads(quads, IntSize(100, 100), layerSize, borders, IntRect(IntPoint(), layerSize)); verifyQuadsExactlyCoverRect(quads, IntRect(IntPoint(), layerSize)); } WITH_AND_WITHOUT_BORDER_TEST(coverageVisibleRectOnTileBoundaries); @@ -216,7 +193,8 @@ static void coverageVisibleRectIntersectsTiles(CCLayerTilingData::BorderTexelOpt IntSize layerSize(250, 250); CCQuadList quads; - getQuads(quads, IntSize(50, 50), IntSize(250, 250), CCLayerTilingData::NoBorderTexels, visibleLayerRect); + OwnPtr<CCSharedQuadState> sharedState; + sharedState = getQuads(quads, IntSize(50, 50), IntSize(250, 250), CCLayerTilingData::NoBorderTexels, visibleLayerRect); verifyQuadsExactlyCoverRect(quads, visibleLayerRect); } WITH_AND_WITHOUT_BORDER_TEST(coverageVisibleRectIntersectsTiles); @@ -228,7 +206,8 @@ static void coverageVisibleRectIntersectsBounds(CCLayerTilingData::BorderTexelOp IntSize layerSize(220, 210); IntRect visibleLayerRect(IntPoint(), layerSize); CCQuadList quads; - getQuads(quads, IntSize(100, 100), layerSize, CCLayerTilingData::NoBorderTexels, visibleLayerRect); + OwnPtr<CCSharedQuadState> sharedState; + sharedState = getQuads(quads, IntSize(100, 100), layerSize, CCLayerTilingData::NoBorderTexels, visibleLayerRect); verifyQuadsExactlyCoverRect(quads, visibleLayerRect); } WITH_AND_WITHOUT_BORDER_TEST(coverageVisibleRectIntersectsBounds); @@ -240,7 +219,8 @@ TEST(CCTiledLayerImplTest, textureInfoForLayerNoBorders) IntSize tileSize(50, 50); IntSize layerSize(250, 250); CCQuadList quads; - getQuads(quads, tileSize, layerSize, CCLayerTilingData::NoBorderTexels, IntRect(IntPoint(), layerSize)); + OwnPtr<CCSharedQuadState> sharedState; + sharedState = getQuads(quads, tileSize, layerSize, CCLayerTilingData::NoBorderTexels, IntRect(IntPoint(), layerSize)); for (size_t i = 0; i < quads.size(); ++i) { ASSERT_EQ(quads[i]->material(), CCDrawQuad::TiledContent) << quadString << i; @@ -249,8 +229,95 @@ TEST(CCTiledLayerImplTest, textureInfoForLayerNoBorders) EXPECT_NE(quad->textureId(), 0u) << quadString << i; EXPECT_EQ(quad->textureOffset(), IntPoint()) << quadString << i; EXPECT_EQ(quad->textureSize(), tileSize) << quadString << i; + EXPECT_EQ(IntRect(0, 0, 1, 1), quad->opaqueRect()) << quadString << i; + } +} + +TEST(CCTiledLayerImplTest, tileOpaqueRectForLayerNoBorders) +{ + DebugScopedSetImplThread scopedImplThread; + + IntSize tileSize(50, 50); + IntSize layerSize(250, 250); + CCQuadList quads; + OwnPtr<CCSharedQuadState> sharedState; + sharedState = getQuads(quads, tileSize, layerSize, CCLayerTilingData::NoBorderTexels, IntRect(IntPoint(), layerSize)); + + for (size_t i = 0; i < quads.size(); ++i) { + ASSERT_EQ(quads[i]->material(), CCDrawQuad::TiledContent) << quadString << i; + CCTileDrawQuad* quad = static_cast<CCTileDrawQuad*>(quads[i].get()); + + EXPECT_EQ(IntRect(0, 0, 1, 1), quad->opaqueRect()) << quadString << i; } } +TEST(CCTiledLayerImplTest, backgroundCoversViewport) +{ + DebugScopedSetImplThread scopedImplThread; + + const IntSize tileSize(10, 10); + const int numTilesX = 2; + const int numTilesY = 2; + const unsigned numTiles = numTilesX * numTilesY; + const IntSize layerSize(tileSize.width() * numTilesX, tileSize.height() * numTilesY); + RefPtr<CCTiledLayerImpl> layer = createLayer(tileSize, layerSize, CCLayerTilingData::NoBorderTexels); + layer->setBackgroundColor(Color::gray); + layer->setBackgroundCoversViewport(true); + + // No gutter rects + { + IntRect clipRect = IntRect(IntPoint(), layerSize); + layer->setClipRect(clipRect); + layer->setVisibleLayerRect(IntRect(IntPoint(), layerSize)); + + OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); + + CCQuadList quads; + layer->appendQuads(quads, sharedQuadState.get()); + EXPECT_EQ(quads.size(), numTiles); + + for (size_t i = 0; i < quads.size(); ++i) + EXPECT_EQ(quads[i]->material(), CCDrawQuad::TiledContent); + } + + // Empty visible content area (fullscreen gutter rect) + { + IntRect clipRect = IntRect(100, 100, 100, 100); + layer->setClipRect(clipRect); + layer->setVisibleLayerRect(IntRect()); + + OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); + CCQuadList quads; + layer->appendQuads(quads, sharedQuadState.get()); + + for (size_t i = 0; i < quads.size(); ++i) + EXPECT_EQ(quads[i]->material(), CCDrawQuad::SolidColor); + + verifyQuadsExactlyCoverRect(quads, clipRect); + } + + // Content area in middle of clip rect (four surrounding gutter rects) + { + IntRect clipRect = IntRect(-50, -50, 100, 100); + layer->setClipRect(clipRect); + layer->setVisibleLayerRect(IntRect(IntPoint(), layerSize)); + + OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState(); + CCQuadList quads; + layer->appendQuads(quads, sharedQuadState.get()); + + unsigned numContentTiles = 0, numGutterTiles = 0; + for (size_t i = 0; i < quads.size(); ++i) { + if (quads[i]->material() == CCDrawQuad::TiledContent) + numContentTiles++; + else if (quads[i]->material() == CCDrawQuad::SolidColor) + numGutterTiles++; + } + EXPECT_EQ(numContentTiles, numTiles); + EXPECT_GE(numGutterTiles, 4u); + + verifyQuadsExactlyCoverRect(quads, clipRect); + } +} } // namespace diff --git a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp index f0b5c411b..1df27c011 100644 --- a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp @@ -29,6 +29,7 @@ #include "CCSchedulerTestCommon.h" #include "FakeWebGraphicsContext3D.h" #include "GraphicsContext3DPrivate.h" +#include "Region.h" #include "TextureManager.h" #include "cc/CCCanvasLayerImpl.h" #include "cc/CCSingleThreadProxy.h" @@ -138,7 +139,8 @@ protected: canvas->contentChanged(); EXPECT_TRUE(canvas->needsDisplay()); - canvas->paintContentsIfDirty(); + Region occludedScreenSpace; + canvas->paintContentsIfDirty(occludedScreenSpace); EXPECT_FALSE(canvas->needsDisplay()); { DebugScopedSetImplThread scopedImplThread; diff --git a/Source/WebKit/chromium/tests/ClipboardChromiumTest.cpp b/Source/WebKit/chromium/tests/ClipboardChromiumTest.cpp new file mode 100644 index 000000000..24c11a4ec --- /dev/null +++ b/Source/WebKit/chromium/tests/ClipboardChromiumTest.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "ClipboardChromium.h" + +#include <gtest/gtest.h> + +using namespace WebCore; + +namespace { + +#if OS(WINDOWS) +const char invalidCharacters[] = "\x00/\\:*?\"<>|"; +#else +const char invalidCharacters[] = + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x7f/"; +#endif +const char longString[] = + "0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368," + "75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352"; + +TEST(ClipboardChromiumTest, Normal) +{ + String name = "name"; + String extension = "ext"; + ClipboardChromium::validateFilename(name, extension); + EXPECT_EQ("name", name); + EXPECT_EQ("ext", extension); +} + +TEST(ClipboardChromiumTest, InvalidCharacters) +{ + String name = makeString("na", String(invalidCharacters, arraysize(invalidCharacters)), "me"); + String extension = makeString("e", String(invalidCharacters, arraysize(invalidCharacters)), "xt"); + ClipboardChromium::validateFilename(name, extension); + EXPECT_EQ("name", name); + EXPECT_EQ("ext", extension); +} + +TEST(ClipboardChromiumTest, ExtensionTooLong) +{ + String name; + String extension = makeString(longString, longString); + ClipboardChromium::validateFilename(name, extension); + EXPECT_EQ(String(), extension); +} + +TEST(ClipboardChromiumTest, NamePlusExtensionTooLong) +{ + String name = makeString(longString, longString); + String extension = longString; + ClipboardChromium::validateFilename(name, extension); + EXPECT_EQ("0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,109", name); + EXPECT_EQ(longString, extension); + EXPECT_EQ(254u, name.length() + extension.length()); +} + +} // anonymous namespace diff --git a/Source/WebKit/chromium/tests/CompositorFakeWebGraphicsContext3D.h b/Source/WebKit/chromium/tests/CompositorFakeWebGraphicsContext3D.h index de1409bd4..0790639d5 100644 --- a/Source/WebKit/chromium/tests/CompositorFakeWebGraphicsContext3D.h +++ b/Source/WebKit/chromium/tests/CompositorFakeWebGraphicsContext3D.h @@ -43,7 +43,7 @@ public: virtual void getShaderiv(WebGLId, WGC3Denum, WGC3Dint* value) { *value = 1; } virtual void getProgramiv(WebGLId, WGC3Denum, WGC3Dint* value) { *value = 1; } -private: +protected: explicit CompositorFakeWebGraphicsContext3D(Attributes attrs) { m_attrs = attrs; diff --git a/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h new file mode 100755 index 000000000..23231038a --- /dev/null +++ b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef FakeCCLayerTreeHostClient_h +#define FakeCCLayerTreeHostClient_h + +#include "config.h" + +#include "cc/CCLayerTreeHost.h" +#include "CompositorFakeGraphicsContext3D.h" + +namespace WebCore { + +class FakeCCLayerTreeHostClient : public CCLayerTreeHostClient { +public: + virtual void updateAnimations(double frameBeginTime) { } + virtual void layout() { } + virtual void applyScrollAndScale(const IntSize& scrollDelta, float pageScale) { } + virtual PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D() + { + GraphicsContext3D::Attributes attrs; + return createCompositorMockGraphicsContext3D(attrs); + } + virtual void didRecreateGraphicsContext(bool success) { } + virtual void didCommitAndDrawFrame() { } + virtual void didCompleteSwapBuffers() { } + + // Used only in the single-threaded path. + virtual void scheduleComposite() { } +}; + +} +#endif // FakeCCLayerTreeHostClient_h diff --git a/Source/WebKit/chromium/tests/FrameTestHelpers.cpp b/Source/WebKit/chromium/tests/FrameTestHelpers.cpp index 1a1145631..ba6666699 100644 --- a/Source/WebKit/chromium/tests/FrameTestHelpers.cpp +++ b/Source/WebKit/chromium/tests/FrameTestHelpers.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "FrameTestHelpers.h" +#include "StdLibExtras.h" #include "WebFrame.h" #include "WebFrameClient.h" #include "WebSettings.h" @@ -71,7 +72,7 @@ class TestWebFrameClient : public WebFrameClient { static WebFrameClient* defaultWebFrameClient() { - static TestWebFrameClient client; + DEFINE_STATIC_LOCAL(TestWebFrameClient, client, ()); return &client; } @@ -80,7 +81,7 @@ class TestWebViewClient : public WebViewClient { static WebViewClient* defaultWebViewClient() { - static TestWebViewClient client; + DEFINE_STATIC_LOCAL(TestWebViewClient, client, ()); return &client; } diff --git a/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp b/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp index 7de6a6c8f..adceadf08 100644 --- a/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp +++ b/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp @@ -159,7 +159,7 @@ TEST(InjectIDBKeyTest, SubProperty) checkInjection(IDBKey::createArray(IDBKey::KeyArray()), SerializedScriptValue::create(object), "bar"); checkInjectionFails(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo.bar.baz"); - checkInjectionFails(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo.xyz.foo"); + checkInjection(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo.xyz.foo"); } } // namespace diff --git a/Source/WebKit/chromium/tests/ImageLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/ImageLayerChromiumTest.cpp index b28f8e8b4..bf889594c 100644 --- a/Source/WebKit/chromium/tests/ImageLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/ImageLayerChromiumTest.cpp @@ -41,8 +41,8 @@ class MockGraphicsLayerClient : public GraphicsLayerClient { virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { } virtual void notifySyncRequired(const GraphicsLayer*) { } virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) { } - virtual bool showDebugBorders() const { return false; } - virtual bool showRepaintCounter() const { return false; } + virtual bool showDebugBorders(const GraphicsLayer*) const { return false; } + virtual bool showRepaintCounter(const GraphicsLayer*) const { return false; } }; class TestImage : public Image { diff --git a/Source/WebKit/chromium/tests/KURLTest.cpp b/Source/WebKit/chromium/tests/KURLTest.cpp index f2abda56b..394c664b1 100644 --- a/Source/WebKit/chromium/tests/KURLTest.cpp +++ b/Source/WebKit/chromium/tests/KURLTest.cpp @@ -316,7 +316,7 @@ TEST(KURLTest, Encode) {"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"}, {" !\"#$%&'()*+,-./", - "%20!%22%23%24%25%26'()*%2B%2C-.%2F"}, + "%20!%22%23%24%25%26'()*%2B%2C-./"}, {"0123456789:;<=>?", "0123456789%3A%3B%3C%3D%3E%3F"}, {"@ABCDEFGHIJKLMNO", diff --git a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp index bc27c4329..43083a1d7 100644 --- a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp @@ -28,6 +28,7 @@ #include "cc/CCLayerTreeHost.h" #include "CCLayerTreeTestCommon.h" +#include "FakeCCLayerTreeHostClient.h" #include "LayerPainterChromium.h" #include "NonCompositedContentHost.h" #include "WebCompositor.h" @@ -50,20 +51,6 @@ using ::testing::AnyNumber; namespace { -class FakeCCLayerTreeHostClient : public CCLayerTreeHostClient { -public: - virtual void updateAnimations(double frameBeginTime) { } - virtual void layout() { } - virtual void applyScrollAndScale(const IntSize& scrollDelta, float pageScale) { } - virtual PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D() { return 0; } - virtual void didRecreateGraphicsContext(bool success) { } - virtual void didCommitAndDrawFrame() { } - virtual void didCompleteSwapBuffers() { } - - // Used only in the single-threaded path. - virtual void scheduleComposite() { } -}; - class MockCCLayerTreeHost : public CCLayerTreeHost { public: MockCCLayerTreeHost() @@ -135,13 +122,13 @@ protected: void createSimpleTestTree() { - m_parent = LayerChromium::create(0); - m_child1 = LayerChromium::create(0); - m_child2 = LayerChromium::create(0); - m_child3 = LayerChromium::create(0); - m_grandChild1 = LayerChromium::create(0); - m_grandChild2 = LayerChromium::create(0); - m_grandChild3 = LayerChromium::create(0); + 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); @@ -164,7 +151,7 @@ protected: TEST_F(LayerChromiumTest, basicCreateAndDestroy) { - RefPtr<LayerChromium> testLayer = LayerChromium::create(0); + RefPtr<LayerChromium> testLayer = LayerChromium::create(); ASSERT_TRUE(testLayer); EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(0); @@ -173,8 +160,8 @@ TEST_F(LayerChromiumTest, basicCreateAndDestroy) TEST_F(LayerChromiumTest, addAndRemoveChild) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); + 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()); @@ -194,11 +181,11 @@ TEST_F(LayerChromiumTest, addAndRemoveChild) TEST_F(LayerChromiumTest, insertChild) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child1 = LayerChromium::create(0); - RefPtr<LayerChromium> child2 = LayerChromium::create(0); - RefPtr<LayerChromium> child3 = LayerChromium::create(0); - RefPtr<LayerChromium> child4 = LayerChromium::create(0); + 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()); @@ -240,9 +227,9 @@ TEST_F(LayerChromiumTest, insertChild) TEST_F(LayerChromiumTest, insertChildPastEndOfList) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child1 = LayerChromium::create(0); - RefPtr<LayerChromium> child2 = LayerChromium::create(0); + 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()); @@ -262,9 +249,9 @@ TEST_F(LayerChromiumTest, insertChildPastEndOfList) TEST_F(LayerChromiumTest, insertSameChildTwice) { - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child1 = LayerChromium::create(0); - RefPtr<LayerChromium> child2 = LayerChromium::create(0); + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child1 = LayerChromium::create(); + RefPtr<LayerChromium> child2 = LayerChromium::create(); parent->setLayerTreeHost(m_layerTreeHost.get()); @@ -291,7 +278,7 @@ TEST_F(LayerChromiumTest, insertSameChildTwice) TEST_F(LayerChromiumTest, replaceChildWithNewChild) { createSimpleTestTree(); - RefPtr<LayerChromium> child4 = LayerChromium::create(0); + RefPtr<LayerChromium> child4 = LayerChromium::create(); EXPECT_FALSE(child4->parent()); @@ -311,8 +298,8 @@ TEST_F(LayerChromiumTest, replaceChildWithNewChildThatHasOtherParent) createSimpleTestTree(); // create another simple tree with testLayer and child4. - RefPtr<LayerChromium> testLayer = LayerChromium::create(0); - RefPtr<LayerChromium> child4 = LayerChromium::create(0); + 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]); @@ -356,11 +343,11 @@ TEST_F(LayerChromiumTest, removeAllChildren) TEST_F(LayerChromiumTest, setChildren) { - RefPtr<LayerChromium> oldParent = LayerChromium::create(0); - RefPtr<LayerChromium> newParent = LayerChromium::create(0); + RefPtr<LayerChromium> oldParent = LayerChromium::create(); + RefPtr<LayerChromium> newParent = LayerChromium::create(); - RefPtr<LayerChromium> child1 = LayerChromium::create(0); - RefPtr<LayerChromium> child2 = LayerChromium::create(0); + RefPtr<LayerChromium> child1 = LayerChromium::create(); + RefPtr<LayerChromium> child2 = LayerChromium::create(); Vector<RefPtr<LayerChromium> > newChildren; newChildren.append(child1); @@ -390,7 +377,7 @@ TEST_F(LayerChromiumTest, getRootLayerAfterTreeManipulations) // For this test we don't care about setNeedsCommit calls. EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1)); - RefPtr<LayerChromium> child4 = LayerChromium::create(0); + RefPtr<LayerChromium> child4 = LayerChromium::create(); EXPECT_EQ(m_parent.get(), m_parent->rootLayer()); EXPECT_EQ(m_parent.get(), m_child1->rootLayer()); @@ -443,7 +430,7 @@ TEST_F(LayerChromiumTest, checkSetNeedsDisplayCausesCorrectBehavior) // 1. sets needsDisplay flag appropriately. // 2. indirectly calls setNeedsCommit, exactly once for each call to setNeedsDisplay. - RefPtr<LayerChromium> testLayer = LayerChromium::create(0); + RefPtr<LayerChromium> testLayer = LayerChromium::create(); testLayer->setLayerTreeHost(m_layerTreeHost.get()); IntSize testBounds = IntSize(501, 508); @@ -458,7 +445,7 @@ TEST_F(LayerChromiumTest, checkSetNeedsDisplayCausesCorrectBehavior) // 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(0); + testLayer = LayerChromium::create(); testLayer->setLayerTreeHost(m_layerTreeHost.get()); EXPECT_FALSE(testLayer->needsDisplay()); @@ -477,43 +464,26 @@ TEST_F(LayerChromiumTest, checkSetNeedsDisplayCausesCorrectBehavior) EXPECT_TRUE(testLayer->needsDisplay()); // Case 4: LayerChromium should accept dirty rects that go beyond its bounds. - testLayer = LayerChromium::create(0); + 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(0); + 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, checkSetNeedsDisplayWithNullDelegate) -{ - RefPtr<LayerChromium> testLayer = LayerChromium::create(0); - IntSize testBounds = IntSize(501, 508); - - FloatRect dirty = FloatRect(10.0f, 15.0f, 1.0f, 2.0f); - - testLayer->setBounds(testBounds); - EXPECT_TRUE(testLayer->needsDisplay()); - - testLayer = LayerChromium::create(0); - EXPECT_FALSE(testLayer->needsDisplay()); - - testLayer->setNeedsDisplayRect(dirty); - EXPECT_TRUE(testLayer->needsDisplay()); -} - TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior) { - RefPtr<LayerChromium> testLayer = LayerChromium::create(0); + RefPtr<LayerChromium> testLayer = LayerChromium::create(); testLayer->setLayerTreeHost(m_layerTreeHost.get()); - RefPtr<LayerChromium> dummyLayer = LayerChromium::create(0); // just a dummy layer for this test case. + RefPtr<LayerChromium> dummyLayer = LayerChromium::create(); // just a dummy layer for this test case. // sanity check of initial test condition EXPECT_FALSE(testLayer->needsDisplay()); @@ -536,6 +506,7 @@ TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior) 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(Color(0.4f, 0.4f, 0.4f))); + EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBackgroundCoversViewport(true)); 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.5f)); @@ -558,8 +529,8 @@ TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior) class LayerChromiumWithContentScaling : public LayerChromium { public: - explicit LayerChromiumWithContentScaling(CCLayerDelegate* delegate) - : LayerChromium(delegate) + explicit LayerChromiumWithContentScaling() + : LayerChromium() { } @@ -576,7 +547,7 @@ public: TEST_F(LayerChromiumTest, checkContentsScaleChangeTriggersNeedsDisplay) { - RefPtr<LayerChromiumWithContentScaling> testLayer = adoptRef(new LayerChromiumWithContentScaling(0)); + RefPtr<LayerChromiumWithContentScaling> testLayer = adoptRef(new LayerChromiumWithContentScaling()); testLayer->setLayerTreeHost(m_layerTreeHost.get()); IntSize testBounds = IntSize(320, 240); @@ -626,11 +597,11 @@ void assertLayerTreeHostMatchesForSubtree(LayerChromium* layer, CCLayerTreeHost* TEST(LayerChromiumLayerTreeHostTest, enteringTree) { WebKit::WebCompositor::initialize(0); - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromium> mask = LayerChromium::create(0); - RefPtr<LayerChromium> replica = LayerChromium::create(0); - RefPtr<LayerChromium> replicaMask = LayerChromium::create(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); @@ -658,7 +629,7 @@ TEST(LayerChromiumLayerTreeHostTest, enteringTree) TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree) { WebKit::WebCompositor::initialize(0); - RefPtr<LayerChromium> parent = LayerChromium::create(0); + RefPtr<LayerChromium> parent = LayerChromium::create(); RefPtr<FakeCCLayerTreeHost> layerTreeHost = FakeCCLayerTreeHost::create(); layerTreeHost->setRootLayer(parent.get()); @@ -666,16 +637,16 @@ TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree) 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(0); - RefPtr<LayerChromium> grandChild = LayerChromium::create(0); + 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(0); + RefPtr<LayerChromium> childMask = LayerChromium::create(); child->setMaskLayer(childMask.get()); - RefPtr<LayerChromium> childReplica = LayerChromium::create(0); + RefPtr<LayerChromium> childReplica = LayerChromium::create(); child->setReplicaLayer(childReplica.get()); - RefPtr<LayerChromium> childReplicaMask = LayerChromium::create(0); + RefPtr<LayerChromium> childReplicaMask = LayerChromium::create(); childReplica->setMaskLayer(childReplicaMask.get()); parent->addChild(child); @@ -689,11 +660,11 @@ TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree) TEST(LayerChromiumLayerTreeHostTest, changeHost) { WebKit::WebCompositor::initialize(0); - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> child = LayerChromium::create(0); - RefPtr<LayerChromium> mask = LayerChromium::create(0); - RefPtr<LayerChromium> replica = LayerChromium::create(0); - RefPtr<LayerChromium> replicaMask = LayerChromium::create(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); @@ -722,11 +693,11 @@ TEST(LayerChromiumLayerTreeHostTest, changeHost) TEST(LayerChromiumLayerTreeHostTest, changeHostInSubtree) { WebKit::WebCompositor::initialize(0); - RefPtr<LayerChromium> firstParent = LayerChromium::create(0); - RefPtr<LayerChromium> firstChild = LayerChromium::create(0); - RefPtr<LayerChromium> secondParent = LayerChromium::create(0); - RefPtr<LayerChromium> secondChild = LayerChromium::create(0); - RefPtr<LayerChromium> secondGrandChild = LayerChromium::create(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); @@ -759,13 +730,13 @@ TEST(LayerChromiumLayerTreeHostTest, changeHostInSubtree) TEST(LayerChromiumLayerTreeHostTest, replaceMaskAndReplicaLayer) { WebKit::WebCompositor::initialize(0); - RefPtr<LayerChromium> parent = LayerChromium::create(0); - RefPtr<LayerChromium> mask = LayerChromium::create(0); - RefPtr<LayerChromium> replica = LayerChromium::create(0); - RefPtr<LayerChromium> maskChild = LayerChromium::create(0); - RefPtr<LayerChromium> replicaChild = LayerChromium::create(0); - RefPtr<LayerChromium> maskReplacement = LayerChromium::create(0); - RefPtr<LayerChromium> replicaReplacement = LayerChromium::create(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()); diff --git a/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp b/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp new file mode 100644 index 000000000..bdbf7bb09 --- /dev/null +++ b/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "LayerTextureUpdater.h" + +#include "BitmapCanvasLayerTextureUpdater.h" +#include "BitmapSkPictureCanvasLayerTextureUpdater.h" +#include "FrameBufferSkPictureCanvasLayerTextureUpdater.h" +#include "GraphicsContext.h" +#include "LayerPainterChromium.h" +#include "PlatformContextSkia.h" +#include "SkPictureCanvasLayerTextureUpdater.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace WebCore; + +namespace { + +struct PaintCallback { + virtual void operator()(GraphicsContext&, const IntRect&) = 0; +}; + +class TestLayerPainterChromium : public LayerPainterChromium { +public: + TestLayerPainterChromium(PaintCallback& callback) : m_callback(callback) { } + + virtual void paint(GraphicsContext& context, const IntRect& contentRect) + { + m_callback(context, contentRect); + } + + private: + PaintCallback& m_callback; +}; + +// Paint callback functions + +struct PaintFillOpaque : public PaintCallback { + virtual void operator()(GraphicsContext& context, const IntRect& contentRect) + { + Color opaque(255, 0, 0, 255); + IntRect top(contentRect.x(), contentRect.y(), contentRect.width(), contentRect.height() / 2); + IntRect bottom(contentRect.x(), contentRect.y() + contentRect.height() / 2, contentRect.width(), contentRect.height() / 2); + context.fillRect(top, opaque, ColorSpaceDeviceRGB); + context.fillRect(bottom, opaque, ColorSpaceDeviceRGB); + } +}; + +struct PaintFillAlpha : public PaintCallback { + virtual void operator()(GraphicsContext& context, const IntRect& contentRect) + { + Color alpha(0, 0, 0, 0); + context.fillRect(contentRect, alpha, ColorSpaceDeviceRGB); + } +}; + +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.maxX(), b.maxX()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.maxY(), b.maxY()); + +TEST(LayerTextureUpdaterTest, testOpaqueRectPresentAfterOpaquePaint) +{ + PaintFillOpaque fillOpaque; + RefPtr<LayerTextureUpdater> updater; + IntRect opaqueRect; + OwnPtr<TestLayerPainterChromium> painter; + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release()); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect); +} + +TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentAfterNonOpaquePaint) +{ + PaintFillAlpha fillAlpha; + RefPtr<LayerTextureUpdater> updater; + IntRect opaqueRect; + OwnPtr<TestLayerPainterChromium> painter; + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release()); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); +} + +TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentForOpaqueLayerWithOpaquePaint) +{ + PaintFillOpaque fillOpaque; + RefPtr<LayerTextureUpdater> updater; + IntRect opaqueRect; + OwnPtr<TestLayerPainterChromium> painter; + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillOpaque)); + updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release()); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); +} + +TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentForOpaqueLayerWithNonOpaquePaint) +{ + PaintFillAlpha fillAlpha; + RefPtr<LayerTextureUpdater> updater; + IntRect opaqueRect; + OwnPtr<TestLayerPainterChromium> painter; + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); + + opaqueRect = IntRect(); + painter = adoptPtr(new TestLayerPainterChromium(fillAlpha)); + updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release()); + updater->setOpaque(true); + updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, &opaqueRect); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/PaintAggregatorTest.cpp b/Source/WebKit/chromium/tests/PaintAggregatorTest.cpp new file mode 100644 index 000000000..fcf374b47 --- /dev/null +++ b/Source/WebKit/chromium/tests/PaintAggregatorTest.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "painting/PaintAggregator.h" + +#include <gtest/gtest.h> + +using namespace WebCore; +using namespace WebKit; + +namespace { + +TEST(PaintAggregator, InitialState) +{ + PaintAggregator greg; + EXPECT_FALSE(greg.hasPendingUpdate()); +} + +TEST(PaintAggregator, SingleInvalidation) +{ + PaintAggregator greg; + + IntRect rect(2, 4, 10, 16); + greg.invalidateRect(rect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + ASSERT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(rect, update.paintRects[0]); +} + +TEST(PaintAggregator, DoubleDisjointInvalidation) +{ + PaintAggregator greg; + + IntRect r1(2, 4, 2, 40); + IntRect r2(4, 2, 40, 2); + + greg.invalidateRect(r1); + greg.invalidateRect(r2); + + IntRect expectedBounds = unionRect(r1, r2); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + EXPECT_EQ(2U, update.paintRects.size()); + + EXPECT_EQ(expectedBounds, update.calculatePaintBounds()); +} + +TEST(PaintAggregator, DisjointInvalidationsCombined) +{ + PaintAggregator greg; + + // Make the rectangles such that they don't overlap but cover a very large + // percentage of the area of covered by their union. This is so we're not + // very sensitive to the combining heuristic in the paint aggregator. + IntRect r1(2, 4, 2, 1000); + IntRect r2(5, 2, 2, 1000); + + greg.invalidateRect(r1); + greg.invalidateRect(r2); + + IntRect expectedBounds = unionRect(r1, r2); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + ASSERT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(expectedBounds, update.paintRects[0]); +} + +TEST(PaintAggregator, SingleScroll) +{ + PaintAggregator greg; + + IntRect rect(1, 2, 3, 4); + IntPoint delta(1, 0); + greg.scrollRect(delta.x(), delta.y(), rect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.paintRects.isEmpty()); + EXPECT_FALSE(update.scrollRect.isEmpty()); + + EXPECT_EQ(rect, update.scrollRect); + + EXPECT_EQ(delta.x(), update.scrollDelta.x()); + EXPECT_EQ(delta.y(), update.scrollDelta.y()); + + IntRect resultingDamage = update.calculateScrollDamage(); + IntRect expectedDamage(1, 2, 1, 4); + EXPECT_EQ(expectedDamage, resultingDamage); +} + +TEST(PaintAggregator, DoubleOverlappingScroll) +{ + PaintAggregator greg; + + IntRect rect(1, 2, 3, 4); + IntPoint delta1(1, 0); + IntPoint delta2(1, 0); + greg.scrollRect(delta1.x(), delta1.y(), rect); + greg.scrollRect(delta2.x(), delta2.y(), rect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.paintRects.isEmpty()); + EXPECT_FALSE(update.scrollRect.isEmpty()); + + EXPECT_EQ(rect, update.scrollRect); + + IntPoint expectedDelta(delta1.x() + delta2.x(), + delta1.y() + delta2.y()); + EXPECT_EQ(expectedDelta.x(), update.scrollDelta.x()); + EXPECT_EQ(expectedDelta.y(), update.scrollDelta.y()); + + IntRect resultingDamage = update.calculateScrollDamage(); + IntRect expectedDamage(1, 2, 2, 4); + EXPECT_EQ(expectedDamage, resultingDamage); +} + +TEST(PaintAggregator, NegatingScroll) +{ + PaintAggregator greg; + + // Scroll twice in opposite directions by equal amounts. The result + // should be no scrolling. + + IntRect rect(1, 2, 3, 4); + IntPoint delta1(1, 0); + IntPoint delta2(-1, 0); + greg.scrollRect(delta1.x(), delta1.y(), rect); + greg.scrollRect(delta2.x(), delta2.y(), rect); + + EXPECT_FALSE(greg.hasPendingUpdate()); +} + +TEST(PaintAggregator, DiagonalScroll) +{ + PaintAggregator greg; + + // We don't support optimized diagonal scrolling, so this should result in + // repainting. + + IntRect rect(1, 2, 3, 4); + IntPoint delta(1, 1); + greg.scrollRect(delta.x(), delta.y(), rect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + ASSERT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(rect, update.paintRects[0]); +} + +TEST(PaintAggregator, ContainedPaintAfterScroll) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + IntRect paintRect(4, 4, 2, 2); + greg.invalidateRect(paintRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + // expecting a paint rect inside the scroll rect + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(scrollRect, update.scrollRect); + EXPECT_EQ(paintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, ContainedPaintBeforeScroll) +{ + PaintAggregator greg; + + IntRect paintRect(4, 4, 2, 2); + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + // Expecting a paint rect inside the scroll rect + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + paintRect.move(2, 0); + + EXPECT_EQ(scrollRect, update.scrollRect); + EXPECT_EQ(paintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, ContainedPaintsBeforeAndAfterScroll) +{ + PaintAggregator greg; + + IntRect paintRect1(4, 4, 2, 2); + greg.invalidateRect(paintRect1); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + IntRect paintRect2(6, 4, 2, 2); + greg.invalidateRect(paintRect2); + + IntRect expectedPaintRect = paintRect2; + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + // Expecting a paint rect inside the scroll rect + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(scrollRect, update.scrollRect); + EXPECT_EQ(expectedPaintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, LargeContainedPaintAfterScroll) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(0, 1, scrollRect); + + IntRect paintRect(0, 0, 10, 9); // Repaint 90% + greg.invalidateRect(paintRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(scrollRect, update.paintRects[0]); +} + +TEST(PaintAggregator, LargeContainedPaintBeforeScroll) +{ + PaintAggregator greg; + + IntRect paintRect(0, 0, 10, 9); // Repaint 90% + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(0, 1, scrollRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(scrollRect, update.paintRects[0]); +} + +TEST(PaintAggregator, OverlappingPaintBeforeScroll) +{ + PaintAggregator greg; + + IntRect paintRect(4, 4, 10, 2); + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + IntRect expectedPaintRect = unionRect(scrollRect, paintRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(expectedPaintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, OverlappingPaintAfterScroll) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + IntRect paintRect(4, 4, 10, 2); + greg.invalidateRect(paintRect); + + IntRect expectedPaintRect = unionRect(scrollRect, paintRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_TRUE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(expectedPaintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, DisjointPaintBeforeScroll) +{ + PaintAggregator greg; + + IntRect paintRect(4, 4, 10, 2); + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 2, 10); + greg.scrollRect(2, 0, scrollRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(paintRect, update.paintRects[0]); + EXPECT_EQ(scrollRect, update.scrollRect); +} + +TEST(PaintAggregator, DisjointPaintAfterScroll) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 2, 10); + greg.scrollRect(2, 0, scrollRect); + + IntRect paintRect(4, 4, 10, 2); + greg.invalidateRect(paintRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(paintRect, update.paintRects[0]); + EXPECT_EQ(scrollRect, update.scrollRect); +} + +TEST(PaintAggregator, ContainedPaintTrimmedByScroll) +{ + PaintAggregator greg; + + IntRect paintRect(4, 4, 6, 6); + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(2, 0, scrollRect); + + // The paint rect should have become narrower. + IntRect expectedPaintRect(6, 4, 4, 6); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(expectedPaintRect, update.paintRects[0]); + EXPECT_EQ(scrollRect, update.scrollRect); +} + +TEST(PaintAggregator, ContainedPaintEliminatedByScroll) +{ + PaintAggregator greg; + + IntRect paintRect(4, 4, 6, 6); + greg.invalidateRect(paintRect); + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(6, 0, scrollRect); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_TRUE(update.paintRects.isEmpty()); + + EXPECT_EQ(scrollRect, update.scrollRect); +} + +TEST(PaintAggregator, ContainedPaintAfterScrollTrimmedByScrollDamage) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(4, 0, scrollRect); + + IntRect paintRect(2, 0, 4, 10); + greg.invalidateRect(paintRect); + + IntRect expectedScrollDamage(0, 0, 4, 10); + IntRect expectedPaintRect(4, 0, 2, 10); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_EQ(1U, update.paintRects.size()); + + EXPECT_EQ(scrollRect, update.scrollRect); + EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage()); + EXPECT_EQ(expectedPaintRect, update.paintRects[0]); +} + +TEST(PaintAggregator, ContainedPaintAfterScrollEliminatedByScrollDamage) +{ + PaintAggregator greg; + + IntRect scrollRect(0, 0, 10, 10); + greg.scrollRect(4, 0, scrollRect); + + IntRect paintRect(2, 0, 2, 10); + greg.invalidateRect(paintRect); + + IntRect expectedScrollDamage(0, 0, 4, 10); + + EXPECT_TRUE(greg.hasPendingUpdate()); + PaintAggregator::PendingUpdate update; + greg.popPendingUpdate(&update); + + EXPECT_FALSE(update.scrollRect.isEmpty()); + EXPECT_TRUE(update.paintRects.isEmpty()); + + EXPECT_EQ(scrollRect, update.scrollRect); + EXPECT_EQ(expectedScrollDamage, update.calculateScrollDamage()); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp new file mode 100644 index 000000000..0ff539023 --- /dev/null +++ b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "PlatformContextSkia.h" + +#include "BitmapImageSingleFrameSkia.h" +#include "GraphicsContext.h" +#include "NativeImageSkia.h" +#include "SkCanvas.h" +#include <gtest/gtest.h> + +using namespace WebCore; + +namespace { + +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.maxX(), b.maxX()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.maxY(), b.maxY()); + +#define EXPECT_PIXELS_MATCH(bitmap, opaqueRect) \ +{ \ + SkAutoLockPixels locker(bitmap); \ + for (int y = opaqueRect.y(); y < opaqueRect.maxY(); ++y) \ + for (int x = opaqueRect.x(); x < opaqueRect.maxX(); ++x) { \ + int alpha = *bitmap.getAddr32(x, y) >> 24; \ + EXPECT_EQ(255, alpha); \ + } \ +} + +TEST(PlatformContextSkiaTest, trackOpaqueTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), alpha, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), opaque, ColorSpaceDeviceRGB, CompositePlusLighter); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), alpha, ColorSpaceDeviceRGB, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 10, 89, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(8, 8, 3, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOut); + EXPECT_EQ_RECT(IntRect(11, 10, 88, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(30, 30, 290, 290), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(40, 20, 290, 50), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), opaque, ColorSpaceDeviceRGB, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), alpha, ColorSpaceDeviceRGB); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 10, 290, 310), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); +} + +TEST(PlatformContextSkiaTest, trackOpaqueJoinTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(20, 20, 10, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(31, 20, 10, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(30, 20, 10, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(20, 31, 20, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(20, 30, 20, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 20), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(9, 20, 10, 20), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 20), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(10, 20, 10, 20), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 20, 30, 20), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(10, 9, 30, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 20, 30, 20), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(10, 10, 30, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 30, 30), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); +} + +TEST(PlatformContextSkiaTest, trackOpaqueLineTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.setShouldAntialias(false); + context.setMiterLimit(0); + context.setStrokeThickness(4); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + context.setCompositeOperation(CompositeSourceOver); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.save(); + context.setStrokeColor(alpha, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 0), IntPoint(100, 0)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(opaque, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 11), IntPoint(100, 11)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + context.setCompositeOperation(CompositeSourceOver); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.save(); + context.setStrokeColor(alpha, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 0), IntPoint(100, 0)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setShouldAntialias(false); + context.save(); + context.setStrokeColor(opaque, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + context.save(); + context.setStrokeColor(opaque, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha, ColorSpaceDeviceRGB); + context.drawLine(IntPoint(0, 11), IntPoint(100, 11)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); +} + +TEST(PlatformContextSkiaTest, trackOpaquePathTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setShouldAntialias(false); + context.setMiterLimit(1); + context.setStrokeThickness(5); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + context.setCompositeOperation(CompositeSourceIn); + + Path path; + + context.setFillColor(alpha, ColorSpaceDeviceRGB); + path.moveTo(FloatPoint(0, 0)); + path.addLineTo(FloatPoint(100, 0)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(opaque, ColorSpaceDeviceRGB); + path.moveTo(FloatPoint(0, 10)); + path.addLineTo(FloatPoint(100, 13)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(alpha, ColorSpaceDeviceRGB); + path.moveTo(FloatPoint(0, 10)); + path.addLineTo(FloatPoint(100, 13)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(alpha, ColorSpaceDeviceRGB); + path.moveTo(FloatPoint(0, 14)); + path.addLineTo(FloatPoint(100, 10)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + path.clear(); +} + +TEST(PlatformContextSkiaTest, trackOpaqueImageTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + SkBitmap drawBitmap; + drawBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10); + drawBitmap.allocPixels(); + + drawBitmap.setIsOpaque(true); + for (int y = 0; y < drawBitmap.height(); ++y) + for (int x = 0; x < drawBitmap.width(); ++x) + *drawBitmap.getAddr32(x, y) = 0xFFFFFFFF; + RefPtr<BitmapImageSingleFrameSkia> opaqueImage = BitmapImageSingleFrameSkia::create(drawBitmap, true); + EXPECT_FALSE(opaqueImage->currentFrameHasAlpha()); + + drawBitmap.setIsOpaque(false); + for (int y = 0; y < drawBitmap.height(); ++y) + for (int x = 0; x < drawBitmap.width(); ++x) + *drawBitmap.getAddr32(x, y) = 0x00000000; + RefPtr<BitmapImageSingleFrameSkia> alphaImage = BitmapImageSingleFrameSkia::create(drawBitmap, true); + EXPECT_TRUE(alphaImage->currentFrameHasAlpha()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), ColorSpaceDeviceRGB, IntPoint(0, 0)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), ColorSpaceDeviceRGB, IntPoint(0, 0)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), ColorSpaceDeviceRGB, IntPoint(5, 5)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), ColorSpaceDeviceRGB, IntPoint(5, 5)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), ColorSpaceDeviceRGB, IntPoint(10, 10)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), ColorSpaceDeviceRGB, IntPoint(10, 10)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawImage(alphaImage.get(), ColorSpaceDeviceRGB, IntPoint(20, 10), CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setAlpha(0.5); + context.drawImage(opaqueImage.get(), ColorSpaceDeviceRGB, IntPoint(25, 15), CompositeSourceIn); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 25, 90, 75), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawImage(alphaImage.get(), ColorSpaceDeviceRGB, IntPoint(10, 20), CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(20, 10, 80, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.save(); + context.setAlpha(0.5); + context.drawImage(opaqueImage.get(), ColorSpaceDeviceRGB, IntPoint(15, 25), CompositeSourceIn); + context.restore(); + EXPECT_EQ_RECT(IntRect(25, 10, 75, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); +} + +TEST(PlatformContextSkiaTest, trackOpaqueOvalTest) +{ + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + + PlatformContextSkia platformContext(&canvas); + platformContext.setTrackOpaqueRegion(true); + GraphicsContext context(&platformContext); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.drawEllipse(IntRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.setShouldAntialias(false); + + context.setFillColor(opaque, ColorSpaceDeviceRGB); + context.drawEllipse(IntRect(10, 10, 50, 30)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setFillColor(alpha, ColorSpaceDeviceRGB); + context.drawEllipse(IntRect(10, 10, 30, 50)); + EXPECT_EQ_RECT(IntRect(40, 10, 60, 90), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + + context.setFillColor(opaque, ColorSpaceDeviceRGB); + context.drawEllipse(IntRect(10, 10, 50, 30)); + EXPECT_EQ_RECT(IntRect(40, 41, 60, 59), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + + context.setFillColor(alpha, ColorSpaceDeviceRGB); + context.drawEllipse(IntRect(20, 10, 30, 50)); + EXPECT_EQ_RECT(IntRect(51, 41, 49, 59), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/TextureManagerTest.cpp b/Source/WebKit/chromium/tests/TextureManagerTest.cpp index 7c088dabc..6fe616c24 100644 --- a/Source/WebKit/chromium/tests/TextureManagerTest.cpp +++ b/Source/WebKit/chromium/tests/TextureManagerTest.cpp @@ -35,34 +35,49 @@ namespace { class FakeTextureAllocator : public TextureAllocator { public: + virtual ~FakeTextureAllocator() { } virtual unsigned createTexture(const IntSize&, GC3Denum) { return 1; } virtual void deleteTexture(unsigned, const IntSize&, GC3Denum) { } }; -FakeTextureAllocator fakeTextureAllocator; -const IntSize textureSize(256, 256); -const GC3Denum textureFormat = GraphicsContext3D::RGBA; +class TextureManagerTest : public testing::Test { +public: + TextureManagerTest() + : m_textureSize(256, 256) + , m_textureFormat(GraphicsContext3D::RGBA) + { + } -size_t texturesMemorySize(size_t textureCount) -{ - return TextureManager::memoryUseBytes(textureSize, textureFormat) * textureCount; -} + virtual ~TextureManagerTest() + { + } -PassOwnPtr<TextureManager> createTextureManager(size_t maxTextures, size_t preferredTextures) -{ - return TextureManager::create(texturesMemorySize(maxTextures), texturesMemorySize(preferredTextures), 1024); -} + size_t texturesMemorySize(size_t textureCount) + { + return TextureManager::memoryUseBytes(m_textureSize, m_textureFormat) * textureCount; + } -bool requestTexture(TextureManager* manager, TextureToken token) -{ - unsigned textureId; - bool result = manager->requestTexture(token, textureSize, textureFormat, textureId); - if (result) - manager->allocateTexture(&fakeTextureAllocator, token); - return result; -} + PassOwnPtr<TextureManager> createTextureManager(size_t maxTextures, size_t preferredTextures) + { + return TextureManager::create(texturesMemorySize(maxTextures), texturesMemorySize(preferredTextures), 1024); + } + + bool requestTexture(TextureManager* manager, TextureToken token) + { + unsigned textureId; + bool result = manager->requestTexture(token, m_textureSize, m_textureFormat, textureId); + if (result) + manager->allocateTexture(&m_fakeTextureAllocator, token); + return result; + } + +private: + FakeTextureAllocator m_fakeTextureAllocator; + const IntSize m_textureSize; + const GC3Denum m_textureFormat; +}; -TEST(TextureManagerTest, requestTextureInPreferredLimit) +TEST_F(TextureManagerTest, requestTextureInPreferredLimit) { const size_t preferredTextures = 8; OwnPtr<TextureManager> textureManager = createTextureManager(preferredTextures * 2, preferredTextures); @@ -82,7 +97,7 @@ TEST(TextureManagerTest, requestTextureInPreferredLimit) EXPECT_EQ(texturesMemorySize(preferredTextures), textureManager->currentMemoryUseBytes()); } -TEST(TextureManagerTest, requestTextureExceedingPreferredLimit) +TEST_F(TextureManagerTest, requestTextureExceedingPreferredLimit) { const size_t maxTextures = 8; const size_t preferredTextures = 4; @@ -114,7 +129,7 @@ TEST(TextureManagerTest, requestTextureExceedingPreferredLimit) EXPECT_EQ(texturesMemorySize(preferredTextures), textureManager->currentMemoryUseBytes()); } -TEST(TextureManagerTest, requestTextureExceedingMaxLimit) +TEST_F(TextureManagerTest, requestTextureExceedingMaxLimit) { const size_t maxTextures = 8; const size_t preferredTextures = 4; @@ -146,7 +161,7 @@ TEST(TextureManagerTest, requestTextureExceedingMaxLimit) EXPECT_FALSE(textureManager->hasTexture(tokens[3])); } -TEST(TextureManagerTest, reduceMemoryToLimit) +TEST_F(TextureManagerTest, reduceMemoryToLimit) { const size_t maxTextures = 8; const size_t preferredTextures = 4; @@ -179,7 +194,7 @@ TEST(TextureManagerTest, reduceMemoryToLimit) EXPECT_EQ(texturesMemorySize(preferredTextures), textureManager->preferredMemoryLimitBytes()); } -TEST(TextureManagerTest, setMaxMemoryLimitBytes) +TEST_F(TextureManagerTest, setMaxMemoryLimitBytes) { const size_t maxTextures = 8; const size_t preferredTextures = 4; @@ -203,7 +218,7 @@ TEST(TextureManagerTest, setMaxMemoryLimitBytes) EXPECT_EQ(texturesMemorySize(preferredTextures), textureManager->maxMemoryLimitBytes()); } -TEST(TextureManagerTest, setPreferredMemoryLimitBytes) +TEST_F(TextureManagerTest, setPreferredMemoryLimitBytes) { const size_t maxTextures = 8; const size_t preferredTextures = 4; diff --git a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp index 93e2ee8be..b0350db49 100644 --- a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp @@ -26,8 +26,12 @@ #include "TiledLayerChromium.h" +#include "CCLayerTreeTestCommon.h" +#include "FakeCCLayerTreeHostClient.h" #include "LayerTextureUpdater.h" +#include "Region.h" #include "TextureManager.h" +#include "WebCompositor.h" #include "cc/CCSingleThreadProxy.h" // For DebugScopedSetImplThread #include "cc/CCTextureUpdater.h" #include "cc/CCTiledLayerImpl.h" @@ -36,6 +40,12 @@ using namespace WebCore; using namespace WTF; +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.width(), b.width()); \ + EXPECT_EQ(a.height(), b.height()); + namespace { class FakeTextureAllocator : public TextureAllocator { @@ -44,6 +54,8 @@ public: virtual void deleteTexture(unsigned, const IntSize&, GC3Denum) { } }; +class FakeTiledLayerChromium; + class FakeLayerTextureUpdater : public LayerTextureUpdater { public: class Texture : public LayerTextureUpdater::Texture { @@ -54,12 +66,32 @@ public: virtual void updateRect(GraphicsContext3D*, TextureAllocator*, const IntRect&, const IntRect&) { } }; - FakeLayerTextureUpdater() { } + FakeLayerTextureUpdater() : m_prepareCount(0) { } virtual ~FakeLayerTextureUpdater() { } + // Sets the rect to invalidate during the next call to prepareToUpdate(). After the next + // call to prepareToUpdate() the rect is reset. + void setRectToInvalidate(const IntRect&, FakeTiledLayerChromium*); + + // Number of times prepareToUpdate has been invoked. + int prepareCount() const { return m_prepareCount; } + void clearPrepareCount() { m_prepareCount = 0; } + + void setOpaquePaintRect(const IntRect& opaquePaintRect) { m_opaquePaintRect = opaquePaintRect; } + + // Last rect passed to prepareToUpdate(). + const IntRect& lastUpdateRect() const { return m_lastUpdateRect; } + virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager* manager) { return adoptPtr(new Texture(ManagedTexture::create(manager))); } virtual SampledTexelFormat sampledTexelFormat(GC3Denum) { return SampledTexelFormatRGBA; } - virtual void prepareToUpdate(const IntRect&, const IntSize&, int, float) { } + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect); + +private: + int m_prepareCount; + IntRect m_rectToInvalidate; + IntRect m_lastUpdateRect; + IntRect m_opaquePaintRect; + RefPtr<FakeTiledLayerChromium> m_layer; }; class FakeCCTiledLayerImpl : public CCTiledLayerImpl { @@ -77,7 +109,7 @@ public: class FakeTiledLayerChromium : public TiledLayerChromium { public: explicit FakeTiledLayerChromium(TextureManager* textureManager) - : TiledLayerChromium(0) + : TiledLayerChromium() , m_fakeTextureUpdater(adoptRef(new FakeLayerTextureUpdater)) , m_textureManager(textureManager) { @@ -108,8 +140,20 @@ public: return TiledLayerChromium::needsIdlePaint(rect); } + bool skipsDraw() const + { + return TiledLayerChromium::skipsDraw(); + } + + FakeLayerTextureUpdater* fakeLayerTextureUpdater() { return m_fakeTextureUpdater.get(); } + virtual TextureManager* textureManager() const { return m_textureManager; } + virtual void paintContentsIfDirty(const Region& /* occludedScreenSpace */) + { + prepareToUpdate(visibleLayerRect()); + } + private: virtual void createTextureUpdater(const CCLayerTreeHost*) { } @@ -122,6 +166,40 @@ private: TextureManager* m_textureManager; }; +class FakeTiledLayerWithScaledBounds : public FakeTiledLayerChromium { +public: + explicit FakeTiledLayerWithScaledBounds(TextureManager* textureManager) + : FakeTiledLayerChromium(textureManager) + { + } + + void setContentBounds(const IntSize& contentBounds) { m_forcedContentBounds = contentBounds; } + virtual IntSize contentBounds() const { return m_forcedContentBounds; } + + FloatRect updateRect() { return m_updateRect; } + +protected: + IntSize m_forcedContentBounds; +}; + +void FakeLayerTextureUpdater::setRectToInvalidate(const IntRect& rect, FakeTiledLayerChromium* layer) +{ + m_rectToInvalidate = rect; + m_layer = layer; +} + +void FakeLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect) +{ + m_prepareCount++; + m_lastUpdateRect = contentRect; + if (!m_rectToInvalidate.isEmpty()) { + m_layer->invalidateRect(m_rectToInvalidate); + m_rectToInvalidate = IntRect(); + m_layer = 0; + } + *resultingOpaqueRect = m_opaquePaintRect; +} + TEST(TiledLayerChromiumTest, pushDirtyTiles) { OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); @@ -259,4 +337,231 @@ TEST(TiledLayerChromiumTest, idlePaintOutOfMemory) layer->pushPropertiesTo(layerImpl.get()); } +TEST(TiledLayerChromiumTest, invalidateFromPrepare) +{ + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get())); + DebugScopedSetImplThread implThread; + RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0)); + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + // The tile size is 100x100, so this invalidates and then paints two tiles. + layer->setBounds(IntSize(100, 200)); + layer->invalidateRect(IntRect(0, 0, 100, 200)); + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + layer->updateCompositorResources(0, updater); + layer->pushPropertiesTo(layerImpl.get()); + + // We should have both tiles on the impl side. + EXPECT_TRUE(layerImpl->hasTileAt(0, 0)); + EXPECT_TRUE(layerImpl->hasTileAt(0, 1)); + + textureManager->unprotectAllTextures(); + + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + // Invoke prepareToUpdate again. As the layer is valid prepareToUpdate shouldn't be invoked on + // the LayerTextureUpdater. + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(0, layer->fakeLayerTextureUpdater()->prepareCount()); + + layer->invalidateRect(IntRect(0, 0, 50, 50)); + // setRectToInvalidate triggers invalidateRect() being invoked from prepareToUpdate. + layer->fakeLayerTextureUpdater()->setRectToInvalidate(IntRect(25, 25, 50, 50), layer.get()); + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount()); + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + // The layer should still be invalid as prepareToUpdate invoked invalidate. + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount()); +} + +TEST(TiledLayerChromiumTest, verifyUpdateRectWhenContentBoundsAreScaled) +{ + // The updateRect (that indicates what was actually painted) should be in + // layer space, not the content space. + + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerWithScaledBounds> layer = adoptRef(new FakeTiledLayerWithScaledBounds(textureManager.get())); + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + IntRect layerBounds(0, 0, 300, 200); + IntRect contentBounds(0, 0, 200, 250); + + layer->setBounds(layerBounds.size()); + layer->setContentBounds(contentBounds.size()); + layer->setVisibleLayerRect(contentBounds); + + // On first update, the updateRect includes all tiles, even beyond the boundaries of the layer. + // However, it should still be in layer space, not content space. + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 300, 300 * 0.8), layer->updateRect()); + + // After the tiles are updated once, another invalidate only needs to update the bounds of the layer. + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(layerBounds), layer->updateRect()); + + // Partial re-paint should also be represented by the updateRect in layer space, not content space. + IntRect partialDamage(30, 100, 10, 10); + layer->invalidateRect(partialDamage); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(45, 80, 15, 8), layer->updateRect()); +} + +TEST(TiledLayerChromiumTest, skipsDrawGetsReset) +{ + // Initialize without threading support. + WebKit::WebCompositor::initialize(0); + FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient; + RefPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCSettings()); + + // Create two 300 x 300 tiled layers. + IntSize contentBounds(300, 300); + IntRect contentRect(IntPoint::zero(), contentBounds); + + RefPtr<FakeTiledLayerChromium> rootLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager())); + RefPtr<FakeTiledLayerChromium> childLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager())); + rootLayer->addChild(childLayer); + + rootLayer->setBounds(contentBounds); + rootLayer->setPosition(FloatPoint(150, 150)); + childLayer->setBounds(contentBounds); + childLayer->setPosition(FloatPoint(150, 150)); + rootLayer->invalidateRect(contentRect); + childLayer->invalidateRect(contentRect); + + // We have enough memory for only one of the two layers. + int memoryLimit = 4 * 300 * 300; // 4 bytes per pixel. + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + ccLayerTreeHost->setRootLayer(rootLayer); + ccLayerTreeHost->setViewportSize(IntSize(300, 300)); + ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit); + ccLayerTreeHost->updateLayers(); + ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater); + + // We'll skip the root layer. + EXPECT_TRUE(rootLayer->skipsDraw()); + EXPECT_FALSE(childLayer->skipsDraw()); + + ccLayerTreeHost->commitComplete(); + + // Remove the child layer. + rootLayer->removeAllChildren(); + + // Need to set the max limit again as it gets overwritten by updateLayers(). + ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit); + ccLayerTreeHost->updateLayers(); + EXPECT_FALSE(rootLayer->skipsDraw()); + + ccLayerTreeHost->setRootLayer(0); + ccLayerTreeHost.clear(); + WebKit::WebCompositor::shutdown(); +} + +TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion) +{ + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get())); + + // The tile size is 100x100, so this invalidates and then paints two tiles in various ways. + + Region occluded; + IntRect contentBounds = IntRect(0, 0, 100, 200); + IntRect visibleBounds = IntRect(0, 0, 100, 150); + + layer->setBounds(contentBounds.size()); + layer->setVisibleLayerRect(visibleBounds); + layer->setDrawOpacity(1); + + // The screenSpaceTransform is verified in CCLayerTreeHostCommonTests + TransformationMatrix screenSpaceTransform; + layer->setScreenSpaceTransform(screenSpaceTransform); + + // If the layer is opaque then the occluded region should be the whole layer's visible region. + layer->setOpaque(true); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(visibleBounds, occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer is not opaque then the occluded region should be empty. + layer->setOpaque(false); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer paints opaque content, then the occluded region should match the visible opaque content. + IntRect opaquePaintRect = IntRect(10, 10, 90, 190); + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If we paint again without invalidating, the same stuff should be occluded. + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect()); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer is transformed then the resulting occluded area needs to be transformed to its target space. + TransformationMatrix transform; + transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + transform.rotate(90); + transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + transform.translate(10, 10); + screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + screenSpaceTransform *= transform; + screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + layer->setScreenSpaceTransform(screenSpaceTransform); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(screenSpaceTransform.mapRect(intersection(opaquePaintRect, visibleBounds)), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // But a non-axis-aligned transform does not get considered for occlusion. + transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + transform.rotate(5); + transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + screenSpaceTransform *= transform; + screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + layer->setScreenSpaceTransform(screenSpaceTransform); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + // FIXME: If we find an opaque rect contained in the rotated non-axis-aligned rect, then + // this won't be an empty result. + EXPECT_EQ_RECT(IntRect(), occluded.bounds()); + EXPECT_EQ(0u, occluded.rects().size()); +} + } // namespace diff --git a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp index ca83846c2..1557a7d93 100644 --- a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp +++ b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp @@ -83,7 +83,7 @@ public: } private: MockLayerChromium(Vector<int>* ccLayerDestructionList) - : LayerChromium(0) + : LayerChromium() , m_ccLayerDestructionList(ccLayerDestructionList) { } @@ -119,9 +119,9 @@ void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer) TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty) { DebugScopedSetImplThread impl; - RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0); - layerTreeRoot->addChild(LayerChromium::create(0)); - layerTreeRoot->addChild(LayerChromium::create(0)); + RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(); + layerTreeRoot->addChild(LayerChromium::create()); + layerTreeRoot->addChild(LayerChromium::create()); RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0); @@ -158,9 +158,9 @@ TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers) TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties) { DebugScopedSetImplThread impl; - RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0); - layerTreeRoot->addChild(LayerChromium::create(0)); - layerTreeRoot->addChild(LayerChromium::create(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.3, 7.4); @@ -254,7 +254,7 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy) oldLayerTreeRoot->removeAllChildren(); // Synchronize again. After the sync all CCLayerImpls from the old tree should be deleted. - RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create(0); + RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create(); ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release()); expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get()); @@ -268,22 +268,22 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy) TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers) { DebugScopedSetImplThread impl; - RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(0); - layerTreeRoot->addChild(LayerChromium::create(0)); - layerTreeRoot->addChild(LayerChromium::create(0)); - layerTreeRoot->addChild(LayerChromium::create(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(0); + RefPtr<LayerChromium> maskLayer = LayerChromium::create(); layerTreeRoot->children()[0]->setMaskLayer(maskLayer.get()); // Second child gets a replica layer. - RefPtr<LayerChromium> replicaLayer = LayerChromium::create(0); + 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(0); - RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create(0); + RefPtr<LayerChromium> replicaLayerWithMask = LayerChromium::create(); + RefPtr<LayerChromium> replicaMaskLayer = LayerChromium::create(); replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get()); layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get()); diff --git a/Source/WebKit/chromium/tests/WebFrameTest.cpp b/Source/WebKit/chromium/tests/WebFrameTest.cpp index 2b2ea7601..06b26469a 100644 --- a/Source/WebKit/chromium/tests/WebFrameTest.cpp +++ b/Source/WebKit/chromium/tests/WebFrameTest.cpp @@ -33,9 +33,11 @@ #include "FrameTestHelpers.h" #include "ResourceError.h" #include "WebDocument.h" +#include "WebFindOptions.h" #include "WebFormElement.h" #include "WebFrame.h" #include "WebFrameClient.h" +#include "WebRange.h" #include "WebScriptSource.h" #include "WebSearchableFormData.h" #include "WebSecurityPolicy.h" @@ -379,4 +381,54 @@ TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds) EXPECT_EQ(1, matchCount); } +TEST_F(WebFrameTest, DISABLED_FindInPage) +{ + registerMockedHttpURLLoad("find.html"); + WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find.html"); + WebFrame* frame = webView->mainFrame(); + const int findIdentifier = 12345; + WebFindOptions options; + + // Find in a <div> element. + EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0)); + frame->stopFinding(false); + WebRange range = frame->selectionRange(); + EXPECT_EQ(5, range.startOffset()); + EXPECT_EQ(9, range.endOffset()); + EXPECT_TRUE(frame->document().focusedNode().isNull()); + + // Find in an <input> value. + EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0)); + // Confirm stopFinding(false) sets the selection on the found text. + frame->stopFinding(false); + range = frame->selectionRange(); + ASSERT_FALSE(range.isNull()); + EXPECT_EQ(5, range.startOffset()); + EXPECT_EQ(9, range.endOffset()); + EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedNode().nodeName()); + + // Find in a <textarea> content. + EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0)); + // Confirm stopFinding(false) sets the selection on the found text. + frame->stopFinding(false); + range = frame->selectionRange(); + ASSERT_FALSE(range.isNull()); + EXPECT_EQ(5, range.startOffset()); + EXPECT_EQ(9, range.endOffset()); + EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedNode().nodeName()); + + // Find in a contentEditable element. + EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0)); + // Confirm stopFinding(false) sets the selection on the found text. + frame->stopFinding(false); + range = frame->selectionRange(); + ASSERT_FALSE(range.isNull()); + EXPECT_EQ(0, range.startOffset()); + EXPECT_EQ(4, range.endOffset()); + // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>. + EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedNode().nodeName()); + + webView->close(); +} + } // namespace diff --git a/Source/WebKit/chromium/tests/data/find.html b/Source/WebKit/chromium/tests/data/find.html new file mode 100644 index 000000000..952c823fb --- /dev/null +++ b/Source/WebKit/chromium/tests/data/find.html @@ -0,0 +1,6 @@ +<body> +<div>foo1 bar1 baz1</div> +<input value="foo2 bar2 baz2"> +<textarea>foo3 bar3 baz3</textarea> +<div contentEditable="true">foo4 <span>bar4</span> baz4</div> +</body> |