diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
| commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
| tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/WebKit/chromium/tests | |
| parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
| download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz | |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/WebKit/chromium/tests')
26 files changed, 3103 insertions, 393 deletions
diff --git a/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp b/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp index 3e93d95de..e14ef9bc0 100644 --- a/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp +++ b/Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp @@ -25,24 +25,20 @@ #include "config.h" #include "cc/CCActiveAnimation.h" - -#include "cc/CCAnimationCurve.h" +#include "CCAnimationTestCommon.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <wtf/Vector.h> -namespace WebCore { +using namespace WebKitTests; +using namespace WebCore; -class FakeFloatAnimation : public CCFloatAnimationCurve { -public: - virtual double duration() const { return 1; } - virtual float getValue(double now) const { return 0; } -}; +namespace { PassOwnPtr<CCActiveAnimation> createActiveAnimation(int iterations) { - OwnPtr<CCActiveAnimation> toReturn(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimation), 1, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toReturn(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve), 0, 1, CCActiveAnimation::Opacity)); toReturn->setIterations(iterations); return toReturn.release(); } @@ -164,4 +160,4 @@ TEST(CCActiveAnimationTest, IsFinished) EXPECT_TRUE(anim->isFinished()); } -} // namespace WebCore +} // namespace diff --git a/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp b/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp new file mode 100644 index 000000000..c9240e31f --- /dev/null +++ b/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp @@ -0,0 +1,133 @@ +/* + * 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 "CCAnimationTestCommon.h" + +#include "GraphicsLayer.h" +#include "LayerChromium.h" +#include "cc/CCLayerAnimationController.h" + +using namespace WebCore; + +namespace { + +template <class Target> +void addOpacityTransition(Target& target, double duration, float startOpacity, float endOpacity) +{ + WebCore::KeyframeValueList values(AnimatedPropertyOpacity); + if (duration > 0) + values.insert(new FloatAnimationValue(0, startOpacity)); + values.insert(new FloatAnimationValue(duration, endOpacity)); + + RefPtr<Animation> animation = Animation::create(); + animation->setDuration(duration); + + IntSize boxSize; + + target.addAnimation(values, boxSize, animation.get(), 0, 0, 0); +} + +} // namespace + +namespace WebKitTests { + +FakeFloatAnimationCurve::FakeFloatAnimationCurve() +{ +} + +FakeFloatAnimationCurve::~FakeFloatAnimationCurve() +{ +} + +PassOwnPtr<WebCore::CCAnimationCurve> FakeFloatAnimationCurve::clone() const +{ + return adoptPtr(new FakeFloatAnimationCurve); +} + +FakeTransformTransition::FakeTransformTransition(double duration) + : m_duration(duration) +{ +} + +FakeTransformTransition::~FakeTransformTransition() +{ +} + +WebCore::TransformationMatrix FakeTransformTransition::getValue(double time, const WebCore::IntSize& size) const +{ + return WebCore::TransformationMatrix(); +} + +PassOwnPtr<WebCore::CCAnimationCurve> FakeTransformTransition::clone() const +{ + return adoptPtr(new FakeTransformTransition(*this)); +} + + +FakeFloatTransition::FakeFloatTransition(double duration, float from, float to) + : m_duration(duration) + , m_from(from) + , m_to(to) +{ +} + +FakeFloatTransition::~FakeFloatTransition() +{ +} + +float FakeFloatTransition::getValue(double time) const +{ + time /= m_duration; + if (time >= 1) + time = 1; + return (1 - time) * m_from + time * m_to; +} + +FakeLayerAnimationControllerImplClient::FakeLayerAnimationControllerImplClient() + : m_opacity(0) +{ +} + +FakeLayerAnimationControllerImplClient::~FakeLayerAnimationControllerImplClient() +{ +} + +PassOwnPtr<WebCore::CCAnimationCurve> FakeFloatTransition::clone() const +{ + return adoptPtr(new FakeFloatTransition(*this)); +} + +void addOpacityTransitionToController(WebCore::CCLayerAnimationController& controller, double duration, float startOpacity, float endOpacity) +{ + addOpacityTransition(controller, duration, startOpacity, endOpacity); +} + +void addOpacityTransitionToLayer(WebCore::LayerChromium& layer, double duration, float startOpacity, float endOpacity) +{ + addOpacityTransition(layer, duration, startOpacity, endOpacity); +} + +} // namespace WebKitTests diff --git a/Source/WebKit/chromium/tests/CCAnimationTestCommon.h b/Source/WebKit/chromium/tests/CCAnimationTestCommon.h new file mode 100644 index 000000000..d13e74ca1 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCAnimationTestCommon.h @@ -0,0 +1,104 @@ +/* + * 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 CCAnimationTestCommon_h +#define CCAnimationTestCommon_h + +#include "cc/CCAnimationCurve.h" +#include "cc/CCLayerAnimationControllerImpl.h" + +#include <wtf/OwnPtr.h> + +namespace WebCore { +class CCLayerAnimationController; +class LayerChromium; +} + +namespace WebKitTests { + +class FakeFloatAnimationCurve : public WebCore::CCFloatAnimationCurve { +public: + FakeFloatAnimationCurve(); + virtual ~FakeFloatAnimationCurve(); + + virtual double duration() const { return 1; } + virtual float getValue(double now) const { return 0; } + virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const; +}; + +class FakeTransformTransition : public WebCore::CCTransformAnimationCurve { +public: + FakeTransformTransition(double duration); + virtual ~FakeTransformTransition(); + + virtual double duration() const { return m_duration; } + virtual WebCore::TransformationMatrix getValue(double time, const WebCore::IntSize&) const; + + virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const; + +private: + double m_duration; +}; + +class FakeFloatTransition : public WebCore::CCFloatAnimationCurve { +public: + FakeFloatTransition(double duration, float from, float to); + virtual ~FakeFloatTransition(); + + virtual double duration() const { return m_duration; } + virtual float getValue(double time) const; + + virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const; + +private: + double m_duration; + float m_from; + float m_to; +}; + +class FakeLayerAnimationControllerImplClient : public WebCore::CCLayerAnimationControllerImplClient { +public: + FakeLayerAnimationControllerImplClient(); + virtual ~FakeLayerAnimationControllerImplClient(); + + virtual int id() const { return 0; } + virtual float opacity() const { return m_opacity; } + virtual void setOpacity(float opacity) { m_opacity = opacity; } + virtual const WebCore::TransformationMatrix& transform() const { return m_transform; } + virtual void setTransform(const WebCore::TransformationMatrix& transform) { m_transform = transform; } + virtual const WebCore::IntSize& bounds() const { return m_bounds; } + +private: + float m_opacity; + WebCore::TransformationMatrix m_transform; + WebCore::IntSize m_bounds; +}; + +void addOpacityTransitionToController(WebCore::CCLayerAnimationController&, double duration, float startOpacity, float endOpacity); + +void addOpacityTransitionToLayer(WebCore::LayerChromium&, double duration, float startOpacity, float endOpacity); + +} // namespace WebKitTests + +#endif // CCAnimationTesctCommon_h diff --git a/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp b/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp new file mode 100644 index 000000000..b7732aeab --- /dev/null +++ b/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp @@ -0,0 +1,241 @@ +/* + * 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/CCKeyframedAnimationCurve.h" + +#include "Length.h" +#include "TranslateTransformOperation.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> + +using namespace WebCore; + +namespace { + +void expectTranslateX(double translateX, const TransformationMatrix& matrix) +{ + TransformationMatrix::DecomposedType decomposedType; + matrix.decompose(decomposedType); + EXPECT_FLOAT_EQ(translateX, decomposedType.translateX); +} + +// Tests that a float animation with one keyframe works as expected. +TEST(CCKeyframedAnimationCurveTest, OneFloatKeyframe) +{ + Vector<CCFloatKeyframe> keyframes; + keyframes.append(CCFloatKeyframe(0, 2)); + OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes)); + EXPECT_FLOAT_EQ(2, curve->getValue(-1)); + EXPECT_FLOAT_EQ(2, curve->getValue(0)); + EXPECT_FLOAT_EQ(2, curve->getValue(0.5)); + EXPECT_FLOAT_EQ(2, curve->getValue(1)); + EXPECT_FLOAT_EQ(2, curve->getValue(2)); +} + +// Tests that a float animation with two keyframes works as expected. +TEST(CCKeyframedAnimationCurveTest, TwoFloatKeyframe) +{ + Vector<CCFloatKeyframe> keyframes; + keyframes.append(CCFloatKeyframe(0, 2)); + keyframes.append(CCFloatKeyframe(1, 4)); + OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes)); + EXPECT_FLOAT_EQ(2, curve->getValue(-1)); + EXPECT_FLOAT_EQ(2, curve->getValue(0)); + EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); + EXPECT_FLOAT_EQ(4, curve->getValue(1)); + EXPECT_FLOAT_EQ(4, curve->getValue(2)); +} + +// Tests that a float animation with three keyframes works as expected. +TEST(CCKeyframedAnimationCurveTest, ThreeFloatKeyframe) +{ + Vector<CCFloatKeyframe> keyframes; + keyframes.append(CCFloatKeyframe(0, 2)); + keyframes.append(CCFloatKeyframe(1, 4)); + keyframes.append(CCFloatKeyframe(2, 8)); + OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes)); + EXPECT_FLOAT_EQ(2, curve->getValue(-1)); + EXPECT_FLOAT_EQ(2, curve->getValue(0)); + EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); + EXPECT_FLOAT_EQ(4, curve->getValue(1)); + EXPECT_FLOAT_EQ(6, curve->getValue(1.5)); + EXPECT_FLOAT_EQ(8, curve->getValue(2)); + EXPECT_FLOAT_EQ(8, curve->getValue(3)); +} + +// Tests that a float animation with multiple keys at a given time works sanely. +TEST(CCKeyframedAnimationCurveTest, RepeatedFloatKeyTimes) +{ + Vector<CCFloatKeyframe> keyframes; + // A step function. + keyframes.append(CCFloatKeyframe(0, 4)); + keyframes.append(CCFloatKeyframe(1, 4)); + keyframes.append(CCFloatKeyframe(1, 6)); + keyframes.append(CCFloatKeyframe(2, 6)); + OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes)); + + EXPECT_FLOAT_EQ(4, curve->getValue(-1)); + EXPECT_FLOAT_EQ(4, curve->getValue(0)); + EXPECT_FLOAT_EQ(4, curve->getValue(0.5)); + + // There is a discontinuity at 1. Any value between 4 and 6 is valid. + float value = curve->getValue(1); + EXPECT_TRUE(value >= 4 && value <= 6); + + EXPECT_FLOAT_EQ(6, curve->getValue(1.5)); + EXPECT_FLOAT_EQ(6, curve->getValue(2)); + EXPECT_FLOAT_EQ(6, curve->getValue(3)); +} + + +// Tests that a transform animation with one keyframe works as expected. +TEST(CCKeyframedAnimationCurveTest, OneTransformKeyframe) +{ + Vector<CCTransformKeyframe> keyframes; + TransformOperations operations; + operations.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + keyframes.append(CCTransformKeyframe(0, operations)); + OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes)); + IntSize layerSize; // ignored + expectTranslateX(2, curve->getValue(-1, layerSize)); + expectTranslateX(2, curve->getValue(0, layerSize)); + expectTranslateX(2, curve->getValue(0.5, layerSize)); + expectTranslateX(2, curve->getValue(1, layerSize)); + expectTranslateX(2, curve->getValue(2, layerSize)); +} + +// Tests that a transform animation with two keyframes works as expected. +TEST(CCKeyframedAnimationCurveTest, TwoTransformKeyframe) +{ + Vector<CCTransformKeyframe> keyframes; + TransformOperations operations1; + operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations2; + operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + keyframes.append(CCTransformKeyframe(0, operations1)); + keyframes.append(CCTransformKeyframe(1, operations2)); + OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes)); + IntSize layerSize; // ignored + expectTranslateX(2, curve->getValue(-1, layerSize)); + expectTranslateX(2, curve->getValue(0, layerSize)); + expectTranslateX(3, curve->getValue(0.5, layerSize)); + expectTranslateX(4, curve->getValue(1, layerSize)); + expectTranslateX(4, curve->getValue(2, layerSize)); +} + +// Tests that a transform animation with three keyframes works as expected. +TEST(CCKeyframedAnimationCurveTest, ThreeTransformKeyframe) +{ + Vector<CCTransformKeyframe> keyframes; + TransformOperations operations1; + operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations2; + operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations3; + operations3.operations().append(TranslateTransformOperation::create(Length(8, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + keyframes.append(CCTransformKeyframe(0, operations1)); + keyframes.append(CCTransformKeyframe(1, operations2)); + keyframes.append(CCTransformKeyframe(2, operations3)); + OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes)); + IntSize layerSize; // ignored + expectTranslateX(2, curve->getValue(-1, layerSize)); + expectTranslateX(2, curve->getValue(0, layerSize)); + expectTranslateX(3, curve->getValue(0.5, layerSize)); + expectTranslateX(4, curve->getValue(1, layerSize)); + expectTranslateX(6, curve->getValue(1.5, layerSize)); + expectTranslateX(8, curve->getValue(2, layerSize)); + expectTranslateX(8, curve->getValue(3, layerSize)); +} + +// Tests that a transform animation with multiple keys at a given time works sanely. +TEST(CCKeyframedAnimationCurveTest, RepeatedTransformKeyTimes) +{ + Vector<CCTransformKeyframe> keyframes; + // A step function. + TransformOperations operations1; + operations1.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations2; + operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations3; + operations3.operations().append(TranslateTransformOperation::create(Length(6, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations4; + operations4.operations().append(TranslateTransformOperation::create(Length(6, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + keyframes.append(CCTransformKeyframe(0, operations1)); + keyframes.append(CCTransformKeyframe(1, operations2)); + keyframes.append(CCTransformKeyframe(1, operations3)); + keyframes.append(CCTransformKeyframe(2, operations4)); + OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes)); + + IntSize layerSize; // ignored + + expectTranslateX(4, curve->getValue(-1, layerSize)); + expectTranslateX(4, curve->getValue(0, layerSize)); + expectTranslateX(4, curve->getValue(0.5, layerSize)); + + // There is a discontinuity at 1. Any value between 4 and 6 is valid. + TransformationMatrix value = curve->getValue(1, layerSize); + TransformationMatrix::DecomposedType decomposedType; + value.decompose(decomposedType); + EXPECT_TRUE(decomposedType.translateX >= 4 && decomposedType.translateX <= 6); + + expectTranslateX(6, curve->getValue(1.5, layerSize)); + expectTranslateX(6, curve->getValue(2, layerSize)); + expectTranslateX(6, curve->getValue(3, layerSize)); +} + +// Tests that invalid lists of keyframes result in nothing being returned from ::create. +TEST(CCKeyframedAnimationCurveTest, InvalidKeyframes) +{ + // It is invalid to pass an empty vector of keyframes to create. + Vector<CCTransformKeyframe> transformKeyframes; + OwnPtr<CCKeyframedTransformAnimationCurve> transformCurve = CCKeyframedTransformAnimationCurve::create(transformKeyframes); + EXPECT_FALSE(transformCurve.get()); + + Vector<CCFloatKeyframe> floatKeyframes; + OwnPtr<CCKeyframedFloatAnimationCurve> floatCurve = CCKeyframedFloatAnimationCurve::create(floatKeyframes); + EXPECT_FALSE(floatCurve.get()); + + // It is invalid to pass a vector of unsorted keyframes to create; + TransformOperations operations1; + operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + TransformOperations operations2; + operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + transformKeyframes.append(CCTransformKeyframe(1, operations1)); + transformKeyframes.append(CCTransformKeyframe(0, operations2)); + transformCurve = CCKeyframedTransformAnimationCurve::create(transformKeyframes); + EXPECT_FALSE(transformCurve.get()); + + floatKeyframes.append(CCFloatKeyframe(1, 2)); + floatKeyframes.append(CCFloatKeyframe(0, 4)); + floatCurve = CCKeyframedFloatAnimationCurve::create(floatKeyframes); + EXPECT_FALSE(floatCurve.get()); +} + + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp index 3d50d06e6..e1aeccc53 100644 --- a/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerAnimationControllerImplTest.cpp @@ -24,92 +24,39 @@ #include "config.h" +#include "CCAnimationTestCommon.h" #include "cc/CCLayerAnimationControllerImpl.h" - -#include "TransformOperations.h" #include "cc/CCAnimationCurve.h" - +#include "cc/CCAnimationEvents.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <wtf/Vector.h> using namespace WebCore; +using namespace WebKitTests; 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; -}; +PassOwnPtr<CCActiveAnimation> createActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, int id, CCActiveAnimation::TargetProperty property) +{ + return CCActiveAnimation::create(curve, 0, id, property); +} // Tests that transitioning opacity from 0 to 1 works as expected. TEST(CCLayerAnimationControllerImplTest, TrivialTransition) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); controller->add(toAdd.release()); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1); + controller->animate(1, *events); EXPECT_EQ(1, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -117,20 +64,21 @@ TEST(CCLayerAnimationControllerImplTest, TrivialTransition) // Tests that two queued animations affecting the same property run in sequence. TEST(CCLayerAnimationControllerImplTest, TrivialQueuing) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1); + controller->animate(1, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(1, dummy.opacity()); - controller->animate(2); + controller->animate(2, *events); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -138,22 +86,23 @@ TEST(CCLayerAnimationControllerImplTest, TrivialQueuing) // Tests interrupting a transition with another transition. TEST(CCLayerAnimationControllerImplTest, Interrupt) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); - controller->animate(0); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(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. + controller->animate(0.5, *events); // second anim starts NOW. EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(1, dummy.opacity()); - controller->animate(1.5); + controller->animate(1.5, *events); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -161,23 +110,24 @@ TEST(CCLayerAnimationControllerImplTest, Interrupt) // Tests scheduling two animations to run together when only one property is free. TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWhenAPropertyIsBlocked) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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->add(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), 1, CCActiveAnimation::Transform)); + controller->add(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), 2, CCActiveAnimation::Transform)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 2, CCActiveAnimation::Opacity)); - controller->animate(0); + controller->animate(0, *events); EXPECT_EQ(0, dummy.opacity()); EXPECT_TRUE(controller->hasActiveAnimation()); - controller->animate(1); + controller->animate(1, *events); // 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); + controller->animate(2, *events); EXPECT_EQ(1, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -187,29 +137,30 @@ TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWhenAPropertyIsBlocked) // for both to finish). TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWithAnAnimWaiting) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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)); + controller->add(createActiveAnimation(adoptPtr(new FakeTransformTransition(2)), 1, CCActiveAnimation::Transform)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5f)), 2, CCActiveAnimation::Opacity)); // Anims with id 1 should both start now. - controller->animate(0); + controller->animate(0, *events); 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); + controller->animate(2, *events); // 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); + controller->animate(3, *events); EXPECT_EQ(0.5f, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -217,22 +168,23 @@ TEST(CCLayerAnimationControllerImplTest, ScheduleTogetherWithAnAnimWaiting) // Tests scheduling an animation to start in the future. TEST(CCLayerAnimationControllerImplTest, ScheduleAnimation) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0); toAdd->setStartTime(1); controller->add(toAdd.release()); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1); + controller->animate(1, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(2); + controller->animate(2, *events); EXPECT_EQ(1, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -240,28 +192,29 @@ TEST(CCLayerAnimationControllerImplTest, ScheduleAnimation) // Tests scheduling an animation to start in the future that's interrupting a running animation. TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimation) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0.5f, 0)), 2, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(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); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(0.5); + controller->animate(0.5, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->animate(1); + controller->animate(1, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); - controller->animate(2); + controller->animate(2, *events); EXPECT_EQ(0, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -270,34 +223,35 @@ TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnim // and there is yet another animation queued to start later. TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnimationWithAnimInQueue) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - controller->add(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity)); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(2, 0.5f, 0)), 2, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(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)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 0.75f)), 3, CCActiveAnimation::Opacity)); // First 2s opacity transition should start immediately. - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(0.5); + controller->animate(0.5, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); EXPECT_TRUE(controller->hasActiveAnimation()); - controller->animate(1); + controller->animate(1, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.5f, dummy.opacity()); - controller->animate(3); + controller->animate(3, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(4); + controller->animate(4, *events); EXPECT_EQ(0.75f, dummy.opacity()); EXPECT_FALSE(controller->hasActiveAnimation()); } @@ -305,64 +259,66 @@ TEST(CCLayerAnimationControllerImplTest, ScheduledAnimationInterruptsRunningAnim // Test that a looping animation loops and for the correct number of iterations. TEST(CCLayerAnimationControllerImplTest, TrivialLooping) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient dummy; OwnPtr<CCLayerAnimationControllerImpl> controller( CCLayerAnimationControllerImpl::create(&dummy)); - OwnPtr<CCActiveAnimation> toAdd(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity)); toAdd->setIterations(3); controller->add(toAdd.release()); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1.25); + controller->animate(1.25, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->animate(1.75); + controller->animate(1.75, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->animate(2.25); + controller->animate(2.25, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->animate(2.75); + controller->animate(2.75, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->animate(3); + controller->animate(3, *events); EXPECT_FALSE(controller->hasActiveAnimation()); EXPECT_EQ(1, dummy.opacity()); // Just be extra sure. - controller->animate(4); + controller->animate(4, *events); EXPECT_EQ(1, dummy.opacity()); } // Test that an infinitely looping animation does indeed go until aborted. TEST(CCLayerAnimationControllerImplTest, InfiniteLooping) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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)); + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity)); toAdd->setIterations(-1); controller->add(toAdd.release()); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1.25); + controller->animate(1.25, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->animate(1.75); + controller->animate(1.75, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->animate(1073741824.25); + controller->animate(1073741824.25, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.25f, dummy.opacity()); - controller->animate(1073741824.75); + controller->animate(1073741824.75, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); @@ -375,80 +331,66 @@ TEST(CCLayerAnimationControllerImplTest, InfiniteLooping) // Test that pausing and resuming work as expected. TEST(CCLayerAnimationControllerImplTest, PauseResume) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity)); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(0.5); + controller->animate(0.5, *events); 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); + controller->animate(1024, *events); 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); + controller->animate(1024.25, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0.75f, dummy.opacity()); - controller->animate(1024.5); + controller->animate(1024.5, *events); EXPECT_FALSE(controller->hasActiveAnimation()); EXPECT_EQ(1, dummy.opacity()); } TEST(CCLayerAnimationControllerImplTest, AbortAGroupedAnimation) { - FakeControllerClient dummy; + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerImplClient 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->add(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), id, CCActiveAnimation::Transform)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), id, CCActiveAnimation::Opacity)); + controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.75f)), 2, CCActiveAnimation::Opacity)); - controller->animate(0); + controller->animate(0, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(0, dummy.opacity()); - controller->animate(1); + controller->animate(1, *events); 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); + controller->animate(1, *events); EXPECT_TRUE(controller->hasActiveAnimation()); EXPECT_EQ(1, dummy.opacity()); - controller->animate(2); + controller->animate(2, *events); 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/CCLayerAnimationControllerTest.cpp b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp new file mode 100644 index 000000000..c4f103a3c --- /dev/null +++ b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp @@ -0,0 +1,215 @@ +/* + * 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/CCLayerAnimationController.h" + +#include "CCAnimationTestCommon.h" +#include "GraphicsLayer.h" +#include "Length.h" +#include "TranslateTransformOperation.h" +#include "cc/CCActiveAnimation.h" +#include "cc/CCAnimationCurve.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +using namespace WebCore; +using namespace WebKitTests; + +namespace { + +void expectTranslateX(double translateX, const TransformationMatrix& matrix) +{ + TransformationMatrix::DecomposedType decomposedType; + matrix.decompose(decomposedType); + EXPECT_FLOAT_EQ(translateX, decomposedType.translateX); +} + +PassOwnPtr<CCActiveAnimation> createActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, int id, CCActiveAnimation::TargetProperty property) +{ + return CCActiveAnimation::create(curve, 0, id, property); +} + +TEST(CCLayerAnimationControllerTest, createOpacityAnimation) +{ + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + const double duration = 1; + WebCore::KeyframeValueList values(AnimatedPropertyOpacity); + values.insert(new FloatAnimationValue(0, 0)); + values.insert(new FloatAnimationValue(duration, 1)); + + RefPtr<Animation> animation = Animation::create(); + animation->setDuration(duration); + + IntSize boxSize; + controller->addAnimation(values, boxSize, animation.get(), 0, 0, 0); + + EXPECT_TRUE(controller->hasActiveAnimation()); + + CCActiveAnimation* activeAnimation = controller->getActiveAnimation(0, CCActiveAnimation::Opacity); + EXPECT_TRUE(activeAnimation); + + EXPECT_EQ(1, activeAnimation->iterations()); + EXPECT_EQ(CCActiveAnimation::Opacity, activeAnimation->targetProperty()); + + EXPECT_EQ(CCAnimationCurve::Float, activeAnimation->curve()->type()); + + const CCFloatAnimationCurve* curve = activeAnimation->curve()->toFloatAnimationCurve(); + EXPECT_TRUE(curve); + + EXPECT_EQ(0, curve->getValue(0)); + EXPECT_EQ(1, curve->getValue(duration)); +} + +TEST(CCLayerAnimationControllerTest, createTransformAnimation) +{ + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + const double duration = 1; + WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform); + + TransformOperations operations1; + operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + values.insert(new TransformAnimationValue(0, &operations1)); + + TransformOperations operations2; + operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X)); + values.insert(new TransformAnimationValue(duration, &operations2)); + + RefPtr<Animation> animation = Animation::create(); + animation->setDuration(duration); + + IntSize boxSize; + controller->addAnimation(values, boxSize, animation.get(), 0, 0, 0); + + EXPECT_TRUE(controller->hasActiveAnimation()); + + CCActiveAnimation* activeAnimation = controller->getActiveAnimation(0, CCActiveAnimation::Transform); + EXPECT_TRUE(activeAnimation); + + EXPECT_EQ(1, activeAnimation->iterations()); + EXPECT_EQ(CCActiveAnimation::Transform, activeAnimation->targetProperty()); + + EXPECT_EQ(CCAnimationCurve::Transform, activeAnimation->curve()->type()); + + const CCTransformAnimationCurve* curve = activeAnimation->curve()->toTransformAnimationCurve(); + EXPECT_TRUE(curve); + + expectTranslateX(2, curve->getValue(0, boxSize)); + expectTranslateX(4, curve->getValue(duration, boxSize)); +} + +TEST(CCLayerAnimationControllerTest, syncNewAnimation) +{ + FakeLayerAnimationControllerImplClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy)); + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1); + + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState()); +} + +TEST(CCLayerAnimationControllerTest, syncAnimationProperties) +{ + FakeLayerAnimationControllerImplClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy)); + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1); + + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState()); + + // Push an animation property change to the impl thread (should not cause an animation to be added). + controller->pauseAnimation(0, 0); + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_EQ(CCActiveAnimation::Paused, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState()); +} + +TEST(CCLayerAnimationControllerTest, syncAbortedAnimation) +{ + FakeLayerAnimationControllerImplClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy)); + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1); + + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState()); + + controller->removeAnimation(0); + + // Abort an animation from the main thread. + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); +} + +TEST(CCLayerAnimationControllerTest, syncCompletedAnimation) +{ + FakeLayerAnimationControllerImplClient dummy; + OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy)); + OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create()); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + + addOpacityTransitionToController(*controller, 1, 0, 1); + + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState()); + + // Step through the animation until it is finished. At the next sync, the main thread's animation should be cleared. + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + controllerImpl->animate(0, *events); + controllerImpl->animate(2, *events); + + EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)); + EXPECT_TRUE(controller->hasActiveAnimation()); + + controller->synchronizeAnimations(controllerImpl.get()); + + EXPECT_FALSE(controller->hasActiveAnimation()); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp index 27728cbef..16a25e12e 100644 --- a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp @@ -88,10 +88,13 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly) Color arbitraryColor = Color(10, 20, 30); TransformationMatrix arbitraryTransform; arbitraryTransform.scale3d(0.1, 0.2, 0.3); + FilterOperations arbitraryFilters; + arbitraryFilters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); // Changing these properties affects the entire subtree of layers. EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setAnchorPoint(arbitraryFloatPoint)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setAnchorPointZ(arbitraryNumber)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setFilters(arbitraryFilters)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setMaskLayer(dummyMask)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setMasksToBounds(true)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setOpaque(true)); diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp index b1fa72918..d2e1cfef9 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp @@ -28,7 +28,6 @@ #include "CCLayerTreeTestCommon.h" #include "LayerChromium.h" -#include "Region.h" #include "TransformationMatrix.h" #include <gmock/gmock.h> @@ -36,12 +35,6 @@ 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) @@ -602,174 +595,4 @@ 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 f59893de9..9ba1cf4ad 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp @@ -52,6 +52,7 @@ public: virtual void onSwapBuffersCompleteOnImplThread() { } virtual void setNeedsRedrawOnImplThread() { m_didRequestRedraw = true; } virtual void setNeedsCommitOnImplThread() { m_didRequestCommit = true; } + virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>) { } static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer) { @@ -67,7 +68,8 @@ public: for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) { if (scrollInfo.scrolls[i].layerId != id) continue; - ASSERT_EQ(scrollInfo.scrolls[i].scrollDelta, scrollDelta); + EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.width()); + EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.height()); timesEncountered++; } @@ -89,6 +91,11 @@ public: } protected: + PassRefPtr<GraphicsContext3D> createContext() + { + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow); + } + DebugScopedSetImplThread m_alwaysImplThread; OwnPtr<CCLayerTreeHostImpl> m_hostImpl; bool m_didRequestCommit; @@ -142,14 +149,14 @@ TEST_F(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls) scrollInfo = m_hostImpl->processScrollDeltas(); ASSERT_EQ(scrollInfo->scrolls.size(), 1u); EXPECT_EQ(root->sentScrollDelta(), scrollDelta); - expectContains(*scrollInfo.get(), root->id(), scrollDelta); + expectContains(*scrollInfo, root->id(), scrollDelta); IntSize scrollDelta2(-5, 27); root->scrollBy(scrollDelta2); scrollInfo = m_hostImpl->processScrollDeltas(); ASSERT_EQ(scrollInfo->scrolls.size(), 1u); EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2); - expectContains(*scrollInfo.get(), root->id(), scrollDelta + scrollDelta2); + expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2); root->scrollBy(IntSize()); scrollInfo = m_hostImpl->processScrollDeltas(); @@ -163,13 +170,28 @@ TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw) root->setScrollPosition(IntPoint(0, 0)); root->setMaxScrollPosition(IntSize(100, 100)); m_hostImpl->setRootLayer(root); - EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0)), CCInputHandlerClient::ScrollStarted); + EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); m_hostImpl->scrollBy(IntSize(0, 10)); m_hostImpl->scrollEnd(); EXPECT_TRUE(m_didRequestRedraw); EXPECT_TRUE(m_didRequestCommit); } +TEST_F(CCLayerTreeHostImplTest, wheelEventHandlers) +{ + RefPtr<CCLayerImpl> root = CCLayerImpl::create(0); + root->setScrollable(true); + root->setScrollPosition(IntPoint(0, 0)); + root->setMaxScrollPosition(IntSize(100, 100)); + m_hostImpl->setRootLayer(root); + root->setHaveWheelEventHandlers(true); + // With registered event handlers, wheel scrolls have to go to the main thread. + EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed); + + // But gesture scrolls can still be handled. + EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted); +} + TEST_F(CCLayerTreeHostImplTest, pinchGesture) { setupScrollAndContentsLayers(IntSize(100, 100)); @@ -184,6 +206,7 @@ TEST_F(CCLayerTreeHostImplTest, pinchGesture) { m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollDelta(IntSize()); float pageScaleDelta = 2; m_hostImpl->pinchGestureBegin(); @@ -200,6 +223,7 @@ TEST_F(CCLayerTreeHostImplTest, pinchGesture) { m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollDelta(IntSize()); float pageScaleDelta = 10; m_hostImpl->pinchGestureBegin(); @@ -214,6 +238,7 @@ TEST_F(CCLayerTreeHostImplTest, pinchGesture) { m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollDelta(IntSize()); scrollLayer->setScrollPosition(IntPoint(50, 50)); float pageScaleDelta = 0.1; @@ -225,7 +250,25 @@ TEST_F(CCLayerTreeHostImplTest, pinchGesture) EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); // Pushed to (0,0) via clamping against contents layer size. - expectContains(*scrollInfo.get(), scrollLayer->id(), IntSize(-50, -50)); + expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); + } + + // Two-finger panning + { + m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); + scrollLayer->setPageScaleDelta(1); + scrollLayer->setScrollDelta(IntSize()); + scrollLayer->setScrollPosition(IntPoint(20, 20)); + + float pageScaleDelta = 1; + m_hostImpl->pinchGestureBegin(); + m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10)); + m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20)); + m_hostImpl->pinchGestureEnd(); + + OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); + EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); + expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10)); } } @@ -255,7 +298,7 @@ TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation) OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas(); EXPECT_EQ(scrollInfo->pageScaleDelta, 2); - expectContains(*scrollInfo.get(), scrollLayer->id(), IntSize(-50, -50)); + expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); } // Anchor zoom-out @@ -272,8 +315,107 @@ TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation) 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)); + expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); + } +} + +class DidDrawCheckLayer : public CCLayerImpl { +public: + static PassRefPtr<DidDrawCheckLayer> create(int id) { return adoptRef(new DidDrawCheckLayer(id)); } + + virtual void didDraw() + { + m_didDrawCalled = true; + } + + virtual void willDraw(LayerRendererChromium*) + { + m_willDrawCalled = true; + } + + bool didDrawCalled() const { return m_didDrawCalled; } + bool willDrawCalled() const { return m_willDrawCalled; } + +private: + explicit DidDrawCheckLayer(int id) + : CCLayerImpl(id) + , m_didDrawCalled(false) + , m_willDrawCalled(false) + { + setAnchorPoint(FloatPoint(0, 0)); + setBounds(IntSize(10, 10)); + setDrawsContent(true); } + + bool m_didDrawCalled; + bool m_willDrawCalled; +}; + +TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer) +{ + RefPtr<GraphicsContext3D> context = createContext(); + m_hostImpl->initializeLayerRenderer(context); + + // Ensure visibleLayerRect for root layer is empty + m_hostImpl->setViewportSize(IntSize(0, 0)); + + RefPtr<DidDrawCheckLayer> root = DidDrawCheckLayer::create(0); + m_hostImpl->setRootLayer(root); + + EXPECT_FALSE(root->willDrawCalled()); + EXPECT_FALSE(root->didDrawCalled()); + + m_hostImpl->drawLayers(); + + EXPECT_FALSE(root->willDrawCalled()); + EXPECT_FALSE(root->didDrawCalled()); + + EXPECT_TRUE(root->visibleLayerRect().isEmpty()); + + // Ensure visibleLayerRect for root layer is not empty + m_hostImpl->setViewportSize(IntSize(10, 10)); + + EXPECT_FALSE(root->willDrawCalled()); + EXPECT_FALSE(root->didDrawCalled()); + + m_hostImpl->drawLayers(); + + EXPECT_TRUE(root->willDrawCalled()); + EXPECT_TRUE(root->didDrawCalled()); + + EXPECT_FALSE(root->visibleLayerRect().isEmpty()); +} + +TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers) +{ + RefPtr<GraphicsContext3D> context = createContext(); + m_hostImpl->initializeLayerRenderer(context); + m_hostImpl->setViewportSize(IntSize(10, 10)); + + RefPtr<DidDrawCheckLayer> root = DidDrawCheckLayer::create(0); + m_hostImpl->setRootLayer(root); + + RefPtr<DidDrawCheckLayer> layer1 = DidDrawCheckLayer::create(1); + root->addChild(layer1); + + RefPtr<DidDrawCheckLayer> layer2 = DidDrawCheckLayer::create(2); + layer1->addChild(layer2); + + layer1->setOpacity(0.3); + layer1->setPreserves3D(false); + + EXPECT_FALSE(root->didDrawCalled()); + EXPECT_FALSE(layer1->didDrawCalled()); + EXPECT_FALSE(layer2->didDrawCalled()); + + m_hostImpl->drawLayers(); + + EXPECT_TRUE(root->didDrawCalled()); + EXPECT_TRUE(layer1->didDrawCalled()); + EXPECT_TRUE(layer2->didDrawCalled()); + + EXPECT_NE(root->renderSurface(), layer1->renderSurface()); + EXPECT_TRUE(!!layer1->renderSurface()); } class BlendStateTrackerContext: public FakeWebGraphicsContext3D { @@ -347,8 +489,7 @@ private: // https://bugs.webkit.org/show_bug.cgi?id=75783 TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) { - GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new BlendStateTrackerContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = createContext(); m_hostImpl->initializeLayerRenderer(context); m_hostImpl->setViewportSize(IntSize(10, 10)); @@ -507,7 +648,6 @@ private: class FakeDrawableCCLayerImpl: public CCLayerImpl { public: explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { } - virtual void draw(LayerRendererChromium* renderer) { } }; // Only reshape when we know we are going to draw. Otherwise, the reshape @@ -515,9 +655,8 @@ public: // viewport size is never set. TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw) { - GraphicsContext3D::Attributes attrs; ReshapeTrackerContext* reshapeTracker = new ReshapeTrackerContext(); - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), GraphicsContext3D::RenderDirectlyToHostWindow); m_hostImpl->initializeLayerRenderer(context); m_hostImpl->setViewportSize(IntSize(10, 10)); @@ -559,9 +698,8 @@ private: // where it should request to swap only the subBuffer that is damaged. TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) { - GraphicsContext3D::Attributes attrs; PartialSwapTrackerContext* partialSwapTracker = new PartialSwapTrackerContext(); - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), GraphicsContext3D::RenderDirectlyToHostWindow); // This test creates its own CCLayerTreeHostImpl, so // that we can force partial swap enabled. diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp index fc414f739..10cfa6931 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp @@ -26,14 +26,18 @@ #include "cc/CCLayerTreeHost.h" +#include "CCAnimationTestCommon.h" #include "CompositorFakeWebGraphicsContext3D.h" #include "ContentLayerChromium.h" +#include "FilterOperations.h" #include "GraphicsContext3DPrivate.h" #include "LayerChromium.h" #include "Region.h" #include "TextureManager.h" #include "WebCompositor.h" #include "WebKit.h" +#include "cc/CCActiveAnimation.h" +#include "cc/CCLayerAnimationController.h" #include "cc/CCLayerImpl.h" #include "cc/CCLayerTreeHostImpl.h" #include "cc/CCScopedThreadProxy.h" @@ -49,6 +53,7 @@ using namespace WebCore; using namespace WebKit; +using namespace WebKitTests; using namespace WTF; namespace { @@ -59,6 +64,7 @@ public: virtual void beginCommitOnCCThread(CCLayerTreeHostImpl*) { } virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*) { } virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*) { } + virtual void animateLayers(CCLayerTreeHostImpl*) { } virtual void applyScrollAndScale(const IntSize&, float) { } virtual void updateAnimations(double frameBeginTime) { } virtual void layout() { } @@ -90,6 +96,13 @@ public: m_testHooks->drawLayersOnCCThread(this); } +protected: + virtual void animateLayers(double frameBeginTimeMs) + { + CCLayerTreeHostImpl::animateLayers(frameBeginTimeMs); + m_testHooks->animateLayers(this); + } + private: MockLayerTreeHostImpl(TestHooks* testHooks, const CCSettings& settings, CCLayerTreeHostImplClient* client) : CCLayerTreeHostImpl(settings, client) @@ -105,7 +118,11 @@ class MockLayerTreeHost : public CCLayerTreeHost { public: static PassRefPtr<MockLayerTreeHost> create(TestHooks* testHooks, CCLayerTreeHostClient* client, PassRefPtr<LayerChromium> rootLayer, const CCSettings& settings) { - RefPtr<MockLayerTreeHost> layerTreeHost = adoptRef(new MockLayerTreeHost(testHooks, client, settings)); + // For these tests, we will enable threaded animations. + CCSettings settingsCopy = settings; + settingsCopy.threadedAnimationEnabled = true; + + RefPtr<MockLayerTreeHost> layerTreeHost = adoptRef(new MockLayerTreeHost(testHooks, client, settingsCopy)); bool success = layerTreeHost->initialize(); EXPECT_TRUE(success); layerTreeHost->setRootLayer(rootLayer); @@ -118,7 +135,10 @@ public: virtual PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHostImpl(CCLayerTreeHostImplClient* client) { - return MockLayerTreeHostImpl::create(m_testHooks, settings(), client); + // For these tests, we will enable threaded animations. + CCSettings settings; + settings.threadedAnimationEnabled = true; + return MockLayerTreeHostImpl::create(m_testHooks, settings, client); } private: @@ -207,10 +227,7 @@ public: webAttrs.alpha = attrs.alpha; OwnPtr<WebGraphicsContext3D> webContext = CompositorFakeWebGraphicsContext3DWithTextureTracking::create(webAttrs); - return GraphicsContext3DPrivate::createGraphicsContextFromWebContext( - webContext.release(), attrs, 0, - GraphicsContext3D::RenderDirectlyToHostWindow, - GraphicsContext3DPrivate::ForUseOnAnotherThread); + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow); } virtual void didCommitAndDrawFrame() @@ -225,7 +242,9 @@ public: { } - virtual void scheduleComposite() { } + virtual void scheduleComposite() + { + } private: explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { } @@ -255,6 +274,11 @@ public: callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimate, this); } + void postAddAnimationToMainThread() + { + callOnMainThread(CCLayerTreeHostTest::dispatchAddAnimation, this); + } + void postSetNeedsCommitToMainThread() { callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsCommit, this); @@ -270,7 +294,6 @@ public: callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimateAndCommit, this); } - void postSetVisibleToMainThread(bool visible) { callOnMainThread(visible ? CCLayerTreeHostTest::dispatchSetVisible : CCLayerTreeHostTest::dispatchSetInvisible, this); @@ -313,6 +336,15 @@ protected: test->m_layerTreeHost->setNeedsAnimate(); } + static void dispatchAddAnimation(void* self) + { + ASSERT(isMainThread()); + CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self); + ASSERT(test); + if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer()) + addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 0, 0, 1); + } + static void dispatchSetNeedsAnimateAndCommit(void* self) { ASSERT(isMainThread()); @@ -789,6 +821,47 @@ TEST_F(CCLayerTreeHostTestSetNeedsAnimateInsideAnimationCallback, runMultiThread runTestThreaded(); } +// Add a layer animation and confirm that CCLayerTreeHostImpl::animateLayers does get +// called and continues to get called. +class CCLayerTreeHostTestAddAnimation : public CCLayerTreeHostTestThreadOnly { +public: + CCLayerTreeHostTestAddAnimation() + : m_numAnimates(0) + , m_layerTreeHostImpl(0) + { + } + + virtual void beginTest() + { + postAddAnimationToMainThread(); + } + + virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl) + { + if (!m_numAnimates) { + // The animation had zero duration so layerTreeHostImpl should no + // longer need to animate its layers. + EXPECT_FALSE(layerTreeHostImpl->needsAnimateLayers()); + m_numAnimates++; + return; + } + endTest(); + } + + virtual void afterTest() + { + } + +private: + int m_numAnimates; + CCLayerTreeHostImpl* m_layerTreeHostImpl; +}; + +TEST_F(CCLayerTreeHostTestAddAnimation, runMultiThread) +{ + runTestThreaded(); +} + class CCLayerTreeHostTestScrollSimple : public CCLayerTreeHostTestThreadOnly { public: CCLayerTreeHostTestScrollSimple() @@ -938,6 +1011,75 @@ TEST_F(CCLayerTreeHostTestScrollMultipleRedraw, DISABLED_runMultiThread) runTestThreaded(); } +// Verifies that startPageScaleAnimation events propagate correctly from CCLayerTreeHost to +// CCLayerTreeHostImpl in the MT compositor. +class CCLayerTreeHostTestStartPageScaleAnimation : public CCLayerTreeHostTest { +public: + + CCLayerTreeHostTestStartPageScaleAnimation() + : m_animationRequested(false) + { + } + + virtual void beginTest() + { + m_layerTreeHost->rootLayer()->setScrollable(true); + m_layerTreeHost->rootLayer()->setScrollPosition(IntPoint()); + postSetNeedsRedrawToMainThread(); + } + + static void requestStartPageScaleAnimation(void* self) + { + CCLayerTreeHostTestStartPageScaleAnimation* test = static_cast<CCLayerTreeHostTestStartPageScaleAnimation*>(self); + if (test->layerTreeHost()) + test->layerTreeHost()->startPageScaleAnimation(IntSize(), false, 1.25, 0); + } + + virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) + { + impl->rootLayer()->setScrollable(true); + impl->rootLayer()->setScrollPosition(IntPoint()); + impl->setPageScaleFactorAndLimits(impl->pageScale(), 0.5, 2); + + // We request animation only once. + if (!m_animationRequested) { + callOnMainThread(CCLayerTreeHostTestStartPageScaleAnimation::requestStartPageScaleAnimation, this); + m_animationRequested = true; + } + } + + virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale) + { + IntPoint position = m_layerTreeHost->rootLayer()->scrollPosition(); + m_layerTreeHost->rootLayer()->setScrollPosition(position + scrollDelta); + m_layerTreeHost->setPageScaleFactorAndLimits(scale, 0.5, 2); + } + + virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl) + { + impl->processScrollDeltas(); + // We get one commit before the first draw, and the animation doesn't happen until the second draw, + // so results available on the third commit. + if (impl->frameNumber() == 2) { + EXPECT_EQ(1.25, impl->pageScale()); + endTest(); + } else + postSetNeedsRedrawToMainThread(); + } + + virtual void afterTest() + { + } + +private: + bool m_animationRequested; +}; + +TEST_F(CCLayerTreeHostTestStartPageScaleAnimation, runTest) +{ + runTest(true); +} + class CCLayerTreeHostTestSetVisible : public CCLayerTreeHostTest { public: @@ -1596,6 +1738,94 @@ public: SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestLayerOcclusion) +class CCLayerTreeHostTestLayerOcclusionWithFilters : public CCLayerTreeHostTest { +public: + CCLayerTreeHostTestLayerOcclusionWithFilters() { } + + 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); + + // If the child layer has a filter that changes alpha values, and 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); + + { + FilterOperations filters; + filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); + child->setFilters(filters); + } + + 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 filter that moves pixels/changes alpha, and is below child2, then child should not inherit occlusion from outside its subtree, + // and should not 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); + + { + FilterOperations filters; + filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Percent), FilterOperation::BLUR)); + child->setFilters(filters); + } + + 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(), 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(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(CCLayerTreeHostTestLayerOcclusionWithFilters) + class CCLayerTreeHostTestManySurfaces : public CCLayerTreeHostTest { public: CCLayerTreeHostTestManySurfaces() { } diff --git a/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp new file mode 100644 index 000000000..678ec9645 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp @@ -0,0 +1,1173 @@ +/* + * 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/CCOcclusionTracker.h" + +#include "FilterOperations.h" +#include "LayerChromium.h" +#include "Region.h" +#include "TransformationMatrix.h" +#include "cc/CCLayerTreeHostCommon.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +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 opaque) +{ + layer->setTransform(transform); + layer->setSublayerTransform(sublayerTransform); + layer->setAnchorPoint(anchor); + layer->setPosition(position); + layer->setBounds(bounds); + layer->setOpaque(opaque); +} + +class LayerChromiumWithForcedDrawsContent : public LayerChromium { +public: + LayerChromiumWithForcedDrawsContent() + : LayerChromium() + { + } + + virtual bool drawsContent() const { return true; } +}; + +// A subclass to expose the total current occlusion. +class TestCCOcclusionTracker : public CCOcclusionTracker { +public: + Region occlusionInScreenSpace() const { return CCOcclusionTracker::m_stack.last().occlusionInScreen; } + Region occlusionInTargetSurface() const { return CCOcclusionTracker::m_stack.last().occlusionInTarget; } + + void setOcclusionInScreenSpace(const Region& region) { CCOcclusionTracker::m_stack.last().occlusionInScreen = region; } + void setOcclusionInTargetSurface(const Region& region) { CCOcclusionTracker::m_stack.last().occlusionInTarget = region; } +}; + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegion) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + 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), true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(parent->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 70, 70)).isEmpty()); + EXPECT_EQ_RECT(IntRect(29, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 30, 70, 70))); + EXPECT_EQ_RECT(IntRect(29, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(30, 29, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(31, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(100, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 30, 70, 70))); + EXPECT_EQ_RECT(IntRect(31, 31, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 31, 70, 70))); + EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 31, 70, 70))); + EXPECT_EQ_RECT(IntRect(29, 31, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 31, 70, 70))); +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotation) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + 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), true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(parent->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 70, 70)).isEmpty()); + EXPECT_EQ_RECT(IntRect(29, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 30, 70, 70))); + EXPECT_EQ_RECT(IntRect(29, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(30, 29, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(31, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 29, 70, 70))); + EXPECT_EQ_RECT(IntRect(100, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 30, 70, 70))); + EXPECT_EQ_RECT(IntRect(31, 31, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 31, 70, 70))); + EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 31, 70, 70))); + EXPECT_EQ_RECT(IntRect(29, 31, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 31, 70, 70))); +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithTranslation) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + 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), true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(parent->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(50, 50, 50, 50))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(49, 50, 50, 50))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(50, 49, 50, 50))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(51, 50, 50, 50))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(50, 51, 50, 50))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(50, 50, 50, 50)).isEmpty()); + EXPECT_EQ_RECT(IntRect(49, 50, 1, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 50, 50, 50))); + EXPECT_EQ_RECT(IntRect(49, 49, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 49, 50, 50))); + EXPECT_EQ_RECT(IntRect(50, 49, 50, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(50, 49, 50, 50))); + EXPECT_EQ_RECT(IntRect(51, 49, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(51, 49, 50, 50))); + EXPECT_EQ_RECT(IntRect(100, 50, 1, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(51, 50, 50, 50))); + EXPECT_EQ_RECT(IntRect(51, 51, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(51, 51, 50, 50))); + EXPECT_EQ_RECT(IntRect(50, 100, 50, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(50, 51, 50, 50))); + EXPECT_EQ_RECT(IntRect(49, 51, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 51, 50, 50))); +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + 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), true); + + child->setMasksToBounds(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(child->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(9, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 429, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 430, 61, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 71))); + + occlusion.markOccludedBehindLayer(child.get()); + occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 39, 70, 60))); + + + /* Justification for the above occlusion 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 + */ +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> child2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child); + child->addChild(layer); + parent->addChild(child2); + + 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), true); + + // |child2| makes |parent|'s surface get considered by CCOcclusionTracker first, instead of |child|'s. This exercises different code in + // leaveToTargetRenderSurface, as the target surface has already been seen. + setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(60, 20), true); + + child->setMasksToBounds(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(parent->renderSurface()); + occlusion.markOccludedBehindLayer(child2.get()); + + EXPECT_EQ_RECT(IntRect(30, 30, 60, 20), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 60, 20), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + occlusion.enterTargetRenderSurface(child->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(9, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 429, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(11, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 431, 60, 70))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)).isEmpty()); + // This is the little piece not occluded by child2 + EXPECT_EQ_RECT(IntRect(9, 430, 1, 10), occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 70))); + // This extends past both sides of child2, so it will be the original rect. + EXPECT_EQ_RECT(IntRect(9, 430, 60, 80), occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 80))); + // This extends past two adjacent sides of child2, and should included the unoccluded parts of each side. + // This also demonstrates that the rect can be arbitrary and does not get clipped to the layer's visibleLayerRect(). + EXPECT_EQ_RECT(IntRect(-10, 430, 20, 70), occlusion.unoccludedContentRect(child.get(), IntRect(-10, 430, 60, 70))); + // This extends past three adjacent sides of child2, so it should contain the unoccluded parts of each side. The left + // and bottom edges are completely unoccluded for some row/column so we get back the original query rect. + EXPECT_EQ_RECT(IntRect(-10, 430, 60, 80), occlusion.unoccludedContentRect(child.get(), IntRect(-10, 430, 60, 80))); + EXPECT_EQ_RECT(IntRect(10, 429, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 429, 60, 70))); + EXPECT_EQ_RECT(IntRect(70, 430, 1, 70), occlusion.unoccludedContentRect(child.get(), IntRect(11, 430, 60, 70))); + EXPECT_EQ_RECT(IntRect(10, 500, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 431, 60, 70))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(10, 430, 60, 70))); + + occlusion.markOccludedBehindLayer(child.get()); + // |child2| should get merged with the surface we are leaving now + occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInTargetSurface().rects().size()); + + Vector<IntRect> screen = occlusion.occlusionInScreenSpace().rects(); + Vector<IntRect> target = occlusion.occlusionInTargetSurface().rects(); + + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70))); + EXPECT_EQ_RECT(IntRect(90, 30, 10, 10), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 70, 70))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 60, 10))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 60, 10))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 60, 10))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 30, 60, 10))); + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 31, 60, 10))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 39, 70, 60))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 60, 10)).isEmpty()); + EXPECT_EQ_RECT(IntRect(29, 30, 1, 10), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 30, 60, 10))); + EXPECT_EQ_RECT(IntRect(30, 29, 60, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 29, 60, 10))); + EXPECT_EQ_RECT(IntRect(90, 30, 1, 10), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 30, 60, 10))); + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 31, 60, 10)).isEmpty()); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60)).isEmpty()); + EXPECT_EQ_RECT(IntRect(29, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 40, 70, 60))); + // This rect is mostly occluded by |child2|. + EXPECT_EQ_RECT(IntRect(90, 39, 10, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 39, 70, 60))); + // This rect extends past top/right ends of |child2|. + EXPECT_EQ_RECT(IntRect(30, 29, 70, 11), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 29, 70, 70))); + // This rect extends past left/right ends of |child2|. + EXPECT_EQ_RECT(IntRect(20, 39, 80, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(20, 39, 80, 60))); + EXPECT_EQ_RECT(IntRect(100, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 40, 70, 60))); + EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 41, 70, 60))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60))); + + + /* Justification for the above occlusion from |layer|: + 100 + +---------------------+ +---------------------+ + | | | |30 Visible region of |layer|: ///// + | 30 | rotate(90) | 30 60 | |child2|: \\\\\ + | 30 + ------------+--------------------+ | 30 +------------+--------------------+ + 100 | | 10 | | | ==> | |\\\\\\\\\\\\| |10 | + | |10+----------|----------------------+ | +--|\\\\\\\\\\\\|-----------------+ | + | + ------------+ | | | | | +------------+//| 420 | | + | | | | | | | | |///////////////|60 | | + | | | | | | | | |///////////////| | | + +----|--|-------------+ | | +--|--|---------------+ | | + | | | | 20|10| 70 | | + | | | | | | | | + | | | |500 | | | | + | | | | | | | | + | | | | | | | | + | | | | | | | | + | | | | | | |10| + +--|-------------------------------+ | | +------------------------------|--+ + | | | 490 | + +---------------------------------+ +---------------------------------+ + 500 500 + */ +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedOffAxisSurface) +{ + TestCCOcclusionTracker occlusion; + 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); + + // Now rotate the child a little more so it is not axis-aligned. The parent will no longer be occluded by |layer|, but + // the child's occlusion should be unchanged. + + TransformationMatrix childTransform; + childTransform.translate(250, 250); + childTransform.rotate(95); + childTransform.translate(-250, -250); + + TransformationMatrix layerTransform; + layerTransform.translate(10, 10); + + 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(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(500, 500), true); + + child->setMasksToBounds(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + IntRect clippedLayerInChild = layerTransform.mapRect(layer->visibleLayerRect()); + + occlusion.enterTargetRenderSurface(child->renderSurface()); + occlusion.markOccludedBehindLayer(layer.get()); + + EXPECT_EQ_RECT(IntRect(), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(0u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(clippedLayerInChild, occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child.get(), clippedLayerInChild)); + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty()); + clippedLayerInChild.move(-1, 0); + EXPECT_FALSE(occlusion.occluded(child.get(), clippedLayerInChild)); + EXPECT_FALSE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty()); + clippedLayerInChild.move(1, 0); + clippedLayerInChild.move(1, 0); + EXPECT_FALSE(occlusion.occluded(child.get(), clippedLayerInChild)); + EXPECT_FALSE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty()); + clippedLayerInChild.move(-1, 0); + clippedLayerInChild.move(0, -1); + EXPECT_FALSE(occlusion.occluded(child.get(), clippedLayerInChild)); + EXPECT_FALSE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty()); + clippedLayerInChild.move(0, 1); + clippedLayerInChild.move(0, 1); + EXPECT_FALSE(occlusion.occluded(child.get(), clippedLayerInChild)); + EXPECT_FALSE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty()); + clippedLayerInChild.move(0, -1); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(0, 0, 500, 500), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(0, 0, 500, 500))); + + occlusion.markOccludedBehindLayer(child.get()); + occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(0u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(0u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(75, 55, 1, 1))); + EXPECT_EQ_RECT(IntRect(75, 55, 1, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(75, 55, 1, 1))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(0, 0, 100, 100), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(0, 0, 100, 100))); +} + +TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers) +{ + // This is similar to the previous test but now we make a few opaque layers inside of |child| so that the occluded parts of child are not a simple rect. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> layer2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child); + child->addChild(layer1); + child->addChild(layer2); + + 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(layer1.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 440), true); + setLayerPropertiesForTesting(layer2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(10, 450), IntSize(500, 60), true); + + child->setMasksToBounds(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(child->renderSurface()); + occlusion.markOccludedBehindLayer(layer2.get()); + occlusion.markOccludedBehindLayer(layer1.get()); + + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(9, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 429, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(11, 430, 60, 70))); + EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 431, 60, 70))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)).isEmpty()); + EXPECT_EQ_RECT(IntRect(9, 430, 1, 70), occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 70))); + EXPECT_EQ_RECT(IntRect(10, 429, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 429, 60, 70))); + EXPECT_EQ_RECT(IntRect(70, 430, 1, 70), occlusion.unoccludedContentRect(child.get(), IntRect(11, 430, 60, 70))); + EXPECT_EQ_RECT(IntRect(10, 500, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 431, 60, 70))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(10, 430, 60, 70))); + + occlusion.markOccludedBehindLayer(child.get()); + occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 40, 70, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 39, 70, 60))); + + EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60)).isEmpty()); + EXPECT_EQ_RECT(IntRect(29, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 40, 70, 60))); + EXPECT_EQ_RECT(IntRect(30, 39, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 39, 70, 60))); + EXPECT_EQ_RECT(IntRect(100, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 40, 70, 60))); + EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 41, 70, 60))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60))); + + + /* Justification for the above occlusion from |layer1| and |layer2|: + + +---------------------+ + | |30 Visible region of |layer1|: ///// + | | Visible region of |layer2|: \\\\\ + | +---------------------------------+ + | | |10 | + | +---------------+-----------------+ | + | | |\\\\\\\\\\\\|//| 420 | | + | | |\\\\\\\\\\\\|//|60 | | + | | |\\\\\\\\\\\\|//| | | + +--|--|------------|--+ | | + 20|10| 70 | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | |10| + | +------------|-----------------|--+ + | | 490 | + +---------------+-----------------+ + 60 440 + */ +} + +TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child1 = LayerChromium::create(); + RefPtr<LayerChromium> child2 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> layer2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child1); + parent->addChild(child2); + child1->addChild(layer1); + child2->addChild(layer2); + + 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(child1.get(), childTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), false); + setLayerPropertiesForTesting(layer1.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(500, 500), true); + setLayerPropertiesForTesting(child2.get(), childTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(20, 40), IntSize(500, 500), false); + setLayerPropertiesForTesting(layer2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(500, 500), true); + + child1->setMasksToBounds(true); + child2->setMasksToBounds(true); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(child2->renderSurface()); + occlusion.markOccludedBehindLayer(layer2.get()); + + EXPECT_EQ_RECT(IntRect(20, 40, 80, 60), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(0, 420, 60, 80), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(0, 420, 60, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-1, 420, 60, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(0, 419, 60, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(0, 420, 61, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(0, 420, 60, 81))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(0, 420, 60, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(0, 420, 60, 80))); + + occlusion.markOccludedBehindLayer(child2.get()); + occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + occlusion.enterTargetRenderSurface(child1->renderSurface()); + occlusion.markOccludedBehindLayer(layer1.get()); + + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(0, 430, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child1.get(), IntRect(0, 430, 70, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-1, 430, 70, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(0, 429, 70, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(0, 430, 71, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(0, 430, 70, 71))); + + // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface. + EXPECT_EQ_RECT(IntRect(0, 430, 10, 70), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(0, 430, 70, 70))); + + occlusion.markOccludedBehindLayer(child1.get()); + occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 30, 80, 70))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 70, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 70, 70))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(20, 40, 80, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(19, 40, 80, 60))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 39, 80, 60))); + + // |child1| and |child2| both draw into parent so they should not occlude it. + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(20, 30, 80, 70))); + + + /* Justification for the above occlusion: + 100 + +---------------------+ + | | + | 30 | child1 + | 30+ ---------------------------------+ + 100 | 40| | child2 | + |20+----------------------------------+ | + | | | | | | + | | | | | | + | | | | | | + +--|-|----------------+ | | + | | | | 500 + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | +--------------------------------|-+ + | | + +----------------------------------+ + 500 + */ +} + +TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child1 = LayerChromium::create(); + RefPtr<LayerChromium> child2 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> layer2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child1); + parent->addChild(child2); + child1->addChild(layer1); + child2->addChild(layer2); + + TransformationMatrix childTransform; + childTransform.translate(250, 250); + childTransform.rotate(90); + childTransform.translate(-250, -250); + + // The owning layers have very different bounds from the surfaces that they own. + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(child1.get(), childTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(10, 10), false); + setLayerPropertiesForTesting(layer1.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(-10, -10), IntSize(510, 510), true); + setLayerPropertiesForTesting(child2.get(), childTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(20, 40), IntSize(10, 10), false); + setLayerPropertiesForTesting(layer2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(-10, -10), IntSize(510, 510), true); + + // Make them both render surfaces + FilterOperations filters; + filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + child1->setFilters(filters); + child2->setFilters(filters); + + child1->setMasksToBounds(false); + child2->setMasksToBounds(false); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(child2->renderSurface()); + occlusion.markOccludedBehindLayer(layer2.get()); + + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-11, 420, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 419, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 71, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 81))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(-10, 420, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child2.get(), IntRect(30, 250, 1, 1))); + + occlusion.markOccludedBehindLayer(child2.get()); + occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + occlusion.enterTargetRenderSurface(child1->renderSurface()); + occlusion.markOccludedBehindLayer(layer1.get()); + + EXPECT_EQ_RECT(IntRect(20, 20, 80, 80), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(-10, 430, 80, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child1.get(), IntRect(-10, 430, 80, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-11, 430, 80, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-10, 429, 80, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-10, 430, 81, 70))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-10, 430, 80, 71))); + + // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface. + EXPECT_EQ_RECT(IntRect(-10, 430, 10, 80), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(-10, 430, 70, 80))); + EXPECT_TRUE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 430, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(-1, 430, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 429, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(1, 430, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 431, 70, 80))); + + occlusion.markOccludedBehindLayer(child1.get()); + occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(20, 20, 80, 80), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(20, 20, 80, 80), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(2u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 20, 80, 80))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 20, 70, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 20, 70, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 19, 70, 80))); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(20, 30, 80, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(19, 30, 80, 70))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 29, 80, 70))); + + // |child1| and |child2| both draw into parent so they should not occlude it. + EXPECT_EQ_RECT(IntRect(20, 20, 80, 80), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(20, 20, 80, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(50, 50, 1, 1))); + + + /* Justification for the above occlusion: + 100 + +---------------------+ + | 20 | layer1 + | 30+ ---------------------------------+ + 100 | 30| | layer2 | + |20+----------------------------------+ | + | | | | | | + | | | | | | + | | | | | | + +--|-|----------------+ | | + | | | | 510 + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | +--------------------------------|-+ + | | + +----------------------------------+ + 510 + */ +} + +TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child1 = LayerChromium::create(); + RefPtr<LayerChromium> child2 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> layer1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> layer2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(child1); + parent->addChild(child2); + child1->addChild(layer1); + child2->addChild(layer2); + + TransformationMatrix child1Transform; + child1Transform.translate(250, 250); + child1Transform.rotate(-90); + child1Transform.translate(-250, -250); + + TransformationMatrix child2Transform; + child2Transform.translate(250, 250); + child2Transform.rotate(90); + child2Transform.translate(-250, -250); + + // The owning layers have very different bounds from the surfaces that they own. + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(child1.get(), child1Transform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 20), IntSize(10, 10), false); + setLayerPropertiesForTesting(layer1.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(-10, -20), IntSize(510, 520), true); + setLayerPropertiesForTesting(child2.get(), child2Transform, identityMatrix, FloatPoint(0, 0), FloatPoint(20, 40), IntSize(10, 10), false); + setLayerPropertiesForTesting(layer2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(-10, -10), IntSize(510, 510), true); + + // Make them both render surfaces + FilterOperations filters; + filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + child1->setFilters(filters); + child2->setFilters(filters); + + child1->setMasksToBounds(false); + child2->setMasksToBounds(false); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + occlusion.enterTargetRenderSurface(child2->renderSurface()); + occlusion.markOccludedBehindLayer(layer2.get()); + + EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-11, 420, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 419, 70, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 71, 80))); + EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 81))); + + // Surface is not occluded by things that draw into itself. + EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(-10, 420, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child2.get(), IntRect(30, 250, 1, 1))); + + occlusion.markOccludedBehindLayer(child2.get()); + occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + occlusion.enterTargetRenderSurface(child1->renderSurface()); + occlusion.markOccludedBehindLayer(layer1.get()); + + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(420, -20, 80, 90), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(child1.get(), IntRect(420, -20, 80, 90))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(419, -20, 80, 90))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(420, -21, 80, 90))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(420, -19, 80, 90))); + EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(421, -20, 80, 90))); + + // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface. + EXPECT_EQ_RECT(IntRect(420, -20, 80, 90), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -20, 80, 90))); + EXPECT_EQ_RECT(IntRect(490, -10, 10, 80), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -10, 80, 80))); + EXPECT_EQ_RECT(IntRect(420, -20, 70, 10), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -20, 70, 90))); + EXPECT_TRUE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -10, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(419, -10, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -11, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(421, -10, 70, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -9, 70, 80))); + + occlusion.markOccludedBehindLayer(child1.get()); + occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface()); + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(10, 20, 90, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(9, 20, 90, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(10, 19, 90, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(11, 20, 90, 80))); + EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(10, 21, 90, 80))); + + // |child1| and |child2| both draw into parent so they should not occlude it. + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(10, 20, 90, 80))); + EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(10, 20, 1, 1))); + EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(99, 20, 1, 1))); + EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(10, 9, 1, 1))); + EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(99, 99, 1, 1))); + + + /* Justification for the above occlusion: + 100 + +---------------------+ + |20 | layer1 + 10+----------------------------------+ + 100 || 30 | layer2 | + |20+----------------------------------+ + || | | | | + || | | | | + || | | | | + +|-|------------------+ | | + | | | | 510 + | | 510 | | + | | | | + | | | | + | | | | + | | | | + | | 520 | | + +----------------------------------+ | + | | + +----------------------------------+ + 510 + */ +} + +TEST(CCOcclusionTrackerTest, occlusionInteractionWithFilters) +{ + // This tests that the right transforms are being used. + TestCCOcclusionTracker occlusion; + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> blurLayer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> opacityLayer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> opaqueLayer = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->createRenderSurface(); + parent->addChild(blurLayer); + parent->addChild(opacityLayer); + parent->addChild(opaqueLayer); + + 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(blurLayer.get(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(opaqueLayer.get(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + setLayerPropertiesForTesting(opacityLayer.get(), layerTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true); + + { + FilterOperations filters; + filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Percent), FilterOperation::BLUR)); + blurLayer->setFilters(filters); + } + + { + FilterOperations filters; + filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + opaqueLayer->setFilters(filters); + } + + { + FilterOperations filters; + filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); + opacityLayer->setFilters(filters); + } + + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + 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); + + // Opacity layer won't contribute to occlusion. + occlusion.enterTargetRenderSurface(opacityLayer->renderSurface()); + occlusion.markOccludedBehindLayer(opacityLayer.get()); + occlusion.finishedTargetRenderSurface(opacityLayer.get(), opacityLayer->renderSurface()); + + EXPECT_TRUE(occlusion.occlusionInScreenSpace().isEmpty()); + EXPECT_TRUE(occlusion.occlusionInTargetSurface().isEmpty()); + + // And has nothing to contribute to its parent surface. + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + EXPECT_TRUE(occlusion.occlusionInScreenSpace().isEmpty()); + EXPECT_TRUE(occlusion.occlusionInTargetSurface().isEmpty()); + + // Opaque layer will contribute to occlusion. + occlusion.enterTargetRenderSurface(opaqueLayer->renderSurface()); + occlusion.markOccludedBehindLayer(opaqueLayer.get()); + occlusion.finishedTargetRenderSurface(opaqueLayer.get(), opaqueLayer->renderSurface()); + + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(0, 430, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + // And it gets translated to the parent surface. + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); + + // The blur layer needs to throw away any occlusion from outside its subtree. + occlusion.enterTargetRenderSurface(blurLayer->renderSurface()); + EXPECT_TRUE(occlusion.occlusionInScreenSpace().isEmpty()); + EXPECT_TRUE(occlusion.occlusionInTargetSurface().isEmpty()); + + // And it won't contribute to occlusion. + occlusion.markOccludedBehindLayer(blurLayer.get()); + occlusion.finishedTargetRenderSurface(blurLayer.get(), blurLayer->renderSurface()); + EXPECT_TRUE(occlusion.occlusionInScreenSpace().isEmpty()); + EXPECT_TRUE(occlusion.occlusionInTargetSurface().isEmpty()); + + // But the opaque layer's occlusion is preserved on the parent. + occlusion.leaveToTargetRenderSurface(parent->renderSurface()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size()); + EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInTargetSurface().bounds()); + EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size()); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp b/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp index 299e5c7e5..d49703e14 100644 --- a/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp +++ b/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp @@ -79,7 +79,7 @@ TEST(CCQuadCullerTest, verifyCullChildLinesUpTopLeft) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 9u); } @@ -92,7 +92,7 @@ TEST(CCQuadCullerTest, verifyCullWhenChildOpacityNotOne) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 13u); } @@ -105,7 +105,7 @@ TEST(CCQuadCullerTest, verifyCullWhenChildOpaqueFlagFalse) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 13u); } @@ -120,7 +120,7 @@ TEST(CCQuadCullerTest, verifyCullCenterTileOnly) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 12u); IntRect quadVisibleRect1 = quadList[1].get()->quadVisibleRect(); @@ -158,7 +158,7 @@ TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize1) quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100)))); EXPECT_EQ(quadList.size(), 2u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 2u); } @@ -181,7 +181,7 @@ TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize2) quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100)))); EXPECT_EQ(quadList.size(), 2u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 2u); } @@ -196,7 +196,7 @@ TEST(CCQuadCullerTest, verifyCullChildLinesUpBottomRight) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 9u); } @@ -212,7 +212,7 @@ TEST(CCQuadCullerTest, verifyCullSubRegion) setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 12u); } @@ -228,7 +228,7 @@ TEST(CCQuadCullerTest, verifyCullSubRegion2) setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 12u); } @@ -244,7 +244,7 @@ TEST(CCQuadCullerTest, verifyCullSubRegionCheckOvercull) setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 13u); } @@ -260,7 +260,7 @@ TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsDontOcclude) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 13u); } @@ -282,8 +282,61 @@ TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsSafelyCulled) setQuads(rootState.get(), childState.get(), quadList); EXPECT_EQ(quadList.size(), 13u); - CCQuadCuller::cullOccludedQuads(quadList); + CCQuadCuller::cullOccludedQuads(quadList, false, IntRect()); EXPECT_EQ(quadList.size(), 12u); } +TEST(CCQuadCullerTest, veriftyCullOutsideScissorOverTile) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + setQuads(rootState.get(), childState.get(), quadList); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(200, 100, 100, 100)); + EXPECT_EQ(quadList.size(), 1u); +} + +TEST(CCQuadCullerTest, veriftyCullOutsideScissorOverCulledTile) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + setQuads(rootState.get(), childState.get(), quadList); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(100, 100, 100, 100)); + EXPECT_EQ(quadList.size(), 1u); +} + +TEST(CCQuadCullerTest, veriftyCullOutsideScissorOverPartialTiles) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + setQuads(rootState.get(), childState.get(), quadList); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(50, 50, 200, 200)); + EXPECT_EQ(quadList.size(), 9u); +} + +TEST(CCQuadCullerTest, veriftyCullOutsideScissorOverNoTiles) +{ + DECLARE_AND_INITIALIZE_TEST_QUADS + + OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true); + OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true); + + setQuads(rootState.get(), childState.get(), quadList); + EXPECT_EQ(quadList.size(), 13u); + CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(500, 500, 100, 100)); + EXPECT_EQ(quadList.size(), 0u); +} + + } // namespace diff --git a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp index 4b3dd27d3..ec0ce0c6a 100644 --- a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp @@ -79,8 +79,8 @@ protected: { GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> mainContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); - RefPtr<GraphicsContext3D> implContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> mainContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), GraphicsContext3D::RenderDirectlyToHostWindow); + RefPtr<GraphicsContext3D> implContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), GraphicsContext3D::RenderDirectlyToHostWindow); MockCanvasContext& mainMock = *static_cast<MockCanvasContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(mainContext.get())); MockCanvasContext& implMock = *static_cast<MockCanvasContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(implContext.get())); diff --git a/Source/WebKit/chromium/tests/CompositorFakeGraphicsContext3D.h b/Source/WebKit/chromium/tests/CompositorFakeGraphicsContext3D.h index 1f0897341..937b62d4c 100644 --- a/Source/WebKit/chromium/tests/CompositorFakeGraphicsContext3D.h +++ b/Source/WebKit/chromium/tests/CompositorFakeGraphicsContext3D.h @@ -37,10 +37,7 @@ static PassRefPtr<GraphicsContext3D> createCompositorMockGraphicsContext3D(Graph webAttrs.alpha = attrs.alpha; OwnPtr<WebKit::WebGraphicsContext3D> webContext = WebKit::CompositorFakeWebGraphicsContext3D::create(webAttrs); - return GraphicsContext3DPrivate::createGraphicsContextFromWebContext( - webContext.release(), attrs, 0, - GraphicsContext3D::RenderDirectlyToHostWindow, - GraphicsContext3DPrivate::ForUseOnAnotherThread); + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow); } } diff --git a/Source/WebKit/chromium/tests/FakeGraphicsContext3DTest.cpp b/Source/WebKit/chromium/tests/FakeGraphicsContext3DTest.cpp index 2b76b80ad..71cb8bab1 100644 --- a/Source/WebKit/chromium/tests/FakeGraphicsContext3DTest.cpp +++ b/Source/WebKit/chromium/tests/FakeGraphicsContext3DTest.cpp @@ -52,7 +52,7 @@ private: TEST(FakeGraphicsContext3DTest, CanOverrideManually) { GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FrameCountingContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FrameCountingContext()), GraphicsContext3D::RenderDirectlyToHostWindow); FrameCountingContext& mockContext = *static_cast<FrameCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get())); for (int i = 0; i < 10; i++) { @@ -73,7 +73,7 @@ public: TEST(FakeGraphicsContext3DTest, CanUseGMock) { GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new GMockContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new GMockContext()), GraphicsContext3D::RenderDirectlyToHostWindow); GMockContext& mockContext = *static_cast<GMockContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get())); EXPECT_CALL(mockContext, getError()) @@ -104,7 +104,7 @@ private: TEST(FakeGraphicsContext3DTest, ContextForThisThreadShouldNotMakeCurrent) { GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatCountsMakeCurrents()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatCountsMakeCurrents()), GraphicsContext3D::RenderDirectlyToHostWindow); EXPECT_TRUE(context); ContextThatCountsMakeCurrents& mockContext = *static_cast<ContextThatCountsMakeCurrents*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get())); EXPECT_EQ(0, mockContext.makeCurrentCount()); @@ -113,7 +113,7 @@ TEST(FakeGraphicsContext3DTest, ContextForThisThreadShouldNotMakeCurrent) TEST(FakeGraphicsContext3DTest, ContextForAnotherThreadShouldNotMakeCurrent) { GraphicsContext3D::Attributes attrs; - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatCountsMakeCurrents()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnAnotherThread); + RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatCountsMakeCurrents()), GraphicsContext3D::RenderDirectlyToHostWindow); EXPECT_TRUE(context); ContextThatCountsMakeCurrents& mockContext = *static_cast<ContextThatCountsMakeCurrents*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get())); EXPECT_EQ(0, mockContext.makeCurrentCount()); diff --git a/Source/WebKit/chromium/tests/FakeWebGraphicsContext3D.h b/Source/WebKit/chromium/tests/FakeWebGraphicsContext3D.h index cf0651b77..ae27da730 100644 --- a/Source/WebKit/chromium/tests/FakeWebGraphicsContext3D.h +++ b/Source/WebKit/chromium/tests/FakeWebGraphicsContext3D.h @@ -65,6 +65,8 @@ public: virtual void setVisibilityCHROMIUM(bool visible) { } + virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { } + virtual WebString getRequestableExtensionsCHROMIUM() { return WebString(); } virtual void requestExtensionCHROMIUM(const char*) { } diff --git a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp index 43083a1d7..2e9ca9661 100644 --- a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp @@ -515,6 +515,7 @@ TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior) EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setReplicaLayer(dummyLayer.get())); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setSublayerTransform(TransformationMatrix(0, 0, 0, 0, 0, 0))); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setScrollable(true)); + EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setHaveWheelEventHandlers(true)); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setScrollPosition(IntPoint(10, 10))); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setTransform(TransformationMatrix(0, 0, 0, 0, 0, 0))); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDoubleSided(false)); @@ -539,10 +540,21 @@ public: return true; } + virtual void setNeedsDisplayRect(const FloatRect& dirtyRect) + { + m_lastNeedsDisplayRect = dirtyRect; + LayerChromium::setNeedsDisplayRect(dirtyRect); + } + void resetNeedsDisplay() { m_needsDisplay = false; } + + const FloatRect& lastNeedsDisplayRect() const { return m_lastNeedsDisplayRect; } + +private: + FloatRect m_lastNeedsDisplayRect; }; TEST_F(LayerChromiumTest, checkContentsScaleChangeTriggersNeedsDisplay) @@ -558,6 +570,7 @@ TEST_F(LayerChromiumTest, checkContentsScaleChangeTriggersNeedsDisplay) EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setContentsScale(testLayer->contentsScale() + 1.f)); EXPECT_TRUE(testLayer->needsDisplay()); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 320, 240), testLayer->lastNeedsDisplayRect()); } class FakeCCLayerTreeHost : public CCLayerTreeHost { diff --git a/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp index 924b42d28..d097c499a 100644 --- a/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp +++ b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp @@ -163,6 +163,30 @@ TEST(PlatformContextSkiaTest, trackOpaqueClipTest) context.clearRect(FloatRect(10, 10, 90, 90)); EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect()); + // The transform and the clip need to interact correctly (transform first) + context.save(); + context.translate(10, 10); + context.clip(FloatRect(20, 20, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 10, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect()); + + // The transform and the clip need to interact correctly (clip first) + context.save(); + context.clip(FloatRect(20, 20, 10, 10)); + context.translate(10, 10); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), platformContext.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect()); + Path path; path.moveTo(FloatPoint(0, 0)); path.addLineTo(FloatPoint(100, 0)); diff --git a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp index fcd3878a6..e03559046 100644 --- a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp @@ -162,6 +162,14 @@ public: return TiledLayerChromium::skipsDraw(); } + virtual void setNeedsDisplayRect(const FloatRect& rect) + { + m_lastNeedsDisplayRect = rect; + TiledLayerChromium::setNeedsDisplayRect(rect); + } + + const FloatRect& lastNeedsDisplayRect() const { return m_lastNeedsDisplayRect; } + FakeLayerTextureUpdater* fakeLayerTextureUpdater() { return m_fakeTextureUpdater.get(); } virtual TextureManager* textureManager() const { return m_textureManager; } @@ -181,6 +189,7 @@ private: RefPtr<FakeLayerTextureUpdater> m_fakeTextureUpdater; TextureManager* m_textureManager; + FloatRect m_lastNeedsDisplayRect; }; class FakeTiledLayerWithScaledBounds : public FakeTiledLayerChromium { @@ -434,6 +443,57 @@ TEST(TiledLayerChromiumTest, verifyUpdateRectWhenContentBoundsAreScaled) EXPECT_FLOAT_RECT_EQ(FloatRect(45, 80, 15, 8), layer->updateRect()); } +TEST(TiledLayerChromiumTest, verifyInvalidationWhenContentsScaleChanges) +{ + 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); + + // Create a layer with one tile. + layer->setBounds(IntSize(100, 100)); + + // Invalidate the entire layer. + layer->setNeedsDisplay(); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 100, 100), layer->lastNeedsDisplayRect()); + + // Push the tiles to the impl side and check that there is exactly one. + layer->prepareToUpdate(IntRect(0, 0, 100, 100)); + layer->updateCompositorResources(0, updater); + layer->pushPropertiesTo(layerImpl.get()); + EXPECT_TRUE(layerImpl->hasTileAt(0, 0)); + EXPECT_FALSE(layerImpl->hasTileAt(0, 1)); + EXPECT_FALSE(layerImpl->hasTileAt(1, 0)); + EXPECT_FALSE(layerImpl->hasTileAt(1, 1)); + + // Change the contents scale and verify that the content rectangle requiring painting + // is not scaled. + layer->setContentsScale(2); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 100, 100), layer->lastNeedsDisplayRect()); + + // The impl side should get 2x2 tiles now. + layer->prepareToUpdate(IntRect(0, 0, 200, 200)); + layer->updateCompositorResources(0, updater); + layer->pushPropertiesTo(layerImpl.get()); + EXPECT_TRUE(layerImpl->hasTileAt(0, 0)); + EXPECT_TRUE(layerImpl->hasTileAt(0, 1)); + EXPECT_TRUE(layerImpl->hasTileAt(1, 0)); + EXPECT_TRUE(layerImpl->hasTileAt(1, 1)); + + // Invalidate the entire layer again, but do not paint. All tiles should be gone now from the + // impl side. + layer->setNeedsDisplay(); + layer->updateCompositorResources(0, updater); + layer->pushPropertiesTo(layerImpl.get()); + EXPECT_FALSE(layerImpl->hasTileAt(0, 0)); + EXPECT_FALSE(layerImpl->hasTileAt(0, 1)); + EXPECT_FALSE(layerImpl->hasTileAt(1, 0)); + EXPECT_FALSE(layerImpl->hasTileAt(1, 1)); +} + TEST(TiledLayerChromiumTest, skipsDrawGetsReset) { // Initialize without threading support. @@ -524,7 +584,7 @@ TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion) occluded = Region(); layer->addSelfToOccludedScreenSpace(occluded); EXPECT_EQ_RECT(IntRect(), occluded.bounds()); - EXPECT_EQ(1u, occluded.rects().size()); + EXPECT_EQ(0u, 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); @@ -546,6 +606,28 @@ TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion) EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); EXPECT_EQ(1u, occluded.rects().size()); + // If we repaint a non-opaque part of the tile, then it shouldn't lose its opaque-ness. And other tiles should + // not be affected. + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect()); + layer->invalidateRect(IntRect(0, 0, 1, 1)); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If we repaint an opaque part of the tile, then it should lose its opaque-ness. But other tiles should still + // not be affected. + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect()); + layer->invalidateRect(IntRect(10, 10, 1, 1)); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(IntRect(10, 100, 90, 100), 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); @@ -556,6 +638,8 @@ TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion) screenSpaceTransform *= transform; screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); layer->setScreenSpaceTransform(screenSpaceTransform); + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect); + layer->invalidateRect(opaquePaintRect); layer->prepareToUpdate(contentBounds); occluded = Region(); diff --git a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp index 1557a7d93..4724b4a43 100644 --- a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp +++ b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp @@ -26,13 +26,16 @@ #include "TreeSynchronizer.h" +#include "CCAnimationTestCommon.h" #include "LayerChromium.h" +#include "cc/CCLayerAnimationController.h" #include "cc/CCLayerImpl.h" #include "cc/CCProxy.h" #include "cc/CCSingleThreadProxy.h" #include <gtest/gtest.h> using namespace WebCore; +using namespace WebKitTests; namespace { @@ -91,6 +94,30 @@ private: Vector<int>* m_ccLayerDestructionList; }; +class FakeLayerAnimationController : public CCLayerAnimationController { +public: + static PassOwnPtr<FakeLayerAnimationController> create() + { + return adoptPtr(new FakeLayerAnimationController); + } + + bool synchronizedAnimations() const { return m_synchronizedAnimations; } + +private: + FakeLayerAnimationController() + : m_synchronizedAnimations(false) + { + } + + virtual void synchronizeAnimations(CCLayerAnimationControllerImpl* controllerImpl) + { + CCLayerAnimationController::synchronizeAnimations(controllerImpl); + m_synchronizedAnimations = true; + } + + bool m_synchronizedAnimations; +}; + void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer) { ASSERT_TRUE(layer); @@ -307,5 +334,19 @@ TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers) expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get()); } +TEST(TreeSynchronizerTest, synchronizeAnimations) +{ + DebugScopedSetImplThread impl; + RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create(); + + layerTreeRoot->setLayerAnimationController(FakeLayerAnimationController::create()); + + EXPECT_FALSE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations()); + + RefPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), 0); + ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.get()); + + EXPECT_TRUE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations()); +} } // namespace diff --git a/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp b/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp index ad5810524..459255e02 100644 --- a/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp +++ b/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp @@ -67,14 +67,13 @@ public: private: virtual void setNeedsRedraw() OVERRIDE { } - virtual ScrollStatus scrollBegin(const WebCore::IntPoint&) OVERRIDE + virtual ScrollStatus scrollBegin(const WebCore::IntPoint&, WebCore::CCInputHandlerClient::ScrollInputType) OVERRIDE { return m_scrollStatus; } virtual void scrollBy(const WebCore::IntSize&) OVERRIDE { } virtual void scrollEnd() OVERRIDE { } - virtual bool haveWheelEventHandlers() OVERRIDE { return false; } virtual void pinchGestureBegin() OVERRIDE { m_pinchStarted = true; diff --git a/Source/WebKit/chromium/tests/WebFrameTest.cpp b/Source/WebKit/chromium/tests/WebFrameTest.cpp index b59001860..f61e98648 100644 --- a/Source/WebKit/chromium/tests/WebFrameTest.cpp +++ b/Source/WebKit/chromium/tests/WebFrameTest.cpp @@ -151,6 +151,78 @@ TEST_F(WebFrameTest, ChromePageNoJavascript) EXPECT_EQ(std::string::npos, content.find("Clobbered")); } +#if ENABLE(GESTURE_EVENTS) +TEST_F(WebFrameTest, DivAutoZoomParamsTest) +{ + registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html"); + + WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html", true)); + int pageWidth = 640; + int pageHeight = 480; + int divPosX = 200; + int divPosY = 200; + int divWidth = 200; + int divHeight = 150; + WebRect doubleTapPoint(250, 250, 0, 0); + webViewImpl->resize(WebSize(pageWidth, pageHeight)); + float scale; + WebPoint scroll; + + // Test for Doubletap scaling + + // Tests for zooming in and out without clamping. + // Set device scale and scale limits so we dont get clamped. + webViewImpl->setDeviceScaleFactor(4); + webViewImpl->setPageScaleFactorLimits(0, 4 / webViewImpl->deviceScaleFactor()); + + // Test zooming into div. + webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll); + float scaledDivWidth = divWidth * scale; + float scaledDivHeight = divHeight * scale; + int hScroll = ((divPosX * scale) - ((pageWidth - scaledDivWidth) / 2)) / scale; + int vScroll = ((divPosY * scale) - ((pageHeight - scaledDivHeight) / 2)) / scale; + EXPECT_NEAR(pageWidth / divWidth, scale, 0.1); + EXPECT_EQ(hScroll, scroll.x); + EXPECT_EQ(vScroll, scroll.y); + + // Test zoom out to overview scale. + webViewImpl->applyScrollAndScale(WebCore::IntSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor()); + webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll); + EXPECT_FLOAT_EQ(1, scale); + EXPECT_EQ(WebPoint(0, 0), scroll); + + // Tests for clamped scaling. + // Test clamp to device scale: + webViewImpl->applyScrollAndScale(WebCore::IntSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor()); + webViewImpl->setDeviceScaleFactor(2.5); + webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll); + EXPECT_FLOAT_EQ(2.5, scale); + + // Test clamp to minimum scale: + webViewImpl->applyScrollAndScale(WebCore::IntSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor()); + webViewImpl->setPageScaleFactorLimits(1.5 / webViewImpl->deviceScaleFactor(), 4 / webViewImpl->deviceScaleFactor()); + webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll); + EXPECT_FLOAT_EQ(1.5, scale); + EXPECT_EQ(WebPoint(0, 0), scroll); + + // Test clamp to maximum scale: + webViewImpl->applyScrollAndScale(WebCore::IntSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor()); + webViewImpl->setDeviceScaleFactor(4); + webViewImpl->setPageScaleFactorLimits(0, 3 / webViewImpl->deviceScaleFactor()); + webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll); + EXPECT_FLOAT_EQ(3, scale); + + + // Test for Non-doubletap scaling + webViewImpl->setPageScaleFactor(1, WebPoint(0, 0)); + webViewImpl->setDeviceScaleFactor(4); + webViewImpl->setPageScaleFactorLimits(0, 4 / webViewImpl->deviceScaleFactor()); + // Test zooming into div. + webViewImpl->computeScaleAndScrollForHitRect(WebRect(250, 250, 10, 10), WebViewImpl::FindInPage, scale, scroll); + EXPECT_NEAR(pageWidth / divWidth, scale, 0.1); +} +#endif + class TestReloadDoesntRedirectWebFrameClient : public WebFrameClient { public: virtual WebNavigationPolicy decidePolicyForNavigation( diff --git a/Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp b/Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp new file mode 100644 index 000000000..423a5969f --- /dev/null +++ b/Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#include "config.h" + +#include "WebSocketDeflater.h" + +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +using namespace WebCore; + +namespace { + +TEST(WebSocketDeflaterTest, TestCompressHello) +{ + // Test the first example on section 4.3 of the specification. + OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15); + ASSERT_TRUE(deflater->initialize()); + OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(); + ASSERT_TRUE(inflater->initialize()); + const char* inputData = "Hello"; + const size_t inputLength = strlen(inputData); + + ASSERT_TRUE(deflater->addBytes(inputData, inputLength)); + ASSERT_TRUE(deflater->finish()); + const char expectedFirst[] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00}; + EXPECT_EQ(sizeof(expectedFirst), deflater->size()); + EXPECT_EQ(0, memcmp(expectedFirst, deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputLength, inflater->size()); + EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size())); + + deflater->reset(); + inflater->reset(); + + ASSERT_TRUE(deflater->addBytes(inputData, inputLength)); + ASSERT_TRUE(deflater->finish()); + const char expectedSecond[] = {0xf2, 0x00, 0x11, 0x00, 0x00}; + EXPECT_EQ(sizeof(expectedSecond), deflater->size()); + EXPECT_EQ(0, memcmp(expectedSecond, deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputLength, inflater->size()); + EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size())); +} + +TEST(WebSocketDeflaterTest, TestMultipleAddBytesCalls) +{ + OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15); + ASSERT_TRUE(deflater->initialize()); + OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(); + ASSERT_TRUE(inflater->initialize()); + Vector<char> inputData(32); + inputData.fill('a'); + + for (size_t i = 0; i < inputData.size(); ++i) + ASSERT_TRUE(deflater->addBytes(inputData.data() + i, 1)); + ASSERT_TRUE(deflater->finish()); + for (size_t i = 0; i < deflater->size(); ++i) + ASSERT_TRUE(inflater->addBytes(deflater->data() + i, 1)); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputData.size(), inflater->size()); + EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size())); +} + +TEST(WebSocketDeflaterTest, TestNoContextTakeOver) +{ + OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15, WebSocketDeflater::DoNotTakeOverContext); + ASSERT_TRUE(deflater->initialize()); + OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(); + ASSERT_TRUE(inflater->initialize()); + const char expected[] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00}; + const char* inputData = "Hello"; + const size_t inputLength = strlen(inputData); + + // If we don't take over context, the second result should be the identical + // with the first one. + for (size_t i = 0; i < 2; ++i) { + ASSERT_TRUE(deflater->addBytes(inputData, inputLength)); + ASSERT_TRUE(deflater->finish()); + EXPECT_EQ(sizeof(expected), deflater->size()); + EXPECT_EQ(0, memcmp(expected, deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputLength, inflater->size()); + EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size())); + deflater->reset(); + inflater->reset(); + } +} + +TEST(WebSocketDeflaterTest, TestWindowBits) +{ + Vector<char> inputData(1024 + 64 * 2); + inputData.fill('a'); + // Modify the head and tail of the inputData so that back-reference + // can be used if the window size is sufficiently-large. + for (size_t j = 0; j < 64; ++j) { + inputData[j] = 'b'; + inputData[inputData.size() - j - 1] = 'b'; + } + + OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(8); + ASSERT_TRUE(deflater->initialize()); + ASSERT_TRUE(deflater->addBytes(inputData.data(), inputData.size())); + ASSERT_TRUE(deflater->finish()); + + OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(8); + ASSERT_TRUE(inflater->initialize()); + ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputData.size(), inflater->size()); + EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size())); +} + +TEST(WebSocketDeflaterTest, TestLargeData) +{ + OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15); + ASSERT_TRUE(deflater->initialize()); + OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(); + ASSERT_TRUE(inflater->initialize()); + Vector<char> inputData(16 * 1024 * 1024); + inputData.fill('a'); + + ASSERT_TRUE(deflater->addBytes(inputData.data(), inputData.size())); + ASSERT_TRUE(deflater->finish()); + ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size())); + ASSERT_TRUE(inflater->finish()); + EXPECT_EQ(inputData.size(), inflater->size()); + EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size())); +} + +} diff --git a/Source/WebKit/chromium/tests/WebSocketExtensionDispatcherTest.cpp b/Source/WebKit/chromium/tests/WebSocketExtensionDispatcherTest.cpp new file mode 100644 index 000000000..358983b83 --- /dev/null +++ b/Source/WebKit/chromium/tests/WebSocketExtensionDispatcherTest.cpp @@ -0,0 +1,179 @@ +/* + * 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. + */ + +#include "config.h" + +#include "WebSocketExtensionDispatcher.h" + +#include "WebSocketExtensionProcessor.h" + +#include <gtest/gtest.h> +#include <wtf/text/StringHash.h> + +using namespace WebCore; + +namespace { + +class WebSocketExtensionDispatcherTest; + +class MockWebSocketExtensionProcessor : public WebSocketExtensionProcessor { +public: + MockWebSocketExtensionProcessor(const String& name, WebSocketExtensionDispatcherTest* test) + : WebSocketExtensionProcessor(name) + , m_test(test) + { + } + virtual String handshakeString() OVERRIDE { return extensionToken(); } + virtual bool processResponse(const HashMap<String, String>&) OVERRIDE; + +private: + WebSocketExtensionDispatcherTest* m_test; +}; + +class WebSocketExtensionDispatcherTest : public testing::Test { +public: + WebSocketExtensionDispatcherTest() { } + + void SetUp() { } + + void TearDown() { } + + void addMockProcessor(const String& extensionToken) + { + m_extensions.addProcessor(adoptPtr(new MockWebSocketExtensionProcessor(extensionToken, this))); + + } + + void appendResult(const String& extensionToken, const HashMap<String, String>& parameters) + { + m_parsedExtensionTokens.append(extensionToken); + m_parsedParameters.append(parameters); + } + +protected: + WebSocketExtensionDispatcher m_extensions; + Vector<String> m_parsedExtensionTokens; + Vector<HashMap<String, String> > m_parsedParameters; +}; + +bool MockWebSocketExtensionProcessor::processResponse(const HashMap<String, String>& parameters) +{ + m_test->appendResult(extensionToken(), parameters); + return true; +} + +TEST_F(WebSocketExtensionDispatcherTest, TestSingle) +{ + addMockProcessor("deflate-frame"); + EXPECT_TRUE(m_extensions.processHeaderValue("deflate-frame")); + EXPECT_EQ(1UL, m_parsedExtensionTokens.size()); + EXPECT_EQ("deflate-frame", m_parsedExtensionTokens[0]); + EXPECT_EQ("deflate-frame", m_extensions.acceptedExtensions()); + EXPECT_EQ(0, m_parsedParameters[0].size()); +} + +TEST_F(WebSocketExtensionDispatcherTest, TestParameters) +{ + addMockProcessor("mux"); + EXPECT_TRUE(m_extensions.processHeaderValue("mux; max-channels=4; flow-control ")); + EXPECT_EQ(1UL, m_parsedExtensionTokens.size()); + EXPECT_EQ("mux", m_parsedExtensionTokens[0]); + EXPECT_EQ(2, m_parsedParameters[0].size()); + HashMap<String, String>::iterator parameter = m_parsedParameters[0].find("max-channels"); + EXPECT_TRUE(parameter != m_parsedParameters[0].end()); + EXPECT_EQ("4", parameter->second); + parameter = m_parsedParameters[0].find("flow-control"); + EXPECT_TRUE(parameter != m_parsedParameters[0].end()); + EXPECT_TRUE(parameter->second.isNull()); +} + +TEST_F(WebSocketExtensionDispatcherTest, TestMultiple) +{ + struct { + String token; + HashMap<String, String> parameters; + } expected[2]; + expected[0].token = "mux"; + expected[0].parameters.add("max-channels", "4"); + expected[0].parameters.add("flow-control", String()); + expected[1].token = "deflate-frame"; + + addMockProcessor("mux"); + addMockProcessor("deflate-frame"); + EXPECT_TRUE(m_extensions.processHeaderValue("mux ; max-channels =4;flow-control, deflate-frame ")); + EXPECT_TRUE(m_extensions.acceptedExtensions().find("mux") != notFound); + EXPECT_TRUE(m_extensions.acceptedExtensions().find("deflate-frame") != notFound); + for (size_t i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) { + EXPECT_EQ(expected[i].token, m_parsedExtensionTokens[i]); + const HashMap<String, String>& expectedParameters = expected[i].parameters; + const HashMap<String, String>& parsedParameters = m_parsedParameters[i]; + EXPECT_EQ(expected[i].parameters.size(), m_parsedParameters[i].size()); + for (HashMap<String, String>::const_iterator iterator = expectedParameters.begin(); iterator != expectedParameters.end(); ++iterator) { + HashMap<String, String>::const_iterator parsed = parsedParameters.find(iterator->first); + EXPECT_TRUE(parsed != parsedParameters.end()); + if (iterator->second.isNull()) + EXPECT_TRUE(parsed->second.isNull()); + else + EXPECT_EQ(iterator->second, parsed->second); + } + } +} + +TEST_F(WebSocketExtensionDispatcherTest, TestQuotedString) +{ + addMockProcessor("x-foo"); + EXPECT_TRUE(m_extensions.processHeaderValue("x-foo; param1=\"quoted string\"; param2=\"\\\"quoted\\\" string\\\\\"")); + EXPECT_EQ(2, m_parsedParameters[0].size()); + EXPECT_EQ("quoted string", m_parsedParameters[0].get("param1")); + EXPECT_EQ("\"quoted\" string\\", m_parsedParameters[0].get("param2")); +} + +TEST_F(WebSocketExtensionDispatcherTest, TestInvalid) +{ + const char* inputs[] = { + "\"x-foo\"", + "x-baz", + "x-foo\\", + "x-(foo)", + "x-foo; ", + "x-foo; bar=", + "x-foo; bar=x y", + "x-foo; bar=\"mismatch quote", + "x-foo; bar=\"\\\"", + "x-foo; \"bar\"=baz", + "x-foo x-bar", + "x-foo, x-baz" + "x-foo, ", + }; + for (size_t i = 0; i < sizeof(inputs) / sizeof(inputs[0]); ++i) { + m_extensions.reset(); + addMockProcessor("x-foo"); + addMockProcessor("x-bar"); + EXPECT_FALSE(m_extensions.processHeaderValue(inputs[i])); + EXPECT_TRUE(m_extensions.acceptedExtensions().isNull()); + } +} + +} diff --git a/Source/WebKit/chromium/tests/WebURLResponseTest.cpp b/Source/WebKit/chromium/tests/WebURLResponseTest.cpp new file mode 100644 index 000000000..112ed8601 --- /dev/null +++ b/Source/WebKit/chromium/tests/WebURLResponseTest.cpp @@ -0,0 +1,78 @@ +/* + * 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: + * + * * 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 "platform/WebURLResponse.h" + +#include <gtest/gtest.h> + +using namespace WebKit; + +namespace { + +class TestExtraData : public WebURLResponse::ExtraData { +public: + explicit TestExtraData(bool* alive) + : m_alive(alive) + { + *alive = true; + } + + virtual ~TestExtraData() { *m_alive = false; } + +private: + bool* m_alive; +}; + +TEST(WebURLResponseTest, ExtraData) +{ + bool alive = false; + { + WebURLResponse urlResponse; + TestExtraData* extraData = new TestExtraData(&alive); + EXPECT_TRUE(alive); + + urlResponse.initialize(); + urlResponse.setExtraData(extraData); + EXPECT_EQ(extraData, urlResponse.extraData()); + { + WebURLResponse otherUrlResponse = urlResponse; + EXPECT_TRUE(alive); + EXPECT_EQ(extraData, otherUrlResponse.extraData()); + EXPECT_EQ(extraData, urlResponse.extraData()); + } + EXPECT_TRUE(alive); + EXPECT_EQ(extraData, urlResponse.extraData()); + } + EXPECT_FALSE(alive); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/data/get_scale_for_auto_zoom_into_div_test.html b/Source/WebKit/chromium/tests/data/get_scale_for_auto_zoom_into_div_test.html new file mode 100644 index 000000000..1817dc47d --- /dev/null +++ b/Source/WebKit/chromium/tests/data/get_scale_for_auto_zoom_into_div_test.html @@ -0,0 +1,13 @@ +<html> + <body> + <div style="background-color: green; position: absolute; left: 0px; top: 0px; width: 640px; height: 480px"> + <p>Top Div</p> + <div style="background-color: white; position: absolute; left: 200px; top: 200px; width: 200px; height: 150px"> + <p id="innerDiv">Div to zoom to</p> + <div style="background-color: red; position: fixed; left: 220px; top: 350px; width: 160px; height: 40px"> + <p id="innerInnerDiv">Div NOT to zoom to</p> + </div> + </div> + </div> + </body> +</html> |
