summaryrefslogtreecommitdiff
path: root/Source/WebKit/chromium/tests
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
commit49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch)
tree5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/WebKit/chromium/tests
parentb211c645d8ab690f713515dfdc84d80b11c27d2c (diff)
downloadqtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/WebKit/chromium/tests')
-rw-r--r--Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp30
-rw-r--r--Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp43
-rw-r--r--Source/WebKit/chromium/tests/CCAnimationTestCommon.h4
-rw-r--r--Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp136
-rw-r--r--Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp95
-rw-r--r--Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp243
-rw-r--r--Source/WebKit/chromium/tests/CCLayerImplTest.cpp24
-rw-r--r--Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp35
-rw-r--r--Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp2025
-rw-r--r--Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp1787
-rw-r--r--Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp929
-rw-r--r--Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp15
-rw-r--r--Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp3
-rw-r--r--Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp42
-rw-r--r--Source/WebKit/chromium/tests/CCSingleThreadProxyTest.cpp133
-rw-r--r--Source/WebKit/chromium/tests/CCTestCommon.h42
-rw-r--r--Source/WebKit/chromium/tests/CCThreadedTest.cpp651
-rw-r--r--Source/WebKit/chromium/tests/CCThreadedTest.h226
-rw-r--r--Source/WebKit/chromium/tests/CCTiledLayerTestCommon.cpp4
-rw-r--r--Source/WebKit/chromium/tests/CCTiledLayerTestCommon.h17
-rw-r--r--Source/WebKit/chromium/tests/Canvas2DLayerBridgeTest.cpp163
-rw-r--r--Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp205
-rw-r--r--Source/WebKit/chromium/tests/DecimalTest.cpp76
-rwxr-xr-xSource/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h2
-rw-r--r--Source/WebKit/chromium/tests/FrameLoaderClientImplTest.cpp7
-rw-r--r--Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp366
-rw-r--r--Source/WebKit/chromium/tests/IDBDatabaseBackendTest.cpp72
-rw-r--r--Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp7
-rw-r--r--Source/WebKit/chromium/tests/LayerChromiumTest.cpp13
-rw-r--r--Source/WebKit/chromium/tests/LayerRendererChromiumTest.cpp128
-rw-r--r--Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp267
-rw-r--r--Source/WebKit/chromium/tests/OpaqueRectTrackingContentLayerDelegateTest.cpp195
-rw-r--r--Source/WebKit/chromium/tests/ScrollAnimatorNoneTest.cpp8
-rw-r--r--Source/WebKit/chromium/tests/ScrollbarLayerChromiumTest.cpp4
-rw-r--r--Source/WebKit/chromium/tests/TextureCopierTest.cpp3
-rw-r--r--Source/WebKit/chromium/tests/TextureLayerChromiumTest.cpp2
-rw-r--r--Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp17
-rw-r--r--Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp99
-rw-r--r--Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp12
-rw-r--r--Source/WebKit/chromium/tests/WebFrameTest.cpp26
-rw-r--r--Source/WebKit/chromium/tests/WebLayerTest.cpp6
-rw-r--r--Source/WebKit/chromium/tests/data/iframe_redirect.html10
42 files changed, 6381 insertions, 1791 deletions
diff --git a/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp b/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp
index bdf3a3ab4..03559f7f1 100644
--- a/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp
+++ b/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp
@@ -585,4 +585,34 @@ TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting)
EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true));
}
+// Test that the loader can allow non-whitelisted response headers for trusted CORS loads.
+TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderAllowResponseHeaders)
+{
+ WebURLRequest request;
+ request.initialize();
+ GURL url = GURL("http://www.other.com/CrossOriginHeaderAllowResponseHeaders.html");
+ request.setURL(url);
+
+ WebString headerNameString(WebString::fromUTF8("non-whitelisted"));
+ m_expectedResponse = WebURLResponse();
+ m_expectedResponse.initialize();
+ m_expectedResponse.setMIMEType("text/html");
+ m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
+ m_expectedResponse.addHTTPHeaderField(headerNameString, "foo");
+ webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath);
+
+ WebURLLoaderOptions options;
+ options.exposeAllResponseHeaders = true; // This turns off response whitelisting.
+ options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
+ m_expectedLoader = createAssociatedURLLoader(options);
+ EXPECT_TRUE(m_expectedLoader);
+ m_expectedLoader->loadAsynchronously(request, this);
+ serveRequests();
+ EXPECT_TRUE(m_didReceiveResponse);
+ EXPECT_TRUE(m_didReceiveData);
+ EXPECT_TRUE(m_didFinishLoading);
+
+ EXPECT_FALSE(m_actualResponse.httpHeaderField(headerNameString).isEmpty());
+}
+
}
diff --git a/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp b/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp
index 0e8c1a401..854595380 100644
--- a/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp
+++ b/Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp
@@ -29,9 +29,12 @@
#include "GraphicsLayer.h"
#include "LayerChromium.h"
#include "TranslateTransformOperation.h"
+#include "cc/CCKeyframedAnimationCurve.h"
#include "cc/CCLayerAnimationController.h"
#include "cc/CCLayerImpl.h"
+#include <public/WebTransformOperations.h>
+
using namespace WebCore;
namespace {
@@ -39,38 +42,38 @@ namespace {
template <class Target>
void addOpacityTransition(Target& target, double duration, float startOpacity, float endOpacity, bool useTimingFunction)
{
- WebCore::KeyframeValueList values(AnimatedPropertyOpacity);
- if (duration > 0)
- values.insert(new FloatAnimationValue(0, startOpacity));
- values.insert(new FloatAnimationValue(duration, endOpacity));
+ OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create());
- RefPtr<Animation> animation = Animation::create();
- animation->setDuration(duration);
-
- if (useTimingFunction)
- animation->setTimingFunction(LinearTimingFunction::create());
+ if (duration > 0)
+ curve->addKeyframe(CCFloatKeyframe::create(0, startOpacity, useTimingFunction ? nullptr : CCEaseTimingFunction::create()));
+ curve->addKeyframe(CCFloatKeyframe::create(duration, endOpacity, nullptr));
- IntSize boxSize;
+ OwnPtr<CCActiveAnimation> animation(CCActiveAnimation::create(curve.release(), 0, 0, CCActiveAnimation::Opacity));
+ animation->setNeedsSynchronizedStartTime(true);
- target.addAnimation(values, boxSize, animation.get(), 0, 0, 0);
+ target.addAnimation(animation.release());
}
template <class Target>
void addAnimatedTransform(Target& target, double duration, int deltaX, int deltaY)
{
static int id = 0;
- WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+ OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create());
- TransformOperations operations;
- operations.operations().append(TranslateTransformOperation::create(Length(deltaX, WebCore::Fixed), Length(deltaY, WebCore::Fixed), TransformOperation::TRANSLATE_X));
- values.insert(new TransformAnimationValue(0, &operations));
+ if (duration > 0) {
+ WebKit::WebTransformOperations startOperations;
+ startOperations.appendTranslate(deltaX, deltaY, 0);
+ curve->addKeyframe(CCTransformKeyframe::create(0, startOperations, nullptr));
+ }
- RefPtr<Animation> animation = Animation::create();
- animation->setDuration(duration);
+ WebKit::WebTransformOperations operations;
+ operations.appendTranslate(deltaX, deltaY, 0);
+ curve->addKeyframe(CCTransformKeyframe::create(duration, operations, nullptr));
- IntSize boxSize;
+ OwnPtr<CCActiveAnimation> animation(CCActiveAnimation::create(curve.release(), id++, 0, CCActiveAnimation::Transform));
+ animation->setNeedsSynchronizedStartTime(true);
- target.addAnimation(values, boxSize, animation.get(), ++id, 0, 0);
+ target.addAnimation(animation.release());
}
} // namespace
@@ -99,7 +102,7 @@ FakeTransformTransition::~FakeTransformTransition()
{
}
-WebKit::WebTransformationMatrix FakeTransformTransition::getValue(double time, const WebCore::IntSize& size) const
+WebKit::WebTransformationMatrix FakeTransformTransition::getValue(double time) const
{
return WebKit::WebTransformationMatrix();
}
diff --git a/Source/WebKit/chromium/tests/CCAnimationTestCommon.h b/Source/WebKit/chromium/tests/CCAnimationTestCommon.h
index 4384117d3..4bbd60112 100644
--- a/Source/WebKit/chromium/tests/CCAnimationTestCommon.h
+++ b/Source/WebKit/chromium/tests/CCAnimationTestCommon.h
@@ -54,7 +54,7 @@ public:
virtual ~FakeTransformTransition();
virtual double duration() const OVERRIDE { return m_duration; }
- virtual WebKit::WebTransformationMatrix getValue(double time, const WebCore::IntSize&) const OVERRIDE;
+ virtual WebKit::WebTransformationMatrix getValue(double time) const OVERRIDE;
virtual PassOwnPtr<WebCore::CCAnimationCurve> clone() const OVERRIDE;
@@ -89,12 +89,10 @@ public:
virtual float opacity() const OVERRIDE { return m_opacity; }
virtual void setTransformFromAnimation(const WebKit::WebTransformationMatrix& transform) OVERRIDE { m_transform = transform; }
virtual const WebKit::WebTransformationMatrix& transform() const OVERRIDE { return m_transform; }
- virtual const WebCore::IntSize& bounds() const OVERRIDE { return m_bounds; }
private:
float m_opacity;
WebKit::WebTransformationMatrix m_transform;
- WebCore::IntSize m_bounds;
};
void addOpacityTransitionToController(WebCore::CCLayerAnimationController&, double duration, float startOpacity, float endOpacity, bool useTimingFunction);
diff --git a/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp b/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp
index 56d85fafa..f498069f0 100644
--- a/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp
+++ b/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp
@@ -58,7 +58,18 @@ void executeCalculateDrawTransformsAndVisibility(CCLayerImpl* root, Vector<CCLay
root->renderSurface()->clearLayerList();
renderSurfaceLayerList.append(root);
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, &layerSorter, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, &layerSorter, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, root->renderSurface()->contentRect());
+}
+
+void clearDamageForAllSurfaces(CCLayerImpl* layer)
+{
+ if (layer->renderSurface())
+ layer->renderSurface()->damageTracker()->didDrawDamagedArea();
+
+ // Recursively clear damage for any existing surface.
+ for (size_t i = 0; i < layer->children().size(); ++i)
+ clearDamageForAllSurfaces(layer->children()[i].get());
}
void emulateDrawingOneFrame(CCLayerImpl* root)
@@ -221,6 +232,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForUpdateRects)
// CASE 1: Setting the update rect should cause the corresponding damage to the surface.
//
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(10, 11, 12, 13));
emulateDrawingOneFrame(root.get());
@@ -230,6 +242,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForUpdateRects)
// CASE 2: The same update rect twice in a row still produces the same damage.
//
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(10, 11, 12, 13));
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -237,6 +250,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForUpdateRects)
// CASE 3: Setting a different update rect should cause damage on the new update region, but no additional exposed old region.
//
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(20, 25, 1, 2));
emulateDrawingOneFrame(root.get());
@@ -252,6 +266,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForPropertyChanges)
// CASE 1: The layer's property changed flag takes priority over update rect.
//
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(10, 11, 12, 13));
child->setOpacity(0.5);
emulateDrawingOneFrame(root.get());
@@ -270,10 +285,12 @@ TEST_F(CCDamageTrackerTest, verifyDamageForPropertyChanges)
// not just the updateRect.
// Cycle one frame of no change, just to sanity check that the next rect is not because of the old damage state.
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
EXPECT_TRUE(root->renderSurface()->damageTracker()->currentDamageRect().isEmpty());
// Then, test the actual layer movement.
+ clearDamageForAllSurfaces(root.get());
child->setPosition(FloatPoint(200, 230));
emulateDrawingOneFrame(root.get());
@@ -297,6 +314,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForTransformedLayer)
// Note carefully, the anchor is actually part of layer->position(). By setting anchor
// to (0.5, 0.5), the layer's position (100, 100) now refers to the center of the
// layer, not the corner. This means the layer has actually changed position.
+ clearDamageForAllSurfaces(root.get());
child->setAnchorPoint(FloatPoint(0.5, 0.5));
emulateDrawingOneFrame(root.get());
@@ -306,6 +324,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForTransformedLayer)
// With the anchor on the layer's center, now we can test the rotation more
// intuitively, since it applies about the layer's anchor.
+ clearDamageForAllSurfaces(root.get());
child->setTransform(rotation);
emulateDrawingOneFrame(root.get());
@@ -326,15 +345,17 @@ TEST_F(CCDamageTrackerTest, verifyDamageForPerspectiveClippedLayer)
// tracked properly.
//
// The transform is constructed so that if w < 0 clipping is not performed, the
- // incorrect rect will be very small, specifically: position (-3.153448, -2.750628) and size 8.548689 x 5.661383.
- // Instead, the correctly transformed rect should actually be very huge (i.e. in theory, infinite)
+ // incorrect rect will be very small, specifically: position (500.972504, 498.544617) and size 0.056610 x 2.910767.
+ // Instead, the correctly transformed rect should actually be very huge (i.e. in theory, -infinity on the left),
+ // and positioned so that the right-most bound rect will be approximately 501 units in root surface space.
+ //
OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface();
CCLayerImpl* child = root->children()[0].get();
WebTransformationMatrix transform;
+ transform.translate3d(500, 500, 0);
transform.applyPerspective(1);
- transform.translate3d(-150, -50, 0);
transform.rotate3d(0, 45, 0);
transform.translate3d(-50, -50, 0);
@@ -352,14 +373,15 @@ TEST_F(CCDamageTrackerTest, verifyDamageForPerspectiveClippedLayer)
EXPECT_TRUE(clipped);
// Damage the child without moving it.
+ clearDamageForAllSurfaces(root.get());
child->setOpacity(0.5);
emulateDrawingOneFrame(root.get());
// The expected damage should cover the entire root surface (500x500), but we don't
// care whether the damage rect was clamped or is larger than the surface for this test.
FloatRect rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
- EXPECT_GE(rootDamageRect.width(), 500);
- EXPECT_GE(rootDamageRect.height(), 500);
+ FloatRect damageWeCareAbout = FloatRect(FloatPoint::zero(), FloatSize(500, 500));
+ EXPECT_TRUE(rootDamageRect.contains(damageWeCareAbout));
}
TEST_F(CCDamageTrackerTest, verifyDamageForBlurredSurface)
@@ -371,12 +393,14 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBlurredSurface)
filters.append(WebFilterOperation::createBlurFilter(5));
int outsetTop, outsetRight, outsetBottom, outsetLeft;
filters.getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft);
- root->setFilters(filters);
// Setting the filter will damage the whole surface.
+ clearDamageForAllSurfaces(root.get());
+ root->setFilters(filters);
emulateDrawingOneFrame(root.get());
// Setting the update rect should cause the corresponding damage to the surface, blurred based on the size of the blur filter.
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(10, 11, 12, 13));
emulateDrawingOneFrame(root.get());
@@ -401,16 +425,17 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
filters.append(WebFilterOperation::createBlurFilter(2));
int outsetTop, outsetRight, outsetBottom, outsetLeft;
filters.getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft);
- child1->setBackgroundFilters(filters);
// Setting the filter will damage the whole surface.
+ clearDamageForAllSurfaces(root.get());
+ child1->setBackgroundFilters(filters);
emulateDrawingOneFrame(root.get());
// CASE 1: Setting the update rect should cause the corresponding damage to
// the surface, blurred based on the size of the child's background blur
// filter.
+ clearDamageForAllSurfaces(root.get());
root->setUpdateRect(FloatRect(297, 297, 2, 2));
-
emulateDrawingOneFrame(root.get());
FloatRect rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -425,8 +450,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
// the surface, blurred based on the size of the child's background blur
// filter. Since the damage extends to the right/bottom outside of the
// blurred layer, only the left/top should end up expanded.
+ clearDamageForAllSurfaces(root.get());
root->setUpdateRect(FloatRect(297, 297, 30, 30));
-
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -440,8 +465,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
// CASE 3: Setting this update rect outside the blurred contentBounds of the blurred
// child1 will not cause it to be expanded.
+ clearDamageForAllSurfaces(root.get());
root->setUpdateRect(FloatRect(30, 30, 2, 2));
-
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -452,8 +477,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
// CASE 4: Setting this update rect inside the blurred contentBounds but outside the
// original contentBounds of the blurred child1 will cause it to be expanded.
+ clearDamageForAllSurfaces(root.get());
root->setUpdateRect(FloatRect(99, 99, 1, 1));
-
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -467,8 +492,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
// CASE 5: Setting the update rect on child2, which is above child1, will
// not get blurred by child1, so it does not need to get expanded.
+ clearDamageForAllSurfaces(root.get());
child2->setUpdateRect(FloatRect(0, 0, 1, 1));
-
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -478,8 +503,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild)
// CASE 6: Setting the update rect on child1 will also blur the damage, so
// that any pixels needed for the blur are redrawn in the current frame.
+ clearDamageForAllSurfaces(root.get());
child1->setUpdateRect(FloatRect(0, 0, 1, 1));
-
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -495,6 +520,9 @@ TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingLayer)
OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface();
CCLayerImpl* child1 = root->children()[0].get();
+ // CASE 1: Adding a new layer should cause the appropriate damage.
+ //
+ clearDamageForAllSurfaces(root.get());
{
OwnPtr<CCLayerImpl> child2 = CCLayerImpl::create(3);
child2->setPosition(FloatPoint(400, 380));
@@ -503,9 +531,6 @@ TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingLayer)
child2->setDrawsContent(true);
root->addChild(child2.release());
}
-
- // CASE 1: Adding a new layer should cause the appropriate damage.
- //
emulateDrawingOneFrame(root.get());
// Sanity check - all 3 layers should be on the same render surface; render surfaces are tested elsewhere.
@@ -518,6 +543,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingLayer)
// last update rect.
// Advance one frame without damage so that we know the damage rect is not leftover from the previous case.
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
EXPECT_TRUE(root->renderSurface()->damageTracker()->currentDamageRect().isEmpty());
@@ -535,6 +561,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForNewUnchangedLayer)
OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface();
+ clearDamageForAllSurfaces(root.get());
{
OwnPtr<CCLayerImpl> child2 = CCLayerImpl::create(3);
child2->setPosition(FloatPoint(400, 380));
@@ -548,7 +575,6 @@ TEST_F(CCDamageTrackerTest, verifyDamageForNewUnchangedLayer)
ASSERT_TRUE(child2->updateRect().isEmpty());
root->addChild(child2.release());
}
-
emulateDrawingOneFrame(root.get());
// Sanity check - all 3 layers should be on the same render surface; render surfaces are tested elsewhere.
@@ -563,6 +589,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMultipleLayers)
OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface();
CCLayerImpl* child1 = root->children()[0].get();
+ // In this test we don't want the above tree manipulation to be considered part of the same frame.
+ clearDamageForAllSurfaces(root.get());
{
OwnPtr<CCLayerImpl> child2 = CCLayerImpl::create(3);
child2->setPosition(FloatPoint(400, 380));
@@ -572,13 +600,12 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMultipleLayers)
root->addChild(child2.release());
}
CCLayerImpl* child2 = root->children()[1].get();
-
- // In this test we don't want the above tree manipulation to be considered part of the same frame.
emulateDrawingOneFrame(root.get());
// Damaging two layers simultaneously should cause combined damage.
// - child1 update rect in surface space: FloatRect(100, 100, 1, 2);
// - child2 update rect in surface space: FloatRect(400, 380, 3, 4);
+ clearDamageForAllSurfaces(root.get());
child1->setUpdateRect(FloatRect(0, 0, 1, 2));
child2->setUpdateRect(FloatRect(0, 0, 3, 4));
emulateDrawingOneFrame(root.get());
@@ -597,6 +624,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForNestedSurfaces)
// CASE 1: Damage to a descendant surface should propagate properly to ancestor surface.
//
+ clearDamageForAllSurfaces(root.get());
grandChild1->setOpacity(0.5);
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
@@ -607,6 +635,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForNestedSurfaces)
// CASE 2: Same as previous case, but with additional damage elsewhere that should be properly unioned.
// - child1 surface damage in root surface space: FloatRect(300, 300, 6, 8);
// - child2 damage in root surface space: FloatRect(11, 11, 18, 18);
+ clearDamageForAllSurfaces(root.get());
grandChild1->setOpacity(0.7f);
child2->setOpacity(0.7f);
emulateDrawingOneFrame(root.get());
@@ -631,6 +660,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForSurfaceChangeFromDescendantLayer)
FloatRect childDamageRect;
FloatRect rootDamageRect;
+ clearDamageForAllSurfaces(root.get());
grandChild1->setPosition(FloatPoint(195, 205));
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
@@ -662,6 +692,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForSurfaceChangeFromAncestorLayer)
FloatRect childDamageRect;
FloatRect rootDamageRect;
+ clearDamageForAllSurfaces(root.get());
child1->setPosition(FloatPoint(50, 50));
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
@@ -685,6 +716,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingRenderSurfaces)
// CASE 1: If a descendant surface disappears, its entire old area becomes exposed.
//
+ clearDamageForAllSurfaces(root.get());
child1->setOpacity(1);
emulateDrawingOneFrame(root.get());
@@ -698,11 +730,13 @@ TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingRenderSurfaces)
// CASE 2: If a descendant surface appears, its entire old area becomes exposed.
// Cycle one frame of no change, just to sanity check that the next rect is not because of the old damage state.
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
EXPECT_TRUE(rootDamageRect.isEmpty());
// Then change the tree so that the render surface is added back.
+ clearDamageForAllSurfaces(root.get());
child1->setOpacity(0.5);
emulateDrawingOneFrame(root.get());
@@ -726,6 +760,7 @@ TEST_F(CCDamageTrackerTest, verifyNoDamageWhenNothingChanged)
// CASE 1: If nothing changes, the damage rect should be empty.
//
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -734,6 +769,7 @@ TEST_F(CCDamageTrackerTest, verifyNoDamageWhenNothingChanged)
// CASE 2: If nothing changes twice in a row, the damage rect should still be empty.
//
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -750,6 +786,7 @@ TEST_F(CCDamageTrackerTest, verifyNoDamageForUpdateRectThatDoesNotDrawContent)
// In our specific tree, the update rect of child1 should not cause any damage to any
// surface because it does not actually draw content.
+ clearDamageForAllSurfaces(root.get());
child1->setUpdateRect(FloatRect(0, 0, 1, 2));
emulateDrawingOneFrame(root.get());
childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
@@ -785,6 +822,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplica)
// CASE 1: adding a reflection about the left edge of grandChild1.
//
+ clearDamageForAllSurfaces(root.get());
{
OwnPtr<CCLayerImpl> grandChild1Replica = CCLayerImpl::create(7);
grandChild1Replica->setPosition(FloatPoint::zero());
@@ -808,6 +846,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplica)
// CASE 2: moving the descendant surface should cause both the original and reflected
// areas to be damaged on the target.
+ clearDamageForAllSurfaces(root.get());
IntRect oldContentRect = child1->renderSurface()->contentRect();
grandChild1->setPosition(FloatPoint(195.0, 205.0));
emulateDrawingOneFrame(root.get());
@@ -827,6 +866,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplica)
// CASE 3: removing the reflection should cause the entire region including reflection
// to damage the target surface.
+ clearDamageForAllSurfaces(root.get());
grandChild1->setReplicaLayer(nullptr);
emulateDrawingOneFrame(root.get());
ASSERT_EQ(oldContentRect.width(), child1->renderSurface()->contentRect().width());
@@ -848,6 +888,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMask)
// In the current implementation of the damage tracker, changes to mask layers should
// damage the entire corresponding surface.
+ clearDamageForAllSurfaces(root.get());
+
// Set up the mask layer.
{
OwnPtr<CCLayerImpl> maskLayer = CCLayerImpl::create(3);
@@ -875,6 +917,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMask)
// CASE 1: the updateRect on a mask layer should damage the entire target surface.
//
+ clearDamageForAllSurfaces(root.get());
maskLayer->setUpdateRect(FloatRect(1, 2, 3, 4));
emulateDrawingOneFrame(root.get());
FloatRect childDamageRect = child->renderSurface()->damageTracker()->currentDamageRect();
@@ -884,12 +927,15 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMask)
//
// Advance one frame without damage so that we know the damage rect is not leftover from the previous case.
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
childDamageRect = child->renderSurface()->damageTracker()->currentDamageRect();
EXPECT_TRUE(childDamageRect.isEmpty());
// Then test the property change.
- maskLayer->setOpacity(0.5);
+ clearDamageForAllSurfaces(root.get());
+ maskLayer->setStackingOrderChanged(true);
+
emulateDrawingOneFrame(root.get());
childDamageRect = child->renderSurface()->damageTracker()->currentDamageRect();
EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 30, 30), childDamageRect);
@@ -898,11 +944,13 @@ TEST_F(CCDamageTrackerTest, verifyDamageForMask)
//
// Advance one frame without damage so that we know the damage rect is not leftover from the previous case.
+ clearDamageForAllSurfaces(root.get());
emulateDrawingOneFrame(root.get());
childDamageRect = child->renderSurface()->damageTracker()->currentDamageRect();
EXPECT_TRUE(childDamageRect.isEmpty());
// Then test mask removal.
+ clearDamageForAllSurfaces(root.get());
child->setMaskLayer(nullptr);
ASSERT_TRUE(child->layerPropertyChanged());
emulateDrawingOneFrame(root.get());
@@ -923,6 +971,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplicaMask)
// Changes to a replica's mask should not damage the original surface, because it is
// not masked. But it does damage the ancestor target surface.
+ clearDamageForAllSurfaces(root.get());
+
// Create a reflection about the left edge of grandChild1.
{
OwnPtr<CCLayerImpl> grandChild1Replica = CCLayerImpl::create(6);
@@ -951,7 +1001,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplicaMask)
ASSERT_TRUE(grandChild1->renderSurface());
// CASE 1: a property change on the mask should damage only the reflected region on the target surface.
- replicaMaskLayer->setOpacity(0.6f);
+ clearDamageForAllSurfaces(root.get());
+ replicaMaskLayer->setStackingOrderChanged(true);
emulateDrawingOneFrame(root.get());
FloatRect grandChildDamageRect = grandChild1->renderSurface()->damageTracker()->currentDamageRect();
@@ -962,6 +1013,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplicaMask)
// CASE 2: removing the replica mask damages only the reflected region on the target surface.
//
+ clearDamageForAllSurfaces(root.get());
grandChild1Replica->setMaskLayer(nullptr);
emulateDrawingOneFrame(root.get());
@@ -982,6 +1034,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplicaMaskWithAnchor)
// incorrect old code incorrectly accounted for the anchor for the replica. A
// non-zero anchor point should not affect the replica reflection.
+ clearDamageForAllSurfaces(root.get());
+
grandChild1->setAnchorPoint(FloatPoint(1.0, 0.0)); // This is the anchor being tested.
{
@@ -1011,7 +1065,9 @@ TEST_F(CCDamageTrackerTest, verifyDamageForReplicaMaskWithAnchor)
ASSERT_TRUE(grandChild1->renderSurface());
// A property change on the replicaMask should damage the reflected region on the target surface.
- replicaMaskLayer->setOpacity(0.6f);
+ clearDamageForAllSurfaces(root.get());
+ replicaMaskLayer->setStackingOrderChanged(true);
+
emulateDrawingOneFrame(root.get());
FloatRect childDamageRect = child1->renderSurface()->damageTracker()->currentDamageRect();
@@ -1026,6 +1082,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageWhenForcedFullDamage)
// Case 1: This test ensures that when the tracker is forced to have full damage, that
// it takes priority over any other partial damage.
//
+ clearDamageForAllSurfaces(root.get());
child->setUpdateRect(FloatRect(10, 11, 12, 13));
root->renderSurface()->damageTracker()->forceFullDamageNextUpdate();
emulateDrawingOneFrame(root.get());
@@ -1035,6 +1092,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageWhenForcedFullDamage)
// Case 2: An additional sanity check that forcing full damage works even when nothing
// on the layer tree changed.
//
+ clearDamageForAllSurfaces(root.get());
root->renderSurface()->damageTracker()->forceFullDamageNextUpdate();
emulateDrawingOneFrame(root.get());
rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
@@ -1058,4 +1116,36 @@ TEST_F(CCDamageTrackerTest, verifyDamageForEmptyLayerList)
EXPECT_TRUE(damageRect.isEmpty());
}
+TEST_F(CCDamageTrackerTest, verifyDamageAccumulatesUntilReset)
+{
+ // If damage is not cleared, it should accumulate.
+
+ OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface();
+ CCLayerImpl* child = root->children()[0].get();
+
+ clearDamageForAllSurfaces(root.get());
+ child->setUpdateRect(FloatRect(10, 11, 1, 2));
+ emulateDrawingOneFrame(root.get());
+
+ // Sanity check damage after the first frame; this isnt the actual test yet.
+ FloatRect rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
+ EXPECT_FLOAT_RECT_EQ(FloatRect(110, 111, 1, 2), rootDamageRect);
+
+ // New damage, without having cleared the previous damage, should be unioned to the previous one.
+ child->setUpdateRect(FloatRect(20, 25, 1, 2));
+ emulateDrawingOneFrame(root.get());
+ rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
+ EXPECT_FLOAT_RECT_EQ(FloatRect(110, 111, 11, 16), rootDamageRect);
+
+ // If we notify the damage tracker that we drew the damaged area, then damage should be emptied.
+ root->renderSurface()->damageTracker()->didDrawDamagedArea();
+ rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
+ EXPECT_TRUE(rootDamageRect.isEmpty());
+
+ // Damage should remain empty even after one frame, since there's yet no new damage
+ emulateDrawingOneFrame(root.get());
+ rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect();
+ EXPECT_TRUE(rootDamageRect.isEmpty());
+}
+
} // namespace
diff --git a/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp b/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp
index ad1ae74ca..eb6bb0363 100644
--- a/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp
+++ b/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp
@@ -31,6 +31,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <public/WebTransformOperations.h>
#include <public/WebTransformationMatrix.h>
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
@@ -113,57 +114,55 @@ TEST(CCKeyframedAnimationCurveTest, RepeatedFloatKeyTimes)
TEST(CCKeyframedAnimationCurveTest, OneTransformKeyframe)
{
OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create());
- TransformOperations operations;
- operations.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+ WebKit::WebTransformOperations operations;
+ operations.appendTranslate(2, 0, 0);
curve->addKeyframe(CCTransformKeyframe::create(0, operations, nullptr));
- 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));
+ expectTranslateX(2, curve->getValue(-1));
+ expectTranslateX(2, curve->getValue(0));
+ expectTranslateX(2, curve->getValue(0.5));
+ expectTranslateX(2, curve->getValue(1));
+ expectTranslateX(2, curve->getValue(2));
}
// Tests that a transform animation with two keyframes works as expected.
TEST(CCKeyframedAnimationCurveTest, TwoTransformKeyframe)
{
OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::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));
+ WebKit::WebTransformOperations operations1;
+ operations1.appendTranslate(2, 0, 0);
+ WebKit::WebTransformOperations operations2;
+ operations2.appendTranslate(4, 0, 0);
+
curve->addKeyframe(CCTransformKeyframe::create(0, operations1, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(1, operations2, nullptr));
- 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));
+ expectTranslateX(2, curve->getValue(-1));
+ expectTranslateX(2, curve->getValue(0));
+ expectTranslateX(3, curve->getValue(0.5));
+ expectTranslateX(4, curve->getValue(1));
+ expectTranslateX(4, curve->getValue(2));
}
// Tests that a transform animation with three keyframes works as expected.
TEST(CCKeyframedAnimationCurveTest, ThreeTransformKeyframe)
{
OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::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));
- TransformOperations operations3;
- operations3.operations().append(TranslateTransformOperation::create(Length(8, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+ WebKit::WebTransformOperations operations1;
+ operations1.appendTranslate(2, 0, 0);
+ WebKit::WebTransformOperations operations2;
+ operations2.appendTranslate(4, 0, 0);
+ WebKit::WebTransformOperations operations3;
+ operations3.appendTranslate(8, 0, 0);
curve->addKeyframe(CCTransformKeyframe::create(0, operations1, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(1, operations2, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(2, operations3, nullptr));
- 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));
+ expectTranslateX(2, curve->getValue(-1));
+ expectTranslateX(2, curve->getValue(0));
+ expectTranslateX(3, curve->getValue(0.5));
+ expectTranslateX(4, curve->getValue(1));
+ expectTranslateX(6, curve->getValue(1.5));
+ expectTranslateX(8, curve->getValue(2));
+ expectTranslateX(8, curve->getValue(3));
}
// Tests that a transform animation with multiple keys at a given time works sanely.
@@ -171,32 +170,30 @@ TEST(CCKeyframedAnimationCurveTest, RepeatedTransformKeyTimes)
{
OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create());
// 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));
+ WebKit::WebTransformOperations operations1;
+ operations1.appendTranslate(4, 0, 0);
+ WebKit::WebTransformOperations operations2;
+ operations2.appendTranslate(4, 0, 0);
+ WebKit::WebTransformOperations operations3;
+ operations3.appendTranslate(6, 0, 0);
+ WebKit::WebTransformOperations operations4;
+ operations4.appendTranslate(6, 0, 0);
curve->addKeyframe(CCTransformKeyframe::create(0, operations1, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(1, operations2, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(1, operations3, nullptr));
curve->addKeyframe(CCTransformKeyframe::create(2, operations4, nullptr));
- IntSize layerSize; // ignored
-
- expectTranslateX(4, curve->getValue(-1, layerSize));
- expectTranslateX(4, curve->getValue(0, layerSize));
- expectTranslateX(4, curve->getValue(0.5, layerSize));
+ expectTranslateX(4, curve->getValue(-1));
+ expectTranslateX(4, curve->getValue(0));
+ expectTranslateX(4, curve->getValue(0.5));
// There is a discontinuity at 1. Any value between 4 and 6 is valid.
- WebTransformationMatrix value = curve->getValue(1, layerSize);
+ WebTransformationMatrix value = curve->getValue(1);
EXPECT_TRUE(value.m41() >= 4 && value.m41() <= 6);
- expectTranslateX(6, curve->getValue(1.5, layerSize));
- expectTranslateX(6, curve->getValue(2, layerSize));
- expectTranslateX(6, curve->getValue(3, layerSize));
+ expectTranslateX(6, curve->getValue(1.5));
+ expectTranslateX(6, curve->getValue(2));
+ expectTranslateX(6, curve->getValue(3));
}
// Tests that the keyframes may be added out of order.
diff --git a/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp
index dbed02c74..72361092a 100644
--- a/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp
@@ -29,7 +29,6 @@
#include "CCAnimationTestCommon.h"
#include "GraphicsLayer.h"
#include "Length.h"
-#include "TranslateTransformOperation.h"
#include "cc/CCActiveAnimation.h"
#include "cc/CCAnimationCurve.h"
@@ -54,197 +53,6 @@ PassOwnPtr<CCActiveAnimation> createActiveAnimation(PassOwnPtr<CCAnimationCurve>
return CCActiveAnimation::create(curve, 0, id, property);
}
-TEST(CCLayerAnimationControllerTest, createOpacityAnimation)
-{
- FakeLayerAnimationControllerClient dummy;
- OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
- 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)
-{
- FakeLayerAnimationControllerClient dummy;
- OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
- 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, createReversedAnimation)
-{
- FakeLayerAnimationControllerClient dummy;
- OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
- 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);
- animation->setDirection(Animation::AnimationDirectionReverse);
-
- 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(4, curve->getValue(0, boxSize));
- expectTranslateX(2, curve->getValue(duration, boxSize));
-}
-
-TEST(CCLayerAnimationControllerTest, createAlternatingAnimation)
-{
- FakeLayerAnimationControllerClient dummy;
- OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
- 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);
- animation->setDirection(Animation::AnimationDirectionAlternate);
- animation->setIterationCount(2);
-
- 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_TRUE(activeAnimation->alternatesDirection());
-
- EXPECT_EQ(2, 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, createReversedAlternatingAnimation)
-{
- FakeLayerAnimationControllerClient dummy;
- OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
- 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);
- animation->setDirection(Animation::AnimationDirectionAlternateReverse);
- animation->setIterationCount(2);
-
- 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_TRUE(activeAnimation->alternatesDirection());
-
- EXPECT_EQ(2, 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(4, curve->getValue(0, boxSize));
- expectTranslateX(2, curve->getValue(duration, boxSize));
-}
-
TEST(CCLayerAnimationControllerTest, syncNewAnimation)
{
FakeLayerAnimationControllerClient dummyImpl;
@@ -333,7 +141,6 @@ TEST(CCLayerAnimationControllerTest, syncPauseAndResume)
EXPECT_EQ(CCActiveAnimation::Running, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
}
-
TEST(CCLayerAnimationControllerTest, doNotSyncFinishedAnimation)
{
FakeLayerAnimationControllerClient dummyImpl;
@@ -375,7 +182,7 @@ TEST(CCLayerAnimationControllerTest, TrivialTransition)
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
EXPECT_EQ(0, dummy.opacity());
@@ -396,7 +203,7 @@ TEST(CCLayerAnimationControllerTest, AnimationsWaitingForStartTimeDoNotFinishIfT
toAdd->setNeedsSynchronizedStartTime(true);
// We should pause at the first keyframe indefinitely waiting for that animation to start.
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
EXPECT_EQ(0, dummy.opacity());
@@ -422,8 +229,8 @@ TEST(CCLayerAnimationControllerTest, TrivialQueuing)
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5)), 2, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5)), 2, CCActiveAnimation::Opacity));
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -443,14 +250,14 @@ TEST(CCLayerAnimationControllerTest, Interrupt)
FakeLayerAnimationControllerClient dummy;
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
EXPECT_EQ(0, dummy.opacity());
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5)), 2, CCActiveAnimation::Opacity));
toAdd->setRunState(CCActiveAnimation::WaitingForNextTick, 0);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
// Since the animation was in the WaitingForNextTick state, it should start right in
// this call to animate.
@@ -470,9 +277,9 @@ TEST(CCLayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked)
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- 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->addAnimation(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), 1, CCActiveAnimation::Transform));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), 2, CCActiveAnimation::Transform));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 2, CCActiveAnimation::Opacity));
controller->animate(0, events.get());
EXPECT_EQ(0, dummy.opacity());
@@ -497,9 +304,9 @@ TEST(CCLayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting)
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- 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.5)), 2, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeTransformTransition(2)), 1, CCActiveAnimation::Transform));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.5)), 2, CCActiveAnimation::Opacity));
// Animations with id 1 should both start now.
controller->animate(0, events.get());
@@ -530,7 +337,7 @@ TEST(CCLayerAnimationControllerTest, ScheduleAnimation)
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->addAnimation(toAdd.release());
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -551,12 +358,12 @@ TEST(CCLayerAnimationControllerTest, ScheduledAnimationInterruptsRunningAnimatio
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0.5, 0)), 2, CCActiveAnimation::Opacity));
toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
toAdd->setStartTime(1);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
// First 2s opacity transition should start immediately.
controller->animate(0, events.get());
@@ -582,14 +389,14 @@ TEST(CCLayerAnimationControllerTest, ScheduledAnimationInterruptsRunningAnimatio
OwnPtr<CCLayerAnimationController> controller(
CCLayerAnimationController::create(&dummy));
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 1, CCActiveAnimation::Opacity));
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0.5, 0)), 2, CCActiveAnimation::Opacity));
toAdd->setRunState(CCActiveAnimation::WaitingForStartTime, 0);
toAdd->setStartTime(1);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 0.75)), 3, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 0.75)), 3, CCActiveAnimation::Opacity));
// First 2s opacity transition should start immediately.
controller->animate(0, events.get());
@@ -620,7 +427,7 @@ TEST(CCLayerAnimationControllerTest, TrivialLooping)
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), 1, CCActiveAnimation::Opacity));
toAdd->setIterations(3);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -657,7 +464,7 @@ TEST(CCLayerAnimationControllerTest, InfiniteLooping)
const int id = 1;
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity));
toAdd->setIterations(-1);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -691,7 +498,7 @@ TEST(CCLayerAnimationControllerTest, PauseResume)
CCLayerAnimationController::create(&dummy));
const int id = 1;
- controller->add(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 0, 1)), id, CCActiveAnimation::Opacity));
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -726,9 +533,9 @@ TEST(CCLayerAnimationControllerTest, AbortAGroupedAnimation)
CCLayerAnimationController::create(&dummy));
const int id = 1;
- 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.75)), 2, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeTransformTransition(1)), id, CCActiveAnimation::Transform));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), id, CCActiveAnimation::Opacity));
+ controller->addAnimation(createActiveAnimation(adoptPtr(new FakeFloatTransition(1, 1, 0.75)), 2, CCActiveAnimation::Opacity));
controller->animate(0, events.get());
EXPECT_TRUE(controller->hasActiveAnimation());
@@ -758,7 +565,7 @@ TEST(CCLayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded)
OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 0, CCActiveAnimation::Opacity));
toAdd->setNeedsSynchronizedStartTime(true);
- controller->add(toAdd.release());
+ controller->addAnimation(toAdd.release());
controller->animate(0, 0);
EXPECT_TRUE(controller->hasActiveAnimation());
diff --git a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp
index 827c9adaa..01f943a64 100644
--- a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp
@@ -42,21 +42,33 @@ namespace {
codeToTest; \
EXPECT_TRUE(root->layerPropertyChanged()); \
EXPECT_TRUE(child->layerPropertyChanged()); \
- EXPECT_TRUE(grandChild->layerPropertyChanged())
+ EXPECT_TRUE(grandChild->layerPropertyChanged()); \
+ EXPECT_FALSE(root->layerSurfacePropertyChanged())
+
#define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(codeToTest) \
root->resetAllChangeTrackingForSubtree(); \
codeToTest; \
EXPECT_FALSE(root->layerPropertyChanged()); \
EXPECT_FALSE(child->layerPropertyChanged()); \
- EXPECT_FALSE(grandChild->layerPropertyChanged())
+ EXPECT_FALSE(grandChild->layerPropertyChanged()); \
+ EXPECT_FALSE(root->layerSurfacePropertyChanged())
#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(codeToTest) \
root->resetAllChangeTrackingForSubtree(); \
codeToTest; \
EXPECT_TRUE(root->layerPropertyChanged()); \
EXPECT_FALSE(child->layerPropertyChanged()); \
- EXPECT_FALSE(grandChild->layerPropertyChanged())
+ EXPECT_FALSE(grandChild->layerPropertyChanged()); \
+ EXPECT_FALSE(root->layerSurfacePropertyChanged())
+
+#define EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED(codeToTest) \
+ root->resetAllChangeTrackingForSubtree(); \
+ codeToTest; \
+ EXPECT_FALSE(root->layerPropertyChanged()); \
+ EXPECT_FALSE(child->layerPropertyChanged()); \
+ EXPECT_FALSE(grandChild->layerPropertyChanged()); \
+ EXPECT_TRUE(root->layerSurfacePropertyChanged())
TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly)
{
@@ -98,11 +110,9 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly)
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setMaskLayer(CCLayerImpl::create(4)));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setMasksToBounds(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setOpaque(true));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setOpacity(arbitraryNumber));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setReplicaLayer(CCLayerImpl::create(5)));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setPosition(arbitraryFloatPoint));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setPreserves3D(true));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setTransform(arbitraryTransform));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setDoubleSided(false)); // constructor initializes it to "true".
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->scrollBy(arbitraryIntSize));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setScrollDelta(arbitraryIntSize));
@@ -117,6 +127,10 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly)
EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundColor(Color::gray));
EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundFilters(arbitraryFilters));
+ // Changing these properties only affects how render surface is drawn
+ EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED(root->setOpacity(arbitraryNumber));
+ EXECUTE_AND_VERIFY_ONLY_SURFACE_CHANGED(root->setTransform(arbitraryTransform));
+
// Special case: check that sublayer transform changes all layer's descendants, but not the layer itself.
root->resetAllChangeTrackingForSubtree();
root->setSublayerTransform(arbitraryTransform);
diff --git a/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp b/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp
index 105c7186e..86a374325 100644
--- a/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp
@@ -122,6 +122,14 @@ void iterateBackToFront(Vector<RefPtr<LayerChromium> >* renderSurfaceLayerList)
}
}
+TEST(CCLayerIteratorTest, emptyTree)
+{
+ Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+
+ iterateBackToFront(&renderSurfaceLayerList);
+ iterateFrontToBack(&renderSurfaceLayerList);
+}
+
TEST(CCLayerIteratorTest, simpleTree)
{
RefPtr<TestLayerChromium> rootLayer = TestLayerChromium::create();
@@ -140,10 +148,11 @@ TEST(CCLayerIteratorTest, simpleTree)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > layerList;
renderSurfaceLayerList.append(rootLayer.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
- WebTransformationMatrix(), WebTransformationMatrix(),
- renderSurfaceLayerList, layerList,
- 256);
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+ WebTransformationMatrix(), WebTransformationMatrix(),
+ renderSurfaceLayerList, layerList,
+ 256);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
iterateBackToFront(&renderSurfaceLayerList);
EXPECT_COUNT(rootLayer, 0, -1, 1);
@@ -187,10 +196,11 @@ TEST(CCLayerIteratorTest, complexTree)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > layerList;
renderSurfaceLayerList.append(rootLayer.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
- WebTransformationMatrix(), WebTransformationMatrix(),
- renderSurfaceLayerList, layerList,
- 256);
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+ WebTransformationMatrix(), WebTransformationMatrix(),
+ renderSurfaceLayerList, layerList,
+ 256);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
iterateBackToFront(&renderSurfaceLayerList);
EXPECT_COUNT(rootLayer, 0, -1, 1);
@@ -246,10 +256,11 @@ TEST(CCLayerIteratorTest, complexTreeMultiSurface)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > layerList;
renderSurfaceLayerList.append(rootLayer.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
- WebTransformationMatrix(), WebTransformationMatrix(),
- renderSurfaceLayerList, layerList,
- 256);
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+ WebTransformationMatrix(), WebTransformationMatrix(),
+ renderSurfaceLayerList, layerList,
+ 256);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
iterateBackToFront(&renderSurfaceLayerList);
EXPECT_COUNT(rootLayer, 0, -1, 1);
diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp
index fce9046c7..89d211e81 100644
--- a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp
@@ -31,7 +31,12 @@
#include "LayerChromium.h"
#include "TranslateTransformOperation.h"
#include "cc/CCLayerAnimationController.h"
+#include "cc/CCLayerImpl.h"
+#include "cc/CCLayerSorter.h"
#include "cc/CCMathUtil.h"
+#include "cc/CCProxy.h"
+#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCThread.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -43,7 +48,8 @@ using WebKit::WebTransformationMatrix;
namespace {
-void setLayerPropertiesForTesting(LayerChromium* layer, const WebTransformationMatrix& transform, const WebTransformationMatrix& sublayerTransform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool preserves3D)
+template<typename LayerType>
+void setLayerPropertiesForTesting(LayerType* layer, const WebTransformationMatrix& transform, const WebTransformationMatrix& sublayerTransform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool preserves3D)
{
layer->setTransform(transform);
layer->setSublayerTransform(sublayerTransform);
@@ -53,13 +59,36 @@ void setLayerPropertiesForTesting(LayerChromium* layer, const WebTransformationM
layer->setPreserves3D(preserves3D);
}
+void setLayerPropertiesForTesting(LayerChromium* layer, const WebTransformationMatrix& transform, const WebTransformationMatrix& sublayerTransform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool preserves3D)
+{
+ setLayerPropertiesForTesting<LayerChromium>(layer, transform, sublayerTransform, anchor, position, bounds, preserves3D);
+}
+
+void setLayerPropertiesForTesting(CCLayerImpl* layer, const WebTransformationMatrix& transform, const WebTransformationMatrix& sublayerTransform, const FloatPoint& anchor, const FloatPoint& position, const IntSize& bounds, bool preserves3D)
+{
+ setLayerPropertiesForTesting<CCLayerImpl>(layer, transform, sublayerTransform, anchor, position, bounds, preserves3D);
+ layer->setContentBounds(bounds);
+}
+
void executeCalculateDrawTransformsAndVisibility(LayerChromium* rootLayer)
{
WebTransformationMatrix identityMatrix;
Vector<RefPtr<LayerChromium> > dummyRenderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > dummyLayerList;
int dummyMaxTextureSize = 512;
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, dummyRenderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, identityMatrix, identityMatrix, dummyRenderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(dummyRenderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
+}
+
+void executeCalculateDrawTransformsAndVisibility(CCLayerImpl* rootLayer)
+{
+ // Note: this version skips layer sorting.
+ WebTransformationMatrix identityMatrix;
+ Vector<CCLayerImpl*> dummyRenderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, identityMatrix, identityMatrix, dummyRenderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(dummyRenderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
}
WebTransformationMatrix remove3DComponentOfMatrix(const WebTransformationMatrix& mat)
@@ -75,6 +104,30 @@ WebTransformationMatrix remove3DComponentOfMatrix(const WebTransformationMatrix&
return ret;
}
+PassOwnPtr<CCLayerImpl> createTreeForFixedPositionTests()
+{
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+ OwnPtr<CCLayerImpl> greatGrandChild = CCLayerImpl::create(4);
+
+ WebTransformationMatrix IdentityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), IdentityMatrix, IdentityMatrix, anchor, position, bounds, false);
+ setLayerPropertiesForTesting(child.get(), IdentityMatrix, IdentityMatrix, anchor, position, bounds, false);
+ setLayerPropertiesForTesting(grandChild.get(), IdentityMatrix, IdentityMatrix, anchor, position, bounds, false);
+ setLayerPropertiesForTesting(greatGrandChild.get(), IdentityMatrix, IdentityMatrix, anchor, position, bounds, false);
+
+ grandChild->addChild(greatGrandChild.release());
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+ root->createRenderSurface();
+
+ return root.release();
+}
+
class LayerChromiumWithForcedDrawsContent : public LayerChromium {
public:
LayerChromiumWithForcedDrawsContent()
@@ -175,7 +228,7 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleLayer)
EXPECT_TRANSFORMATION_MATRIX_EQ(expectedResult, layer->screenSpaceTransform());
// Case 7: Verify that position pre-multiplies the layer transform.
- // The current implementation of calculateDrawTransformsAndVisibility does this implicitly, but it is
+ // The current implementation of calculateDrawTransforms does this implicitly, but it is
// still worth testing to detect accidental regressions.
expectedResult = positionTransform * translationToAnchor * layerTransform * translationToAnchor.inverse();
setLayerPropertiesForTesting(layer.get(), layerTransform, identityMatrix, FloatPoint(0.5f, 0.0f), FloatPoint(5.0f, 1.2f), IntSize(10, 12), false);
@@ -318,6 +371,558 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleRenderSurface)
EXPECT_TRANSFORMATION_MATRIX_EQ(parentCompositeTransform, child->targetRenderSurface()->screenSpaceTransform());
}
+TEST(CCLayerTreeHostCommonTest, scissorRectNoClip)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ /*
+ Layers are created as follows:
+
+ +--------------------+
+ | 1 |
+ | +-----------+ |
+ | | 2 | |
+ | | +-------------------+
+ | | | 3 |
+ | | +-------------------+
+ | | | |
+ | +-----------+ |
+ | |
+ | |
+ +--------------------+
+
+ Layers 1, 2 have render surfaces
+ */
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+
+ IntRect rootRect(0, 0, 100, 100);
+ IntRect childRect(10, 10, 50, 50);
+ IntRect grandChildRect(5, 5, 150, 150);
+
+ root->createRenderSurface();
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+ root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+ root->setDrawsContent(true);
+ root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+ child->setAnchorPoint(FloatPoint(0, 0));
+ child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+ child->setOpacity(0.5f);
+ child->setBounds(IntSize(childRect.width(), childRect.height()));
+ child->setDrawsContent(true);
+
+ grandChild->setAnchorPoint(FloatPoint(0, 0));
+ grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+ grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+ grandChild->setDrawsContent(true);
+
+ CCLayerImpl* childPtr = child.get();
+ CCLayerImpl* grandChildPtr = grandChild.get();
+
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ {
+ WebTransformationMatrix identityMatrix;
+ Vector<CCLayerImpl*> layerList;
+ int dummyMaxTextureSize = 512;
+ CCLayerSorter layerSorter;
+
+ renderSurfaceLayerList.append(root.get());
+
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+ FloatRect dummyDamageRect;
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+ }
+
+ ASSERT_TRUE(childPtr->renderSurface());
+ ASSERT_TRUE(root->renderSurface());
+ ASSERT_FALSE(grandChildPtr->renderSurface());
+
+ EXPECT_EQ(renderSurfaceLayerList.size(), 2U);
+
+ ASSERT_EQ(root->clipRect(), IntRect(0, 0, 0, 0));
+
+ // Layer's clipRect is a union of all its children's bounds
+ ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+ ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, 0, 0));
+
+ ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+ ASSERT_EQ(childPtr->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+
+ ASSERT_FALSE(root->usesLayerClipping());
+ ASSERT_FALSE(childPtr->usesLayerClipping());
+ ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+
+ // Damage the entire screen
+ IntRect rootDamage(rootRect);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // child surface doesn't have a clip rect, therefore it will be computed as intersection
+ // between root surface's contentrect and child surface's drawable content rect.
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(childRect.x(), childRect.y(), rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+ // The damage is the entire rootRect, but child layer starts at an offset.
+ // Even though it has bounds, it is not clipping to bounds so its children
+ // (which extend beyond the bounds) extend the scissor rect
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ // Grand child will have the same scissor rect as it doesn't have a surface
+ // of its own
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ // Empty damage
+ rootDamage = IntRect(0, 0, 0, 0);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Empty damage == empty scissor
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Partial damage within child
+ rootDamage = IntRect(10, 10, 20, 20);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child does not have its own surface, so its scissor rect is identical to child's
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Partial damage beyond child
+ rootDamage = IntRect(10, 10, 80, 80);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child does not have its own surface, so its scissor rect is identical to child's
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Partial damage beyond root
+ rootDamage = IntRect(10, 10, 110, 110);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Root does not use layer clipping, so its content rect will be used to intersect with damage
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Children's content rects are bigger than the root's so they don't clip the damage rect, but change its offset.
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+}
+
+TEST(CCLayerTreeHostCommonTest, scissorRectWithClip)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ /*
+ Layers are created as follows:
+
+ +--------------------+
+ | 1 |
+ | +-----------+ |
+ | | 2 | |
+ | | +-------------------+
+ | | | 3 |
+ | | +-------------------+
+ | | | |
+ | +-----------+ |
+ | |
+ | |
+ +--------------------+
+
+ Layers 1, 2 have render surfaces
+ */
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+
+ IntRect rootRect(0, 0, 100, 100);
+ IntRect childRect(10, 10, 50, 50);
+ IntRect grandChildRect(5, 5, 150, 150);
+
+ root->createRenderSurface();
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+ root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+ root->setDrawsContent(true);
+ root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+ child->setAnchorPoint(FloatPoint(0, 0));
+ child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+ child->setOpacity(0.5f);
+ child->setBounds(IntSize(childRect.width(), childRect.height()));
+ child->setDrawsContent(true);
+
+ grandChild->setAnchorPoint(FloatPoint(0, 0));
+ grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+ grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+ grandChild->setDrawsContent(true);
+
+ CCLayerImpl* childPtr = child.get();
+ CCLayerImpl* grandChildPtr = grandChild.get();
+
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+
+ root->setMasksToBounds(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ {
+ WebTransformationMatrix identityMatrix;
+ Vector<CCLayerImpl*> layerList;
+ int dummyMaxTextureSize = 512;
+ CCLayerSorter layerSorter;
+
+ renderSurfaceLayerList.append(root.get());
+
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+ FloatRect dummyDamageRect;
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+ }
+
+ ASSERT_TRUE(childPtr->renderSurface());
+ ASSERT_TRUE(root->renderSurface());
+ ASSERT_FALSE(grandChildPtr->renderSurface());
+
+ EXPECT_EQ(renderSurfaceLayerList.size(), 2U);
+
+ // Now root is clipping to its bounds
+ ASSERT_EQ(root->clipRect(), rootRect);
+
+ // Layer's clipRect is a union of all its children's bounds
+ ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+ ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, 0, 0));
+
+ ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+
+ // Child surface's clipping rect is now set to root's
+ ASSERT_EQ(childPtr->renderSurface()->clipRect(), rootRect);
+
+ ASSERT_TRUE(root->usesLayerClipping());
+ ASSERT_FALSE(childPtr->usesLayerClipping());
+ ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+
+ // Damage the entire screen
+ IntRect rootDamage(rootRect);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootRect));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+ // The damage is the entire rootRect, but child layer starts at an offset.
+ // Even though it has bounds, it is not clipping to bounds so its children
+ // (which extend beyond the bounds) extend the scissor rect
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ // Grand child will have the same scissor rect as it doesn't have a surface
+ // of its own
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ // Empty damage
+ rootDamage = IntRect(0, 0, 0, 0);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Empty damage == empty scissor
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Partial damage within child
+ rootDamage = IntRect(10, 10, 20, 20);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child does not have its own surface, so its scissor rect is identical to child's
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Partial damage beyond child
+ rootDamage = IntRect(10, 10, 80, 80);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child does not have its own surface, so its scissor rect is identical to child's
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Partial damage beyond root
+ rootDamage = IntRect(10, 10, 110, 110);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Root does not use layer clipping, so its content rect will be used to intersect with damage
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Now the scissor rects are clipped by surfaces contentRect
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+}
+
+TEST(CCLayerTreeHostCommonTest, scissorRectWithClipAndSpaceTransform)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ /*
+ Layers are created as follows:
+
+ +--------------------+
+ | 1 |
+ | +-----------+ |
+ | | 2 | |
+ | | +-------------------+
+ | | | 3,4 |
+ | | +-------------------+
+ | | | |
+ | +-----------+ |
+ | |
+ | |
+ +--------------------+
+
+ Layers 1, 2 and 3 have render surfaces
+ */
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+ OwnPtr<CCLayerImpl> grandChild2 = CCLayerImpl::create(4);
+
+ IntRect rootRect(0, 0, 100, 100);
+ IntRect childRect(10, 10, 50, 50);
+ IntRect grandChildRect(5, 5, 150, 150);
+
+ root->createRenderSurface();
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+ root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+ root->setDrawsContent(true);
+ root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+ child->setAnchorPoint(FloatPoint(0, 0));
+ child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+ child->setOpacity(0.5f);
+ child->setBounds(IntSize(childRect.width(), childRect.height()));
+ child->setDrawsContent(true);
+
+ grandChild->setAnchorPoint(FloatPoint(0, 0));
+ grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+ grandChild->setOpacity(0.5f);
+ grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+ grandChild->setDrawsContent(true);
+
+ grandChild2->setAnchorPoint(FloatPoint(0, 0));
+ grandChild2->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+ grandChild2->setOpacity(0.5f);
+ grandChild2->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+ grandChild2->setDrawsContent(true);
+
+ CCLayerImpl* childPtr = child.get();
+ CCLayerImpl* grandChildPtr = grandChild.get();
+
+ grandChild->addChild(grandChild2.release());
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+
+ root->setMasksToBounds(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ {
+ WebTransformationMatrix identityMatrix;
+ Vector<CCLayerImpl*> layerList;
+ int dummyMaxTextureSize = 512;
+ CCLayerSorter layerSorter;
+
+ renderSurfaceLayerList.append(root.get());
+
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+ FloatRect dummyDamageRect;
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+ }
+
+ ASSERT_TRUE(childPtr->renderSurface());
+ ASSERT_TRUE(root->renderSurface());
+ ASSERT_TRUE(grandChildPtr->renderSurface());
+
+ EXPECT_EQ(renderSurfaceLayerList.size(), 3U);
+
+ // Now root is clipping to its bounds
+ ASSERT_EQ(root->clipRect(), rootRect);
+
+ ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, childRect.x() + grandChildRect.width() , childRect.y() + grandChildRect.height()));
+
+ // Grandchild now clips
+ ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+
+ ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+
+ // Child surface's clipping rect is now set to root's
+ ASSERT_EQ(childPtr->renderSurface()->clipRect(), rootRect);
+
+ ASSERT_TRUE(root->usesLayerClipping());
+ ASSERT_FALSE(childPtr->usesLayerClipping());
+ ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+
+ // Damage the entire screen
+ IntRect rootDamage(rootRect);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootRect));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+ // The damage is the entire rootRect, but child layer starts at an offset.
+ // Even though it has bounds, it is not clipping to bounds so its children
+ // (which extend beyond the bounds) extend the scissor rect
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+ // Grand child is now scissored by the render surface
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x() - grandChildRect.x(), rootRect.height() - childRect.y() - grandChildRect.y()));
+
+ // Empty damage
+ rootDamage = IntRect(0, 0, 0, 0);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Empty damage == empty scissor
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Partial damage within child
+ rootDamage = IntRect(10, 10, 20, 20);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child now gets scissored by its target surface as well as root
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+
+ // Partial damage beyond child
+ rootDamage = IntRect(10, 10, 80, 80);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Entire damage rect is within the root surface
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer
+ EXPECT_EQ(root->scissorRect(), rootDamage);
+
+ // Entire damage rect is within the layer, but with different offset
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+ // Grand child now gets scissored by its target surface as well as root
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+
+ // Partial damage beyond root
+ rootDamage = IntRect(10, 10, 110, 110);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+
+ // Scissors are not computed for root
+ EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+ // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Root does not use layer clipping, so its content rect will be used to intersect with damage
+ // Result is that root damage rect is clipped at root layer boundary
+ EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Now the scissor rects are clipped by surfaces contentRect
+ EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+ // Grandchild's scissor rect is clipped by its target surface
+ EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+}
+
TEST(CCLayerTreeHostCommonTest, verifyTransformsForReplica)
{
RefPtr<LayerChromium> parent = LayerChromium::create();
@@ -545,7 +1150,10 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForClipLayer)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > dummyLayerList;
int dummyMaxTextureSize = 512;
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ FloatRect dummyDamageRect;
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
// The child layer's content is entirely outside the parent's clip rect, so the intermediate
// render surface should have been removed. Render surfaces without children or visible
@@ -573,7 +1181,9 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForTransparentChild)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > dummyLayerList;
int dummyMaxTextureSize = 512;
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
// Since the layer is transparent, renderSurface1->renderSurface() should not have gotten added anywhere.
// Also, the drawable content rect should not have been extended by the children.
@@ -601,18 +1211,612 @@ TEST(CCLayerTreeHostCommonTest, verifyForceRenderSurface)
Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
Vector<RefPtr<LayerChromium> > dummyLayerList;
int dummyMaxTextureSize = 512;
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
EXPECT_TRUE(renderSurface1->renderSurface());
EXPECT_EQ(renderSurfaceLayerList.size(), 1U);
renderSurfaceLayerList.clear();
renderSurface1->setForceRenderSurface(false);
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
EXPECT_FALSE(renderSurface1->renderSurface());
EXPECT_EQ(renderSurfaceLayerList.size(), 0U);
}
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithDirectContainer)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // is the direct parent of the fixed-position layer.
+
+ DebugScopedSetImplThread scopedImplThread;
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setFixedToContainerLayer(true);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The expected drawTransforms without any scroll should still include a translation to the center of the layer (i.e. translation by 50, 50).
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform = expectedChildTransform;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 10
+ child->setScrollDelta(IntSize(10, 10));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child is affected by scrollDelta, but the fixed position grandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(40, 40);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithTransformedDirectContainer)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // is the direct parent of the fixed-position layer, but that container is transformed.
+ // In this case, the fixed position element inherits the container's transform,
+ // but the scrollDelta that has to be undone should not be affected by that transform.
+ //
+ // Transforms are in general non-commutative; using something like a non-uniform scale
+ // helps to verify that translations and non-uniform scales are applied in the correct
+ // order.
+
+ DebugScopedSetImplThread scopedImplThread;
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+
+ // This scale will cause child and grandChild to be effectively 200 x 800 with respect to the targetRenderSurface.
+ WebTransformationMatrix nonUniformScale;
+ nonUniformScale.scaleNonUniform(2, 8);
+ child->setTransform(nonUniformScale);
+
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setFixedToContainerLayer(true);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The expected drawTransforms without any scroll should still include a translation to the center of the layer (i.e. translation by 50, 50).
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.multiply(nonUniformScale);
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform = expectedChildTransform;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 20
+ child->setScrollDelta(IntSize(10, 20));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The child should be affected by scrollDelta, but the fixed position grandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, -20); // scrollDelta
+ expectedChildTransform.multiply(nonUniformScale);
+ expectedChildTransform.translate(50, 50);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithDistantContainer)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // is NOT the direct parent of the fixed-position layer.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ CCLayerImpl* greatGrandChild = grandChild->children()[0].get();
+
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setPosition(FloatPoint(8, 6));
+ greatGrandChild->setFixedToContainerLayer(true);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.translate(58, 56);
+
+ WebTransformationMatrix expectedGreatGrandChildTransform = expectedGrandChildTransform;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 10
+ child->setScrollDelta(IntSize(10, 10));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child and grandChild are affected by scrollDelta, but the fixed position greatGrandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(40, 40);
+ expectedGrandChildTransform.makeIdentity();
+ expectedGrandChildTransform.translate(48, 46);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithDistantContainerAndTransforms)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // is NOT the direct parent of the fixed-position layer, and the hierarchy has various
+ // transforms that have to be processed in the correct order.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ CCLayerImpl* greatGrandChild = grandChild->children()[0].get();
+
+ WebTransformationMatrix rotationAboutZ;
+ rotationAboutZ.rotate3d(0, 0, 90);
+
+ child->setIsContainerForFixedPositionLayers(true);
+ child->setTransform(rotationAboutZ);
+ grandChild->setPosition(FloatPoint(8, 6));
+ grandChild->setTransform(rotationAboutZ);
+ greatGrandChild->setFixedToContainerLayer(true); // greatGrandChild is positioned upside-down with respect to the targetRenderSurface
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.multiply(rotationAboutZ);
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.multiply(rotationAboutZ); // child's local transform is inherited
+ expectedGrandChildTransform.translate(8, 6); // translation because of position occurs before layer's local transform.
+ expectedGrandChildTransform.multiply(rotationAboutZ); // grandChild's local transform
+ expectedGrandChildTransform.translate(50, 50); // translation because of half-width half-height occurs after layer's local transform
+
+ WebTransformationMatrix expectedGreatGrandChildTransform = expectedGrandChildTransform;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 20
+ child->setScrollDelta(IntSize(10, 20));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child and grandChild are affected by scrollDelta, but the fixed position greatGrandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, -20); // scrollDelta
+ expectedChildTransform.multiply(rotationAboutZ);
+ expectedChildTransform.translate(50, 50);
+
+ expectedGrandChildTransform.makeIdentity();
+ expectedGrandChildTransform.translate(-10, -20); // child's scrollDelta is inherited
+ expectedGrandChildTransform.multiply(rotationAboutZ); // child's local transform is inherited
+ expectedGrandChildTransform.translate(8, 6); // translation because of position occurs before layer's local transform.
+ expectedGrandChildTransform.multiply(rotationAboutZ); // grandChild's local transform
+ expectedGrandChildTransform.translate(50, 50); // translation because of half-width half-height occurs after layer's local transform
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithMultipleScrollDeltas)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // has multiple ancestors that have nonzero scrollDelta before reaching the space where the layer is fixed.
+ // In this test, each scrollDelta occurs in a different space because of each layer's local transform.
+ // This test checks for correct scroll compensation when the fixed-position container
+ // is NOT the direct parent of the fixed-position layer, and the hierarchy has various
+ // transforms that have to be processed in the correct order.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ CCLayerImpl* greatGrandChild = grandChild->children()[0].get();
+
+ WebTransformationMatrix rotationAboutZ;
+ rotationAboutZ.rotate3d(0, 0, 90);
+
+ child->setIsContainerForFixedPositionLayers(true);
+ child->setTransform(rotationAboutZ);
+ grandChild->setPosition(FloatPoint(8, 6));
+ grandChild->setTransform(rotationAboutZ);
+ greatGrandChild->setFixedToContainerLayer(true); // greatGrandChild is positioned upside-down with respect to the targetRenderSurface
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.multiply(rotationAboutZ);
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.multiply(rotationAboutZ); // child's local transform is inherited
+ expectedGrandChildTransform.translate(8, 6); // translation because of position occurs before layer's local transform.
+ expectedGrandChildTransform.multiply(rotationAboutZ); // grandChild's local transform
+ expectedGrandChildTransform.translate(50, 50); // translation because of half-width half-height occurs after layer's local transform
+
+ WebTransformationMatrix expectedGreatGrandChildTransform = expectedGrandChildTransform;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 20
+ child->setScrollDelta(IntSize(10, 0));
+ grandChild->setScrollDelta(IntSize(5, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child and grandChild are affected by scrollDelta, but the fixed position greatGrandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, 0); // scrollDelta
+ expectedChildTransform.multiply(rotationAboutZ);
+ expectedChildTransform.translate(50, 50);
+
+ expectedGrandChildTransform.makeIdentity();
+ expectedGrandChildTransform.translate(-10, 0); // child's scrollDelta is inherited
+ expectedGrandChildTransform.multiply(rotationAboutZ); // child's local transform is inherited
+ expectedGrandChildTransform.translate(-5, 0); // grandChild's scrollDelta
+ expectedGrandChildTransform.translate(8, 6); // translation because of position occurs before layer's local transform.
+ expectedGrandChildTransform.multiply(rotationAboutZ); // grandChild's local transform
+ expectedGrandChildTransform.translate(50, 50); // translation because of half-width half-height occurs after layer's local transform
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithIntermediateSurfaceAndTransforms)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // contributes to a different renderSurface than the fixed-position layer. In this
+ // case, the surface originTransforms also have to be accounted for when checking the
+ // scrollDelta.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ CCLayerImpl* greatGrandChild = grandChild->children()[0].get();
+
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setPosition(FloatPoint(8, 6));
+ grandChild->setForceRenderSurface(true);
+ greatGrandChild->setFixedToContainerLayer(true);
+ greatGrandChild->setDrawsContent(true);
+
+ WebTransformationMatrix rotationAboutZ;
+ rotationAboutZ.rotate3d(0, 0, 90);
+ grandChild->setTransform(rotationAboutZ);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+ WebTransformationMatrix expectedSurfaceOriginTransform;
+ expectedSurfaceOriginTransform.translate(8, 6);
+ expectedSurfaceOriginTransform.multiply(rotationAboutZ);
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.translate(50, 50);
+ WebTransformationMatrix expectedGreatGrandChildTransform;
+ expectedGreatGrandChildTransform.translate(50, 50);
+ ASSERT_TRUE(grandChild->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedSurfaceOriginTransform, grandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 30
+ child->setScrollDelta(IntSize(10, 30));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the grandChild remains unchanged, because it scrolls along with the
+ // renderSurface, and the translation is actually in the renderSurface. But, the fixed
+ // position greatGrandChild is more awkward: its actually being drawn with respect to
+ // the renderSurface, but it needs to remain fixed with resepct to a container beyond
+ // that surface. So, the net result is that, unlike previous tests where the fixed
+ // position layer's transform remains unchanged, here the fixed position layer's
+ // transform explicitly contains the translation that cancels out the scroll.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, -30); // scrollDelta
+ expectedChildTransform.translate(50, 50);
+
+ expectedSurfaceOriginTransform.makeIdentity();
+ expectedSurfaceOriginTransform.translate(-10, -30); // scrollDelta
+ expectedSurfaceOriginTransform.translate(8, 6);
+ expectedSurfaceOriginTransform.multiply(rotationAboutZ);
+
+ // The rotation and its inverse are needed to place the scrollDelta compensation in
+ // the correct space. This test will fail if the rotation/inverse are backwards, too,
+ // so it requires perfect order of operations.
+ expectedGreatGrandChildTransform.makeIdentity();
+ expectedGreatGrandChildTransform.multiply(rotationAboutZ.inverse());
+ expectedGreatGrandChildTransform.translate(10, 30); // explicit canceling out the scrollDelta that gets embedded in the fixed position layer's surface.
+ expectedGreatGrandChildTransform.multiply(rotationAboutZ);
+ expectedGreatGrandChildTransform.translate(50, 50);
+
+ ASSERT_TRUE(grandChild->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedSurfaceOriginTransform, grandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithMultipleIntermediateSurfaces)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // contributes to a different renderSurface than the fixed-position layer, with
+ // additional renderSurfaces in-between. This checks that the conversion to ancestor
+ // surfaces is accumulated properly in the final matrix transform.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ CCLayerImpl* greatGrandChild = grandChild->children()[0].get();
+
+ // Add one more layer to the test tree for this scenario.
+ {
+ WebTransformationMatrix identity;
+ OwnPtr<CCLayerImpl> fixedPositionChild = CCLayerImpl::create(5);
+ setLayerPropertiesForTesting(fixedPositionChild.get(), identity, identity, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+ greatGrandChild->addChild(fixedPositionChild.release());
+ }
+ CCLayerImpl* fixedPositionChild = greatGrandChild->children()[0].get();
+
+ // Actually set up the scenario here.
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setPosition(FloatPoint(8, 6));
+ grandChild->setForceRenderSurface(true);
+ greatGrandChild->setPosition(FloatPoint(140, 120));
+ greatGrandChild->setForceRenderSurface(true);
+ fixedPositionChild->setFixedToContainerLayer(true);
+ fixedPositionChild->setDrawsContent(true);
+
+ // The additional rotations, which are non-commutative with translations, help to
+ // verify that we have correct order-of-operations in the final scroll compensation.
+ WebTransformationMatrix rotationAboutZ;
+ rotationAboutZ.rotate3d(0, 0, 90);
+ grandChild->setTransform(rotationAboutZ);
+ greatGrandChild->setTransform(rotationAboutZ);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildSurfaceOriginTransform;
+ expectedGrandChildSurfaceOriginTransform.translate(8, 6);
+ expectedGrandChildSurfaceOriginTransform.multiply(rotationAboutZ);
+
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGreatGrandChildSurfaceOriginTransform;
+ expectedGreatGrandChildSurfaceOriginTransform.translate(140, 120);
+ expectedGreatGrandChildSurfaceOriginTransform.multiply(rotationAboutZ);
+
+ WebTransformationMatrix expectedGreatGrandChildTransform;
+ expectedGreatGrandChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedFixedPositionChildTransform;
+ expectedFixedPositionChildTransform.translate(50, 50);
+
+ ASSERT_TRUE(grandChild->renderSurface());
+ ASSERT_TRUE(greatGrandChild->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildSurfaceOriginTransform, grandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildSurfaceOriginTransform, greatGrandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedFixedPositionChildTransform, fixedPositionChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 30
+ child->setScrollDelta(IntSize(10, 30));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, -30); // scrollDelta
+ expectedChildTransform.translate(50, 50);
+
+ expectedGrandChildSurfaceOriginTransform.makeIdentity();
+ expectedGrandChildSurfaceOriginTransform.translate(-10, -30); // scrollDelta
+ expectedGrandChildSurfaceOriginTransform.translate(8, 6);
+ expectedGrandChildSurfaceOriginTransform.multiply(rotationAboutZ);
+
+ // grandChild, greatGrandChild, and greatGrandChild's surface are not expected to
+ // change, since they are all not fixed, and they are all drawn with respect to
+ // grandChild's surface that already has the scrollDelta accounted for.
+
+ // But the great-great grandchild, "fixedPositionChild", should have a transform that explicitly cancels out the scrollDelta.
+ // The expected transform is:
+ // compoundOriginTransform.inverse() * translate(positive scrollDelta) * compoundOriginTransform * half-width-half-height translation
+ WebTransformationMatrix compoundOriginTransform; // transform from greatGrandChildSurface's origin to the root surface.
+ compoundOriginTransform.translate(8, 6); // origin translation of grandChild
+ compoundOriginTransform.multiply(rotationAboutZ); // rotation of grandChild
+ compoundOriginTransform.translate(140, 120); // origin translation of greatGrandChild
+ compoundOriginTransform.multiply(rotationAboutZ); // rotation of greatGrandChild
+
+ expectedFixedPositionChildTransform.makeIdentity();
+ expectedFixedPositionChildTransform.multiply(compoundOriginTransform.inverse());
+ expectedFixedPositionChildTransform.translate(10, 30); // explicit canceling out the scrollDelta that gets embedded in the fixed position layer's surface.
+ expectedFixedPositionChildTransform.multiply(compoundOriginTransform);
+ expectedFixedPositionChildTransform.translate(50, 50);
+
+ ASSERT_TRUE(grandChild->renderSurface());
+ ASSERT_TRUE(greatGrandChild->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildSurfaceOriginTransform, grandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildSurfaceOriginTransform, greatGrandChild->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGreatGrandChildTransform, greatGrandChild->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedFixedPositionChildTransform, fixedPositionChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerWithContainerLayerThatHasSurface)
+{
+ // This test checks for correct scroll compensation when the fixed-position container
+ // itself has a renderSurface. In this case, the container layer should be treated
+ // like a layer that contributes to a targetRenderSurface, and that targetRenderSurface
+ // is completely irrelevant; it should not affect the scroll compensation.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+
+ child->setIsContainerForFixedPositionLayers(true);
+ child->setForceRenderSurface(true);
+ grandChild->setFixedToContainerLayer(true);
+ grandChild->setDrawsContent(true);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The expected draw transforms without any scroll should still include a translation to the center of the layer (i.e. translation by 50, 50).
+ WebTransformationMatrix expectedSurfaceOriginTransform;
+ expectedSurfaceOriginTransform.translate(0, 0);
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.translate(50, 50);
+ ASSERT_TRUE(child->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedSurfaceOriginTransform, child->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 10
+ child->setScrollDelta(IntSize(10, 10));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The surface is translated by scrollDelta, the child transform doesn't change
+ // because it scrolls along with the surface, but the fixed position grandChild
+ // needs to compensate for the scroll translation.
+ expectedSurfaceOriginTransform.makeIdentity();
+ expectedSurfaceOriginTransform.translate(-10, -10);
+ expectedGrandChildTransform.makeIdentity();
+ expectedGrandChildTransform.translate(60, 60);
+ ASSERT_TRUE(child->renderSurface());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedSurfaceOriginTransform, child->renderSurface()->originTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerThatIsAlsoFixedPositionContainer)
+{
+ // This test checks the scenario where a fixed-position layer also happens to be a
+ // container itself for a descendant fixed position layer. In particular, the layer
+ // should not accidentally be fixed to itself.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+
+ child->setIsContainerForFixedPositionLayers(true);
+ grandChild->setFixedToContainerLayer(true);
+
+ // This should not confuse the grandChild. If correct, the grandChild would still be considered fixed to its container (i.e. "child").
+ grandChild->setIsContainerForFixedPositionLayers(true);
+
+ // Case 1: scrollDelta of 0, 0
+ child->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The expected draw transforms without any scroll should still include a translation to the center of the layer (i.e. translation by 50, 50).
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.translate(50, 50);
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.translate(50, 50);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+
+ // Case 2: scrollDelta of 10, 10
+ child->setScrollDelta(IntSize(10, 10));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child is affected by scrollDelta, but the fixed position grandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(40, 40);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyScrollCompensationForFixedPositionLayerThatHasNoContainer)
+{
+ // This test checks scroll compensation when a fixed-position layer does not find any
+ // ancestor that is a "containerForFixedPositionLayers". In this situation, the layer should
+ // be fixed to the viewport -- not the rootLayer, which may have transforms of its own.
+ DebugScopedSetImplThread scopedImplThread;
+
+ OwnPtr<CCLayerImpl> root = createTreeForFixedPositionTests();
+ CCLayerImpl* child = root->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+
+ WebTransformationMatrix rotationByZ;
+ rotationByZ.rotate3d(0, 0, 90);
+
+ root->setTransform(rotationByZ);
+ grandChild->setFixedToContainerLayer(true);
+
+ // Case 1: root scrollDelta of 0, 0
+ root->setScrollDelta(IntSize(0, 0));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // The expected draw transforms without any scroll should still include a translation to the center of the layer (i.e. translation by 50, 50).
+ WebTransformationMatrix expectedChildTransform;
+ expectedChildTransform.multiply(rotationByZ);
+ expectedChildTransform.translate(50, 50);
+
+ WebTransformationMatrix expectedGrandChildTransform;
+ expectedGrandChildTransform.multiply(rotationByZ);
+ expectedGrandChildTransform.translate(50, 50);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+
+ // Case 2: root scrollDelta of 10, 10
+ root->setScrollDelta(IntSize(10, 10));
+ executeCalculateDrawTransformsAndVisibility(root.get());
+
+ // Here the child is affected by scrollDelta, but the fixed position grandChild should not be affected.
+ expectedChildTransform.makeIdentity();
+ expectedChildTransform.translate(-10, -10); // the scrollDelta
+ expectedChildTransform.multiply(rotationByZ);
+ expectedChildTransform.translate(50, 50);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedGrandChildTransform, grandChild->drawTransform());
+}
+
TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces)
{
// The entire subtree of layers that are outside the clipRect should be culled away,
@@ -666,7 +1870,11 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ FloatRect dummyDamageRect;
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
+
ASSERT_EQ(2U, renderSurfaceLayerList.size());
EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id());
@@ -725,7 +1933,9 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfacesCrashRepro)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
ASSERT_EQ(2U, renderSurfaceLayerList.size());
EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id());
@@ -776,7 +1986,7 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsSurfaceWithoutVisibleContent)
parent->createRenderSurface();
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
// Without an animation, we should cull child and grandChild from the renderSurfaceLayerList.
ASSERT_EQ(1U, renderSurfaceLayerList.size());
@@ -795,7 +2005,7 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsSurfaceWithoutVisibleContent)
parent->createRenderSurface();
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
// With an animating transform, we should keep child and grandChild in the renderSurfaceLayerList.
ASSERT_EQ(3U, renderSurfaceLayerList.size());
@@ -855,7 +2065,10 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectIsPropagatedCorrectlyToLayers)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
+
EXPECT_INT_RECT_EQ(IntRect(IntPoint::zero(), IntSize(20, 20)), grandChild1->clipRect());
EXPECT_INT_RECT_EQ(IntRect(IntPoint::zero(), IntSize(20, 20)), grandChild2->clipRect());
@@ -927,7 +2140,9 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectIsPropagatedCorrectlyToSurfaces)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
ASSERT_TRUE(grandChild1->renderSurface());
ASSERT_TRUE(grandChild2->renderSurface());
@@ -1408,7 +2623,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithoutPreserves3d)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
// Verify which renderSurfaces were created.
EXPECT_FALSE(frontFacingChild->renderSurface());
@@ -1513,7 +2728,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3d)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
// Verify which renderSurfaces were created.
EXPECT_FALSE(frontFacingChild->renderSurface());
@@ -1598,7 +2813,9 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithAnimatingTransforms)
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
EXPECT_FALSE(child->renderSurface());
EXPECT_TRUE(animatingSurface->renderSurface());
@@ -1670,7 +2887,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3dForFlattenin
parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
renderSurfaceLayerList.append(parent.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
// Verify which renderSurfaces were created.
EXPECT_TRUE(frontFacingSurface->renderSurface());
@@ -1693,6 +2910,780 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3dForFlattenin
EXPECT_EQ(child1->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[1]->id());
}
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForEmptyLayerList)
+{
+ // Hit testing on an empty renderSurfaceLayerList should return a null pointer.
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+
+ IntPoint testPoint(0, 0);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(10, 20);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSingleLayer)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ IntPoint testPoint(101, 101);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(-1, -1);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the root layer.
+ testPoint = IntPoint(1, 1);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+
+ testPoint = IntPoint(99, 99);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForUninvertibleTransform)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix uninvertibleTransform;
+ uninvertibleTransform.setM11(0);
+ uninvertibleTransform.setM22(0);
+ uninvertibleTransform.setM33(0);
+ uninvertibleTransform.setM44(0);
+ ASSERT_FALSE(uninvertibleTransform.isInvertible());
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), uninvertibleTransform, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+ ASSERT_FALSE(root->screenSpaceTransform().isInvertible());
+
+ // Hit testing any point should not hit the layer. If the invertible matrix is
+ // accidentally ignored and treated like an identity, then the hit testing will
+ // incorrectly hit the layer when it shouldn't.
+ IntPoint testPoint(1, 1);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(10, 10);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(10, 30);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(50, 50);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(67, 48);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(99, 99);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(-1, -1);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSinglePositionedLayer)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(50, 50); // this layer is positioned, and hit testing should correctly know where the layer is located.
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ IntPoint testPoint(49, 49);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Even though the layer exists at (101, 101), it should not be visible there since the root renderSurface would clamp it.
+ testPoint = IntPoint(101, 101);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the root layer.
+ testPoint = IntPoint(51, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+
+ testPoint = IntPoint(99, 99);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSingleRotatedLayer)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ WebTransformationMatrix rotation45DegreesAboutCenter;
+ rotation45DegreesAboutCenter.translate(50, 50);
+ rotation45DegreesAboutCenter.rotate3d(0, 0, 45);
+ rotation45DegreesAboutCenter.translate(-50, -50);
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), rotation45DegreesAboutCenter, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for points outside the layer.
+ // These corners would have been inside the un-transformed layer, but they should not hit the correctly transformed layer.
+ IntPoint testPoint(99, 99);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(1, 1);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the root layer.
+ testPoint = IntPoint(1, 50);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+
+ // Hit testing the corners that would overlap the unclipped layer, but are outside the clipped region.
+ testPoint = IntPoint(50, -1);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_FALSE(resultLayer);
+
+ testPoint = IntPoint(-1, 50);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_FALSE(resultLayer);
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSinglePerspectiveLayer)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+
+ // perspectiveProjectionAboutCenter * translationByZ is designed so that the 100 x 100 layer becomes 50 x 50, and remains centered at (50, 50).
+ WebTransformationMatrix perspectiveProjectionAboutCenter;
+ perspectiveProjectionAboutCenter.translate(50, 50);
+ perspectiveProjectionAboutCenter.applyPerspective(1);
+ perspectiveProjectionAboutCenter.translate(-50, -50);
+ WebTransformationMatrix translationByZ;
+ translationByZ.translate3d(0, 0, -1);
+
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), perspectiveProjectionAboutCenter * translationByZ, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for points outside the layer.
+ // These corners would have been inside the un-transformed layer, but they should not hit the correctly transformed layer.
+ IntPoint testPoint(24, 24);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ testPoint = IntPoint(76, 76);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the root layer.
+ testPoint = IntPoint(26, 26);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+
+ testPoint = IntPoint(74, 74);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSingleLayerWithScaledContents)
+{
+ // A layer's visibleLayerRect is actually in the layer's content space. The
+ // screenSpaceTransform converts from the layer's origin space to screen space. This
+ // test makes sure that hit testing works correctly accounts for the contents scale.
+ // A contentsScale that is not 1 effectively forces a non-identity transform between
+ // layer's content space and layer's origin space, which is not included in the
+ // screenSpaceTransformn. The hit testing code must take this into account.
+ //
+ // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
+ // contentsScale is ignored, then hit testing will mis-interpret the visibleLayerRect
+ // as being larger than the actual bounds of the layer.
+ //
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(12345);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(25, 25);
+ IntSize bounds(50, 50);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ root->setContentBounds(IntSize(100, 100));
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ // The visibleLayerRect is actually 100x100, even though the layout size of the layer is 50x50, positioned at 25x25.
+ EXPECT_INT_RECT_EQ(IntRect(IntPoint::zero(), IntSize(100, 100)), root->visibleLayerRect());
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ IntPoint testPoint(24, 24);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Even though the layer exists at (101, 101), it should not be visible there since the root renderSurface would clamp it.
+ // This case in particular is likely to fail if contents scale is not correctly accounted for.
+ testPoint = IntPoint(76, 76);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the root layer.
+ testPoint = IntPoint(26, 26);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+
+ testPoint = IntPoint(74, 74);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(12345, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForSimpleClippedLayer)
+{
+ // Test that hit-testing will only work for the visible portion of a layer, and not
+ // the entire layer bounds. Here we just test the simple axis-aligned case.
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(123);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(25, 25); // this layer is positioned, and hit testing should correctly know where the layer is located.
+ IntSize bounds(50, 50);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setMasksToBounds(true);
+
+ {
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(456);
+ position = FloatPoint(-50, -50);
+ bounds = IntSize(300, 300);
+ setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child->setDrawsContent(true);
+ root->addChild(child.release());
+ }
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, root->renderSurface()->layerList().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ // Despite the child layer being very large, it should be clipped to the root layer's bounds.
+ IntPoint testPoint(24, 24);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Even though the layer exists at (101, 101), it should not be visible there since the root renderSurface would clamp it.
+ testPoint = IntPoint(76, 76);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Hit testing for a point inside should return the child layer.
+ testPoint = IntPoint(26, 26);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(456, resultLayer->id());
+
+ testPoint = IntPoint(74, 74);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(456, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForMultiClippedRotatedLayer)
+{
+ // This test checks whether hit testing correctly avoids hit testing with multiple
+ // ancestors that clip in non axis-aligned ways. To pass this test, the hit testing
+ // algorithm needs to recognize that multiple parent layers may clip the layer, and
+ // should not actually hit those clipped areas.
+ //
+ // The child and grandChild layers are both initialized to clip the rotatedLeaf. The
+ // child layer is rotated about the top-left corner, so that the root + child clips
+ // combined create a triangle. The rotatedLeaf will only be visible where it overlaps
+ // this triangle.
+ //
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(123);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setMasksToBounds(true);
+
+ {
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(456);
+ OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(789);
+ OwnPtr<CCLayerImpl> rotatedLeaf = CCLayerImpl::create(2468);
+
+ position = FloatPoint(10, 10);
+ bounds = IntSize(80, 80);
+ setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child->setMasksToBounds(true);
+
+ WebTransformationMatrix rotation45DegreesAboutCorner;
+ rotation45DegreesAboutCorner.rotate3d(0, 0, 45);
+
+ position = FloatPoint(0, 0); // remember, positioned with respect to its parent which is already at 10, 10
+ bounds = IntSize(200, 200); // to ensure it covers at least sqrt(2) * 100.
+ setLayerPropertiesForTesting(grandChild.get(), rotation45DegreesAboutCorner, identityMatrix, anchor, position, bounds, false);
+ grandChild->setMasksToBounds(true);
+
+ // Rotates about the center of the layer
+ WebTransformationMatrix rotatedLeafTransform;
+ rotatedLeafTransform.translate(-10, -10); // cancel out the grandParent's position
+ rotatedLeafTransform.rotate3d(0, 0, -45); // cancel out the corner 45-degree rotation of the parent.
+ rotatedLeafTransform.translate(50, 50);
+ rotatedLeafTransform.rotate3d(0, 0, 45);
+ rotatedLeafTransform.translate(-50, -50);
+ position = FloatPoint(0, 0);
+ bounds = IntSize(100, 100);
+ setLayerPropertiesForTesting(rotatedLeaf.get(), rotatedLeafTransform, identityMatrix, anchor, position, bounds, false);
+ rotatedLeaf->setDrawsContent(true);
+
+ grandChild->addChild(rotatedLeaf.release());
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+ }
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ // The grandChild is expected to create a renderSurface because it masksToBounds and is not axis aligned.
+ ASSERT_EQ(2u, renderSurfaceLayerList.size());
+ ASSERT_EQ(1u, renderSurfaceLayerList[0]->renderSurface()->layerList().size());
+ ASSERT_EQ(789, renderSurfaceLayerList[0]->renderSurface()->layerList()[0]->id()); // grandChild's surface.
+ ASSERT_EQ(1u, renderSurfaceLayerList[1]->renderSurface()->layerList().size());
+ ASSERT_EQ(2468, renderSurfaceLayerList[1]->renderSurface()->layerList()[0]->id());
+
+ // (11, 89) is close to the the bottom left corner within the clip, but it is not inside the layer.
+ IntPoint testPoint(11, 89);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Closer inwards from the bottom left will overlap the layer.
+ testPoint = IntPoint(25, 75);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(2468, resultLayer->id());
+
+ // (4, 50) is inside the unclipped layer, but that corner of the layer should be
+ // clipped away by the grandParent and should not get hit. If hit testing blindly uses
+ // visibleLayerRect without considering how parent may clip the layer, then hit
+ // testing would accidentally think that the point successfully hits the layer.
+ testPoint = IntPoint(4, 50);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // (11, 50) is inside the layer and within the clipped area.
+ testPoint = IntPoint(11, 50);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(2468, resultLayer->id());
+
+ // Around the middle, just to the right and up, would have hit the layer except that
+ // that area should be clipped away by the parent.
+ testPoint = IntPoint(51, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ EXPECT_FALSE(resultLayer);
+
+ // Around the middle, just to the left and down, should successfully hit the layer.
+ testPoint = IntPoint(49, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(2468, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForMultipleLayers)
+{
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ {
+ // child 1 and child2 are initialized to overlap between x=50 and x=60.
+ // grandChild is set to overlap both child1 and child2 between y=50 and y=60.
+ // The expected stacking order is:
+ // (front) child2, (second) grandChild, (third) child1, and (back) the root layer behind all other layers.
+
+ OwnPtr<CCLayerImpl> child1 = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> child2 = CCLayerImpl::create(3);
+ OwnPtr<CCLayerImpl> grandChild1 = CCLayerImpl::create(4);
+
+ position = FloatPoint(10, 10);
+ bounds = IntSize(50, 50);
+ setLayerPropertiesForTesting(child1.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child1->setDrawsContent(true);
+
+ position = FloatPoint(50, 10);
+ bounds = IntSize(50, 50);
+ setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child2->setDrawsContent(true);
+
+ // Remember that grandChild is positioned with respect to its parent (i.e. child1).
+ // In screen space, the intended position is (10, 50), with size 100 x 50.
+ position = FloatPoint(0, 40);
+ bounds = IntSize(100, 50);
+ setLayerPropertiesForTesting(grandChild1.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ grandChild1->setDrawsContent(true);
+
+ child1->addChild(grandChild1.release());
+ root->addChild(child1.release());
+ root->addChild(child2.release());
+ }
+
+ CCLayerImpl* child1 = root->children()[0].get();
+ CCLayerImpl* child2 = root->children()[1].get();
+ CCLayerImpl* grandChild1 = child1->children()[0].get();
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_TRUE(child1);
+ ASSERT_TRUE(child2);
+ ASSERT_TRUE(grandChild1);
+ ASSERT_EQ(1u, renderSurfaceLayerList.size());
+ ASSERT_EQ(4u, root->renderSurface()->layerList().size());
+ ASSERT_EQ(1, root->renderSurface()->layerList()[0]->id()); // root layer
+ ASSERT_EQ(2, root->renderSurface()->layerList()[1]->id()); // child1
+ ASSERT_EQ(4, root->renderSurface()->layerList()[2]->id()); // grandChild1
+ ASSERT_EQ(3, root->renderSurface()->layerList()[3]->id()); // child2
+
+ // Nothing overlaps the rootLayer at (1, 1), so hit testing there should find the root layer.
+ IntPoint testPoint = IntPoint(1, 1);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(1, resultLayer->id());
+
+ // At (15, 15), child1 and root are the only layers. child1 is expected to be on top.
+ testPoint = IntPoint(15, 15);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(2, resultLayer->id());
+
+ // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
+ testPoint = IntPoint(51, 20);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (80, 51), child2 and grandChild1 overlap. child2 is expected to be on top.
+ testPoint = IntPoint(80, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (51, 51), all layers overlap each other. child2 is expected to be on top of all other layers.
+ testPoint = IntPoint(51, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (20, 51), child1 and grandChild1 overlap. grandChild1 is expected to be on top.
+ testPoint = IntPoint(20, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(4, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifyHitTestingForMultipleLayerLists)
+{
+ //
+ // The geometry is set up similarly to the previous case, but
+ // all layers are forced to be renderSurfaces now.
+ //
+ DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ root->createRenderSurface();
+ root->renderSurface()->setContentRect(IntRect(IntPoint::zero(), IntSize(100, 100)));
+
+ WebTransformationMatrix identityMatrix;
+ FloatPoint anchor(0, 0);
+ FloatPoint position(0, 0);
+ IntSize bounds(100, 100);
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ root->setDrawsContent(true);
+
+ {
+ // child 1 and child2 are initialized to overlap between x=50 and x=60.
+ // grandChild is set to overlap both child1 and child2 between y=50 and y=60.
+ // The expected stacking order is:
+ // (front) child2, (second) grandChild, (third) child1, and (back) the root layer behind all other layers.
+
+ OwnPtr<CCLayerImpl> child1 = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> child2 = CCLayerImpl::create(3);
+ OwnPtr<CCLayerImpl> grandChild1 = CCLayerImpl::create(4);
+
+ position = FloatPoint(10, 10);
+ bounds = IntSize(50, 50);
+ setLayerPropertiesForTesting(child1.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child1->setDrawsContent(true);
+ child1->setForceRenderSurface(true);
+
+ position = FloatPoint(50, 10);
+ bounds = IntSize(50, 50);
+ setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ child2->setDrawsContent(true);
+ child2->setForceRenderSurface(true);
+
+ // Remember that grandChild is positioned with respect to its parent (i.e. child1).
+ // In screen space, the intended position is (10, 50), with size 100 x 50.
+ position = FloatPoint(0, 40);
+ bounds = IntSize(100, 50);
+ setLayerPropertiesForTesting(grandChild1.get(), identityMatrix, identityMatrix, anchor, position, bounds, false);
+ grandChild1->setDrawsContent(true);
+ grandChild1->setForceRenderSurface(true);
+
+ child1->addChild(grandChild1.release());
+ root->addChild(child1.release());
+ root->addChild(child2.release());
+ }
+
+ CCLayerImpl* child1 = root->children()[0].get();
+ CCLayerImpl* child2 = root->children()[1].get();
+ CCLayerImpl* grandChild1 = child1->children()[0].get();
+
+ Vector<CCLayerImpl*> renderSurfaceLayerList;
+ Vector<CCLayerImpl*> dummyLayerList;
+ int dummyMaxTextureSize = 512;
+ renderSurfaceLayerList.append(root.get());
+ CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, FloatRect()); // empty scissorRect will help ensure we're hit testing the correct rect.
+
+ // Sanity check the scenario we just created.
+ ASSERT_TRUE(child1);
+ ASSERT_TRUE(child2);
+ ASSERT_TRUE(grandChild1);
+ ASSERT_TRUE(child1->renderSurface());
+ ASSERT_TRUE(child2->renderSurface());
+ ASSERT_TRUE(grandChild1->renderSurface());
+ ASSERT_EQ(4u, renderSurfaceLayerList.size());
+ ASSERT_EQ(3u, root->renderSurface()->layerList().size()); // The root surface has the root layer, and child1's and child2's renderSurfaces.
+ ASSERT_EQ(2u, child1->renderSurface()->layerList().size()); // The child1 surface has the child1 layer and grandChild1's renderSurface.
+ ASSERT_EQ(1u, child2->renderSurface()->layerList().size());
+ ASSERT_EQ(1u, grandChild1->renderSurface()->layerList().size());
+ ASSERT_EQ(1, renderSurfaceLayerList[0]->id()); // root layer
+ ASSERT_EQ(2, renderSurfaceLayerList[1]->id()); // child1
+ ASSERT_EQ(4, renderSurfaceLayerList[2]->id()); // grandChild1
+ ASSERT_EQ(3, renderSurfaceLayerList[3]->id()); // child2
+
+ // Nothing overlaps the rootLayer at (1, 1), so hit testing there should find the root layer.
+ IntPoint testPoint = IntPoint(1, 1);
+ CCLayerImpl* resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(1, resultLayer->id());
+
+ // At (15, 15), child1 and root are the only layers. child1 is expected to be on top.
+ testPoint = IntPoint(15, 15);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(2, resultLayer->id());
+
+ // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
+ testPoint = IntPoint(51, 20);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (80, 51), child2 and grandChild1 overlap. child2 is expected to be on top.
+ testPoint = IntPoint(80, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (51, 51), all layers overlap each other. child2 is expected to be on top of all other layers.
+ testPoint = IntPoint(51, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(3, resultLayer->id());
+
+ // At (20, 51), child1 and grandChild1 overlap. grandChild1 is expected to be on top.
+ testPoint = IntPoint(20, 51);
+ resultLayer = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(testPoint, renderSurfaceLayerList);
+ ASSERT_TRUE(resultLayer);
+ EXPECT_EQ(4, resultLayer->id());
+}
+
+TEST(CCLayerTreeHostCommonTest, verifySubtreeSearch)
+{
+ RefPtr<LayerChromium> root = LayerChromium::create();
+ RefPtr<LayerChromium> child = LayerChromium::create();
+ RefPtr<LayerChromium> grandChild = LayerChromium::create();
+ RefPtr<LayerChromium> maskLayer = LayerChromium::create();
+ RefPtr<LayerChromium> replicaLayer = LayerChromium::create();
+
+ grandChild->setReplicaLayer(replicaLayer.get());
+ child->addChild(grandChild.get());
+ child->setMaskLayer(maskLayer.get());
+ root->addChild(child.get());
+
+ int nonexistentId = -1;
+ EXPECT_EQ(root, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), root->id()));
+ EXPECT_EQ(child, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), child->id()));
+ EXPECT_EQ(grandChild, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), grandChild->id()));
+ EXPECT_EQ(maskLayer, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), maskLayer->id()));
+ EXPECT_EQ(replicaLayer, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), replicaLayer->id()));
+ EXPECT_EQ(0, CCLayerTreeHostCommon::findLayerInSubtree(root.get(), nonexistentId));
+}
+
// FIXME:
// continue working on https://bugs.webkit.org/show_bug.cgi?id=68942
// - add a test to verify clipping that changes the "center point"
diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp
index 91c2d1dff..738c88190 100644
--- a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp
@@ -28,18 +28,24 @@
#include "CCAnimationTestCommon.h"
#include "CCLayerTestCommon.h"
+#include "CCTestCommon.h"
#include "FakeWebGraphicsContext3D.h"
#include "GraphicsContext3DPrivate.h"
#include "LayerRendererChromium.h"
+#include "cc/CCIOSurfaceLayerImpl.h"
#include "cc/CCLayerImpl.h"
#include "cc/CCLayerTilingData.h"
#include "cc/CCQuadCuller.h"
+#include "cc/CCRenderPassDrawQuad.h"
#include "cc/CCScrollbarLayerImpl.h"
+#include "cc/CCSettings.h"
#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCSolidColorDrawQuad.h"
#include "cc/CCTextureLayerImpl.h"
#include "cc/CCTileDrawQuad.h"
#include "cc/CCTiledLayerImpl.h"
#include "cc/CCVideoLayerImpl.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <public/WebVideoFrame.h>
#include <public/WebVideoFrameProvider.h>
@@ -49,6 +55,12 @@ using namespace WebCore;
using namespace WebKit;
using namespace WebKitTests;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::AnyNumber;
+using ::testing::AtLeast;
+using ::testing::_;
+
namespace {
class CCLayerTreeHostImplTest : public testing::Test, public CCLayerTreeHostImplClient {
@@ -57,7 +69,7 @@ public:
: m_didRequestCommit(false)
, m_didRequestRedraw(false)
{
- CCSettings settings;
+ CCLayerTreeSettings settings;
m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
m_hostImpl->setViewportSize(IntSize(10, 10));
@@ -70,6 +82,28 @@ public:
virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { }
virtual void postSetContentsMemoryAllocationLimitBytesToMainThreadOnImplThread(size_t) OVERRIDE { }
+ PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, PassRefPtr<CCGraphicsContext> graphicsContext, PassOwnPtr<CCLayerImpl> rootPtr)
+ {
+ CCSettings::setPartialSwapEnabled(partialSwap);
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
+
+ myHostImpl->initializeLayerRenderer(graphicsContext, UnthrottledUploader);
+ myHostImpl->setViewportSize(IntSize(10, 10));
+
+ OwnPtr<CCLayerImpl> root = rootPtr;
+
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(0, 0));
+ root->setBounds(IntSize(10, 10));
+ root->setContentBounds(IntSize(10, 10));
+ root->setVisibleLayerRect(IntRect(0, 0, 10, 10));
+ root->setDrawsContent(true);
+ myHostImpl->setRootLayer(root.release());
+ return myHostImpl.release();
+ }
+
static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
{
ASSERT_EQ(layer->scrollDelta(), IntSize());
@@ -106,10 +140,31 @@ public:
m_hostImpl->setRootLayer(root.release());
}
+ static PassOwnPtr<CCLayerImpl> createScrollableLayer(int id, const FloatPoint& position, const IntSize& size)
+ {
+ OwnPtr<CCLayerImpl> layer = CCLayerImpl::create(id);
+ layer->setScrollable(true);
+ layer->setDrawsContent(true);
+ layer->setPosition(position);
+ layer->setBounds(size);
+ layer->setContentBounds(size);
+ layer->setMaxScrollPosition(IntSize(size.width() * 2, size.height() * 2));
+ return layer.release();
+ }
+
+ void initializeLayerRendererAndDrawFrame()
+ {
+ m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
+ m_hostImpl->drawLayers(frame);
+ m_hostImpl->didDrawAllLayers(frame);
+ }
+
protected:
- PassRefPtr<GraphicsContext3D> createContext()
+ PassRefPtr<CCGraphicsContext> createContext()
{
- return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ return CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow));
}
DebugScopedSetImplThread m_alwaysImplThread;
@@ -118,6 +173,7 @@ protected:
OwnPtr<CCLayerTreeHostImpl> m_hostImpl;
bool m_didRequestCommit;
bool m_didRequestRedraw;
+ CCScopedSettings m_scopedSettings;
};
TEST_F(CCLayerTreeHostImplTest, scrollDeltaNoLayers)
@@ -189,13 +245,9 @@ TEST_F(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls)
TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
{
- {
- OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
- root->setScrollable(true);
- root->setScrollPosition(IntPoint(0, 0));
- root->setMaxScrollPosition(IntSize(100, 100));
- m_hostImpl->setRootLayer(root.release());
- }
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
m_hostImpl->scrollBy(IntSize(0, 10));
@@ -204,20 +256,57 @@ TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
EXPECT_TRUE(m_didRequestCommit);
}
+TEST_F(CCLayerTreeHostImplTest, scrollWithoutRootLayer)
+{
+ // We should not crash when trying to scroll an empty layer tree.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
+}
+
+TEST_F(CCLayerTreeHostImplTest, replaceTreeWhileScrolling)
+{
+ const int scrollLayerId = 0;
+
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
+
+ // We should not crash if the tree is replaced while we are scrolling.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->detachLayerTree();
+
+ setupScrollAndContentsLayers(IntSize(100, 100));
+
+ // We should still be scrolling, because the scrolled layer also exists in the new tree.
+ IntSize scrollDelta(0, 10);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo, scrollLayerId, scrollDelta);
+}
+
+TEST_F(CCLayerTreeHostImplTest, clearRootRenderSurfaceAndScroll)
+{
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
+
+ // We should be able to scroll even if the root layer loses its render surface after the most
+ // recent render.
+ m_hostImpl->rootLayer()->clearRenderSurface();
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+}
+
TEST_F(CCLayerTreeHostImplTest, wheelEventHandlers)
{
- {
- OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
- root->setScrollable(true);
- root->setScrollPosition(IntPoint(0, 0));
- root->setMaxScrollPosition(IntSize(100, 100));
- m_hostImpl->setRootLayer(root.release());
- }
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
CCLayerImpl* root = m_hostImpl->rootLayer();
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);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
// But gesture scrolls can still be handled.
EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
@@ -225,27 +314,29 @@ TEST_F(CCLayerTreeHostImplTest, wheelEventHandlers)
TEST_F(CCLayerTreeHostImplTest, shouldScrollOnMainThread)
{
- OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
- root->setScrollable(true);
- root->setScrollPosition(IntPoint(0, 0));
- root->setMaxScrollPosition(IntSize(100, 100));
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
+ CCLayerImpl* root = m_hostImpl->rootLayer();
+
root->setShouldScrollOnMainThread(true);
- m_hostImpl->setRootLayer(root.release());
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollFailed);
+
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread);
}
TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic)
{
- OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
- root->setScrollable(true);
- root->setScrollPosition(IntPoint(0, 0));
- root->setMaxScrollPosition(IntSize(100, 100));
+ setupScrollAndContentsLayers(IntSize(200, 200));
+ m_hostImpl->setViewportSize(IntSize(100, 100));
+ initializeLayerRendererAndDrawFrame();
+ CCLayerImpl* root = m_hostImpl->rootLayer();
+
root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
- m_hostImpl->setRootLayer(root.release());
+
// All scroll types inside the non-fast scrollable region should fail.
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollFailed);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread);
// All scroll types outside this region should succeed.
EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
@@ -258,16 +349,13 @@ TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic)
TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
{
- OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
- root->setScrollable(true);
- root->setScrollPosition(IntPoint(0, 0));
- root->setMaxScrollPosition(IntSize(100, 100));
+ setupScrollAndContentsLayers(IntSize(200, 200));
+ m_hostImpl->setViewportSize(IntSize(100, 100));
+ CCLayerImpl* root = m_hostImpl->rootLayer();
+
root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
root->setPosition(FloatPoint(-25, 0));
- m_hostImpl->setRootLayer(root.release());
- CCLayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
- m_hostImpl->drawLayers(frame); // Update draw transforms so we can correctly map points into layer space.
+ initializeLayerRendererAndDrawFrame();
// This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels.
EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
@@ -275,15 +363,16 @@ TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
m_hostImpl->scrollEnd();
// This point is still inside the non-fast region.
- EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
}
TEST_F(CCLayerTreeHostImplTest, pinchGesture)
{
setupScrollAndContentsLayers(IntSize(100, 100));
m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
- CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer();
+ CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
ASSERT(scrollLayer);
const float minPageScale = 0.5, maxPageScale = 4;
@@ -362,8 +451,9 @@ TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation)
{
setupScrollAndContentsLayers(IntSize(100, 100));
m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
- CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer();
+ CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
ASSERT(scrollLayer);
const float minPageScale = 0.5, maxPageScale = 4;
@@ -407,6 +497,101 @@ TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation)
}
}
+TEST_F(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhilePinchZooming)
+{
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
+
+ CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
+ ASSERT(scrollLayer);
+
+ const float minPageScale = 0.5, maxPageScale = 4;
+
+ // Pinch zoom in.
+ {
+ // Start a pinch in gesture at the bottom right corner of the viewport.
+ const float zoomInDelta = 2;
+ m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(zoomInDelta, IntPoint(50, 50));
+
+ // Because we are pinch zooming in, we shouldn't get any scroll or page
+ // scale deltas.
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, 1);
+ EXPECT_EQ(scrollInfo->scrolls.size(), 0u);
+
+ // Once the gesture ends, we get the final scroll and page scale values.
+ m_hostImpl->pinchGestureEnd();
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, zoomInDelta);
+ expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
+ }
+
+ // Pinch zoom out.
+ {
+ // Start a pinch out gesture at the bottom right corner of the viewport.
+ const float zoomOutDelta = 0.75;
+ m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(zoomOutDelta, IntPoint(50, 50));
+
+ // Since we are pinch zooming out, we should get an update to zoom all
+ // the way out to the minimum page scale.
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
+ expectContains(*scrollInfo, scrollLayer->id(), IntSize(0, 0));
+
+ // Once the gesture ends, we get the final scroll and page scale values.
+ m_hostImpl->pinchGestureEnd();
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, zoomOutDelta);
+ expectContains(*scrollInfo, scrollLayer->id(), IntSize(8, 8));
+ }
+}
+
+TEST_F(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhileAnimatingPageScale)
+{
+ setupScrollAndContentsLayers(IntSize(100, 100));
+ m_hostImpl->setViewportSize(IntSize(50, 50));
+ initializeLayerRendererAndDrawFrame();
+
+ CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
+ ASSERT(scrollLayer);
+
+ const float minPageScale = 0.5, maxPageScale = 4;
+ const double startTime = 1;
+ const double duration = 0.1;
+ const double halfwayThroughAnimation = startTime + duration / 2;
+ const double endTime = startTime + duration;
+
+ // Start a page scale animation.
+ const float pageScaleDelta = 2;
+ m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
+ m_hostImpl->startPageScaleAnimation(IntSize(50, 50), false, pageScaleDelta, startTime, duration);
+
+ // We should immediately get the final zoom and scroll values for the
+ // animation.
+ m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
+ expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
+
+ // Scrolling during the animation is ignored.
+ const IntSize scrollDelta(0, 10);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ // The final page scale and scroll deltas should match what we got
+ // earlier.
+ m_hostImpl->animate(endTime, endTime);
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
+ expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
+}
+
class DidDrawCheckLayer : public CCTiledLayerImpl {
public:
static PassOwnPtr<DidDrawCheckLayer> create(int id) { return adoptPtr(new DidDrawCheckLayer(id)); }
@@ -416,7 +601,7 @@ public:
m_didDrawCalled = true;
}
- virtual void willDraw(LayerRendererChromium*)
+ virtual void willDraw(CCRenderer*, CCGraphicsContext*)
{
m_willDrawCalled = true;
}
@@ -424,6 +609,12 @@ public:
bool didDrawCalled() const { return m_didDrawCalled; }
bool willDrawCalled() const { return m_willDrawCalled; }
+ void clearDidDrawCheck()
+ {
+ m_didDrawCalled = false;
+ m_willDrawCalled = false;
+ }
+
protected:
explicit DidDrawCheckLayer(int id)
: CCTiledLayerImpl(id)
@@ -432,7 +623,12 @@ protected:
{
setAnchorPoint(FloatPoint(0, 0));
setBounds(IntSize(10, 10));
+ setContentBounds(IntSize(10, 10));
setDrawsContent(true);
+ setSkipsDraw(false);
+
+ OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::HasBorderTexels);
+ setTilingData(*tiler.get());
}
private:
@@ -485,6 +681,42 @@ TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
EXPECT_FALSE(layer->visibleLayerRect().isEmpty());
}
+TEST_F(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer)
+{
+ // Make the viewport large so that we can have large layers that get considered for occlusion (small layers do not).
+ IntSize bigSize(1000, 1000);
+ m_hostImpl->setViewportSize(bigSize);
+
+ m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
+ DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
+
+ root->addChild(DidDrawCheckLayer::create(1));
+ DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
+
+ root->addChild(DidDrawCheckLayer::create(2));
+ DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children()[1].get());
+ // This layer covers the occludedLayer above. Make this layer large so it can occlude.
+ topLayer->setBounds(bigSize);
+ topLayer->setContentBounds(bigSize);
+ topLayer->setOpaque(true);
+
+ CCLayerTreeHostImpl::FrameData frame;
+
+ EXPECT_FALSE(occludedLayer->willDrawCalled());
+ EXPECT_FALSE(occludedLayer->didDrawCalled());
+ EXPECT_FALSE(topLayer->willDrawCalled());
+ EXPECT_FALSE(topLayer->didDrawCalled());
+
+ EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
+ m_hostImpl->drawLayers(frame);
+ m_hostImpl->didDrawAllLayers(frame);
+
+ EXPECT_FALSE(occludedLayer->willDrawCalled());
+ EXPECT_FALSE(occludedLayer->didDrawCalled());
+ EXPECT_TRUE(topLayer->willDrawCalled());
+ EXPECT_TRUE(topLayer->didDrawCalled());
+}
+
TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
{
m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
@@ -562,9 +794,7 @@ TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
root->addChild(MissingTextureAnimatingLayer::create(1, true, false, true));
- m_didRequestCommit = false;
EXPECT_FALSE(m_hostImpl->prepareToDraw(frame));
- EXPECT_TRUE(m_didRequestCommit);
m_hostImpl->drawLayers(frame);
m_hostImpl->didDrawAllLayers(frame);
@@ -578,6 +808,299 @@ TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
m_hostImpl->didDrawAllLayers(frame);
}
+TEST_F(CCLayerTreeHostImplTest, scrollRootIgnored)
+{
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
+ root->setScrollable(false);
+ m_hostImpl->setRootLayer(root.release());
+ initializeLayerRendererAndDrawFrame();
+
+ // Scroll event is ignored because layer is not scrollable.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
+ EXPECT_FALSE(m_didRequestRedraw);
+ EXPECT_FALSE(m_didRequestCommit);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollNonCompositedRoot)
+{
+ // Test the configuration where a non-composited root layer is embedded in a
+ // scrollable outer layer.
+ IntSize surfaceSize(10, 10);
+
+ OwnPtr<CCLayerImpl> contentLayer = CCLayerImpl::create(1);
+ contentLayer->setIsNonCompositedContent(true);
+ contentLayer->setDrawsContent(true);
+ contentLayer->setPosition(IntPoint(5, 5));
+ contentLayer->setBounds(surfaceSize);
+ contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize.height() * 2));
+
+ OwnPtr<CCLayerImpl> scrollLayer = CCLayerImpl::create(0);
+ scrollLayer->setScrollable(true);
+ scrollLayer->setMaxScrollPosition(surfaceSize);
+ scrollLayer->addChild(contentLayer.release());
+
+ m_hostImpl->setRootLayer(scrollLayer.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(IntSize(0, 10));
+ m_hostImpl->scrollEnd();
+ EXPECT_TRUE(m_didRequestRedraw);
+ EXPECT_TRUE(m_didRequestCommit);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollChildCallsCommitAndRedraw)
+{
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
+ root->addChild(createScrollableLayer(1, FloatPoint(5, 5), surfaceSize));
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(IntSize(0, 10));
+ m_hostImpl->scrollEnd();
+ EXPECT_TRUE(m_didRequestRedraw);
+ EXPECT_TRUE(m_didRequestCommit);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollMissesChild)
+{
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
+ root->addChild(createScrollableLayer(1, FloatPoint(5, 5), surfaceSize));
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ // Scroll event is ignored because the input coordinate is outside the layer boundaries.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(15, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
+ EXPECT_FALSE(m_didRequestRedraw);
+ EXPECT_FALSE(m_didRequestCommit);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollMissesBackfacingChild)
+{
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
+ OwnPtr<CCLayerImpl> child = createScrollableLayer(1, FloatPoint(5, 5), surfaceSize);
+ m_hostImpl->setViewportSize(surfaceSize);
+
+ WebTransformationMatrix matrix;
+ matrix.rotate3d(180, 0, 0);
+ child->setTransform(matrix);
+ child->setDoubleSided(false);
+
+ root->addChild(child.release());
+ m_hostImpl->setRootLayer(root.release());
+ initializeLayerRendererAndDrawFrame();
+
+ // Scroll event is ignored because the scrollable layer is not facing the viewer and there is
+ // nothing scrollable behind it.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
+ EXPECT_FALSE(m_didRequestRedraw);
+ EXPECT_FALSE(m_didRequestCommit);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollBlockedByContentLayer)
+{
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> contentLayer = createScrollableLayer(0, FloatPoint(5, 5), surfaceSize);
+ contentLayer->setShouldScrollOnMainThread(true);
+ contentLayer->setScrollable(false);
+
+ OwnPtr<CCLayerImpl> scrollLayer = createScrollableLayer(1, FloatPoint(5, 5), surfaceSize);
+ scrollLayer->addChild(contentLayer.release());
+
+ m_hostImpl->setRootLayer(scrollLayer.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ // Scrolling fails because the content layer is asking to be scrolled on the main thread.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnMainThread)
+{
+ IntSize surfaceSize(10, 10);
+ float pageScale = 2;
+ OwnPtr<CCLayerImpl> root = createScrollableLayer(0, FloatPoint(5, 5), surfaceSize);
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ IntSize scrollDelta(0, 10);
+ IntSize expectedScrollDelta(scrollDelta);
+ IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ // Set new page scale from main thread.
+ m_hostImpl->setPageScaleFactorAndLimits(pageScale, pageScale, pageScale);
+
+ // The scale should apply to the scroll delta.
+ expectedScrollDelta.scale(pageScale);
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), 0, expectedScrollDelta);
+
+ // The scroll range should also have been updated.
+ EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
+
+ // The page scale delta remains constant because the impl thread did not scale.
+ EXPECT_EQ(m_hostImpl->rootLayer()->pageScaleDelta(), 1);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnImplThread)
+{
+ IntSize surfaceSize(10, 10);
+ float pageScale = 2;
+ OwnPtr<CCLayerImpl> root = createScrollableLayer(0, FloatPoint(5, 5), surfaceSize);
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
+ initializeLayerRendererAndDrawFrame();
+
+ IntSize scrollDelta(0, 10);
+ IntSize expectedScrollDelta(scrollDelta);
+ IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ // Set new page scale on impl thread by pinching.
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(pageScale, IntPoint());
+ m_hostImpl->pinchGestureEnd();
+
+ // The scroll delta is not scaled because the main thread did not scale.
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), 0, expectedScrollDelta);
+
+ // The scroll range should also have been updated.
+ EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
+
+ // The page scale delta should match the new scale on the impl side.
+ EXPECT_EQ(m_hostImpl->rootLayer()->pageScaleDelta(), pageScale);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollChildAndChangePageScaleOnMainThread)
+{
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
+ // Also mark the root scrollable so it becomes the root scroll layer.
+ root->setScrollable(true);
+ root->addChild(createScrollableLayer(1, FloatPoint(5, 5), surfaceSize));
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+
+ CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0].get();
+
+ IntSize scrollDelta(0, 10);
+ IntSize expectedScrollDelta(scrollDelta);
+ IntSize expectedMaxScroll(child->maxScrollPosition());
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ float pageScale = 2;
+ m_hostImpl->setPageScaleFactorAndLimits(pageScale, 1, pageScale);
+
+ // The scale should apply to the scroll delta.
+ expectedScrollDelta.scale(pageScale);
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), 1, expectedScrollDelta);
+
+ // The scroll range should not have changed.
+ EXPECT_EQ(child->maxScrollPosition(), expectedMaxScroll);
+
+ // The page scale delta remains constant because the impl thread did not scale.
+ EXPECT_EQ(child->pageScaleDelta(), 1);
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollChildBeyondLimit)
+{
+ // Scroll a child layer beyond its maximum scroll range and make sure the
+ // parent layer is scrolled on the axis on which the child was unable to
+ // scroll.
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = createScrollableLayer(0, FloatPoint(5, 5), surfaceSize);
+
+ OwnPtr<CCLayerImpl> grandChild = createScrollableLayer(2, FloatPoint(5, 5), surfaceSize);
+ grandChild->setScrollPosition(IntPoint(0, 5));
+
+ OwnPtr<CCLayerImpl> child = createScrollableLayer(1, FloatPoint(5, 5), surfaceSize);
+ child->setScrollPosition(IntPoint(3, 0));
+ child->addChild(grandChild.release());
+
+ root->addChild(child.release());
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+ {
+ IntSize scrollDelta(-3, -7);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+
+ // The grand child should have scrolled up to its limit.
+ CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0].get();
+ CCLayerImpl* grandChild = child->children()[0].get();
+ expectContains(*scrollInfo.get(), grandChild->id(), IntSize(0, -5));
+
+ // The child should have only scrolled on the other axis.
+ expectContains(*scrollInfo.get(), child->id(), IntSize(-3, 0));
+ }
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollEventBubbling)
+{
+ // When we try to scroll a non-scrollable child layer, the scroll delta
+ // should be applied to one of its ancestors if possible.
+ IntSize surfaceSize(10, 10);
+ OwnPtr<CCLayerImpl> root = createScrollableLayer(0, FloatPoint(5, 5), surfaceSize);
+ OwnPtr<CCLayerImpl> child = createScrollableLayer(1, FloatPoint(5, 5), surfaceSize);
+
+ child->setScrollable(false);
+ root->addChild(child.release());
+
+ m_hostImpl->setRootLayer(root.release());
+ m_hostImpl->setViewportSize(surfaceSize);
+ initializeLayerRendererAndDrawFrame();
+ {
+ IntSize scrollDelta(0, 4);
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ m_hostImpl->scrollBy(scrollDelta);
+ m_hostImpl->scrollEnd();
+
+ OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+
+ // Only the root should have scrolled.
+ ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollDelta);
+ }
+}
+
+TEST_F(CCLayerTreeHostImplTest, scrollBeforeRedraw)
+{
+ IntSize surfaceSize(10, 10);
+ m_hostImpl->setRootLayer(createScrollableLayer(0, FloatPoint(5, 5), surfaceSize));
+ m_hostImpl->setViewportSize(surfaceSize);
+
+ // Draw one frame and then immediately rebuild the layer tree to mimic a tree synchronization.
+ initializeLayerRendererAndDrawFrame();
+ m_hostImpl->detachLayerTree();
+ m_hostImpl->setRootLayer(createScrollableLayer(0, FloatPoint(5, 5), surfaceSize));
+
+ // Scrolling should still work even though we did not draw yet.
+ EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+}
+
class BlendStateTrackerContext: public FakeWebGraphicsContext3D {
public:
BlendStateTrackerContext() : m_blend(false) { }
@@ -646,6 +1169,7 @@ private:
{
setAnchorPoint(FloatPoint(0, 0));
setBounds(IntSize(10, 10));
+ setContentBounds(IntSize(10, 10));
setDrawsContent(true);
}
@@ -666,6 +1190,7 @@ TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
root->setAnchorPoint(FloatPoint(0, 0));
root->setBounds(IntSize(10, 10));
+ root->setContentBounds(root->bounds());
root->setDrawsContent(false);
m_hostImpl->setRootLayer(root.release());
}
@@ -988,7 +1513,8 @@ TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
{
ReshapeTrackerContext* reshapeTracker = new ReshapeTrackerContext();
RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
- m_hostImpl->initializeLayerRenderer(context, UnthrottledUploader);
+ RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
+ m_hostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
root->setAnchorPoint(FloatPoint(0, 0));
@@ -1031,13 +1557,14 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
{
PartialSwapTrackerContext* partialSwapTracker = new PartialSwapTrackerContext();
RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
+ RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
// This test creates its own CCLayerTreeHostImpl, so
// that we can force partial swap enabled.
- CCSettings settings;
- settings.partialSwapEnabled = true;
+ CCLayerTreeSettings settings;
+ CCSettings::setPartialSwapEnabled(true);
OwnPtr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this);
- layerTreeHostImpl->initializeLayerRenderer(context, UnthrottledUploader);
+ layerTreeHostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
layerTreeHostImpl->setViewportSize(IntSize(500, 500));
CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
@@ -1099,6 +1626,349 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
}
+} // namespace
+
+class FakeLayerWithQuads : public CCLayerImpl {
+public:
+ static PassOwnPtr<FakeLayerWithQuads> create(int id) { return adoptPtr(new FakeLayerWithQuads(id)); }
+
+ virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
+ {
+ const Color gray(100, 100, 100);
+ IntRect quadRect(0, 0, 5, 5);
+ OwnPtr<CCDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray);
+ quadList.append(myQuad.release());
+ }
+
+private:
+ FakeLayerWithQuads(int id)
+ : CCLayerImpl(id)
+ {
+ }
+};
+
+namespace {
+
+class MockContext : public FakeWebGraphicsContext3D {
+public:
+ MOCK_METHOD1(useProgram, void(WebGLId program));
+ MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
+ MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value));
+ MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
+ MOCK_METHOD1(getString, WebString(WGC3Denum name));
+ MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
+ MOCK_METHOD1(enable, void(WGC3Denum cap));
+ MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height));
+};
+
+class MockContextHarness {
+private:
+ MockContext* m_context;
+public:
+ MockContextHarness(MockContext* context)
+ : m_context(context)
+ {
+ // Catch "uninteresting" calls
+ EXPECT_CALL(*m_context, useProgram(_))
+ .Times(0);
+
+ EXPECT_CALL(*m_context, drawElements(_, _, _, _))
+ .Times(0);
+
+ // These are not asserted
+ EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
+ .WillRepeatedly(Return());
+
+ // Any other strings are empty
+ EXPECT_CALL(*m_context, getString(_))
+ .WillRepeatedly(Return(WebString()));
+
+ // Support for partial swap, if needed
+ EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
+ .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
+
+ EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
+ .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
+
+ // Any un-sanctioned calls to enable() are OK
+ EXPECT_CALL(*m_context, enable(_))
+ .WillRepeatedly(Return());
+ }
+
+ void mustDrawSolidQuad()
+ {
+ EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0))
+ .WillOnce(Return())
+ .RetiresOnSaturation();
+
+ // 1 is hardcoded return value of fake createProgram()
+ EXPECT_CALL(*m_context, useProgram(1))
+ .WillOnce(Return())
+ .RetiresOnSaturation();
+
+ }
+
+ void mustSetScissor(int x, int y, int width, int height)
+ {
+ EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*m_context, scissor(x, y, width, height))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return());
+ }
+
+};
+
+TEST_F(CCLayerTreeHostImplTest, noPartialSwap)
+{
+ MockContext* mockContext = new MockContext();
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+ MockContextHarness harness(mockContext);
+
+ harness.mustDrawSolidQuad();
+ harness.mustSetScissor(0, 0, 10, 10);
+
+ // Run test case
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context, FakeLayerWithQuads::create(1));
+
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+TEST_F(CCLayerTreeHostImplTest, partialSwap)
+{
+ MockContext* mockContext = new MockContext();
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+ MockContextHarness harness(mockContext);
+
+ harness.mustDrawSolidQuad();
+ harness.mustSetScissor(0, 0, 10, 10);
+
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
+
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+TEST_F(CCLayerTreeHostImplTest, partialSwapNoUpdate)
+{
+ MockContext* mockContext = new MockContext();
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+ MockContextHarness harness(mockContext);
+
+ harness.mustDrawSolidQuad();
+ harness.mustSetScissor(0, 8, 2, 2);
+ harness.mustDrawSolidQuad();
+ harness.mustSetScissor(0, 0, 10, 10);
+
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
+
+ // Draw once to make sure layer is not new
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ // Generate update in layer
+ CCLayerImpl* root = myHostImpl->rootLayer();
+ root->setUpdateRect(FloatRect(0, 0, 2, 2));
+
+ // This draw should generate no new udpates
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+class PartialSwapContext: public FakeWebGraphicsContext3D {
+public:
+ WebString getString(WGC3Denum name)
+ {
+ if (name == GraphicsContext3D::EXTENSIONS)
+ return WebString("GL_CHROMIUM_post_sub_buffer");
+ return WebString();
+ }
+
+ WebString getRequestableExtensionsCHROMIUM()
+ {
+ return WebString("GL_CHROMIUM_post_sub_buffer");
+ }
+};
+
+static PassOwnPtr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client)
+{
+ CCSettings::setPartialSwapEnabled(partialSwap);
+
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client);
+ myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
+ myHostImpl->setViewportSize(IntSize(100, 100));
+
+ /*
+ Layers are created as follows:
+
+ +--------------------+
+ | 1 |
+ | +-----------+ |
+ | | 2 | |
+ | | +-------------------+
+ | | | 3 |
+ | | +-------------------+
+ | | | |
+ | +-----------+ |
+ | |
+ | |
+ +--------------------+
+
+ Layers 1, 2 have render surfaces
+ */
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+ OwnPtr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
+
+ IntRect rootRect(0, 0, 100, 100);
+ IntRect childRect(10, 10, 50, 50);
+ IntRect grandChildRect(5, 5, 150, 150);
+
+ root->createRenderSurface();
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+ root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+ root->setContentBounds(root->bounds());
+ root->setVisibleLayerRect(rootRect);
+ root->setDrawsContent(false);
+ root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+ child->setAnchorPoint(FloatPoint(0, 0));
+ child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+ child->setOpacity(0.5f);
+ child->setBounds(IntSize(childRect.width(), childRect.height()));
+ child->setContentBounds(child->bounds());
+ child->setVisibleLayerRect(childRect);
+ child->setDrawsContent(false);
+
+ grandChild->setAnchorPoint(FloatPoint(0, 0));
+ grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+ grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+ grandChild->setContentBounds(grandChild->bounds());
+ grandChild->setVisibleLayerRect(grandChildRect);
+ grandChild->setDrawsContent(true);
+
+ child->addChild(grandChild.release());
+ root->addChild(child.release());
+
+ myHostImpl->setRootLayer(root.release());
+ return myHostImpl.release();
+}
+
+TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
+{
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this);
+
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Just for consistency, the most interesting stuff already happened
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ // Verify all quads have been computed
+ ASSERT_EQ(2U, frame.renderPasses.size());
+ ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
+ EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
+ }
+}
+
+TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
+{
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this);
+
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Just for consistency, the most interesting stuff already happened
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ // Verify all quads have been computed
+ ASSERT_EQ(2U, frame.renderPasses.size());
+ ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
+ EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
+ }
+}
+
+TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnScissoredLayer)
+{
+ CCLayerTreeSettings settings;
+ CCSettings::setPartialSwapEnabled(true);
+
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
+ myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
+ myHostImpl->setViewportSize(IntSize(10, 10));
+
+ myHostImpl->setRootLayer(DidDrawCheckLayer::create(1));
+ DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(myHostImpl->rootLayer());
+ root->setMasksToBounds(true);
+
+ root->addChild(DidDrawCheckLayer::create(2));
+ DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
+
+ CCLayerTreeHostImpl::FrameData frame;
+
+ EXPECT_FALSE(root->willDrawCalled());
+ EXPECT_FALSE(root->didDrawCalled());
+ EXPECT_FALSE(layer->willDrawCalled());
+ EXPECT_FALSE(layer->didDrawCalled());
+
+ // We should draw everything the first frame.
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ EXPECT_TRUE(root->willDrawCalled());
+ EXPECT_TRUE(root->didDrawCalled());
+ EXPECT_TRUE(layer->willDrawCalled());
+ EXPECT_TRUE(layer->didDrawCalled());
+
+ root->clearDidDrawCheck();
+ layer->clearDidDrawCheck();
+
+ EXPECT_FALSE(root->willDrawCalled());
+ EXPECT_FALSE(root->didDrawCalled());
+ EXPECT_FALSE(layer->willDrawCalled());
+ EXPECT_FALSE(layer->didDrawCalled());
+
+ // Drawing again, we should scissor out everything since there is no damage.
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+
+ EXPECT_FALSE(root->willDrawCalled());
+ EXPECT_FALSE(root->didDrawCalled());
+ EXPECT_FALSE(layer->willDrawCalled());
+ EXPECT_FALSE(layer->didDrawCalled());
+}
+
// Make sure that context lost notifications are propagated through the tree.
class ContextLostNotificationCheckLayer : public CCLayerImpl {
public:
@@ -1151,7 +2021,7 @@ public:
TEST_F(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost)
{
// The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
- m_hostImpl->initializeLayerRenderer(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow), UnthrottledUploader);
+ m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow)), UnthrottledUploader);
m_hostImpl->finishAllRendering();
}
@@ -1165,26 +2035,6 @@ private:
ScrollbarLayerFakePaint(int id) : CCScrollbarLayerImpl(id) { }
};
-TEST_F(CCLayerTreeHostImplTest, scrollbarLayerLostContext)
-{
- m_hostImpl->setRootLayer(ScrollbarLayerFakePaint::create(0));
- ScrollbarLayerFakePaint* scrollbar = static_cast<ScrollbarLayerFakePaint*>(m_hostImpl->rootLayer());
- scrollbar->setBounds(IntSize(1, 1));
- scrollbar->setContentBounds(IntSize(1, 1));
- scrollbar->setDrawsContent(true);
-
- for (int i = 0; i < 2; ++i) {
- CCLayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
- ASSERT(frame.renderPasses.size() == 1);
- CCRenderPass* renderPass = frame.renderPasses[0].get();
- // Scrollbar layer should always generate quads, even after lost context
- EXPECT_GT(renderPass->quadList().size(), 0u);
- m_hostImpl->didDrawAllLayers(frame);
- m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
- }
-}
-
// Fake WebGraphicsContext3D that will cause a failure if trying to use a
// resource that wasn't created by it (resources created by
// FakeWebGraphicsContext3D have an id of 1).
@@ -1312,6 +2162,38 @@ private:
Client* m_client;
};
+class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3D {
+public:
+ virtual WebString getString(WGC3Denum name) OVERRIDE
+ {
+ if (name == WebCore::GraphicsContext3D::EXTENSIONS)
+ return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
+
+ return WebString();
+ }
+
+ static PassRefPtr<GraphicsContext3D> createGraphicsContext()
+ {
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new StrictWebGraphicsContext3DWithIOSurface()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ }
+};
+
+class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D {
+public:
+ virtual WebString getString(WGC3Denum name) OVERRIDE
+ {
+ if (name == WebCore::GraphicsContext3D::EXTENSIONS)
+ return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
+
+ return WebString();
+ }
+
+ static PassRefPtr<GraphicsContext3D> createGraphicsContext()
+ {
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DWithIOSurface()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ }
+};
+
TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
{
OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(0));
@@ -1344,8 +2226,21 @@ TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
videoLayer->setAnchorPoint(FloatPoint(0, 0));
videoLayer->setContentBounds(IntSize(10, 10));
videoLayer->setDrawsContent(true);
+ videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
rootLayer->addChild(videoLayer.release());
+ OwnPtr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(4);
+ ioSurfaceLayer->setBounds(IntSize(10, 10));
+ ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
+ ioSurfaceLayer->setContentBounds(IntSize(10, 10));
+ ioSurfaceLayer->setDrawsContent(true);
+ ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
+ ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
+ rootLayer->addChild(ioSurfaceLayer.release());
+
+ // Use a context that supports IOSurfaces
+ m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(FakeWebGraphicsContext3DWithIOSurface::createGraphicsContext()), UnthrottledUploader);
+
m_hostImpl->setRootLayer(rootLayer.release());
CCLayerTreeHostImpl::FrameData frame;
@@ -1354,13 +2249,757 @@ TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
m_hostImpl->didDrawAllLayers(frame);
m_hostImpl->swapBuffers();
- // Lose the context, replacing it with a StrictWebGraphicsContext3D, that
- // will warn if any resource from the previous context gets used.
- m_hostImpl->initializeLayerRenderer(StrictWebGraphicsContext3D::createGraphicsContext(), UnthrottledUploader);
+ // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSurface,
+ // that will warn if any resource from the previous context gets used.
+ m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(StrictWebGraphicsContext3DWithIOSurface::createGraphicsContext()), UnthrottledUploader);
+ EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
+ m_hostImpl->drawLayers(frame);
+ m_hostImpl->didDrawAllLayers(frame);
+ m_hostImpl->swapBuffers();
+}
+
+// Fake WebGraphicsContext3D that tracks the number of textures in use.
+class TrackingWebGraphicsContext3D : public FakeWebGraphicsContext3D {
+public:
+ TrackingWebGraphicsContext3D()
+ : m_nextTextureId(1)
+ , m_numTextures(0)
+ { }
+
+ virtual WebGLId createTexture() OVERRIDE
+ {
+ WebGLId id = m_nextTextureId;
+ ++m_nextTextureId;
+
+ m_textures.set(id, true);
+ ++m_numTextures;
+ return id;
+ }
+
+ virtual void deleteTexture(WebGLId id) OVERRIDE
+ {
+ if (!m_textures.get(id))
+ return;
+
+ m_textures.set(id, false);
+ --m_numTextures;
+ }
+
+ virtual WebString getString(WGC3Denum name) OVERRIDE
+ {
+ if (name == WebCore::GraphicsContext3D::EXTENSIONS)
+ return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
+
+ return WebString();
+ }
+
+ PassRefPtr<GraphicsContext3D> createGraphicsContext()
+ {
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(this), GraphicsContext3D::RenderDirectlyToHostWindow);
+ }
+
+ unsigned numTextures() const { return m_numTextures; }
+
+private:
+ WebGLId m_nextTextureId;
+ HashMap<WebGLId, bool> m_textures;
+ unsigned m_numTextures;
+};
+
+TEST_F(CCLayerTreeHostImplTest, layersFreeTextures)
+{
+ OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(1));
+ rootLayer->setBounds(IntSize(10, 10));
+ rootLayer->setAnchorPoint(FloatPoint(0, 0));
+
+ OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2);
+ tileLayer->setBounds(IntSize(10, 10));
+ tileLayer->setAnchorPoint(FloatPoint(0, 0));
+ tileLayer->setContentBounds(IntSize(10, 10));
+ tileLayer->setDrawsContent(true);
+ tileLayer->setSkipsDraw(false);
+ OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels));
+ tilingData->setBounds(IntSize(10, 10));
+ tileLayer->setTilingData(*tilingData);
+ tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
+ rootLayer->addChild(tileLayer.release());
+
+ OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3);
+ textureLayer->setBounds(IntSize(10, 10));
+ textureLayer->setAnchorPoint(FloatPoint(0, 0));
+ textureLayer->setContentBounds(IntSize(10, 10));
+ textureLayer->setDrawsContent(true);
+ textureLayer->setTextureId(1);
+ rootLayer->addChild(textureLayer.release());
+
+ FakeVideoFrameProvider provider;
+ OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provider);
+ videoLayer->setBounds(IntSize(10, 10));
+ videoLayer->setAnchorPoint(FloatPoint(0, 0));
+ videoLayer->setContentBounds(IntSize(10, 10));
+ videoLayer->setDrawsContent(true);
+ videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
+ rootLayer->addChild(videoLayer.release());
+
+ OwnPtr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(5);
+ ioSurfaceLayer->setBounds(IntSize(10, 10));
+ ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
+ ioSurfaceLayer->setContentBounds(IntSize(10, 10));
+ ioSurfaceLayer->setDrawsContent(true);
+ ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
+ ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
+ rootLayer->addChild(ioSurfaceLayer.release());
+
+ // Lose the context, replacing it with a TrackingWebGraphicsContext3D, that
+ // tracks the number of textures allocated. This pointer is owned by its
+ // GraphicsContext3D.
+ TrackingWebGraphicsContext3D* trackingWebGraphicsContext = new TrackingWebGraphicsContext3D();
+ m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(trackingWebGraphicsContext->createGraphicsContext()), UnthrottledUploader);
+
+ m_hostImpl->setRootLayer(rootLayer.release());
+
+ CCLayerTreeHostImpl::FrameData frame;
EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
m_hostImpl->drawLayers(frame);
m_hostImpl->didDrawAllLayers(frame);
m_hostImpl->swapBuffers();
+
+ EXPECT_GT(trackingWebGraphicsContext->numTextures(), 0u);
+
+ // Kill the layer tree.
+ m_hostImpl->setRootLayer(CCLayerImpl::create(100));
+ // FIXME: Remove this when we don't use ManagedTextures in impl layers.
+ m_hostImpl->layerRenderer()->implTextureManager()->deleteEvictedTextures(m_hostImpl->layerRenderer()->implTextureAllocator());
+ // There should be no textures left in use after.
+ EXPECT_EQ(0u, trackingWebGraphicsContext->numTextures());
+}
+
+class MockDrawQuadsToFillScreenContext : public FakeWebGraphicsContext3D {
+public:
+ MOCK_METHOD1(useProgram, void(WebGLId program));
+ MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
+};
+
+TEST_F(CCLayerTreeHostImplTest, hasTransparentBackground)
+{
+ MockDrawQuadsToFillScreenContext* mockContext = new MockDrawQuadsToFillScreenContext();
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+
+ // Run test case
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context, CCLayerImpl::create(1));
+ myHostImpl->setBackgroundColor(Color::white);
+
+ // Verify one quad is drawn when transparent background set is not set.
+ myHostImpl->setHasTransparentBackground(false);
+ EXPECT_CALL(*mockContext, useProgram(_))
+ .Times(1);
+ EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
+ .Times(1);
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ Mock::VerifyAndClearExpectations(&mockContext);
+
+ // Verify no quads are drawn when transparent background is set.
+ myHostImpl->setHasTransparentBackground(true);
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+TEST_F(CCLayerTreeHostImplTest, surfaceTextureCaching)
+{
+ CCSettings::setPartialSwapEnabled(true);
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
+
+ RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
+
+ myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
+ myHostImpl->setViewportSize(IntSize(100, 100));
+
+ OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+ CCLayerImpl* rootPtr = root.get();
+
+ root->setAnchorPoint(FloatPoint(0, 0));
+ root->setPosition(FloatPoint(0, 0));
+ root->setBounds(IntSize(100, 100));
+ root->setContentBounds(IntSize(100, 100));
+ root->setVisibleLayerRect(IntRect(0, 0, 100, 100));
+ root->setDrawsContent(true);
+ myHostImpl->setRootLayer(root.release());
+
+ // Intermediate layer does not own a surface, and does not draw content.
+ OwnPtr<CCLayerImpl> intermediateLayer = CCLayerImpl::create(2);
+ CCLayerImpl* intermediateLayerPtr = intermediateLayer.get();
+
+ intermediateLayerPtr->setAnchorPoint(FloatPoint(0, 0));
+ intermediateLayerPtr->setPosition(FloatPoint(10, 10));
+ intermediateLayerPtr->setBounds(IntSize(100, 100));
+ intermediateLayerPtr->setContentBounds(IntSize(100, 100));
+ intermediateLayerPtr->setVisibleLayerRect(IntRect(0, 0, 100, 100));
+ intermediateLayerPtr->setDrawsContent(false); // only children draw content
+ rootPtr->addChild(intermediateLayer.release());
+
+ OwnPtr<CCLayerImpl> surfaceLayer = CCLayerImpl::create(3);
+ CCLayerImpl* surfaceLayerPtr = surfaceLayer.get();
+
+ // Surface layer is the layer that changes its opacity
+ // It will contain other layers that draw content.
+ surfaceLayerPtr->setAnchorPoint(FloatPoint(0, 0));
+ surfaceLayerPtr->setPosition(FloatPoint(10, 10));
+ surfaceLayerPtr->setBounds(IntSize(50, 50));
+ surfaceLayerPtr->setContentBounds(IntSize(50, 50));
+ surfaceLayerPtr->setVisibleLayerRect(IntRect(0, 0, 50, 50));
+ surfaceLayerPtr->setDrawsContent(false); // only children draw content
+ surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface
+ intermediateLayerPtr->addChild(surfaceLayer.release());
+
+ // Child of the surface layer will produce some quads
+ OwnPtr<FakeLayerWithQuads> child = FakeLayerWithQuads::create(4);
+ FakeLayerWithQuads* childPtr = child.get();
+
+ childPtr->setAnchorPoint(FloatPoint(0, 0));
+ childPtr->setPosition(FloatPoint(5, 5));
+ childPtr->setBounds(IntSize(10, 10));
+ childPtr->setContentBounds(IntSize(10, 10));
+ childPtr->setVisibleLayerRect(IntRect(0, 0, 10, 10));
+ childPtr->setDrawsContent(true);
+
+ surfaceLayerPtr->addChild(child.release());
+
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive two render passes, each with one quad
+ ASSERT_EQ(2U, frame.renderPasses.size());
+ EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
+
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
+ CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
+ EXPECT_TRUE(quad->renderPass()->targetSurface()->contentsChanged());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Draw without any change
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive two EMPTY render passes
+ ASSERT_EQ(2U, frame.renderPasses.size());
+ EXPECT_EQ(0U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(0U, frame.renderPasses[1]->quadList().size());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Change opacity and draw
+ surfaceLayerPtr->setOpacity(0.6f);
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive one render pass, as the other one should be culled
+ ASSERT_EQ(1U, frame.renderPasses.size());
+
+ EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
+ CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
+ EXPECT_FALSE(quad->renderPass()->targetSurface()->contentsChanged());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Change less benign property and draw - should have contents changed flag
+ surfaceLayerPtr->setStackingOrderChanged(true);
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive two render passes, each with one quad
+ ASSERT_EQ(2U, frame.renderPasses.size());
+
+ EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
+
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
+ CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
+ EXPECT_TRUE(quad->renderPass()->targetSurface()->contentsChanged());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Change opacity again, but evict the cached surface texture
+ surfaceLayerPtr->setOpacity(0.5f);
+ ManagedTexture* contentsTexture = surfaceLayerPtr->renderSurface()->contentsTexture();
+ ASSERT_TRUE(contentsTexture->isValid(contentsTexture->size(), contentsTexture->format()));
+ CCRenderer* renderer = myHostImpl->layerRenderer();
+ TextureManager* textureManager = renderer->implTextureManager();
+ size_t maxMemoryLimit = textureManager->maxMemoryLimitBytes();
+
+ // This should evice all cached surfaces
+ textureManager->setMaxMemoryLimitBytes(0);
+
+ // Restore original limit
+ textureManager->setMaxMemoryLimitBytes(maxMemoryLimit);
+
+ // Was our surface evicted?
+ ASSERT_FALSE(contentsTexture->isValid(contentsTexture->size(), contentsTexture->format()));
+
+ // Change opacity and draw
+ surfaceLayerPtr->setOpacity(0.6f);
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive two render passes
+ ASSERT_EQ(2U, frame.renderPasses.size());
+
+ // Even though not enough properties changed, the entire thing must be
+ // redrawn as we don't have cached textures
+ EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
+
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
+ CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
+ EXPECT_FALSE(quad->renderPass()->targetSurface()->contentsChanged());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Draw without any change, to make sure the state is clear
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive two EMPTY render passes
+ ASSERT_EQ(2U, frame.renderPasses.size());
+ EXPECT_EQ(0U, frame.renderPasses[0]->quadList().size());
+ EXPECT_EQ(0U, frame.renderPasses[1]->quadList().size());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+
+ // Change opacity on the intermediate layer
+ WebTransformationMatrix transform = intermediateLayerPtr->transform();
+ transform.setM11(1.0001);
+ intermediateLayerPtr->setTransform(transform);
+ {
+ CCLayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+ // Must receive one render pass, as the other one should be culled.
+ ASSERT_EQ(1U, frame.renderPasses.size());
+ EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
+
+ EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
+ CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
+ EXPECT_FALSE(quad->renderPass()->targetSurface()->contentsChanged());
+
+ myHostImpl->drawLayers(frame);
+ myHostImpl->didDrawAllLayers(frame);
+ }
+}
+
+struct RenderPassCacheEntry {
+ mutable OwnPtr<CCRenderPass> renderPassPtr;
+ CCRenderPass* renderPass;
+
+ RenderPassCacheEntry(PassOwnPtr<CCRenderPass> r)
+ : renderPassPtr(r),
+ renderPass(renderPassPtr.get())
+ {
+ }
+
+ RenderPassCacheEntry()
+ {
+ }
+
+ RenderPassCacheEntry(const RenderPassCacheEntry& entry)
+ : renderPassPtr(entry.renderPassPtr.release()),
+ renderPass(entry.renderPass)
+ {
+ }
+
+ RenderPassCacheEntry& operator=(const RenderPassCacheEntry& entry)
+ {
+ renderPassPtr = entry.renderPassPtr.release();
+ renderPass = entry.renderPass;
+ return *this;
+ }
+};
+
+struct RenderPassRemovalTestData {
+ CCRenderPassList renderPassList;
+ std::map<char, RenderPassCacheEntry> renderPassCache;
+ std::map<const CCRenderPass*, char> renderPassId;
+ Vector<OwnPtr<CCRenderSurface> > renderSurfaceStore;
+ Vector<OwnPtr<CCLayerImpl> > layerStore;
+ OwnPtr<CCSharedQuadState> sharedQuadState;
+};
+
+class FakeRenderSurface : public CCRenderSurface {
+private:
+ bool m_hasCachedTexture;
+ bool m_contentsChanged;
+
+public:
+ FakeRenderSurface(CCLayerImpl* layerImpl)
+ : CCRenderSurface(layerImpl),
+ m_hasCachedTexture(false)
+ {
+ }
+
+ virtual bool hasCachedContentsTexture() const OVERRIDE
+ {
+ return m_hasCachedTexture;
+ }
+
+ virtual bool prepareContentsTexture(LayerRendererChromium* lrc) OVERRIDE
+ {
+ return true;
+ }
+
+ virtual bool contentsChanged() const OVERRIDE
+ {
+ return m_contentsChanged;
+ }
+
+ void setHasCachedTexture(bool hasCachedTexture)
+ {
+ m_hasCachedTexture = hasCachedTexture;
+ }
+
+ void setContentsChanged(bool contentsChanged)
+ {
+ m_contentsChanged = contentsChanged;
+ }
+};
+
+class CCTestRenderPass: public CCRenderPass {
+public:
+ static PassOwnPtr<CCRenderPass> create(CCRenderSurface* targetSurface)
+ {
+ return adoptPtr(new CCTestRenderPass(targetSurface));
+ }
+
+protected:
+ CCTestRenderPass(CCRenderSurface* surface)
+ : CCRenderPass(surface)
+ {
+ }
+
+public:
+ void appendQuad(PassOwnPtr<CCDrawQuad> quad)
+ {
+ m_quadList.append(quad);
+ }
+};
+
+static PassOwnPtr<CCRenderPass> createDummyRenderPass(RenderPassRemovalTestData& testData)
+{
+ OwnPtr<CCLayerImpl> layerImpl = CCLayerImpl::create(1);
+ CCRenderSurface* renderSurface = new FakeRenderSurface(layerImpl.get());
+ OwnPtr<CCRenderPass> renderPassPtr = CCTestRenderPass::create(renderSurface);
+
+ testData.renderSurfaceStore.append(adoptPtr(renderSurface));
+ testData.layerStore.append(layerImpl.release());
+ return renderPassPtr.release();
+}
+
+static void configureRenderPassTestData(const char* testScript, RenderPassRemovalTestData& testData)
+{
+ // One shared state for all quads - we don't need the correct details
+ testData.sharedQuadState = CCSharedQuadState::create(WebTransformationMatrix(), WebTransformationMatrix(), IntRect(), IntRect(), 1.0, true);
+
+ const char* currentChar = testScript;
+
+ // Pre-create root pass
+ OwnPtr<CCRenderPass> rootRenderPass = createDummyRenderPass(testData);
+ testData.renderPassId.insert(std::pair<CCRenderPass*, char>(rootRenderPass.get(), testScript[0]));
+ testData.renderPassCache.insert(std::pair<char, RenderPassCacheEntry>(testScript[0], RenderPassCacheEntry(rootRenderPass.release())));
+ while (*currentChar != '\0') {
+ char renderPassId = currentChar[0];
+ currentChar++;
+
+ OwnPtr<CCRenderPass> renderPass;
+
+ bool isReplica = false;
+ if (!testData.renderPassCache[renderPassId].renderPassPtr.get())
+ isReplica = true;
+
+ renderPass = testData.renderPassCache[renderPassId].renderPassPtr.release();
+
+ // Cycle through quad data and create all quads
+ while (*currentChar != '\n' && *currentChar != '\0') {
+ if (*currentChar == 's') {
+ // Solid color draw quad
+ OwnPtr<CCDrawQuad> quad = CCSolidColorDrawQuad::create(testData.sharedQuadState.get(), IntRect(0, 0, 10, 10), Color::white);
+
+ static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.release());
+ currentChar++;
+ } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) {
+ // RenderPass draw quad
+ char newRenderPassId = *currentChar;
+ currentChar++;
+ bool hasTexture = false;
+ bool contentsChanged = true;
+
+ if (*currentChar == '[') {
+ currentChar++;
+ while ((*currentChar != ']') && (*currentChar != '\0')) {
+ switch (*currentChar) {
+ case 'c':
+ contentsChanged = false;
+ break;
+ case 't':
+ hasTexture = true;
+ break;
+ }
+ currentChar++;
+ }
+ if (*currentChar == ']')
+ currentChar++;
+ }
+
+ CCRenderPass* refRenderPassPtr;
+
+ if (testData.renderPassCache.find(newRenderPassId) == testData.renderPassCache.end()) {
+ OwnPtr<CCRenderPass> refRenderPass = createDummyRenderPass(testData);
+ refRenderPassPtr = refRenderPass.get();
+ FakeRenderSurface* refRenderSurface = static_cast<FakeRenderSurface*>(refRenderPass->targetSurface());
+ refRenderSurface->setHasCachedTexture(hasTexture);
+ refRenderSurface->setContentsChanged(contentsChanged);
+ testData.renderPassId.insert(std::pair<CCRenderPass*, char>(refRenderPass.get(), newRenderPassId));
+ testData.renderPassCache.insert(std::pair<char, RenderPassCacheEntry>(newRenderPassId, RenderPassCacheEntry(refRenderPass.release())));
+ } else
+ refRenderPassPtr = testData.renderPassCache[newRenderPassId].renderPass;
+
+ OwnPtr<CCRenderPassDrawQuad> quad = CCRenderPassDrawQuad::create(testData.sharedQuadState.get(), IntRect(), refRenderPassPtr, isReplica, WebKit::WebFilterOperations(), WebKit::WebFilterOperations(), 1);
+ static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.release());
+ }
+ }
+ testData.renderPassList.insert(0, renderPass.release());
+ if (*currentChar != '\0')
+ currentChar++;
+ }
+}
+
+void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buffer)
+{
+ char* pos = buffer;
+ CCRenderPassList::const_reverse_iterator it = testData.renderPassList.rbegin();
+ while (it != testData.renderPassList.rend()) {
+ CCRenderPass* currentPass = it->get();
+ char passId = testData.renderPassId.find(currentPass)->second;
+ *pos = passId;
+ pos++;
+
+ CCQuadList::const_iterator quadListIterator = currentPass->quadList().begin();
+ while (quadListIterator != currentPass->quadList().end()) {
+ CCDrawQuad* currentQuad = (*quadListIterator).get();
+ switch (currentQuad->material()) {
+ case CCDrawQuad::SolidColor:
+ *pos = 's';
+ pos++;
+ break;
+ case CCDrawQuad::RenderPass:
+ {
+ CCRenderPassDrawQuad* renderPassDrawQuad = static_cast<CCRenderPassDrawQuad*>(currentQuad);
+ const CCRenderPass* refPass = renderPassDrawQuad->renderPass();
+ char refPassId = testData.renderPassId.find(refPass)->second;
+ *pos = refPassId;
+ pos++;
+ }
+ break;
+ default:
+ *pos = 'x';
+ pos++;
+ break;
+ }
+
+ quadListIterator++;
+ }
+ *pos = '\n';
+ pos++;
+ it++;
+ }
+ *pos = '\0';
+}
+
+// Each CCRenderPassList is represented by a string which describes the configuration.
+// The syntax of the string is as follows:
+//
+// RsssssX[c]ssYsssZ[t]ssW[ct]
+// Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^ ^
+// These are solid color quads-----------------------------+ | | | | |
+// Identifies RenderPassDrawQuad's RenderPass-----------------+ | | | |
+// This quad's contents didn't change---------------------------+ | | |
+// This quad's contents changed and it has no texture---------------+ | |
+// This quad has texture but its contents changed-------------------------+ |
+// This quad's contents didn't change and it has texture - will be removed------+
+//
+// Expected results have exactly the same syntax, except they do not use square brackets,
+// since we only check the structure, not attributes.
+//
+// Test case configuration consists of initialization script and expected results,
+// all in the same format.
+struct TestCase {
+ const char* name;
+ const char* initScript;
+ const char* expectedResult;
+};
+
+TestCase removeRenderPassesCases[] =
+ {
+ {
+ "Single root pass",
+ "Rssss\n",
+ "Rssss\n"
+ }, {
+ "Single pass - no quads",
+ "R\n",
+ "R\n"
+ }, {
+ "Two passes, no removal",
+ "RssssAsss\n"
+ "Assss\n",
+ "RssssAsss\n"
+ "Assss\n"
+ }, {
+ "Two passes, remove last",
+ "RssssA[ct]sss\n"
+ "Assss\n",
+ "RssssAsss\n"
+ }, {
+ "Have texture but contents changed - leave pass",
+ "RssssA[t]sss\n"
+ "Assss\n",
+ "RssssAsss\n"
+ "Assss\n"
+ }, {
+ "Contents didn't change but no texture - leave pass",
+ "RssssA[c]sss\n"
+ "Assss\n",
+ "RssssAsss\n"
+ "Assss\n"
+ }, {
+ "Replica: two quads reference the same pass; remove",
+ "RssssA[ct]A[ct]sss\n"
+ "Assss\n",
+ "RssssAAsss\n"
+ }, {
+ "Replica: two quads reference the same pass; leave",
+ "RssssA[c]A[c]sss\n"
+ "Assss\n",
+ "RssssAAsss\n"
+ "Assss\n",
+ }, {
+ "Many passes, remove all",
+ "RssssA[ct]sss\n"
+ "AsssB[ct]C[ct]s\n"
+ "BsssD[ct]ssE[ct]F[ct]\n"
+ "Essssss\n"
+ "CG[ct]\n"
+ "Dsssssss\n"
+ "Fsssssss\n"
+ "Gsss\n",
+
+ "RssssAsss\n"
+ }, {
+ "Deep recursion, remove all",
+
+ "RsssssA[ct]ssss\n"
+ "AssssBsss\n"
+ "BC\n"
+ "CD\n"
+ "DE\n"
+ "EF\n"
+ "FG\n"
+ "GH\n"
+ "HsssIsss\n"
+ "IJ\n"
+ "Jssss\n",
+
+ "RsssssAssss\n"
+ }, {
+ "Wide recursion, remove all",
+ "RA[ct]B[ct]C[ct]D[ct]E[ct]F[ct]G[ct]H[ct]I[ct]J[ct]\n"
+ "As\n"
+ "Bs\n"
+ "Cssss\n"
+ "Dssss\n"
+ "Es\n"
+ "F\n"
+ "Gs\n"
+ "Hs\n"
+ "Is\n"
+ "Jssss\n",
+
+ "RABCDEFGHIJ\n"
+ }, {
+ "Remove passes regardless of cache state",
+ "RssssA[ct]sss\n"
+ "AsssBCs\n"
+ "BsssD[c]ssE[t]F\n"
+ "Essssss\n"
+ "CG\n"
+ "Dsssssss\n"
+ "Fsssssss\n"
+ "Gsss\n",
+
+ "RssssAsss\n"
+ }, {
+ "Leave some passes, remove others",
+
+ "RssssA[c]sss\n"
+ "AsssB[t]C[ct]s\n"
+ "BsssD[c]ss\n"
+ "CG\n"
+ "Dsssssss\n"
+ "Gsss\n",
+
+ "RssssAsss\n"
+ "AsssBCs\n"
+ "BsssDss\n"
+ "Dsssssss\n"
+ }, {
+ 0, 0, 0
+ }
+ };
+
+static void verifyRenderPassTestData(TestCase& testCase, RenderPassRemovalTestData& testData)
+{
+ char actualResult[1024];
+ dumpRenderPassTestData(testData, actualResult);
+ EXPECT_STREQ(testCase.expectedResult, actualResult) << "In test case: " << testCase.name;
+}
+
+TEST(RenderPassRemovalTest, testRemoveRenderPasses)
+{
+ int testCaseIndex = 0;
+ while (removeRenderPassesCases[testCaseIndex].name) {
+ DebugScopedSetImplThread implThread;
+ RenderPassRemovalTestData testData;
+ CCRenderPassList skippedPasses;
+ configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initScript, testData);
+ CCLayerTreeHostImpl::removePassesWithCachedTextures(testData.renderPassList, skippedPasses);
+ verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testData);
+ testCaseIndex++;
+ }
}
} // namespace
diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp
index b996006ae..544eca88b 100644
--- a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp
+++ b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp
@@ -27,38 +27,20 @@
#include "cc/CCLayerTreeHost.h"
#include "AnimationIdVendor.h"
-#include "CCAnimationTestCommon.h"
#include "CCOcclusionTrackerTestCommon.h"
-#include "CCTiledLayerTestCommon.h"
-#include "CompositorFakeWebGraphicsContext3D.h"
+#include "CCThreadedTest.h"
#include "ContentLayerChromium.h"
-#include "FakeWebGraphicsContext3D.h"
#include "GraphicsContext3DPrivate.h"
-#include "LayerChromium.h"
-#include "TextureManager.h"
-#include "WebCompositor.h"
-#include "WebKit.h"
-#include "cc/CCActiveAnimation.h"
-#include "cc/CCLayerAnimationController.h"
-#include "cc/CCLayerAnimationDelegate.h"
-#include "cc/CCLayerImpl.h"
#include "cc/CCLayerTreeHostImpl.h"
-#include "cc/CCScopedThreadProxy.h"
-#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCSettings.h"
#include "cc/CCTextureUpdater.h"
-#include "cc/CCThreadTask.h"
#include "cc/CCTimingFunction.h"
#include "platform/WebThread.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <public/Platform.h>
-#include <public/WebFilterOperation.h>
-#include <public/WebFilterOperations.h>
-#include <wtf/Locker.h>
#include <wtf/MainThread.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/ThreadingPrimitives.h>
-#include <wtf/Vector.h>
+#include <wtf/OwnArrayPtr.h>
using namespace WebCore;
using namespace WebKit;
@@ -73,683 +55,8 @@ using namespace WTF;
namespace {
-class CompositorFakeWebGraphicsContext3DWithTextureTracking : public CompositorFakeWebGraphicsContext3D {
-public:
- static PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> create(Attributes attrs)
- {
- return adoptPtr(new CompositorFakeWebGraphicsContext3DWithTextureTracking(attrs));
- }
-
- virtual WebGLId createTexture()
- {
- WebGLId texture = m_textures.size() + 1;
- m_textures.append(texture);
- return texture;
- }
-
- virtual void deleteTexture(WebGLId texture)
- {
- for (size_t i = 0; i < m_textures.size(); i++) {
- if (m_textures[i] == texture) {
- m_textures.remove(i);
- break;
- }
- }
- }
-
- virtual void bindTexture(WGC3Denum /* target */, WebGLId texture)
- {
- m_usedTextures.add(texture);
- }
-
- int numTextures() const { return static_cast<int>(m_textures.size()); }
- int texture(int i) const { return m_textures[i]; }
- void resetTextures() { m_textures.clear(); }
-
- int numUsedTextures() const { return static_cast<int>(m_usedTextures.size()); }
- bool usedTexture(int texture) const { return m_usedTextures.find(texture) != m_usedTextures.end(); }
- void resetUsedTextures() { m_usedTextures.clear(); }
-
-private:
- explicit CompositorFakeWebGraphicsContext3DWithTextureTracking(Attributes attrs) : CompositorFakeWebGraphicsContext3D(attrs)
- {
- }
-
- Vector<WebGLId> m_textures;
- HashSet<WebGLId, DefaultHash<WebGLId>::Hash, UnsignedWithZeroKeyHashTraits<WebGLId> > m_usedTextures;
-};
-
-// Used by test stubs to notify the test when something interesting happens.
-class TestHooks : public CCLayerAnimationDelegate {
-public:
- virtual void beginCommitOnCCThread(CCLayerTreeHostImpl*) { }
- virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*) { }
- virtual void prepareToDrawOnCCThread(CCLayerTreeHostImpl*) { }
- virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*) { }
- virtual void animateLayers(CCLayerTreeHostImpl*, double monotonicTime) { }
- virtual void willAnimateLayers(CCLayerTreeHostImpl*, double monotonicTime) { }
- virtual void applyScrollAndScale(const IntSize&, float) { }
- virtual void updateAnimations(double monotonicTime) { }
- virtual void layout() { }
- virtual void didRecreateContext(bool succeeded) { }
- virtual void didCommit() { }
- virtual void didCommitAndDrawFrame() { }
- virtual void scheduleComposite() { }
-
- // Implementation of CCLayerAnimationDelegate
- virtual void notifyAnimationStarted(double time) { }
- virtual void notifyAnimationFinished(double time) { }
-
- virtual PassRefPtr<GraphicsContext3D> createContext()
- {
- GraphicsContext3D::Attributes attrs;
- WebGraphicsContext3D::Attributes webAttrs;
- webAttrs.alpha = attrs.alpha;
-
- OwnPtr<WebGraphicsContext3D> webContext = CompositorFakeWebGraphicsContext3DWithTextureTracking::create(webAttrs);
- return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow);
- }
-};
-
-// Adapts CCLayerTreeHostImpl for test. Runs real code, then invokes test hooks.
-class MockLayerTreeHostImpl : public CCLayerTreeHostImpl {
-public:
- static PassOwnPtr<MockLayerTreeHostImpl> create(TestHooks* testHooks, const CCSettings& settings, CCLayerTreeHostImplClient* client)
- {
- return adoptPtr(new MockLayerTreeHostImpl(testHooks, settings, client));
- }
-
- virtual void beginCommit()
- {
- CCLayerTreeHostImpl::beginCommit();
- m_testHooks->beginCommitOnCCThread(this);
- }
-
- virtual void commitComplete()
- {
- CCLayerTreeHostImpl::commitComplete();
- m_testHooks->commitCompleteOnCCThread(this);
- }
-
- virtual bool prepareToDraw(FrameData& frame)
- {
- bool result = CCLayerTreeHostImpl::prepareToDraw(frame);
- m_testHooks->prepareToDrawOnCCThread(this);
- return result;
- }
-
- virtual void drawLayers(const FrameData& frame)
- {
- CCLayerTreeHostImpl::drawLayers(frame);
- m_testHooks->drawLayersOnCCThread(this);
- }
-
- // Make these public.
- typedef Vector<CCLayerImpl*> CCLayerList;
- using CCLayerTreeHostImpl::calculateRenderSurfaceLayerList;
-
-protected:
- virtual void animateLayers(double monotonicTime, double wallClockTime)
- {
- m_testHooks->willAnimateLayers(this, monotonicTime);
- CCLayerTreeHostImpl::animateLayers(monotonicTime, wallClockTime);
- m_testHooks->animateLayers(this, monotonicTime);
- }
-
- virtual double lowFrequencyAnimationInterval() const
- {
- return 1.0 / 60;
- }
-
-private:
- MockLayerTreeHostImpl(TestHooks* testHooks, const CCSettings& settings, CCLayerTreeHostImplClient* client)
- : CCLayerTreeHostImpl(settings, client)
- , m_testHooks(testHooks)
- {
- }
-
- TestHooks* m_testHooks;
-};
-
-// Adapts CCLayerTreeHost for test. Injects MockLayerTreeHostImpl.
-class MockLayerTreeHost : public CCLayerTreeHost {
-public:
- static PassOwnPtr<MockLayerTreeHost> create(TestHooks* testHooks, CCLayerTreeHostClient* client, PassRefPtr<LayerChromium> rootLayer, const CCSettings& settings)
- {
- // For these tests, we will enable threaded animations.
- CCSettings settingsCopy = settings;
- settingsCopy.threadedAnimationEnabled = true;
-
- OwnPtr<MockLayerTreeHost> layerTreeHost(adoptPtr(new MockLayerTreeHost(testHooks, client, settingsCopy)));
- bool success = layerTreeHost->initialize();
- EXPECT_TRUE(success);
- layerTreeHost->setRootLayer(rootLayer);
-
- // LayerTreeHostImpl won't draw if it has 1x1 viewport.
- layerTreeHost->setViewportSize(IntSize(1, 1));
-
- layerTreeHost->rootLayer()->setLayerAnimationDelegate(testHooks);
-
- return layerTreeHost.release();
- }
-
- virtual PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
- {
- // For these tests, we will enable threaded animations.
- CCSettings copySettings = settings();
- copySettings.threadedAnimationEnabled = true;
- return MockLayerTreeHostImpl::create(m_testHooks, copySettings, client);
- }
-
- virtual void didAddAnimation() OVERRIDE
- {
- m_didAddAnimationWasCalled = true;
- CCLayerTreeHost::didAddAnimation();
- }
-
- bool didAddAnimationWasCalled()
- {
- return m_didAddAnimationWasCalled;
- }
-
-private:
- MockLayerTreeHost(TestHooks* testHooks, CCLayerTreeHostClient* client, const CCSettings& settings)
- : CCLayerTreeHost(client, settings)
- , m_testHooks(testHooks)
- , m_didAddAnimationWasCalled(false)
- {
- }
-
- TestHooks* m_testHooks;
- bool m_didAddAnimationWasCalled;
-};
-
-// Implementation of CCLayerTreeHost callback interface.
-class MockLayerTreeHostClient : public CCLayerTreeHostClient {
-public:
- static PassOwnPtr<MockLayerTreeHostClient> create(TestHooks* testHooks)
- {
- return adoptPtr(new MockLayerTreeHostClient(testHooks));
- }
-
- virtual void willBeginFrame() OVERRIDE
- {
- }
-
- virtual void didBeginFrame() OVERRIDE
- {
- }
-
- virtual void updateAnimations(double monotonicTime) OVERRIDE
- {
- m_testHooks->updateAnimations(monotonicTime);
- }
-
- virtual void layout() OVERRIDE
- {
- m_testHooks->layout();
- }
-
- virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale) OVERRIDE
- {
- m_testHooks->applyScrollAndScale(scrollDelta, scale);
- }
-
- virtual PassRefPtr<GraphicsContext3D> createContext() OVERRIDE
- {
- return m_testHooks->createContext();
- }
-
- virtual void willCommit() OVERRIDE
- {
- }
-
- virtual void didCommit() OVERRIDE
- {
- m_testHooks->didCommit();
- }
-
- virtual void didCommitAndDrawFrame() OVERRIDE
- {
- m_testHooks->didCommitAndDrawFrame();
- }
-
- virtual void didCompleteSwapBuffers() OVERRIDE
- {
- }
-
- virtual void didRecreateContext(bool succeeded) OVERRIDE
- {
- m_testHooks->didRecreateContext(succeeded);
- }
-
- virtual void scheduleComposite() OVERRIDE
- {
- m_testHooks->scheduleComposite();
- }
-
-private:
- explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
-
- TestHooks* m_testHooks;
-};
-
-// The CCLayerTreeHostTest runs with the main loop running. It instantiates a single MockLayerTreeHost and associated
-// MockLayerTreeHostImpl/MockLayerTreeHostClient.
-//
-// beginTest() is called once the main message loop is running and the layer tree host is initialized.
-//
-// Key stages of the drawing loop, e.g. drawing or commiting, redirect to CCLayerTreeHostTest methods of similar names.
-// To track the commit process, override these functions.
-//
-// The test continues until someone calls endTest. endTest can be called on any thread, but be aware that
-// ending the test is an asynchronous process.
-class CCLayerTreeHostTest : public testing::Test, TestHooks {
-public:
- virtual void afterTest() = 0;
- virtual void beginTest() = 0;
-
- void endTest();
- void endTestAfterDelay(int delayMilliseconds);
-
- void postSetNeedsAnimateToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimate, this);
- }
-
- void postAddAnimationToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchAddAnimation, this);
- }
-
- void postAddInstantAnimationToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchAddInstantAnimation, this);
- }
-
- void postSetNeedsCommitToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsCommit, this);
- }
-
- void AcquireLayerTextures()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchAcquireLayerTextures, this);
- }
-
- void postSetNeedsRedrawToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsRedraw, this);
- }
-
- void postSetNeedsAnimateAndCommitToMainThread()
- {
- callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimateAndCommit, this);
- }
-
- void postSetVisibleToMainThread(bool visible)
- {
- callOnMainThread(visible ? CCLayerTreeHostTest::dispatchSetVisible : CCLayerTreeHostTest::dispatchSetInvisible, this);
- }
-
- void timeout()
- {
- m_timedOut = true;
- endTest();
- }
-
- void clearTimeout()
- {
- m_timeoutTask = 0;
- }
-
- void clearEndTestTask()
- {
- m_endTestTask = 0;
- }
-
- CCLayerTreeHost* layerTreeHost() { return m_layerTreeHost.get(); }
-
-
-protected:
- CCLayerTreeHostTest()
- : m_beginning(false)
- , m_endWhenBeginReturns(false)
- , m_timedOut(false)
- , m_finished(false)
- , m_scheduled(false)
- , m_started(false)
- , m_endTestTask(0)
- { }
-
- void doBeginTest();
-
- virtual void scheduleComposite()
- {
- if (!m_started || m_scheduled || m_finished)
- return;
- m_scheduled = true;
- callOnMainThread(&CCLayerTreeHostTest::dispatchComposite, this);
- }
-
- static void onEndTest(void* self)
- {
- ASSERT(isMainThread());
- WebKit::Platform::current()->currentThread()->exitRunLoop();
- }
-
- static void dispatchSetNeedsAnimate(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->setNeedsAnimate();
- }
-
- static void dispatchAddInstantAnimation(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
- addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 0, 0, 0.5, false);
- }
-
- static void dispatchAddAnimation(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
- addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 10, 0, 0.5, true);
- }
-
- static void dispatchSetNeedsAnimateAndCommit(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost) {
- test->m_layerTreeHost->setNeedsAnimate();
- test->m_layerTreeHost->setNeedsCommit();
- }
- }
-
- static void dispatchSetNeedsCommit(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT_TRUE(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->setNeedsCommit();
- }
-
- static void dispatchAcquireLayerTextures(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT_TRUE(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->acquireLayerTextures();
- }
-
- static void dispatchSetNeedsRedraw(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT_TRUE(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->setNeedsRedraw();
- }
-
- static void dispatchSetVisible(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->setVisible(true);
- }
-
- static void dispatchSetInvisible(void* self)
- {
- ASSERT(isMainThread());
-
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(test);
- if (test->m_finished)
- return;
-
- if (test->m_layerTreeHost)
- test->m_layerTreeHost->setVisible(false);
- }
-
- static void dispatchComposite(void* self)
- {
- CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
- ASSERT(isMainThread());
- ASSERT(test);
- test->m_scheduled = false;
- if (test->m_layerTreeHost && !test->m_finished)
- test->m_layerTreeHost->composite();
- }
-
- class TimeoutTask : public WebThread::Task {
- public:
- explicit TimeoutTask(CCLayerTreeHostTest* test)
- : m_test(test)
- {
- }
-
- void clearTest()
- {
- m_test = 0;
- }
-
- virtual ~TimeoutTask()
- {
- if (m_test)
- m_test->clearTimeout();
- }
-
- virtual void run()
- {
- if (m_test)
- m_test->timeout();
- }
-
- private:
- CCLayerTreeHostTest* m_test;
- };
-
- class BeginTask : public WebThread::Task {
- public:
- explicit BeginTask(CCLayerTreeHostTest* test)
- : m_test(test)
- {
- }
-
- virtual ~BeginTask() { }
- virtual void run()
- {
- m_test->doBeginTest();
- }
- private:
- CCLayerTreeHostTest* m_test;
- };
-
- class EndTestTask : public WebThread::Task {
- public:
- explicit EndTestTask(CCLayerTreeHostTest* test)
- : m_test(test)
- {
- }
-
- virtual ~EndTestTask()
- {
- if (m_test)
- m_test->clearEndTestTask();
- }
-
- void clearTest()
- {
- m_test = 0;
- }
-
- virtual void run()
- {
- if (m_test)
- m_test->endTest();
- }
-
- private:
- CCLayerTreeHostTest* m_test;
- };
-
- virtual void runTest(bool threaded)
- {
- if (threaded) {
- m_webThread = adoptPtr(WebKit::Platform::current()->createThread("CCLayerTreeHostTest"));
- WebCompositor::initialize(m_webThread.get());
- } else
- WebCompositor::initialize(0);
-
- ASSERT(CCProxy::isMainThread());
- m_mainThreadProxy = CCScopedThreadProxy::create(CCProxy::mainThread());
-
- m_beginTask = new BeginTask(this);
- WebKit::Platform::current()->currentThread()->postDelayedTask(m_beginTask, 0); // postDelayedTask takes ownership of the task
- m_timeoutTask = new TimeoutTask(this);
- WebKit::Platform::current()->currentThread()->postDelayedTask(m_timeoutTask, 5000);
- WebKit::Platform::current()->currentThread()->enterRunLoop();
-
- if (m_layerTreeHost && m_layerTreeHost->rootLayer())
- m_layerTreeHost->rootLayer()->setLayerTreeHost(0);
- m_layerTreeHost.clear();
-
- if (m_timeoutTask)
- m_timeoutTask->clearTest();
-
- if (m_endTestTask)
- m_endTestTask->clearTest();
-
- ASSERT_FALSE(m_layerTreeHost.get());
- m_client.clear();
- if (m_timedOut) {
- FAIL() << "Test timed out";
- WebCompositor::shutdown();
- return;
- }
- afterTest();
- WebCompositor::shutdown();
- }
-
- CCSettings m_settings;
- OwnPtr<MockLayerTreeHostClient> m_client;
- OwnPtr<CCLayerTreeHost> m_layerTreeHost;
-
-private:
- bool m_beginning;
- bool m_endWhenBeginReturns;
- bool m_timedOut;
- bool m_finished;
- bool m_scheduled;
- bool m_started;
-
- OwnPtr<WebThread> m_webThread;
- RefPtr<CCScopedThreadProxy> m_mainThreadProxy;
- TimeoutTask* m_timeoutTask;
- BeginTask* m_beginTask;
- EndTestTask* m_endTestTask;
-};
-
-void CCLayerTreeHostTest::doBeginTest()
-{
- ASSERT(isMainThread());
- m_client = MockLayerTreeHostClient::create(this);
-
- RefPtr<LayerChromium> rootLayer = LayerChromium::create();
- m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings);
- ASSERT_TRUE(m_layerTreeHost);
- rootLayer->setLayerTreeHost(m_layerTreeHost.get());
- m_layerTreeHost->setSurfaceReady();
-
- m_started = true;
- m_beginning = true;
- beginTest();
- m_beginning = false;
- if (m_endWhenBeginReturns)
- onEndTest(static_cast<void*>(this));
-}
-
-void CCLayerTreeHostTest::endTest()
-{
- m_finished = true;
-
- // If we are called from the CCThread, re-call endTest on the main thread.
- if (!isMainThread())
- m_mainThreadProxy->postTask(createCCThreadTask(this, &CCLayerTreeHostTest::endTest));
- else {
- // For the case where we endTest during beginTest(), set a flag to indicate that
- // the test should end the second beginTest regains control.
- if (m_beginning)
- m_endWhenBeginReturns = true;
- else
- onEndTest(static_cast<void*>(this));
- }
-}
-
-void CCLayerTreeHostTest::endTestAfterDelay(int delayMilliseconds)
-{
- // If we are called from the CCThread, re-call endTest on the main thread.
- if (!isMainThread())
- m_mainThreadProxy->postTask(createCCThreadTask(this, &CCLayerTreeHostTest::endTestAfterDelay, delayMilliseconds));
- else {
- m_endTestTask = new EndTestTask(this);
- WebKit::Platform::current()->currentThread()->postDelayedTask(m_endTestTask, delayMilliseconds);
- }
-}
-
-class CCLayerTreeHostTestThreadOnly : public CCLayerTreeHostTest {
-public:
- void runTestThreaded()
- {
- CCLayerTreeHostTest::runTest(true);
- }
-};
+class CCLayerTreeHostTest : public CCThreadedTest { };
+class CCLayerTreeHostTestThreadOnly : public CCThreadedTestThreadOnly { };
// Shortlived layerTreeHosts shouldn't die.
class CCLayerTreeHostTestShortlived1 : public CCLayerTreeHostTest {
@@ -770,18 +77,6 @@ public:
}
};
-#define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
- TEST_F(TEST_FIXTURE_NAME, runSingleThread) \
- { \
- runTest(false); \
- } \
- TEST_F(TEST_FIXTURE_NAME, runMultiThread) \
- { \
- runTest(true); \
- }
-
-SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestShortlived1)
-
// Shortlived layerTreeHosts shouldn't die with a commit in flight.
class CCLayerTreeHostTestShortlived2 : public CCLayerTreeHostTest {
public:
@@ -1076,7 +371,7 @@ public:
virtual void beginTest()
{
- AcquireLayerTextures();
+ postAcquireLayerTextures();
postSetNeedsRedrawToMainThread(); // should be inhibited without blocking
postSetNeedsCommitToMainThread();
}
@@ -1133,7 +428,7 @@ public:
else {
postSetVisibleToMainThread(false);
postSetVisibleToMainThread(true);
- AcquireLayerTextures();
+ postAcquireLayerTextures();
postSetNeedsCommitToMainThread();
}
}
@@ -1287,6 +582,50 @@ TEST_F(CCLayerTreeHostTestAddAnimation, runMultiThread)
runTestThreaded();
}
+// Add a layer animation to a layer, but continually fail to draw. Confirm that after
+// a while, we do eventually force a draw.
+class CCLayerTreeHostTestCheckerboardDoesNotStarveDraws : public CCLayerTreeHostTestThreadOnly {
+public:
+ CCLayerTreeHostTestCheckerboardDoesNotStarveDraws()
+ : m_startedAnimating(false)
+ {
+ }
+
+ virtual void beginTest()
+ {
+ postAddAnimationToMainThread();
+ }
+
+ virtual void afterTest()
+ {
+ }
+
+ virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime)
+ {
+ m_startedAnimating = true;
+ }
+
+ virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*)
+ {
+ if (m_startedAnimating)
+ endTest();
+ }
+
+ virtual bool prepareToDrawOnCCThread(CCLayerTreeHostImpl*)
+ {
+ return false;
+ }
+
+private:
+ bool m_startedAnimating;
+};
+
+// Starvation can only be an issue with the MT compositor.
+TEST_F(CCLayerTreeHostTestCheckerboardDoesNotStarveDraws, runMultiThread)
+{
+ runTestThreaded();
+}
+
// Ensures that animations continue to be ticked when we are backgrounded.
class CCLayerTreeHostTestTickAnimationWhileBackgrounded : public CCLayerTreeHostTestThreadOnly {
public:
@@ -1446,56 +785,6 @@ private:
SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestSynchronizeAnimationStartTimes)
-class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
-public:
- virtual bool makeContextCurrent() { return false; }
-};
-
-// Ensures that we do not animate
-class CCLayerTreeHostTestInitializeLayerRendererFailsAfterAddAnimation : public CCLayerTreeHostTest {
-public:
- CCLayerTreeHostTestInitializeLayerRendererFailsAfterAddAnimation()
- {
- }
-
- virtual void beginTest()
- {
- // This will cause the animation timer to be set which will fire in
- // CCSingleThreadProxy::animationTimerDelay() seconds.
- postAddAnimationToMainThread();
- }
-
- virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime)
- {
- ASSERT_NOT_REACHED();
- }
-
- virtual void didRecreateContext(bool succeeded)
- {
- EXPECT_FALSE(succeeded);
-
- // Make sure we wait CCSingleThreadProxy::animationTimerDelay() seconds
- // (use ceil just to be sure). If the timer was not disabled, we will
- // attempt to call CCSingleThreadProxy::compositeImmediately and the
- // test will fail.
- endTestAfterDelay(ceil(CCSingleThreadProxy::animationTimerDelay() * 1000));
- }
-
- virtual PassRefPtr<GraphicsContext3D> createContext() OVERRIDE
- {
- return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow);
- }
-
- virtual void afterTest()
- {
- }
-};
-
-TEST_F(CCLayerTreeHostTestInitializeLayerRendererFailsAfterAddAnimation, runSingleThread)
-{
- runTest(false);
-}
-
// Ensures that main thread animations have their start times synchronized with impl thread animations.
class CCLayerTreeHostTestAnimationFinishedEvents : public CCLayerTreeHostTestThreadOnly {
public:
@@ -1886,8 +1175,7 @@ class CCLayerTreeHostTestSetVisible : public CCLayerTreeHostTest {
public:
CCLayerTreeHostTestSetVisible()
- : m_numCommits(0)
- , m_numDraws(0)
+ : m_numDraws(0)
{
}
@@ -1911,7 +1199,6 @@ public:
}
private:
- int m_numCommits;
int m_numDraws;
};
@@ -1927,7 +1214,7 @@ public:
{
}
- virtual void paintContents(GraphicsContext&, const IntRect&)
+ virtual void paintContents(SkCanvas*, const IntRect&, IntRect&)
{
// Set layer opacity to 0.
m_test->layerTreeHost()->rootLayer()->setOpacity(0);
@@ -2021,7 +1308,7 @@ class MockContentLayerDelegate : public ContentLayerDelegate {
public:
bool drawsContent() const { return true; }
MOCK_CONST_METHOD0(preserves3D, bool());
- void paintContents(GraphicsContext&, const IntRect&) { }
+ void paintContents(SkCanvas*, const IntRect&, IntRect&) { }
void notifySyncRequired() { }
};
@@ -2032,13 +1319,13 @@ public:
: m_rootLayer(ContentLayerChromium::create(&m_delegate))
, m_childLayer(ContentLayerChromium::create(&m_delegate))
{
- m_settings.deviceScaleFactor = 1.5;
}
virtual void beginTest()
{
// The device viewport should be scaled by the device scale factor.
m_layerTreeHost->setViewportSize(IntSize(40, 40));
+ m_layerTreeHost->setDeviceScaleFactor(1.5);
EXPECT_EQ(IntSize(40, 40), m_layerTreeHost->viewportSize());
EXPECT_EQ(IntSize(60, 60), m_layerTreeHost->deviceViewportSize());
@@ -2064,7 +1351,7 @@ public:
// Should only do one commit.
EXPECT_EQ(0, impl->sourceFrameNumber());
// Device scale factor should come over to impl.
- EXPECT_NEAR(impl->settings().deviceScaleFactor, 1.5, 0.00001);
+ EXPECT_NEAR(impl->deviceScaleFactor(), 1.5, 0.00001);
// Both layers are on impl.
ASSERT_EQ(1u, impl->rootLayer()->children().size());
@@ -2093,7 +1380,7 @@ public:
EXPECT_EQ_RECT(IntRect(0, 0, 60, 60), root->renderSurface()->contentRect());
WebTransformationMatrix scaleTransform;
- scaleTransform.scale(impl->settings().deviceScaleFactor);
+ scaleTransform.scale(impl->deviceScaleFactor());
// The root layer is scaled by 2x.
WebTransformationMatrix rootScreenSpaceTransform = scaleTransform;
@@ -2154,7 +1441,7 @@ public:
virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl)
{
- CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+ CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()->context3D()));
switch (impl->sourceFrameNumber()) {
case 0:
@@ -2188,7 +1475,7 @@ public:
virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
{
- CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+ CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()->context3D()));
// Number of textures used for draw should always be one.
EXPECT_EQ(1, context->numUsedTextures());
@@ -2258,7 +1545,7 @@ public:
virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl)
{
- CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+ CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()->context3D()));
switch (impl->sourceFrameNumber()) {
case 0:
@@ -2327,7 +1614,7 @@ public:
virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
{
- CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()));
+ CompositorFakeWebGraphicsContext3DWithTextureTracking* context = static_cast<CompositorFakeWebGraphicsContext3DWithTextureTracking*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(impl->context()->context3D()));
// Number of textures used for drawing should two except for frame 4
// where the viewport only contains one layer.
@@ -2940,33 +2227,115 @@ SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestFinishAllRendering)
// correctly recognized.
class CCLayerTreeHostTestLayerAddedWithAnimation : public CCLayerTreeHostTest {
public:
- CCLayerTreeHostTestLayerAddedWithAnimation() { }
+ CCLayerTreeHostTestLayerAddedWithAnimation()
+ : m_addedAnimation(false)
+ {
+ }
virtual void beginTest()
{
- EXPECT_FALSE(static_cast<MockLayerTreeHost*>(layerTreeHost())->didAddAnimationWasCalled());
+ EXPECT_FALSE(m_addedAnimation);
RefPtr<LayerChromium> layer = LayerChromium::create();
- layer->setLayerAnimationDelegate(&m_animationDelegate);
+ layer->setLayerAnimationDelegate(this);
// Any valid CCAnimationCurve will do here.
OwnPtr<CCAnimationCurve> curve(CCEaseTimingFunction::create());
OwnPtr<CCActiveAnimation> animation(CCActiveAnimation::create(curve.release(), AnimationIdVendor::getNextAnimationId(), AnimationIdVendor::getNextGroupId(), CCActiveAnimation::Opacity));
- layer->layerAnimationController()->add(animation.release());
+ layer->layerAnimationController()->addAnimation(animation.release());
// We add the animation *before* attaching the layer to the tree.
m_layerTreeHost->rootLayer()->addChild(layer);
- EXPECT_TRUE(static_cast<MockLayerTreeHost*>(layerTreeHost())->didAddAnimationWasCalled());
+ EXPECT_TRUE(m_addedAnimation);
endTest();
}
+ virtual void didAddAnimation()
+ {
+ m_addedAnimation = true;
+ }
+
virtual void afterTest() { }
private:
- ::TestHooks m_animationDelegate;
+ bool m_addedAnimation;
};
SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestLayerAddedWithAnimation)
+class CCLayerTreeHostTestScrollChildLayer : public CCLayerTreeHostTest, public LayerChromiumScrollDelegate {
+public:
+ CCLayerTreeHostTestScrollChildLayer()
+ : m_scrollAmount(2, 1)
+ {
+ }
+
+ virtual void beginTest() OVERRIDE
+ {
+ m_layerTreeHost->setViewportSize(IntSize(10, 10));
+ m_rootScrollLayer = ContentLayerChromium::create(&m_mockDelegate);
+ m_rootScrollLayer->setBounds(IntSize(10, 10));
+ m_rootScrollLayer->setIsDrawable(true);
+ m_rootScrollLayer->setScrollable(true);
+ m_rootScrollLayer->setMaxScrollPosition(IntSize(100, 100));
+ m_layerTreeHost->rootLayer()->addChild(m_rootScrollLayer);
+ m_childLayer = ContentLayerChromium::create(&m_mockDelegate);
+ m_childLayer->setLayerScrollDelegate(this);
+ m_childLayer->setBounds(IntSize(50, 50));
+ m_childLayer->setIsDrawable(true);
+ m_childLayer->setScrollable(true);
+ m_childLayer->setMaxScrollPosition(IntSize(100, 100));
+ m_rootScrollLayer->addChild(m_childLayer);
+ postSetNeedsCommitToMainThread();
+ }
+
+ virtual void didScroll(const IntSize& scrollDelta) OVERRIDE
+ {
+ m_reportedScrollAmount = scrollDelta;
+ }
+
+ virtual void applyScrollAndScale(const IntSize& scrollDelta, float) OVERRIDE
+ {
+ IntPoint position = m_rootScrollLayer->scrollPosition();
+ m_rootScrollLayer->setScrollPosition(position + scrollDelta);
+ }
+
+ virtual void beginCommitOnCCThread(CCLayerTreeHostImpl* impl) OVERRIDE
+ {
+ EXPECT_EQ(m_rootScrollLayer->scrollPosition(), IntPoint());
+ if (!m_layerTreeHost->frameNumber())
+ EXPECT_EQ(m_childLayer->scrollPosition(), IntPoint());
+ else
+ EXPECT_EQ(m_childLayer->scrollPosition(), IntPoint() + m_scrollAmount);
+ }
+
+ virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) OVERRIDE
+ {
+ if (impl->frameNumber() == 1) {
+ EXPECT_EQ(impl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
+ impl->scrollBy(m_scrollAmount);
+ impl->scrollEnd();
+ } else if (impl->frameNumber() == 2)
+ endTest();
+ }
+
+ virtual void afterTest() OVERRIDE
+ {
+ EXPECT_EQ(m_scrollAmount, m_reportedScrollAmount);
+ }
+
+private:
+ const IntSize m_scrollAmount;
+ IntSize m_reportedScrollAmount;
+ MockContentLayerDelegate m_mockDelegate;
+ RefPtr<LayerChromium> m_childLayer;
+ RefPtr<LayerChromium> m_rootScrollLayer;
+};
+
+TEST_F(CCLayerTreeHostTestScrollChildLayer, runMultiThread)
+{
+ runTest(true);
+}
+
} // namespace
diff --git a/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp
index 80317a008..8631b1942 100644
--- a/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp
+++ b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp
@@ -132,7 +132,10 @@ struct CCOcclusionTrackerTestMainThreadTypes {
typedef CCLayerIterator<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, CCLayerIteratorActions::FrontToBack> LayerIterator;
typedef CCOcclusionTracker OcclusionTrackerType;
- static PassLayerPtrType createLayer() { return LayerChromium::create(); }
+ static PassLayerPtrType createLayer()
+ {
+ return LayerChromium::create();
+ }
static PassContentLayerPtrType createContentLayer() { return adoptRef(new ContentLayerType()); }
};
@@ -261,7 +264,10 @@ protected:
root->setClipRect(IntRect(IntPoint::zero(), root->bounds()));
m_renderSurfaceLayerListImpl.append(m_root.get());
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListImpl, dummyLayerList, 0, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListImpl, dummyLayerList, 0, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(m_renderSurfaceLayerListImpl, root->renderSurface()->contentRect());
+
m_layerIterator = m_layerIteratorBegin = Types::LayerIterator::begin(&m_renderSurfaceLayerListImpl);
}
@@ -277,7 +283,10 @@ protected:
root->setClipRect(IntRect(IntPoint::zero(), root->bounds()));
m_renderSurfaceLayerListChromium.append(m_root);
- CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListChromium, dummyLayerList, dummyMaxTextureSize);
+ CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListChromium, dummyLayerList, dummyMaxTextureSize);
+
+ CCLayerTreeHostCommon::calculateVisibleAndScissorRects(m_renderSurfaceLayerListChromium, root->renderSurface()->contentRect());
+
m_layerIterator = m_layerIteratorBegin = Types::LayerIterator::begin(&m_renderSurfaceLayerListChromium);
}
diff --git a/Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp b/Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp
index 5cbe7fc54..c8b0edaed 100644
--- a/Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp
+++ b/Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp
@@ -111,6 +111,7 @@ TEST(CCRenderSurfaceTest, sanityCheckSurfaceCreatesCorrectSharedQuadState)
renderSurface->setOriginTransform(origin);
renderSurface->setContentRect(contentRect);
renderSurface->setClipRect(clipRect);
+ renderSurface->setScissorRect(clipRect);
renderSurface->setDrawOpacity(1);
OwnPtr<CCSharedQuadState> sharedQuadState = renderSurface->createSharedQuadState();
@@ -119,7 +120,7 @@ TEST(CCRenderSurfaceTest, sanityCheckSurfaceCreatesCorrectSharedQuadState)
EXPECT_EQ(30, sharedQuadState->layerTransform().m41());
EXPECT_EQ(40, sharedQuadState->layerTransform().m42());
EXPECT_EQ(contentRect, sharedQuadState->layerRect());
- EXPECT_EQ(clipRect, sharedQuadState->clipRect());
+ EXPECT_EQ(clipRect, sharedQuadState->scissorRect());
EXPECT_EQ(1, sharedQuadState->opacity());
EXPECT_FALSE(sharedQuadState->isOpaque());
}
diff --git a/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp b/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp
index 2731c76fd..a99149ba9 100644
--- a/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp
+++ b/Source/WebKit/chromium/tests/CCSchedulerStateMachineTest.cpp
@@ -285,6 +285,48 @@ TEST(CCSchedulerStateMachineTest, TestCommitAfterFailedAndSuccessfulDrawDoesNotA
EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
}
+TEST(CCSchedulerStateMachineTest, TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit)
+{
+ CCSchedulerStateMachine state;
+ state.setCanBeginFrame(true);
+ state.setVisible(true);
+ state.setMaximumNumberOfFailedDrawsBeforeDrawIsForced(1);
+
+ // Start a commit.
+ state.setNeedsCommit();
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_FRAME, state.nextAction());
+ state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_FRAME);
+ EXPECT_TRUE(state.commitPending());
+
+ // Then initiate a draw.
+ state.setNeedsRedraw();
+ EXPECT_TRUE(state.vsyncCallbackNeeded());
+ state.didEnterVSync();
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.nextAction());
+ EXPECT_TRUE(state.redrawPending());
+
+ // Fail the draw.
+ state.updateState(CCSchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE);
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_NONE, state.nextAction());
+ state.didDrawIfPossibleCompleted(false);
+ EXPECT_TRUE(state.redrawPending());
+ // But the commit is ongoing.
+ EXPECT_TRUE(state.commitPending());
+
+ // Finish the commit. Note, we should not yet be forcing a draw, but should
+ // continue the commit as usual.
+ state.beginFrameComplete();
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES, state.nextAction());
+ state.updateState(CCSchedulerStateMachine::ACTION_BEGIN_UPDATE_MORE_RESOURCES);
+ state.beginUpdateMoreResourcesComplete(false);
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_COMMIT, state.nextAction());
+ state.updateState(CCSchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_TRUE(state.redrawPending());
+
+ // The redraw should be forced in this case.
+ EXPECT_EQ(CCSchedulerStateMachine::ACTION_DRAW_FORCED, state.nextAction());
+}
+
TEST(CCSchedulerStateMachineTest, TestFailedDrawIsRetriedNextVSync)
{
CCSchedulerStateMachine state;
diff --git a/Source/WebKit/chromium/tests/CCSingleThreadProxyTest.cpp b/Source/WebKit/chromium/tests/CCSingleThreadProxyTest.cpp
new file mode 100644
index 000000000..4fe40f241
--- /dev/null
+++ b/Source/WebKit/chromium/tests/CCSingleThreadProxyTest.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 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/CCSingleThreadProxy.h"
+
+#include "CCThreadedTest.h"
+#include "CompositorFakeWebGraphicsContext3D.h"
+#include "FakeWebGraphicsContext3D.h"
+#include "GraphicsContext3DPrivate.h"
+#include "platform/WebThread.h"
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace WebKitTests;
+
+class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
+public:
+ virtual bool makeContextCurrent() { return false; }
+};
+
+class CCSingleThreadProxyTestInitializeLayerRendererFailsAfterAddAnimation : public CCThreadedTest {
+public:
+ CCSingleThreadProxyTestInitializeLayerRendererFailsAfterAddAnimation()
+ {
+ }
+
+ virtual void beginTest()
+ {
+ // This will cause the animation timer to be set which will fire in
+ // CCSingleThreadProxy::animationTimerDelay() seconds.
+ postAddAnimationToMainThread();
+ }
+
+ virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual void didRecreateContext(bool succeeded)
+ {
+ EXPECT_FALSE(succeeded);
+
+ // Make sure we wait CCSingleThreadProxy::animationTimerDelay() seconds
+ // (use ceil just to be sure). If the timer was not disabled, we will
+ // attempt to call CCSingleThreadProxy::compositeImmediately and the
+ // test will fail.
+ endTestAfterDelay(ceil(CCSingleThreadProxy::animationTimerDelay() * 1000));
+ }
+
+ virtual PassRefPtr<GraphicsContext3D> createContext() OVERRIDE
+ {
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow);
+ }
+
+ virtual void afterTest()
+ {
+ }
+};
+
+TEST_F(CCSingleThreadProxyTestInitializeLayerRendererFailsAfterAddAnimation, runSingleThread)
+{
+ runTest(false);
+}
+
+class CCSingleThreadProxyTestDidAddAnimationBeforeInitializingLayerRenderer : public CCThreadedTest {
+public:
+ CCSingleThreadProxyTestDidAddAnimationBeforeInitializingLayerRenderer()
+ {
+ }
+
+ virtual void beginTest()
+ {
+ // This will cause the animation timer to be set which will fire in
+ // CCSingleThreadProxy::animationTimerDelay() seconds.
+ postDidAddAnimationToMainThread();
+ }
+
+ virtual void animateLayers(CCLayerTreeHostImpl*, double)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual void didRecreateContext(bool)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual void didAddAnimation()
+ {
+ // Make sure we wait CCSingleThreadProxy::animationTimerDelay() seconds
+ // (use ceil just to be sure). If the timer was not disabled, we will
+ // attempt to call CCSingleThreadProxy::compositeImmediately and the
+ // test will fail.
+ endTestAfterDelay(ceil(CCSingleThreadProxy::animationTimerDelay() * 1000));
+ }
+
+ virtual PassRefPtr<GraphicsContext3D> createContext() OVERRIDE
+ {
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow);
+ }
+
+ virtual void afterTest()
+ {
+ }
+};
+
+TEST_F(CCSingleThreadProxyTestDidAddAnimationBeforeInitializingLayerRenderer, runSingleThread)
+{
+ runTest(false);
+}
diff --git a/Source/WebKit/chromium/tests/CCTestCommon.h b/Source/WebKit/chromium/tests/CCTestCommon.h
new file mode 100644
index 000000000..89fce9818
--- /dev/null
+++ b/Source/WebKit/chromium/tests/CCTestCommon.h
@@ -0,0 +1,42 @@
+/*
+ * 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 CCTestCommon_h
+#define CCTestCommon_h
+
+#include "cc/CCSettings.h"
+
+namespace WebKitTests {
+
+// If you have a test that modifies or uses global settings, keep an instance
+// of this class to ensure that you start and end with a clean slate.
+class CCScopedSettings {
+public:
+ CCScopedSettings() { WebCore::CCSettings::reset(); }
+ ~CCScopedSettings() { WebCore::CCSettings::reset(); }
+};
+
+} // namespace WebKitTests
+
+#endif // CCTestCommon_h
diff --git a/Source/WebKit/chromium/tests/CCThreadedTest.cpp b/Source/WebKit/chromium/tests/CCThreadedTest.cpp
new file mode 100644
index 000000000..57b6df14e
--- /dev/null
+++ b/Source/WebKit/chromium/tests/CCThreadedTest.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2011 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 "CCThreadedTest.h"
+
+#include "AnimationIdVendor.h"
+#include "CCAnimationTestCommon.h"
+#include "CCOcclusionTrackerTestCommon.h"
+#include "CCTiledLayerTestCommon.h"
+#include "ContentLayerChromium.h"
+#include "FakeWebGraphicsContext3D.h"
+#include "GraphicsContext3DPrivate.h"
+#include "LayerChromium.h"
+#include "TextureManager.h"
+#include "WebCompositor.h"
+#include "WebKit.h"
+#include "cc/CCActiveAnimation.h"
+#include "cc/CCLayerAnimationController.h"
+#include "cc/CCLayerAnimationDelegate.h"
+#include "cc/CCLayerImpl.h"
+#include "cc/CCLayerTreeHostImpl.h"
+#include "cc/CCScopedThreadProxy.h"
+#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCTextureUpdater.h"
+#include "cc/CCThreadTask.h"
+#include "cc/CCTimingFunction.h"
+#include "platform/WebThread.h"
+#include <gmock/gmock.h>
+#include <public/Platform.h>
+#include <public/WebFilterOperation.h>
+#include <public/WebFilterOperations.h>
+#include <wtf/Locker.h>
+#include <wtf/MainThread.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/ThreadingPrimitives.h>
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace WTF;
+
+namespace WebKitTests {
+
+PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> CompositorFakeWebGraphicsContext3DWithTextureTracking::create(Attributes attrs)
+{
+ return adoptPtr(new CompositorFakeWebGraphicsContext3DWithTextureTracking(attrs));
+}
+
+WebGLId CompositorFakeWebGraphicsContext3DWithTextureTracking::createTexture()
+{
+ WebGLId texture = m_textures.size() + 1;
+ m_textures.append(texture);
+ return texture;
+}
+
+void CompositorFakeWebGraphicsContext3DWithTextureTracking::deleteTexture(WebGLId texture)
+{
+ for (size_t i = 0; i < m_textures.size(); i++) {
+ if (m_textures[i] == texture) {
+ m_textures.remove(i);
+ break;
+ }
+ }
+}
+
+void CompositorFakeWebGraphicsContext3DWithTextureTracking::bindTexture(WGC3Denum /* target */, WebGLId texture)
+{
+ m_usedTextures.add(texture);
+}
+
+int CompositorFakeWebGraphicsContext3DWithTextureTracking::numTextures() const { return static_cast<int>(m_textures.size()); }
+int CompositorFakeWebGraphicsContext3DWithTextureTracking::texture(int i) const { return m_textures[i]; }
+void CompositorFakeWebGraphicsContext3DWithTextureTracking::resetTextures() { m_textures.clear(); }
+
+int CompositorFakeWebGraphicsContext3DWithTextureTracking::numUsedTextures() const { return static_cast<int>(m_usedTextures.size()); }
+bool CompositorFakeWebGraphicsContext3DWithTextureTracking::usedTexture(int texture) const { return m_usedTextures.find(texture) != m_usedTextures.end(); }
+void CompositorFakeWebGraphicsContext3DWithTextureTracking::resetUsedTextures() { m_usedTextures.clear(); }
+
+CompositorFakeWebGraphicsContext3DWithTextureTracking::CompositorFakeWebGraphicsContext3DWithTextureTracking(Attributes attrs) : CompositorFakeWebGraphicsContext3D(attrs)
+{
+}
+
+PassRefPtr<GraphicsContext3D> TestHooks::createContext()
+{
+ GraphicsContext3D::Attributes attrs;
+ WebGraphicsContext3D::Attributes webAttrs;
+ webAttrs.alpha = attrs.alpha;
+
+ OwnPtr<WebGraphicsContext3D> webContext = CompositorFakeWebGraphicsContext3DWithTextureTracking::create(webAttrs);
+ return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow);
+}
+
+PassOwnPtr<MockLayerTreeHostImpl> MockLayerTreeHostImpl::create(TestHooks* testHooks, const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
+{
+ return adoptPtr(new MockLayerTreeHostImpl(testHooks, settings, client));
+}
+
+void MockLayerTreeHostImpl::beginCommit()
+{
+ CCLayerTreeHostImpl::beginCommit();
+ m_testHooks->beginCommitOnCCThread(this);
+}
+
+void MockLayerTreeHostImpl::commitComplete()
+{
+ CCLayerTreeHostImpl::commitComplete();
+ m_testHooks->commitCompleteOnCCThread(this);
+}
+
+bool MockLayerTreeHostImpl::prepareToDraw(FrameData& frame)
+{
+ bool result = CCLayerTreeHostImpl::prepareToDraw(frame);
+ if (!m_testHooks->prepareToDrawOnCCThread(this))
+ result = false;
+ return result;
+}
+
+void MockLayerTreeHostImpl::drawLayers(const FrameData& frame)
+{
+ CCLayerTreeHostImpl::drawLayers(frame);
+ m_testHooks->drawLayersOnCCThread(this);
+}
+
+void MockLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTime)
+{
+ m_testHooks->willAnimateLayers(this, monotonicTime);
+ CCLayerTreeHostImpl::animateLayers(monotonicTime, wallClockTime);
+ m_testHooks->animateLayers(this, monotonicTime);
+}
+
+double MockLayerTreeHostImpl::lowFrequencyAnimationInterval() const
+{
+ return 1.0 / 60;
+}
+
+MockLayerTreeHostImpl::MockLayerTreeHostImpl(TestHooks* testHooks, const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
+ : CCLayerTreeHostImpl(settings, client)
+ , m_testHooks(testHooks)
+{
+}
+
+// Adapts CCLayerTreeHost for test. Injects MockLayerTreeHostImpl.
+class MockLayerTreeHost : public WebCore::CCLayerTreeHost {
+public:
+ static PassOwnPtr<MockLayerTreeHost> create(TestHooks* testHooks, WebCore::CCLayerTreeHostClient* client, PassRefPtr<WebCore::LayerChromium> rootLayer, const WebCore::CCLayerTreeSettings& settings)
+ {
+ OwnPtr<MockLayerTreeHost> layerTreeHost(adoptPtr(new MockLayerTreeHost(testHooks, client, settings)));
+ bool success = layerTreeHost->initialize();
+ EXPECT_TRUE(success);
+ layerTreeHost->setRootLayer(rootLayer);
+
+ // LayerTreeHostImpl won't draw if it has 1x1 viewport.
+ layerTreeHost->setViewportSize(IntSize(1, 1));
+
+ layerTreeHost->rootLayer()->setLayerAnimationDelegate(testHooks);
+
+ return layerTreeHost.release();
+ }
+
+ virtual PassOwnPtr<WebCore::CCLayerTreeHostImpl> createLayerTreeHostImpl(WebCore::CCLayerTreeHostImplClient* client)
+ {
+ return MockLayerTreeHostImpl::create(m_testHooks, settings(), client);
+ }
+
+ virtual void didAddAnimation() OVERRIDE
+ {
+ CCLayerTreeHost::didAddAnimation();
+ m_testHooks->didAddAnimation();
+ }
+
+private:
+ MockLayerTreeHost(TestHooks* testHooks, WebCore::CCLayerTreeHostClient* client, const WebCore::CCLayerTreeSettings& settings)
+ : CCLayerTreeHost(client, settings)
+ , m_testHooks(testHooks)
+ {
+ }
+
+ TestHooks* m_testHooks;
+};
+
+// Implementation of CCLayerTreeHost callback interface.
+class MockLayerTreeHostClient : public MockCCLayerTreeHostClient {
+public:
+ static PassOwnPtr<MockLayerTreeHostClient> create(TestHooks* testHooks)
+ {
+ return adoptPtr(new MockLayerTreeHostClient(testHooks));
+ }
+
+ virtual void willBeginFrame() OVERRIDE
+ {
+ }
+
+ virtual void didBeginFrame() OVERRIDE
+ {
+ }
+
+ virtual void updateAnimations(double monotonicTime) OVERRIDE
+ {
+ m_testHooks->updateAnimations(monotonicTime);
+ }
+
+ virtual void layout() OVERRIDE
+ {
+ m_testHooks->layout();
+ }
+
+ virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale) OVERRIDE
+ {
+ m_testHooks->applyScrollAndScale(scrollDelta, scale);
+ }
+
+ virtual PassRefPtr<GraphicsContext3D> createContext3D() OVERRIDE
+ {
+ return m_testHooks->createContext();
+ }
+
+ virtual void willCommit() OVERRIDE
+ {
+ }
+
+ virtual void didCommit() OVERRIDE
+ {
+ m_testHooks->didCommit();
+ }
+
+ virtual void didCommitAndDrawFrame() OVERRIDE
+ {
+ m_testHooks->didCommitAndDrawFrame();
+ }
+
+ virtual void didCompleteSwapBuffers() OVERRIDE
+ {
+ }
+
+ virtual void didRecreateContext(bool succeeded) OVERRIDE
+ {
+ m_testHooks->didRecreateContext(succeeded);
+ }
+
+ virtual void scheduleComposite() OVERRIDE
+ {
+ m_testHooks->scheduleComposite();
+ }
+
+private:
+ explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
+
+ TestHooks* m_testHooks;
+};
+
+class TimeoutTask : public WebThread::Task {
+public:
+ explicit TimeoutTask(CCThreadedTest* test)
+ : m_test(test)
+ {
+ }
+
+ void clearTest()
+ {
+ m_test = 0;
+ }
+
+ virtual ~TimeoutTask()
+ {
+ if (m_test)
+ m_test->clearTimeout();
+ }
+
+ virtual void run()
+ {
+ if (m_test)
+ m_test->timeout();
+ }
+
+private:
+ CCThreadedTest* m_test;
+};
+
+class BeginTask : public WebThread::Task {
+public:
+ explicit BeginTask(CCThreadedTest* test)
+ : m_test(test)
+ {
+ }
+
+ virtual ~BeginTask() { }
+ virtual void run()
+ {
+ m_test->doBeginTest();
+ }
+private:
+ CCThreadedTest* m_test;
+};
+
+class EndTestTask : public WebThread::Task {
+public:
+ explicit EndTestTask(CCThreadedTest* test)
+ : m_test(test)
+ {
+ }
+
+ virtual ~EndTestTask()
+ {
+ if (m_test)
+ m_test->clearEndTestTask();
+ }
+
+ void clearTest()
+ {
+ m_test = 0;
+ }
+
+ virtual void run()
+ {
+ if (m_test)
+ m_test->endTest();
+ }
+
+private:
+ CCThreadedTest* m_test;
+};
+
+CCThreadedTest::CCThreadedTest()
+ : m_beginning(false)
+ , m_endWhenBeginReturns(false)
+ , m_timedOut(false)
+ , m_finished(false)
+ , m_scheduled(false)
+ , m_started(false)
+ , m_endTestTask(0)
+{ }
+
+void CCThreadedTest::endTest()
+{
+ m_finished = true;
+
+ // If we are called from the CCThread, re-call endTest on the main thread.
+ if (!isMainThread())
+ m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadedTest::endTest));
+ else {
+ // For the case where we endTest during beginTest(), set a flag to indicate that
+ // the test should end the second beginTest regains control.
+ if (m_beginning)
+ m_endWhenBeginReturns = true;
+ else
+ onEndTest(static_cast<void*>(this));
+ }
+}
+
+void CCThreadedTest::endTestAfterDelay(int delayMilliseconds)
+{
+ // If we are called from the CCThread, re-call endTest on the main thread.
+ if (!isMainThread())
+ m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadedTest::endTestAfterDelay, delayMilliseconds));
+ else {
+ m_endTestTask = new EndTestTask(this);
+ WebKit::Platform::current()->currentThread()->postDelayedTask(m_endTestTask, delayMilliseconds);
+ }
+}
+
+void CCThreadedTest::postSetNeedsAnimateToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchSetNeedsAnimate, this);
+}
+
+void CCThreadedTest::postAddAnimationToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchAddAnimation, this);
+}
+
+void CCThreadedTest::postAddInstantAnimationToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchAddInstantAnimation, this);
+}
+
+void CCThreadedTest::postSetNeedsCommitToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchSetNeedsCommit, this);
+}
+
+void CCThreadedTest::postAcquireLayerTextures()
+{
+ callOnMainThread(CCThreadedTest::dispatchAcquireLayerTextures, this);
+}
+
+void CCThreadedTest::postSetNeedsRedrawToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchSetNeedsRedraw, this);
+}
+
+void CCThreadedTest::postSetNeedsAnimateAndCommitToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchSetNeedsAnimateAndCommit, this);
+}
+
+void CCThreadedTest::postSetVisibleToMainThread(bool visible)
+{
+ callOnMainThread(visible ? CCThreadedTest::dispatchSetVisible : CCThreadedTest::dispatchSetInvisible, this);
+}
+
+void CCThreadedTest::postDidAddAnimationToMainThread()
+{
+ callOnMainThread(CCThreadedTest::dispatchDidAddAnimation, this);
+}
+
+void CCThreadedTest::doBeginTest()
+{
+ ASSERT(isMainThread());
+ m_client = MockLayerTreeHostClient::create(this);
+
+ RefPtr<LayerChromium> rootLayer = LayerChromium::create();
+ m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings);
+ ASSERT_TRUE(m_layerTreeHost);
+ rootLayer->setLayerTreeHost(m_layerTreeHost.get());
+ m_layerTreeHost->setSurfaceReady();
+
+ m_started = true;
+ m_beginning = true;
+ beginTest();
+ m_beginning = false;
+ if (m_endWhenBeginReturns)
+ onEndTest(static_cast<void*>(this));
+}
+
+void CCThreadedTest::timeout()
+{
+ m_timedOut = true;
+ endTest();
+}
+
+void CCThreadedTest::scheduleComposite()
+{
+ if (!m_started || m_scheduled || m_finished)
+ return;
+ m_scheduled = true;
+ callOnMainThread(&CCThreadedTest::dispatchComposite, this);
+}
+
+void CCThreadedTest::onEndTest(void* self)
+{
+ ASSERT(isMainThread());
+ WebKit::Platform::current()->currentThread()->exitRunLoop();
+}
+
+void CCThreadedTest::dispatchSetNeedsAnimate(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->setNeedsAnimate();
+}
+
+void CCThreadedTest::dispatchAddInstantAnimation(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
+ addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 0, 0, 0.5, false);
+}
+
+void CCThreadedTest::dispatchAddAnimation(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
+ addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 10, 0, 0.5, true);
+}
+
+void CCThreadedTest::dispatchSetNeedsAnimateAndCommit(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost) {
+ test->m_layerTreeHost->setNeedsAnimate();
+ test->m_layerTreeHost->setNeedsCommit();
+ }
+}
+
+void CCThreadedTest::dispatchSetNeedsCommit(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT_TRUE(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->setNeedsCommit();
+}
+
+void CCThreadedTest::dispatchAcquireLayerTextures(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT_TRUE(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->acquireLayerTextures();
+}
+
+void CCThreadedTest::dispatchSetNeedsRedraw(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT_TRUE(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->setNeedsRedraw();
+}
+
+void CCThreadedTest::dispatchSetVisible(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->setVisible(true);
+}
+
+void CCThreadedTest::dispatchSetInvisible(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->setVisible(false);
+}
+
+void CCThreadedTest::dispatchComposite(void* self)
+{
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(isMainThread());
+ ASSERT(test);
+ test->m_scheduled = false;
+ if (test->m_layerTreeHost && !test->m_finished)
+ test->m_layerTreeHost->composite();
+}
+
+void CCThreadedTest::dispatchDidAddAnimation(void* self)
+{
+ ASSERT(isMainThread());
+
+ CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
+ ASSERT(test);
+ if (test->m_finished)
+ return;
+
+ if (test->m_layerTreeHost)
+ test->m_layerTreeHost->didAddAnimation();
+}
+
+void CCThreadedTest::runTest(bool threaded)
+{
+ // For these tests, we will enable threaded animations.
+ WebCompositor::setAcceleratedAnimationEnabled(true);
+
+ if (threaded) {
+ m_webThread = adoptPtr(WebKit::Platform::current()->createThread("CCThreadedTest"));
+ WebCompositor::initialize(m_webThread.get());
+ } else
+ WebCompositor::initialize(0);
+
+ ASSERT(CCProxy::isMainThread());
+ m_mainThreadProxy = CCScopedThreadProxy::create(CCProxy::mainThread());
+
+ m_beginTask = new BeginTask(this);
+ WebKit::Platform::current()->currentThread()->postDelayedTask(m_beginTask, 0); // postDelayedTask takes ownership of the task
+ m_timeoutTask = new TimeoutTask(this);
+ WebKit::Platform::current()->currentThread()->postDelayedTask(m_timeoutTask, 5000);
+ WebKit::Platform::current()->currentThread()->enterRunLoop();
+
+ if (m_layerTreeHost && m_layerTreeHost->rootLayer())
+ m_layerTreeHost->rootLayer()->setLayerTreeHost(0);
+ m_layerTreeHost.clear();
+
+ if (m_timeoutTask)
+ m_timeoutTask->clearTest();
+
+ if (m_endTestTask)
+ m_endTestTask->clearTest();
+
+ ASSERT_FALSE(m_layerTreeHost.get());
+ m_client.clear();
+ if (m_timedOut) {
+ FAIL() << "Test timed out";
+ WebCompositor::shutdown();
+ return;
+ }
+ afterTest();
+ WebCompositor::shutdown();
+}
+
+} // namespace WebKitTests
diff --git a/Source/WebKit/chromium/tests/CCThreadedTest.h b/Source/WebKit/chromium/tests/CCThreadedTest.h
new file mode 100644
index 000000000..c0ca44fee
--- /dev/null
+++ b/Source/WebKit/chromium/tests/CCThreadedTest.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011 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 CCThreadedTest_h
+#define CCThreadedTest_h
+
+#include "CompositorFakeWebGraphicsContext3D.h"
+#include "cc/CCLayerAnimationDelegate.h"
+#include "cc/CCLayerTreeHost.h"
+#include "cc/CCLayerTreeHostImpl.h"
+#include "cc/CCScopedThreadProxy.h"
+#include <gtest/gtest.h>
+
+namespace WebCore {
+class CCLayerImpl;
+class CCLayerTreeHost;
+class CCLayerTreeHostClient;
+class CCLayerTreeHostImpl;
+class GraphicsContext3D;
+}
+
+namespace WebKit {
+class WebThread;
+}
+
+namespace WebKitTests {
+
+// Used by test stubs to notify the test when something interesting happens.
+class TestHooks : public WebCore::CCLayerAnimationDelegate {
+public:
+ virtual void beginCommitOnCCThread(WebCore::CCLayerTreeHostImpl*) { }
+ virtual void commitCompleteOnCCThread(WebCore::CCLayerTreeHostImpl*) { }
+ virtual bool prepareToDrawOnCCThread(WebCore::CCLayerTreeHostImpl*) { return true; }
+ virtual void drawLayersOnCCThread(WebCore::CCLayerTreeHostImpl*) { }
+ virtual void animateLayers(WebCore::CCLayerTreeHostImpl*, double monotonicTime) { }
+ virtual void willAnimateLayers(WebCore::CCLayerTreeHostImpl*, double monotonicTime) { }
+ virtual void applyScrollAndScale(const WebCore::IntSize&, float) { }
+ virtual void updateAnimations(double monotonicTime) { }
+ virtual void layout() { }
+ virtual void didRecreateContext(bool succeeded) { }
+ virtual void didAddAnimation() { }
+ virtual void didCommit() { }
+ virtual void didCommitAndDrawFrame() { }
+ virtual void scheduleComposite() { }
+
+ // Implementation of CCLayerAnimationDelegate
+ virtual void notifyAnimationStarted(double time) { }
+ virtual void notifyAnimationFinished(double time) { }
+
+ virtual PassRefPtr<WebCore::GraphicsContext3D> createContext();
+};
+
+class TimeoutTask;
+class BeginTask;
+class EndTestTask;
+
+class MockCCLayerTreeHostClient : public WebCore::CCLayerTreeHostClient {
+};
+
+// The CCThreadedTests runs with the main loop running. It instantiates a single MockLayerTreeHost and associated
+// MockLayerTreeHostImpl/MockLayerTreeHostClient.
+//
+// beginTest() is called once the main message loop is running and the layer tree host is initialized.
+//
+// Key stages of the drawing loop, e.g. drawing or commiting, redirect to CCThreadedTest methods of similar names.
+// To track the commit process, override these functions.
+//
+// The test continues until someone calls endTest. endTest can be called on any thread, but be aware that
+// ending the test is an asynchronous process.
+class CCThreadedTest : public testing::Test, public TestHooks {
+public:
+ virtual void afterTest() = 0;
+ virtual void beginTest() = 0;
+
+ void endTest();
+ void endTestAfterDelay(int delayMilliseconds);
+
+ void postSetNeedsAnimateToMainThread();
+ void postAddAnimationToMainThread();
+ void postAddInstantAnimationToMainThread();
+ void postSetNeedsCommitToMainThread();
+ void postAcquireLayerTextures();
+ void postSetNeedsRedrawToMainThread();
+ void postSetNeedsAnimateAndCommitToMainThread();
+ void postSetVisibleToMainThread(bool visible);
+ void postDidAddAnimationToMainThread();
+
+ void doBeginTest();
+ void timeout();
+
+ void clearTimeout() { m_timeoutTask = 0; }
+ void clearEndTestTask() { m_endTestTask = 0; }
+
+ WebCore::CCLayerTreeHost* layerTreeHost() { return m_layerTreeHost.get(); }
+
+protected:
+ CCThreadedTest();
+
+ virtual void scheduleComposite();
+
+ static void onEndTest(void* self);
+
+ static void dispatchSetNeedsAnimate(void* self);
+ static void dispatchAddInstantAnimation(void* self);
+ static void dispatchAddAnimation(void* self);
+ static void dispatchSetNeedsAnimateAndCommit(void* self);
+ static void dispatchSetNeedsCommit(void* self);
+ static void dispatchAcquireLayerTextures(void* self);
+ static void dispatchSetNeedsRedraw(void* self);
+ static void dispatchSetVisible(void* self);
+ static void dispatchSetInvisible(void* self);
+ static void dispatchComposite(void* self);
+ static void dispatchDidAddAnimation(void* self);
+
+ virtual void runTest(bool threaded);
+
+ WebCore::CCLayerTreeSettings m_settings;
+ OwnPtr<MockCCLayerTreeHostClient> m_client;
+ OwnPtr<WebCore::CCLayerTreeHost> m_layerTreeHost;
+
+private:
+ bool m_beginning;
+ bool m_endWhenBeginReturns;
+ bool m_timedOut;
+ bool m_finished;
+ bool m_scheduled;
+ bool m_started;
+
+ OwnPtr<WebKit::WebThread> m_webThread;
+ RefPtr<WebCore::CCScopedThreadProxy> m_mainThreadProxy;
+ TimeoutTask* m_timeoutTask;
+ BeginTask* m_beginTask;
+ EndTestTask* m_endTestTask;
+};
+
+class CCThreadedTestThreadOnly : public CCThreadedTest {
+public:
+ void runTestThreaded()
+ {
+ CCThreadedTest::runTest(true);
+ }
+};
+
+// Adapts CCLayerTreeHostImpl for test. Runs real code, then invokes test hooks.
+class MockLayerTreeHostImpl : public WebCore::CCLayerTreeHostImpl {
+public:
+ static PassOwnPtr<MockLayerTreeHostImpl> create(TestHooks*, const WebCore::CCLayerTreeSettings&, WebCore::CCLayerTreeHostImplClient*);
+
+ virtual void beginCommit();
+ virtual void commitComplete();
+ virtual bool prepareToDraw(FrameData&);
+ virtual void drawLayers(const FrameData&);
+
+ // Make these public.
+ typedef Vector<WebCore::CCLayerImpl*> CCLayerList;
+ using CCLayerTreeHostImpl::calculateRenderSurfaceLayerList;
+
+protected:
+ virtual void animateLayers(double monotonicTime, double wallClockTime);
+ virtual double lowFrequencyAnimationInterval() const;
+
+private:
+ MockLayerTreeHostImpl(TestHooks*, const WebCore::CCLayerTreeSettings&, WebCore::CCLayerTreeHostImplClient*);
+
+ TestHooks* m_testHooks;
+};
+
+class CompositorFakeWebGraphicsContext3DWithTextureTracking : public WebKit::CompositorFakeWebGraphicsContext3D {
+public:
+ static PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> create(Attributes);
+
+ virtual WebKit::WebGLId createTexture();
+
+ virtual void deleteTexture(WebKit::WebGLId texture);
+
+ virtual void bindTexture(WebKit::WGC3Denum target, WebKit::WebGLId texture);
+
+ int numTextures() const;
+ int texture(int texture) const;
+ void resetTextures();
+
+ int numUsedTextures() const;
+ bool usedTexture(int texture) const;
+ void resetUsedTextures();
+
+private:
+ explicit CompositorFakeWebGraphicsContext3DWithTextureTracking(Attributes attrs);
+
+ Vector<WebKit::WebGLId> m_textures;
+ HashSet<WebKit::WebGLId, DefaultHash<WebKit::WebGLId>::Hash, WTF::UnsignedWithZeroKeyHashTraits<WebKit::WebGLId> > m_usedTextures;
+};
+
+} // namespace WebKitTests
+
+#define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
+ TEST_F(TEST_FIXTURE_NAME, runSingleThread) \
+ { \
+ runTest(false); \
+ } \
+ TEST_F(TEST_FIXTURE_NAME, runMultiThread) \
+ { \
+ runTest(true); \
+ }
+
+#endif // CCThreadedTest_h
diff --git a/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.cpp b/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.cpp
index 46d11a96e..7484b70f3 100644
--- a/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.cpp
+++ b/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.cpp
@@ -40,7 +40,7 @@ FakeLayerTextureUpdater::Texture::~Texture()
{
}
-void FakeLayerTextureUpdater::Texture::updateRect(GraphicsContext3D*, TextureAllocator* allocator, const IntRect&, const IntRect&)
+void FakeLayerTextureUpdater::Texture::updateRect(CCGraphicsContext*, TextureAllocator* allocator, const IntRect&, const IntRect&)
{
if (allocator)
texture()->allocate(allocator);
@@ -63,7 +63,7 @@ FakeLayerTextureUpdater::~FakeLayerTextureUpdater()
{
}
-void FakeLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect& resultingOpaqueRect)
+void FakeLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize&, float, IntRect& resultingOpaqueRect)
{
m_prepareCount++;
m_lastUpdateRect = contentRect;
diff --git a/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.h b/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.h
index 4eb875b1e..68fef6420 100644
--- a/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.h
+++ b/Source/WebKit/chromium/tests/CCTiledLayerTestCommon.h
@@ -25,7 +25,6 @@
#ifndef CCTiledLayerTestCommon_h
#define CCTiledLayerTestCommon_h
-#include "GraphicsContext3D.h"
#include "IntRect.h"
#include "IntSize.h"
#include "LayerTextureUpdater.h"
@@ -34,6 +33,7 @@
#include "TextureManager.h"
#include "TextureUploader.h"
#include "TiledLayerChromium.h"
+#include "cc/CCGraphicsContext.h"
#include "cc/CCTextureUpdater.h"
#include "cc/CCTiledLayerImpl.h"
@@ -48,8 +48,8 @@ public:
Texture(FakeLayerTextureUpdater*, PassOwnPtr<WebCore::ManagedTexture>);
virtual ~Texture();
- virtual void updateRect(WebCore::GraphicsContext3D*, WebCore::TextureAllocator* , const WebCore::IntRect&, const WebCore::IntRect&);
- virtual void prepareRect(const WebCore::IntRect&);
+ virtual void updateRect(WebCore::CCGraphicsContext*, WebCore::TextureAllocator* , const WebCore::IntRect&, const WebCore::IntRect&) OVERRIDE;
+ virtual void prepareRect(const WebCore::IntRect&) OVERRIDE;
private:
FakeLayerTextureUpdater* m_layer;
@@ -58,10 +58,10 @@ public:
FakeLayerTextureUpdater();
virtual ~FakeLayerTextureUpdater();
- virtual PassOwnPtr<WebCore::LayerTextureUpdater::Texture> createTexture(WebCore::TextureManager*);
- virtual SampledTexelFormat sampledTexelFormat(GC3Denum) { return SampledTexelFormatRGBA; }
+ virtual PassOwnPtr<WebCore::LayerTextureUpdater::Texture> createTexture(WebCore::TextureManager*) OVERRIDE;
+ virtual SampledTexelFormat sampledTexelFormat(GC3Denum) OVERRIDE { return SampledTexelFormatRGBA; }
- virtual void prepareToUpdate(const WebCore::IntRect& contentRect, const WebCore::IntSize&, int, float, WebCore::IntRect& resultingOpaqueRect);
+ virtual void prepareToUpdate(const WebCore::IntRect& contentRect, const WebCore::IntSize&, float, WebCore::IntRect& resultingOpaqueRect) OVERRIDE;
// Sets the rect to invalidate during the next call to prepareToUpdate(). After the next
// call to prepareToUpdate() the rect is reset.
void setRectToInvalidate(const WebCore::IntRect&, FakeTiledLayerChromium*);
@@ -156,7 +156,8 @@ public:
class FakeTextureCopier : public WebCore::TextureCopier {
public:
- virtual void copyTexture(WebCore::GraphicsContext3D*, unsigned, unsigned, const WebCore::IntSize&) { }
+ virtual void copyTexture(WebCore::CCGraphicsContext*, unsigned, unsigned, const WebCore::IntSize&) { }
+ virtual void copyToTexture(WebCore::CCGraphicsContext*, const void*, unsigned, const WebCore::IntSize&, GC3Denum) { }
};
class FakeTextureUploader : public WebCore::TextureUploader {
@@ -164,7 +165,7 @@ public:
virtual bool isBusy() { return false; }
virtual void beginUploads() { }
virtual void endUploads() { }
- virtual void uploadTexture(WebCore::GraphicsContext3D* context, WebCore::LayerTextureUpdater::Texture* texture, WebCore::TextureAllocator* allocator, const WebCore::IntRect sourceRect, const WebCore::IntRect destRect) { texture->updateRect(context, allocator, sourceRect, destRect); }
+ virtual void uploadTexture(WebCore::CCGraphicsContext* context, WebCore::LayerTextureUpdater::Texture* texture, WebCore::TextureAllocator* allocator, const WebCore::IntRect sourceRect, const WebCore::IntRect destRect) { texture->updateRect(context, allocator, sourceRect, destRect); }
};
}
diff --git a/Source/WebKit/chromium/tests/Canvas2DLayerBridgeTest.cpp b/Source/WebKit/chromium/tests/Canvas2DLayerBridgeTest.cpp
new file mode 100644
index 000000000..bacf873fc
--- /dev/null
+++ b/Source/WebKit/chromium/tests/Canvas2DLayerBridgeTest.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 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 "Canvas2DLayerBridge.h"
+
+#include "FakeWebGraphicsContext3D.h"
+#include "GraphicsContext3DPrivate.h"
+#include "ImageBuffer.h"
+#include "LayerChromium.h"
+#include "TextureManager.h"
+#include "WebCompositor.h"
+#include "WebKit.h"
+#include "cc/CCGraphicsContext.h"
+#include "cc/CCTextureUpdater.h"
+#include "platform/WebKitPlatformSupport.h"
+#include "platform/WebThread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wtf/RefPtr.h>
+
+using namespace WebCore;
+using namespace WebKit;
+using testing::InSequence;
+using testing::Return;
+using testing::Test;
+
+namespace {
+
+class MockCanvasContext : public FakeWebGraphicsContext3D {
+public:
+ MOCK_METHOD0(flush, void(void));
+ MOCK_METHOD0(createTexture, unsigned(void));
+ MOCK_METHOD1(deleteTexture, void(unsigned));
+
+ virtual GrGLInterface* onCreateGrGLInterface() OVERRIDE { return 0; }
+};
+
+class MockWebTextureUpdater : public WebTextureUpdater {
+public:
+ MOCK_METHOD3(appendCopy, void(unsigned, unsigned, WebSize));
+};
+
+} // namespace
+
+enum ThreadMode {
+ SingleThreaded, Threaded
+};
+
+class Canvas2DLayerBridgeTest : public Test {
+protected:
+ void fullLifecycleTest(ThreadMode threadMode, DeferralMode deferralMode)
+ {
+ GraphicsContext3D::Attributes attrs;
+
+ RefPtr<GraphicsContext3D> mainContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ RefPtr<CCGraphicsContext> ccMainContext = CCGraphicsContext::create3D(mainContext);
+ RefPtr<GraphicsContext3D> implContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ RefPtr<CCGraphicsContext> ccImplContext = CCGraphicsContext::create3D(implContext);
+
+ MockCanvasContext& mainMock = *static_cast<MockCanvasContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(mainContext.get()));
+ MockCanvasContext& implMock = *static_cast<MockCanvasContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(implContext.get()));
+
+ MockWebTextureUpdater updater;
+
+ const IntSize size(300, 150);
+
+ OwnPtr<WebThread> thread;
+ if (threadMode == Threaded)
+ thread = adoptPtr(WebKit::Platform::current()->createThread("Canvas2DLayerBridgeTest"));
+ WebCompositor::initialize(thread.get());
+
+ WebGLId backTextureId = 1;
+ WebGLId frontTextureId = 1;
+
+ // Threaded and non deferred canvases are double buffered.
+ if (threadMode == Threaded && deferralMode == NonDeferred) {
+ frontTextureId = 2;
+ // Create texture (on the main thread) and do the copy (on the impl thread).
+ EXPECT_CALL(mainMock, createTexture()).WillOnce(Return(frontTextureId));
+ }
+
+ OwnPtr<Canvas2DLayerBridge> bridge = Canvas2DLayerBridge::create(mainContext.get(), size, deferralMode, backTextureId);
+
+ ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+
+ EXPECT_CALL(mainMock, flush());
+ if (threadMode == Threaded && deferralMode == NonDeferred)
+ EXPECT_CALL(updater, appendCopy(backTextureId, frontTextureId, WebSize(300, 150)));
+ EXPECT_EQ(frontTextureId, bridge->prepareTexture(updater));
+ ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+ ::testing::Mock::VerifyAndClearExpectations(&updater);
+
+ if (threadMode == Threaded && deferralMode == NonDeferred) {
+ EXPECT_CALL(mainMock, deleteTexture(frontTextureId));
+ EXPECT_CALL(mainMock, flush());
+ }
+ bridge.clear();
+ ::testing::Mock::VerifyAndClearExpectations(&implMock);
+
+ WebCompositor::shutdown();
+ }
+};
+
+namespace {
+
+TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreadedDeferred)
+{
+ fullLifecycleTest(SingleThreaded, NonDeferred);
+}
+
+TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreadedNonDeferred)
+{
+ fullLifecycleTest(SingleThreaded, Deferred);
+}
+
+TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleThreadedNonDeferred)
+{
+ fullLifecycleTest(Threaded, NonDeferred);
+}
+
+TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleThreadedDeferred)
+{
+ fullLifecycleTest(Threaded, Deferred);
+}
+
+TEST(Canvas2DLayerBridgeTest2, testClearClient)
+{
+ GraphicsContext3D::Attributes attrs;
+
+ RefPtr<GraphicsContext3D> mainContext = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockCanvasContext()), GraphicsContext3D::RenderDirectlyToHostWindow);
+ OwnPtr<Canvas2DLayerBridge> bridge = Canvas2DLayerBridge::create(mainContext.get(), IntSize(100, 100), Deferred, 1);
+ RefPtr<LayerChromium> layer = bridge->layer();
+ bridge.clear();
+ CCTextureUpdater updater;
+ layer->update(updater, 0);
+}
+
+} // namespace
+
diff --git a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp
deleted file mode 100644
index b42485b71..000000000
--- a/Source/WebKit/chromium/tests/Canvas2DLayerChromiumTest.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Canvas2DLayerChromium.h"
-
-#include "CCSchedulerTestCommon.h"
-#include "FakeCCLayerTreeHostClient.h"
-#include "FakeWebGraphicsContext3D.h"
-#include "GraphicsContext3DPrivate.h"
-#include "Region.h"
-#include "TextureCopier.h"
-#include "TextureManager.h"
-#include "WebCompositor.h"
-#include "WebKit.h"
-#include "cc/CCSingleThreadProxy.h"
-#include "cc/CCTextureLayerImpl.h"
-#include "cc/CCTextureUpdater.h"
-#include "platform/WebKitPlatformSupport.h"
-#include "platform/WebThread.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <wtf/RefPtr.h>
-
-using namespace WebCore;
-using namespace WebKit;
-using namespace WebKitTests;
-using testing::InSequence;
-using testing::Return;
-using testing::Test;
-
-namespace {
-
-class FakeCCLayerTreeHost : public CCLayerTreeHost {
-public:
- static PassOwnPtr<FakeCCLayerTreeHost> create()
- {
- OwnPtr<FakeCCLayerTreeHost> host(adoptPtr(new FakeCCLayerTreeHost));
- host->initialize();
- return host.release();
- }
-
-private:
- FakeCCLayerTreeHost()
- : CCLayerTreeHost(&m_client, CCSettings())
- {
- }
-
- FakeCCLayerTreeHostClient m_client;
-};
-
-class MockCanvasContext : public FakeWebGraphicsContext3D {
-public:
- MOCK_METHOD0(flush, void(void));
-};
-
-class MockTextureAllocator : public TextureAllocator {
-public:
- MOCK_METHOD2(createTexture, unsigned(const IntSize&, GC3Denum));
- MOCK_METHOD3(deleteTexture, void(unsigned, const IntSize&, GC3Denum));
-};
-
-class MockTextureCopier : public TextureCopier {
-public:
- MOCK_METHOD4(copyTexture, void(GraphicsContext3D*, unsigned, unsigned, const IntSize&));
-};
-
-class MockTextureUploader : public TextureUploader {
-public:
- MOCK_METHOD0(isBusy, bool());
- MOCK_METHOD0(beginUploads, void());
- MOCK_METHOD0(endUploads, void());
- MOCK_METHOD5(uploadTexture, void(GraphicsContext3D*, LayerTextureUpdater::Texture*, TextureAllocator*, const IntRect, const IntRect));
-};
-
-} // namespace
-
-class Canvas2DLayerChromiumTest : public Test {
-protected:
- void fullLifecycleTest(bool threaded, bool deferred)
- {
- GraphicsContext3D::Attributes attrs;
-
- 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()));
-
- MockTextureAllocator allocatorMock;
- MockTextureCopier copierMock;
- MockTextureUploader uploaderMock;
- CCTextureUpdater updater;
-
- const IntSize size(300, 150);
-
- OwnPtr<WebThread> thread;
- if (threaded)
- thread = adoptPtr(WebKit::Platform::current()->createThread("Canvas2DLayerChromiumTest"));
- WebCompositor::initialize(thread.get());
-
- OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
- // Force an update, so that we get a valid TextureManager.
- layerTreeHost->updateLayers(updater);
-
- const WebGLId backTextureId = 1;
- const WebGLId frontTextureId = 2;
- {
- InSequence sequence;
-
- // Paint canvas contents on the main thread.
- EXPECT_CALL(mainMock, flush());
-
- // Note that the canvas backing texture is doublebuffered only when using the threaded
- // compositor and not using deferred canvas rendering
- if (threaded && !deferred) {
- // Create texture and do the copy (on the impl thread).
- EXPECT_CALL(allocatorMock, createTexture(size, GraphicsContext3D::RGBA))
- .WillOnce(Return(frontTextureId));
- EXPECT_CALL(copierMock, copyTexture(implContext.get(), backTextureId, frontTextureId, size));
- EXPECT_CALL(implMock, flush());
-
- // Teardown TextureManager.
- EXPECT_CALL(allocatorMock, deleteTexture(frontTextureId, size, GraphicsContext3D::RGBA));
- }
- }
-
- RefPtr<Canvas2DLayerChromium> canvas = Canvas2DLayerChromium::create(mainContext.get(), size, deferred ? Deferred : NonDeferred);
- canvas->setIsDrawable(true);
- canvas->setLayerTreeHost(layerTreeHost.get());
- canvas->setBounds(IntSize(600, 300));
- canvas->setTextureId(backTextureId);
-
- canvas->setNeedsDisplay();
- EXPECT_TRUE(canvas->needsDisplay());
- canvas->update(updater, 0);
- EXPECT_FALSE(canvas->needsDisplay());
- {
- DebugScopedSetImplThread scopedImplThread;
-
- OwnPtr<CCLayerImpl> layerImpl = canvas->createCCLayerImpl();
- EXPECT_EQ(0u, static_cast<CCTextureLayerImpl*>(layerImpl.get())->textureId());
-
- updater.update(implContext.get(), &allocatorMock, &copierMock, &uploaderMock, 1);
- canvas->pushPropertiesTo(layerImpl.get());
-
- if (threaded && !deferred)
- EXPECT_EQ(frontTextureId, static_cast<CCTextureLayerImpl*>(layerImpl.get())->textureId());
- else
- EXPECT_EQ(backTextureId, static_cast<CCTextureLayerImpl*>(layerImpl.get())->textureId());
- }
- canvas.clear();
- layerTreeHost->contentsTextureManager()->reduceMemoryToLimit(0);
- layerTreeHost->contentsTextureManager()->deleteEvictedTextures(&allocatorMock);
- layerTreeHost.clear();
- WebCompositor::shutdown();
- }
-};
-
-namespace {
-
-TEST_F(Canvas2DLayerChromiumTest, testFullLifecycleSingleThread)
-{
- fullLifecycleTest(false, false);
-}
-
-TEST_F(Canvas2DLayerChromiumTest, testFullLifecycleThreaded)
-{
- fullLifecycleTest(true, false);
-}
-
-TEST_F(Canvas2DLayerChromiumTest, testFullLifecycleSingleThreadDeferred)
-{
- fullLifecycleTest(false, true);
-}
-
-TEST_F(Canvas2DLayerChromiumTest, testFullLifecycleThreadedDeferred)
-{
- fullLifecycleTest(true, true);
-}
-
-} // namespace
diff --git a/Source/WebKit/chromium/tests/DecimalTest.cpp b/Source/WebKit/chromium/tests/DecimalTest.cpp
index 18457fdf4..db80f5bfe 100644
--- a/Source/WebKit/chromium/tests/DecimalTest.cpp
+++ b/Source/WebKit/chromium/tests/DecimalTest.cpp
@@ -556,6 +556,32 @@ TEST_F(DecimalTest, FloorSpecialValues)
EXPECT_EQ(Decimal::nan(), Decimal::nan().floor());
}
+TEST_F(DecimalTest, FromDouble)
+{
+ EXPECT_EQ(encode(0, 0, Positive), Decimal::fromDouble(0.0));
+ EXPECT_EQ(encode(0, 0, Negative), Decimal::fromDouble(-0.0));
+ EXPECT_EQ(encode(1, 0, Positive), Decimal::fromDouble(1));
+ EXPECT_EQ(encode(1, 0, Negative), Decimal::fromDouble(-1));
+ EXPECT_EQ(encode(123, 0, Positive), Decimal::fromDouble(123));
+ EXPECT_EQ(encode(123, 0, Negative), Decimal::fromDouble(-123));
+ EXPECT_EQ(encode(1, -1, Positive), Decimal::fromDouble(0.1));
+ EXPECT_EQ(encode(1, -1, Negative), Decimal::fromDouble(-0.1));
+}
+
+TEST_F(DecimalTest, FromDoubleLimits)
+{
+ EXPECT_EQ(encode(UINT64_C(2220446049250313), -31, Positive), Decimal::fromDouble(std::numeric_limits<double>::epsilon()));
+ EXPECT_EQ(encode(UINT64_C(2220446049250313), -31, Negative), Decimal::fromDouble(-std::numeric_limits<double>::epsilon()));
+ EXPECT_EQ(encode(UINT64_C(17976931348623157), 292, Positive), Decimal::fromDouble(std::numeric_limits<double>::max()));
+ EXPECT_EQ(encode(UINT64_C(17976931348623157), 292, Negative), Decimal::fromDouble(-std::numeric_limits<double>::max()));
+ EXPECT_EQ(encode(UINT64_C(22250738585072014), -324, Positive), Decimal::fromDouble(std::numeric_limits<double>::min()));
+ EXPECT_EQ(encode(UINT64_C(22250738585072014), -324, Negative), Decimal::fromDouble(-std::numeric_limits<double>::min()));
+ EXPECT_TRUE(Decimal::fromDouble(std::numeric_limits<double>::infinity()).isInfinity());
+ EXPECT_TRUE(Decimal::fromDouble(-std::numeric_limits<double>::infinity()).isInfinity());
+ EXPECT_TRUE(Decimal::fromDouble(std::numeric_limits<double>::quiet_NaN()).isNaN());
+ EXPECT_TRUE(Decimal::fromDouble(-std::numeric_limits<double>::quiet_NaN()).isNaN());
+}
+
TEST_F(DecimalTest, FromInt32)
{
EXPECT_EQ(encode(0, 0, Positive), Decimal(0));
@@ -750,24 +776,32 @@ TEST_F(DecimalTest, NegateSpecialValues)
TEST_F(DecimalTest, Predicates)
{
EXPECT_TRUE(Decimal::zero(Positive).isFinite());
+ EXPECT_FALSE(Decimal::zero(Positive).isInfinity());
+ EXPECT_FALSE(Decimal::zero(Positive).isNaN());
EXPECT_TRUE(Decimal::zero(Positive).isPositive());
EXPECT_FALSE(Decimal::zero(Positive).isNegative());
EXPECT_FALSE(Decimal::zero(Positive).isSpecial());
EXPECT_TRUE(Decimal::zero(Positive).isZero());
EXPECT_TRUE(Decimal::zero(Negative).isFinite());
+ EXPECT_FALSE(Decimal::zero(Negative).isInfinity());
+ EXPECT_FALSE(Decimal::zero(Negative).isNaN());
EXPECT_FALSE(Decimal::zero(Negative).isPositive());
EXPECT_TRUE(Decimal::zero(Negative).isNegative());
EXPECT_FALSE(Decimal::zero(Negative).isSpecial());
EXPECT_TRUE(Decimal::zero(Negative).isZero());
EXPECT_TRUE(Decimal(123).isFinite());
+ EXPECT_FALSE(Decimal(123).isInfinity());
+ EXPECT_FALSE(Decimal(123).isNaN());
EXPECT_TRUE(Decimal(123).isPositive());
EXPECT_FALSE(Decimal(123).isNegative());
EXPECT_FALSE(Decimal(123).isSpecial());
EXPECT_FALSE(Decimal(123).isZero());
EXPECT_TRUE(Decimal(-123).isFinite());
+ EXPECT_FALSE(Decimal(-123).isInfinity());
+ EXPECT_FALSE(Decimal(-123).isNaN());
EXPECT_FALSE(Decimal(-123).isPositive());
EXPECT_TRUE(Decimal(-123).isNegative());
EXPECT_FALSE(Decimal(-123).isSpecial());
@@ -777,18 +811,24 @@ TEST_F(DecimalTest, Predicates)
TEST_F(DecimalTest, PredicatesSpecialValues)
{
EXPECT_FALSE(Decimal::infinity(Positive).isFinite());
+ EXPECT_TRUE(Decimal::infinity(Positive).isInfinity());
+ EXPECT_FALSE(Decimal::infinity(Positive).isNaN());
EXPECT_TRUE(Decimal::infinity(Positive).isPositive());
EXPECT_FALSE(Decimal::infinity(Positive).isNegative());
EXPECT_TRUE(Decimal::infinity(Positive).isSpecial());
EXPECT_FALSE(Decimal::infinity(Positive).isZero());
EXPECT_FALSE(Decimal::infinity(Negative).isFinite());
+ EXPECT_TRUE(Decimal::infinity(Negative).isInfinity());
+ EXPECT_FALSE(Decimal::infinity(Negative).isNaN());
EXPECT_FALSE(Decimal::infinity(Negative).isPositive());
EXPECT_TRUE(Decimal::infinity(Negative).isNegative());
EXPECT_TRUE(Decimal::infinity(Negative).isSpecial());
EXPECT_FALSE(Decimal::infinity(Negative).isZero());
EXPECT_FALSE(Decimal::nan().isFinite());
+ EXPECT_FALSE(Decimal::nan().isInfinity());
+ EXPECT_TRUE(Decimal::nan().isNaN());
EXPECT_TRUE(Decimal::nan().isSpecial());
EXPECT_FALSE(Decimal::nan().isZero());
}
@@ -940,6 +980,42 @@ TEST_F(DecimalTest, SubtractSpecialValues)
EXPECT_EQ(NaN, MinusInfinity - NaN);
}
+TEST_F(DecimalTest, ToDouble)
+{
+ EXPECT_EQ(0.0, encode(0, 0, Positive).toDouble());
+ EXPECT_EQ(-0.0, encode(0, 0, Negative).toDouble());
+
+ EXPECT_EQ(1.0, encode(1, 0, Positive).toDouble());
+ EXPECT_EQ(-1.0, encode(1, 0, Negative).toDouble());
+
+ EXPECT_EQ(0.1, encode(1, -1, Positive).toDouble());
+ EXPECT_EQ(-0.1, encode(1, -1, Negative).toDouble());
+ EXPECT_EQ(0.3, encode(3, -1, Positive).toDouble());
+ EXPECT_EQ(-0.3, encode(3, -1, Negative).toDouble());
+ EXPECT_EQ(0.6, encode(6, -1, Positive).toDouble());
+ EXPECT_EQ(-0.6, encode(6, -1, Negative).toDouble());
+ EXPECT_EQ(0.7, encode(7, -1, Positive).toDouble());
+ EXPECT_EQ(-0.7, encode(7, -1, Negative).toDouble());
+
+ EXPECT_EQ(0.01, encode(1, -2, Positive).toDouble());
+ EXPECT_EQ(0.001, encode(1, -3, Positive).toDouble());
+ EXPECT_EQ(0.0001, encode(1, -4, Positive).toDouble());
+ EXPECT_EQ(0.00001, encode(1, -5, Positive).toDouble());
+
+ EXPECT_EQ(1e+308, encode(1, 308, Positive).toDouble());
+ EXPECT_EQ(1e-307, encode(1, -307, Positive).toDouble());
+
+ EXPECT_TRUE(isinf(encode(1, 1000, Positive).toDouble()));
+ EXPECT_EQ(0.0, encode(1, -1000, Positive).toDouble());
+}
+
+TEST_F(DecimalTest, ToDoubleSpecialValues)
+{
+ EXPECT_TRUE(isinf(Decimal::infinity(Decimal::Positive).toDouble()));
+ EXPECT_TRUE(isinf(Decimal::infinity(Decimal::Negative).toDouble()));
+ EXPECT_TRUE(isnan(Decimal::nan().toDouble()));
+}
+
TEST_F(DecimalTest, ToString)
{
EXPECT_EQ(String("0"), Decimal::zero(Positive).toString());
diff --git a/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h
index 992509c4f..6ab616d3c 100755
--- a/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h
+++ b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h
@@ -39,7 +39,7 @@ public:
virtual void updateAnimations(double monotonicFrameBeginTime) OVERRIDE { }
virtual void layout() OVERRIDE { }
virtual void applyScrollAndScale(const IntSize& scrollDelta, float pageScale) OVERRIDE { }
- virtual PassRefPtr<GraphicsContext3D> createContext() OVERRIDE
+ virtual PassRefPtr<GraphicsContext3D> createContext3D() OVERRIDE
{
GraphicsContext3D::Attributes attrs;
return createCompositorMockGraphicsContext3D(attrs);
diff --git a/Source/WebKit/chromium/tests/FrameLoaderClientImplTest.cpp b/Source/WebKit/chromium/tests/FrameLoaderClientImplTest.cpp
index 8fc9e42b2..12ca68418 100644
--- a/Source/WebKit/chromium/tests/FrameLoaderClientImplTest.cpp
+++ b/Source/WebKit/chromium/tests/FrameLoaderClientImplTest.cpp
@@ -46,13 +46,12 @@ namespace {
class TestWebFrameClient : public WebFrameClient {
public:
- bool userAgent(const WebURL& url, WebString* userAgent) OVERRIDE
+ WebString userAgentOverride(WebFrame* frame, const WebURL& url) OVERRIDE
{
if (m_userAgentOverride.isEmpty())
- return false;
+ return WebString();
- *userAgent = m_userAgentOverride;
- return true;
+ return m_userAgentOverride;
}
void setUserAgentOverride(const WebString& userAgent)
diff --git a/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp
index b7aa85746..4fdcf4f41 100644
--- a/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp
@@ -27,56 +27,372 @@
#include "GraphicsLayerChromium.h"
#include "CCAnimationTestCommon.h"
+#include "CompositorFakeGraphicsContext3D.h"
+#include "GraphicsContext3D.h"
+#include "GraphicsContext3DPrivate.h"
#include "GraphicsLayer.h"
#include "LayerChromium.h"
+#include "Matrix3DTransformOperation.h"
+#include "RotateTransformOperation.h"
+#include "TranslateTransformOperation.h"
+#include "WebCompositor.h"
+
+#include "cc/CCLayerTreeHost.h"
+#include "cc/CCLayerTreeHostImpl.h"
+#include "cc/CCSingleThreadProxy.h"
+
#include <gtest/gtest.h>
#include <wtf/PassOwnPtr.h>
using namespace WebCore;
+using namespace WebKit;
using namespace WebKitTests;
namespace {
class MockGraphicsLayerClient : public GraphicsLayerClient {
public:
- virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { }
- virtual void notifySyncRequired(const GraphicsLayer*) { }
- virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) { }
- virtual bool showDebugBorders(const GraphicsLayer*) const { return false; }
- virtual bool showRepaintCounter(const GraphicsLayer*) const { return false; }
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) OVERRIDE { }
+ virtual void notifySyncRequired(const GraphicsLayer*) OVERRIDE { }
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) OVERRIDE { }
+ virtual bool showDebugBorders(const GraphicsLayer*) const OVERRIDE { return false; }
+ virtual bool showRepaintCounter(const GraphicsLayer*) const OVERRIDE { return false; }
};
-TEST(GraphicsLayerChromiumTest, updateLayerPreserves3DWithAnimations)
-{
- MockGraphicsLayerClient client;
- OwnPtr<GraphicsLayerChromium> graphicsLayer = static_pointer_cast<GraphicsLayerChromium>(GraphicsLayer::create(&client));
- ASSERT_TRUE(graphicsLayer.get());
+class MockLayerTreeHostClient : public CCLayerTreeHostClient {
+public:
+ virtual void willBeginFrame() OVERRIDE { }
+ virtual void didBeginFrame() OVERRIDE { }
+ virtual void updateAnimations(double frameBeginTime) OVERRIDE { }
+ virtual void layout() OVERRIDE { }
+ virtual void applyScrollAndScale(const IntSize& scrollDelta, float pageScale) OVERRIDE { }
+ virtual PassRefPtr<GraphicsContext3D> createContext3D() OVERRIDE
+ {
+ GraphicsContext3D::Attributes attrs;
+ return createCompositorMockGraphicsContext3D(attrs);
+ }
+ virtual void didRecreateContext(bool success) OVERRIDE { }
+ virtual void willCommit() OVERRIDE { }
+ virtual void didCommit() OVERRIDE { }
+ virtual void didCommitAndDrawFrame() OVERRIDE { }
+ virtual void didCompleteSwapBuffers() OVERRIDE { }
+ virtual void scheduleComposite() OVERRIDE { }
+};
+
+class MockLayerTreeHost : public CCLayerTreeHost {
+public:
+ static PassOwnPtr<MockLayerTreeHost> create()
+ {
+ CCLayerTreeSettings settings;
+ OwnPtr<MockLayerTreeHost> layerTreeHost(adoptPtr(new MockLayerTreeHost(new MockLayerTreeHostClient(), settings)));
+ bool success = layerTreeHost->initialize();
+ EXPECT_TRUE(success);
+ layerTreeHost->setRootLayer(LayerChromium::create());
+ layerTreeHost->setViewportSize(IntSize(1, 1));
+ return layerTreeHost.release();
+ }
+
+ virtual PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
+ {
+ return CCLayerTreeHostImpl::create(settings(), client);
+ }
+
+private:
+ MockLayerTreeHost(CCLayerTreeHostClient* client, const CCLayerTreeSettings& settings)
+ : CCLayerTreeHost(client, settings)
+ {
+ }
+};
+
+class GraphicsLayerChromiumTest : public testing::Test {
+public:
+ GraphicsLayerChromiumTest()
+ {
+ // For these tests, we will enable threaded animations.
+ WebCompositor::setAcceleratedAnimationEnabled(true);
+ WebCompositor::initialize(0);
+ m_graphicsLayer = static_pointer_cast<GraphicsLayerChromium>(GraphicsLayer::create(&m_client));
+ m_platformLayer = static_cast<LayerChromium*>(m_graphicsLayer->platformLayer());
+ m_layerTreeHost = MockLayerTreeHost::create();
+ m_platformLayer->setLayerTreeHost(m_layerTreeHost.get());
+ }
+
+ virtual ~GraphicsLayerChromiumTest()
+ {
+ m_graphicsLayer.clear();
+ m_layerTreeHost.clear();
+ WebCompositor::shutdown();
+ }
+
+protected:
+ static void expectTranslateX(double translateX, const WebTransformationMatrix& matrix)
+ {
+ EXPECT_FLOAT_EQ(translateX, matrix.m41());
+ }
+
+ LayerChromium* m_platformLayer;
+ OwnPtr<GraphicsLayerChromium> m_graphicsLayer;
+ OwnPtr<CCLayerTreeHost> m_layerTreeHost;
- LayerChromium* platformLayer = static_cast<LayerChromium*>(graphicsLayer->platformLayer());
- ASSERT_TRUE(platformLayer);
+private:
+ MockGraphicsLayerClient m_client;
+ DebugScopedSetMainThread m_main;
+};
- ASSERT_FALSE(platformLayer->hasActiveAnimation());
+TEST_F(GraphicsLayerChromiumTest, updateLayerPreserves3DWithAnimations)
+{
+ ASSERT_FALSE(m_platformLayer->hasActiveAnimation());
OwnPtr<CCActiveAnimation> floatAnimation(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve), 0, 1, CCActiveAnimation::Opacity));
- platformLayer->layerAnimationController()->add(floatAnimation.release());
+ m_platformLayer->layerAnimationController()->addAnimation(floatAnimation.release());
+
+ ASSERT_TRUE(m_platformLayer->hasActiveAnimation());
+
+ m_graphicsLayer->setPreserves3D(true);
+
+ m_platformLayer = static_cast<LayerChromium*>(m_graphicsLayer->platformLayer());
+ ASSERT_TRUE(m_platformLayer);
+
+ ASSERT_TRUE(m_platformLayer->hasActiveAnimation());
+ m_platformLayer->removeAnimation(0);
+ ASSERT_FALSE(m_platformLayer->hasActiveAnimation());
+
+ m_graphicsLayer->setPreserves3D(false);
+
+ m_platformLayer = static_cast<LayerChromium*>(m_graphicsLayer->platformLayer());
+ ASSERT_TRUE(m_platformLayer);
+
+ ASSERT_FALSE(m_platformLayer->hasActiveAnimation());
+}
+
+TEST_F(GraphicsLayerChromiumTest, createOpacityAnimation)
+{
+ 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;
+ bool addedAnimation = m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_TRUE(addedAnimation);
+
+ EXPECT_TRUE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+
+ CCActiveAnimation* activeAnimation = m_platformLayer->layerAnimationController()->getActiveAnimation(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_F(GraphicsLayerChromiumTest, createTransformAnimation)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformOperations operations1;
+ operations1.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformOperations operations2;
+ operations2.operations().append(TranslateTransformOperation::create(Length(4, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_TRUE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+
+ CCActiveAnimation* activeAnimation = m_platformLayer->layerAnimationController()->getActiveAnimation(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));
+ expectTranslateX(4, curve->getValue(duration));
+}
+
+TEST_F(GraphicsLayerChromiumTest, createTransformAnimationWithBigRotation)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformOperations operations1;
+ operations1.operations().append(RotateTransformOperation::create(0, TransformOperation::ROTATE));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformOperations operations2;
+ operations2.operations().append(RotateTransformOperation::create(270, TransformOperation::ROTATE));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_FALSE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+}
+
+TEST_F(GraphicsLayerChromiumTest, createTransformAnimationWithSingularMatrix)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformationMatrix matrix1;
+ TransformOperations operations1;
+ operations1.operations().append(Matrix3DTransformOperation::create(matrix1));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformationMatrix matrix2;
+ matrix2.setM11(0);
+ TransformOperations operations2;
+ operations2.operations().append(Matrix3DTransformOperation::create(matrix2));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_FALSE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+}
+
+TEST_F(GraphicsLayerChromiumTest, createReversedAnimation)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformOperations operations1;
+ operations1.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformOperations operations2;
+ operations2.operations().append(TranslateTransformOperation::create(Length(4, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+ animation->setDirection(Animation::AnimationDirectionReverse);
+
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_TRUE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+
+ CCActiveAnimation* activeAnimation = m_platformLayer->layerAnimationController()->getActiveAnimation(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(4, curve->getValue(0));
+ expectTranslateX(2, curve->getValue(duration));
+}
+
+TEST_F(GraphicsLayerChromiumTest, createAlternatingAnimation)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformOperations operations1;
+ operations1.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformOperations operations2;
+ operations2.operations().append(TranslateTransformOperation::create(Length(4, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+ animation->setDirection(Animation::AnimationDirectionAlternate);
+ animation->setIterationCount(2);
+
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
+
+ EXPECT_TRUE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
+
+ CCActiveAnimation* activeAnimation = m_platformLayer->layerAnimationController()->getActiveAnimation(CCActiveAnimation::Transform);
+ EXPECT_TRUE(activeAnimation);
+ EXPECT_TRUE(activeAnimation->alternatesDirection());
+
+ EXPECT_EQ(2, 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));
+ expectTranslateX(4, curve->getValue(duration));
+}
+
+TEST_F(GraphicsLayerChromiumTest, createReversedAlternatingAnimation)
+{
+ const double duration = 1;
+ WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+ TransformOperations operations1;
+ operations1.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(0, &operations1));
+
+ TransformOperations operations2;
+ operations2.operations().append(TranslateTransformOperation::create(Length(4, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TRANSLATE_X));
+ values.insert(new TransformAnimationValue(duration, &operations2));
+
+ RefPtr<Animation> animation = Animation::create();
+ animation->setDuration(duration);
+ animation->setDirection(Animation::AnimationDirectionAlternateReverse);
+ animation->setIterationCount(2);
- ASSERT_TRUE(platformLayer->hasActiveAnimation());
+ IntSize boxSize;
+ m_graphicsLayer->addAnimation(values, boxSize, animation.get(), "", 0);
- graphicsLayer->setPreserves3D(true);
+ EXPECT_TRUE(m_platformLayer->layerAnimationController()->hasActiveAnimation());
- platformLayer = static_cast<LayerChromium*>(graphicsLayer->platformLayer());
- ASSERT_TRUE(platformLayer);
+ CCActiveAnimation* activeAnimation = m_platformLayer->layerAnimationController()->getActiveAnimation(CCActiveAnimation::Transform);
+ EXPECT_TRUE(activeAnimation);
+ EXPECT_TRUE(activeAnimation->alternatesDirection());
- ASSERT_TRUE(platformLayer->hasActiveAnimation());
- platformLayer->removeAnimation(0);
- ASSERT_FALSE(platformLayer->hasActiveAnimation());
+ EXPECT_EQ(2, activeAnimation->iterations());
+ EXPECT_EQ(CCActiveAnimation::Transform, activeAnimation->targetProperty());
- graphicsLayer->setPreserves3D(false);
+ EXPECT_EQ(CCAnimationCurve::Transform, activeAnimation->curve()->type());
- platformLayer = static_cast<LayerChromium*>(graphicsLayer->platformLayer());
- ASSERT_TRUE(platformLayer);
+ const CCTransformAnimationCurve* curve = activeAnimation->curve()->toTransformAnimationCurve();
+ EXPECT_TRUE(curve);
- ASSERT_FALSE(platformLayer->hasActiveAnimation());
+ expectTranslateX(4, curve->getValue(0));
+ expectTranslateX(2, curve->getValue(duration));
}
} // namespace
diff --git a/Source/WebKit/chromium/tests/IDBDatabaseBackendTest.cpp b/Source/WebKit/chromium/tests/IDBDatabaseBackendTest.cpp
new file mode 100644
index 000000000..098a7327f
--- /dev/null
+++ b/Source/WebKit/chromium/tests/IDBDatabaseBackendTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 "IDBBackingStore.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBFactoryBackendImpl.h"
+#include "IDBFakeBackingStore.h"
+#include "IDBIndexBackendImpl.h"
+#include "IDBObjectStoreBackendImpl.h"
+#include "IDBTransactionCoordinator.h"
+
+#include <gtest/gtest.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+using namespace WebCore;
+
+namespace {
+
+TEST(IDBDatabaseBackendTest, BackingStoreRetention)
+{
+ RefPtr<IDBFakeBackingStore> backingStore = adoptRef(new IDBFakeBackingStore());
+ EXPECT_TRUE(backingStore->hasOneRef());
+
+ IDBTransactionCoordinator* coordinator = 0;
+ IDBFactoryBackendImpl* factory = 0;
+ RefPtr<IDBDatabaseBackendImpl> db = IDBDatabaseBackendImpl::create("db", backingStore.get(), coordinator, factory, "uniqueid");
+ EXPECT_GT(backingStore->refCount(), 1);
+
+ const bool autoIncrement = false;
+ RefPtr<IDBObjectStoreBackendImpl> store = IDBObjectStoreBackendImpl::create(db.get(), "store", String("keyPath"), autoIncrement);
+ EXPECT_GT(backingStore->refCount(), 1);
+
+ const bool unique = false;
+ const bool multiEntry = false;
+ RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(db.get(), store.get(), "index", String("keyPath"), unique, multiEntry);
+ EXPECT_GT(backingStore->refCount(), 1);
+
+ db.clear();
+ EXPECT_TRUE(backingStore->hasOneRef());
+ store.clear();
+ EXPECT_TRUE(backingStore->hasOneRef());
+ index.clear();
+ EXPECT_TRUE(backingStore->hasOneRef());
+}
+
+} // namespace
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp b/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp
index 8f5b8ef01..9934e5c79 100644
--- a/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp
+++ b/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp
@@ -620,10 +620,17 @@ TEST(IDBLevelDBCodingTest, ComparisonTest)
keys.append(DatabaseNameKey::encode("a", "a"));
keys.append(DatabaseMetaDataKey::encode(1, DatabaseMetaDataKey::kOriginName));
keys.append(ObjectStoreMetaDataKey::encode(1, 1, 0));
+ keys.append(ObjectStoreMetaDataKey::encode(1, 1, 1));
+ keys.append(ObjectStoreMetaDataKey::encodeMaxKey(1, 1));
+ keys.append(ObjectStoreMetaDataKey::encodeMaxKey(1, 2));
keys.append(ObjectStoreMetaDataKey::encodeMaxKey(1));
keys.append(IndexMetaDataKey::encode(1, 1, 30, 0));
keys.append(IndexMetaDataKey::encode(1, 1, 31, 0));
keys.append(IndexMetaDataKey::encode(1, 1, 31, 1));
+ keys.append(IndexMetaDataKey::encodeMaxKey(1, 1, 31));
+ keys.append(IndexMetaDataKey::encodeMaxKey(1, 1, 32));
+ keys.append(IndexMetaDataKey::encodeMaxKey(1, 1));
+ keys.append(IndexMetaDataKey::encodeMaxKey(1, 2));
keys.append(ObjectStoreFreeListKey::encode(1, 1));
keys.append(ObjectStoreFreeListKey::encodeMaxKey(1));
keys.append(IndexFreeListKey::encode(1, 1, kMinimumIndexId));
diff --git a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp
index 8213dd812..cd4fcc340 100644
--- a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp
@@ -57,7 +57,7 @@ namespace {
class MockCCLayerTreeHost : public CCLayerTreeHost {
public:
MockCCLayerTreeHost()
- : CCLayerTreeHost(&m_fakeClient, CCSettings())
+ : CCLayerTreeHost(&m_fakeClient, CCLayerTreeSettings())
{
initialize();
}
@@ -70,7 +70,7 @@ private:
class MockLayerPainterChromium : public LayerPainterChromium {
public:
- virtual void paint(GraphicsContext&, const IntRect&) { }
+ virtual void paint(SkCanvas*, const IntRect&, IntRect&) { }
};
@@ -80,11 +80,13 @@ protected:
{
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
m_layerTreeHost = adoptPtr(new MockCCLayerTreeHost);
}
virtual void TearDown()
{
+ DebugScopedSetMainThread main;
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_parent.clear();
@@ -614,7 +616,7 @@ public:
private:
FakeCCLayerTreeHost()
- : CCLayerTreeHost(&m_client, CCSettings())
+ : CCLayerTreeHost(&m_client, CCLayerTreeSettings())
{
}
@@ -639,6 +641,7 @@ void assertLayerTreeHostMatchesForSubtree(LayerChromium* layer, CCLayerTreeHost*
TEST(LayerChromiumLayerTreeHostTest, enteringTree)
{
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
@@ -671,6 +674,7 @@ TEST(LayerChromiumLayerTreeHostTest, enteringTree)
TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree)
{
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
RefPtr<LayerChromium> parent = LayerChromium::create();
OwnPtr<FakeCCLayerTreeHost> layerTreeHost(FakeCCLayerTreeHost::create());
@@ -702,6 +706,7 @@ TEST(LayerChromiumLayerTreeHostTest, addingLayerSubtree)
TEST(LayerChromiumLayerTreeHostTest, changeHost)
{
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> child = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
@@ -735,6 +740,7 @@ TEST(LayerChromiumLayerTreeHostTest, changeHost)
TEST(LayerChromiumLayerTreeHostTest, changeHostInSubtree)
{
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
RefPtr<LayerChromium> firstParent = LayerChromium::create();
RefPtr<LayerChromium> firstChild = LayerChromium::create();
RefPtr<LayerChromium> secondParent = LayerChromium::create();
@@ -772,6 +778,7 @@ TEST(LayerChromiumLayerTreeHostTest, changeHostInSubtree)
TEST(LayerChromiumLayerTreeHostTest, replaceMaskAndReplicaLayer)
{
WebKit::WebCompositor::initialize(0);
+ DebugScopedSetMainThread main;
RefPtr<LayerChromium> parent = LayerChromium::create();
RefPtr<LayerChromium> mask = LayerChromium::create();
RefPtr<LayerChromium> replica = LayerChromium::create();
diff --git a/Source/WebKit/chromium/tests/LayerRendererChromiumTest.cpp b/Source/WebKit/chromium/tests/LayerRendererChromiumTest.cpp
index 4ed35986c..9269217c3 100644
--- a/Source/WebKit/chromium/tests/LayerRendererChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/LayerRendererChromiumTest.cpp
@@ -25,9 +25,12 @@
#include "config.h"
#include "LayerRendererChromium.h"
+#include "CCTestCommon.h"
#include "FakeWebGraphicsContext3D.h"
#include "GraphicsContext3D.h"
#include "GraphicsContext3DPrivate.h"
+#include "WebCompositor.h"
+#include "cc/CCSettings.h"
#include "cc/CCSingleThreadProxy.h"
#include <gmock/gmock.h>
@@ -35,6 +38,7 @@
using namespace WebCore;
using namespace WebKit;
+using namespace WebKitTests;
class FrameCountingMemoryAllocationSettingContext : public FakeWebGraphicsContext3D {
public:
@@ -54,44 +58,56 @@ public:
// Methods added for test.
int frameCount() { return m_frame; }
- void setMemoryAllocation(WebGraphicsMemoryAllocation allocation) { m_memoryAllocationChangedCallback->onMemoryAllocationChanged(allocation); }
+ void setMemoryAllocation(WebGraphicsMemoryAllocation allocation)
+ {
+ ASSERT(CCProxy::isImplThread());
+ // In single threaded mode we expect this callback on main thread.
+ DebugScopedSetMainThread main;
+ m_memoryAllocationChangedCallback->onMemoryAllocationChanged(allocation);
+ }
private:
int m_frame;
WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* m_memoryAllocationChangedCallback;
};
-class FakeLayerRendererChromiumClient : public LayerRendererChromiumClient {
+class FakeCCRendererClient : public CCRendererClient {
public:
- FakeLayerRendererChromiumClient()
+ FakeCCRendererClient()
: m_setFullRootLayerDamageCount(0)
, m_rootLayer(CCLayerImpl::create(1))
+ , m_memoryAllocationLimitBytes(0)
{
m_rootLayer->createRenderSurface();
+ m_rootRenderPass = CCRenderPass::create(m_rootLayer->renderSurface());
}
- // LayerRendererChromiumClient methods.
+ // CCRendererClient methods.
virtual const IntSize& deviceViewportSize() const OVERRIDE { static IntSize fakeSize; return fakeSize; }
- virtual const CCSettings& settings() const OVERRIDE { static CCSettings fakeSettings; return fakeSettings; }
+ virtual const CCLayerTreeSettings& settings() const OVERRIDE { static CCLayerTreeSettings fakeSettings; return fakeSettings; }
virtual void didLoseContext() OVERRIDE { }
virtual void onSwapBuffersComplete() OVERRIDE { }
virtual void setFullRootLayerDamage() OVERRIDE { m_setFullRootLayerDamageCount++; }
- virtual void setContentsMemoryAllocationLimitBytes(size_t) OVERRIDE { }
+ virtual void setContentsMemoryAllocationLimitBytes(size_t bytes) OVERRIDE { m_memoryAllocationLimitBytes = bytes; }
// Methods added for test.
int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; }
- CCLayerImpl* rootLayer() { return m_rootLayer.get(); }
+ CCRenderPass* rootRenderPass() { return m_rootRenderPass.get(); }
+
+ size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; }
private:
int m_setFullRootLayerDamageCount;
DebugScopedSetImplThread m_implThread;
OwnPtr<CCLayerImpl> m_rootLayer;
+ OwnPtr<CCRenderPass> m_rootRenderPass;
+ size_t m_memoryAllocationLimitBytes;
};
class FakeLayerRendererChromium : public LayerRendererChromium {
public:
- FakeLayerRendererChromium(LayerRendererChromiumClient* client, PassRefPtr<GraphicsContext3D> context) : LayerRendererChromium(client, context, UnthrottledUploader) { }
+ FakeLayerRendererChromium(CCRendererClient* client, PassRefPtr<GraphicsContext3D> context) : LayerRendererChromium(client, context, UnthrottledUploader) { }
// LayerRendererChromium methods.
@@ -113,9 +129,15 @@ protected:
virtual void SetUp()
{
+ WebKit::WebCompositor::initialize(0);
m_layerRendererChromium.initialize();
}
+ virtual void TearDown()
+ {
+ WebKit::WebCompositor::shutdown();
+ }
+
void swapBuffers()
{
m_layerRendererChromium.swapBuffers(IntRect());
@@ -126,8 +148,9 @@ protected:
RefPtr<GraphicsContext3D> m_context;
FrameCountingMemoryAllocationSettingContext& m_mockContext;
- FakeLayerRendererChromiumClient m_mockClient;
+ FakeCCRendererClient m_mockClient;
FakeLayerRendererChromium m_layerRendererChromium;
+ CCScopedSettings m_scopedSettings;
};
// Test LayerRendererChromium discardFramebuffer functionality:
@@ -179,7 +202,7 @@ TEST_F(LayerRendererChromiumTest, SwapBuffersWhileBackbufferDiscardedShouldIgnor
swapBuffers();
EXPECT_EQ(0, m_mockContext.frameCount());
EXPECT_EQ(2, m_mockClient.setFullRootLayerDamageCount());
-
+
swapBuffers();
EXPECT_EQ(0, m_mockContext.frameCount());
EXPECT_EQ(3, m_mockClient.setFullRootLayerDamageCount());
@@ -194,7 +217,7 @@ TEST_F(LayerRendererChromiumTest, DiscardedBackbufferIsRecreatredForScopeDuratio
EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
- m_layerRendererChromium.beginDrawingFrame(m_mockClient.rootLayer()->renderSurface());
+ m_layerRendererChromium.beginDrawingFrame(m_mockClient.rootRenderPass());
EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
swapBuffers();
@@ -270,7 +293,8 @@ public:
// This test isn't using the same fixture as LayerRendererChromiumTest, and you can't mix TEST() and TEST_F() with the same name, hence LRC2.
TEST(LayerRendererChromiumTest2, initializationDoesNotMakeSynchronousCalls)
{
- FakeLayerRendererChromiumClient mockClient;
+ CCScopedSettings scopedSettings;
+ FakeCCRendererClient mockClient;
FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ForbidSynchronousCallContext), GraphicsContext3D::RenderDirectlyToHostWindow));
EXPECT_TRUE(layerRendererChromium.initialize());
@@ -311,8 +335,86 @@ private:
TEST(LayerRendererChromiumTest2, initializationWithQuicklyLostContextDoesNotAssert)
{
- FakeLayerRendererChromiumClient mockClient;
+ CCScopedSettings scopedSettings;
+ FakeCCRendererClient mockClient;
FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new LoseContextOnFirstGetContext), GraphicsContext3D::RenderDirectlyToHostWindow));
layerRendererChromium.initialize();
}
+
+class ContextThatDoesNotSupportMemoryManagmentExtensions : public FakeWebGraphicsContext3D {
+public:
+ ContextThatDoesNotSupportMemoryManagmentExtensions() { }
+
+ // WebGraphicsContext3D methods.
+
+ // This method would normally do a glSwapBuffers under the hood.
+ virtual void prepareTexture() { }
+ virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { }
+ virtual WebString getString(WebKit::WGC3Denum name) { return WebString(); }
+};
+
+TEST(LayerRendererChromiumTest2, initializationWithoutGpuMemoryManagerExtensionSupportShouldDefaultToNonZeroAllocation)
+{
+ FakeCCRendererClient mockClient;
+ FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatDoesNotSupportMemoryManagmentExtensions), GraphicsContext3D::RenderDirectlyToHostWindow));
+
+ layerRendererChromium.initialize();
+
+ EXPECT_GT(mockClient.memoryAllocationLimitBytes(), 0ul);
+}
+
+class ClearCountingContext : public FakeWebGraphicsContext3D {
+public:
+ ClearCountingContext() : m_clear(0) { }
+
+ virtual void clear(WGC3Dbitfield)
+ {
+ m_clear++;
+ }
+
+ int clearCount() const { return m_clear; }
+
+private:
+ int m_clear;
+};
+
+TEST(LayerRendererChromiumTest2, opaqueBackground)
+{
+ FakeCCRendererClient mockClient;
+ RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
+ FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
+
+ mockClient.rootRenderPass()->setHasTransparentBackground(false);
+
+ EXPECT_TRUE(layerRendererChromium.initialize());
+
+ layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
+ layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
+ layerRendererChromium.finishDrawingFrame();
+
+ // On DEBUG builds, render passes with opaque background clear to blue to
+ // easily see regions that were not drawn on the screen.
+#if defined(NDEBUG)
+ EXPECT_EQ(0, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
+#else
+ EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
+#endif
+}
+
+TEST(LayerRendererChromiumTest2, transparentBackground)
+{
+ FakeCCRendererClient mockClient;
+ RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
+ FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
+
+ mockClient.rootRenderPass()->setHasTransparentBackground(true);
+
+ EXPECT_TRUE(layerRendererChromium.initialize());
+
+ layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
+ layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
+ layerRendererChromium.finishDrawingFrame();
+
+ EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
+}
diff --git a/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp b/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp
deleted file mode 100644
index d1a97bb5b..000000000
--- a/Source/WebKit/chromium/tests/LayerTextureUpdaterTest.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "LayerTextureUpdater.h"
-
-#include "BitmapCanvasLayerTextureUpdater.h"
-#include "BitmapSkPictureCanvasLayerTextureUpdater.h"
-#include "FrameBufferSkPictureCanvasLayerTextureUpdater.h"
-#include "GraphicsContext.h"
-#include "LayerPainterChromium.h"
-#include "PlatformContextSkia.h"
-#include "SkPictureCanvasLayerTextureUpdater.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using namespace WebCore;
-
-namespace {
-
-struct PaintCallback {
- virtual void operator()(GraphicsContext&, const IntRect&) = 0;
-};
-
-class TestLayerPainterChromium : public LayerPainterChromium {
-public:
- TestLayerPainterChromium(PaintCallback& callback) : m_callback(callback) { }
-
- virtual void paint(GraphicsContext& context, const IntRect& contentRect)
- {
- m_callback(context, contentRect);
- }
-
- private:
- PaintCallback& m_callback;
-};
-
-// Paint callback functions
-
-struct PaintFillOpaque : public PaintCallback {
- virtual void operator()(GraphicsContext& context, const IntRect& contentRect)
- {
- Color opaque(255, 0, 0, 255);
- IntRect top(contentRect.x(), contentRect.y(), contentRect.width(), contentRect.height() / 2);
- IntRect bottom(contentRect.x(), contentRect.y() + contentRect.height() / 2, contentRect.width(), contentRect.height() / 2);
- context.fillRect(top, opaque, ColorSpaceDeviceRGB);
- context.fillRect(bottom, opaque, ColorSpaceDeviceRGB);
- }
-};
-
-struct PaintFillAlpha : public PaintCallback {
- virtual void operator()(GraphicsContext& context, const IntRect& contentRect)
- {
- Color alpha(0, 0, 0, 0);
- context.fillRect(contentRect, alpha, ColorSpaceDeviceRGB);
- }
-};
-
-struct PaintFillPartialOpaque : public PaintCallback {
- PaintFillPartialOpaque(IntRect opaqueRect)
- : m_opaqueRect(opaqueRect)
- {
- }
-
- virtual void operator()(GraphicsContext& context, const IntRect& contentRect)
- {
- Color alpha(0, 0, 0, 0);
- context.fillRect(contentRect, alpha, ColorSpaceDeviceRGB);
-
- IntRect fillOpaque = m_opaqueRect;
- fillOpaque.intersect(contentRect);
-
- Color opaque(255, 255, 255, 255);
- context.fillRect(fillOpaque, opaque, ColorSpaceDeviceRGB);
- }
-
- IntRect m_opaqueRect;
-};
-
-#define EXPECT_EQ_RECT(a, b) \
- EXPECT_EQ(a.x(), b.x()); \
- EXPECT_EQ(a.maxX(), b.maxX()); \
- EXPECT_EQ(a.y(), b.y()); \
- EXPECT_EQ(a.maxY(), b.maxY());
-
-TEST(LayerTextureUpdaterTest, testOpaqueRectPresentAfterOpaquePaint)
-{
- PaintFillOpaque fillOpaque;
- RefPtr<LayerTextureUpdater> updater;
- IntRect opaqueRect;
- OwnPtr<TestLayerPainterChromium> painter;
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release());
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 400, 400), opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentAfterNonOpaquePaint)
-{
- PaintFillAlpha fillAlpha;
- RefPtr<LayerTextureUpdater> updater;
- IntRect opaqueRect;
- OwnPtr<TestLayerPainterChromium> painter;
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release());
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentForOpaqueLayerWithOpaquePaint)
-{
- PaintFillOpaque fillOpaque;
- RefPtr<LayerTextureUpdater> updater;
- IntRect opaqueRect;
- OwnPtr<TestLayerPainterChromium> painter;
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillOpaque));
- updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release());
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testOpaqueRectNotPresentForOpaqueLayerWithNonOpaquePaint)
-{
- PaintFillAlpha fillAlpha;
- RefPtr<LayerTextureUpdater> updater;
- IntRect opaqueRect;
- OwnPtr<TestLayerPainterChromium> painter;
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = BitmapSkPictureCanvasLayerTextureUpdater::create(painter.release(), false);
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-
- opaqueRect = IntRect();
- painter = adoptPtr(new TestLayerPainterChromium(fillAlpha));
- updater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(painter.release());
- updater->setOpaque(true);
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testPartialOpaqueRectNoTransform)
-{
- IntRect partialRect(100, 200, 50, 75);
- PaintFillPartialOpaque fillPartial(partialRect);
- OwnPtr<TestLayerPainterChromium> painter(adoptPtr(new TestLayerPainterChromium(fillPartial)));
- RefPtr<LayerTextureUpdater> updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
-
- IntRect opaqueRect;
- updater->prepareToUpdate(IntRect(0, 0, 400, 400), IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(partialRect, opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testPartialOpaqueRectTranslation)
-{
- IntRect partialRect(100, 200, 50, 75);
- PaintFillPartialOpaque fillPartial(partialRect);
-
- OwnPtr<TestLayerPainterChromium> painter(adoptPtr(new TestLayerPainterChromium(fillPartial)));
- RefPtr<LayerTextureUpdater> updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
-
- IntRect opaqueRect;
- IntRect contentRect(11, 12, 389, 388);
- updater->prepareToUpdate(contentRect, IntSize(400, 400), 0, 1, opaqueRect);
- EXPECT_EQ_RECT(partialRect, opaqueRect);
-}
-
-TEST(LayerTextureUpdaterTest, testPartialOpaqueRectScale)
-{
- float contentsScale = 0.5;
-
- IntRect partialRect(9, 20, 50, 75);
- IntRect partialDeviceRect(partialRect);
- PaintFillPartialOpaque fillPartial(partialDeviceRect);
- OwnPtr<TestLayerPainterChromium> painter(adoptPtr(new TestLayerPainterChromium(fillPartial)));
- RefPtr<LayerTextureUpdater> updater = BitmapCanvasLayerTextureUpdater::create(painter.release(), false);
-
- IntRect opaqueRect;
- IntRect contentRect(4, 6, 396, 394);
- updater->prepareToUpdate(contentRect, IntSize(400, 400), 0, contentsScale, opaqueRect);
-
- // Original rect: 9, 20, 50, 75
- // Scaled down to half size: 4.5, 10, 25, 37.5
- // Enclosed int rect: 5, 10, 24, 37
- // Scaled back up to content: 10, 20, 48, 74
- IntRect scaledRect(10, 20, 48, 74);
- EXPECT_EQ_RECT(scaledRect, opaqueRect);
-}
-
-} // namespace
diff --git a/Source/WebKit/chromium/tests/OpaqueRectTrackingContentLayerDelegateTest.cpp b/Source/WebKit/chromium/tests/OpaqueRectTrackingContentLayerDelegateTest.cpp
new file mode 100644
index 000000000..dd60a97b7
--- /dev/null
+++ b/Source/WebKit/chromium/tests/OpaqueRectTrackingContentLayerDelegateTest.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 "OpaqueRectTrackingContentLayerDelegate.h"
+
+#include "Color.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "skia/ext/platform_canvas.h"
+#include <public/WebRect.h>
+
+#include <gtest/gtest.h>
+
+using WebKit::WebRect;
+using namespace WebCore;
+
+namespace {
+
+struct PaintCallback {
+ virtual void operator()(GraphicsContext&, const IntRect&) = 0;
+};
+
+class TestLayerPainterChromium : public GraphicsContextPainter {
+public:
+ TestLayerPainterChromium(PaintCallback& callback) : m_callback(callback) { }
+
+ virtual void paint(GraphicsContext& context, const IntRect& contentRect) OVERRIDE
+ {
+ m_callback(context, contentRect);
+ }
+
+ private:
+ PaintCallback& m_callback;
+};
+
+// Paint callback functions
+
+struct PaintFillOpaque : public PaintCallback {
+ virtual void operator()(GraphicsContext& context, const IntRect& contentRect) OVERRIDE
+ {
+ Color opaque(255, 0, 0, 255);
+ IntRect top(contentRect.x(), contentRect.y(), contentRect.width(), contentRect.height() / 2);
+ IntRect bottom(contentRect.x(), contentRect.y() + contentRect.height() / 2, contentRect.width(), contentRect.height() / 2);
+ context.fillRect(top, opaque, ColorSpaceDeviceRGB);
+ context.fillRect(bottom, opaque, ColorSpaceDeviceRGB);
+ }
+};
+
+struct PaintFillAlpha : public PaintCallback {
+ virtual void operator()(GraphicsContext& context, const IntRect& contentRect)
+ {
+ Color alpha(0, 0, 0, 0);
+ context.fillRect(contentRect, alpha, ColorSpaceDeviceRGB);
+ }
+};
+
+struct PaintFillPartialOpaque : public PaintCallback {
+ PaintFillPartialOpaque(IntRect opaqueRect)
+ : m_opaqueRect(opaqueRect)
+ {
+ }
+
+ virtual void operator()(GraphicsContext& context, const IntRect& contentRect)
+ {
+ Color alpha(0, 0, 0, 0);
+ context.fillRect(contentRect, alpha, ColorSpaceDeviceRGB);
+
+ IntRect fillOpaque = m_opaqueRect;
+ fillOpaque.intersect(contentRect);
+
+ Color opaque(255, 255, 255, 255);
+ context.fillRect(fillOpaque, opaque, ColorSpaceDeviceRGB);
+ }
+
+ IntRect m_opaqueRect;
+};
+
+#define EXPECT_EQ_RECT(a, b) \
+ EXPECT_EQ(a.x, b.x); \
+ EXPECT_EQ(a.width, b.width); \
+ EXPECT_EQ(a.y, b.y); \
+ EXPECT_EQ(a.height, b.height);
+
+class OpaqueRectTrackingContentLayerDelegateTest : public testing::Test {
+public:
+ OpaqueRectTrackingContentLayerDelegateTest()
+ : m_skCanvas(adoptPtr(skia::CreateBitmapCanvas(canvasRect().width, canvasRect().height, false)))
+ {
+ }
+
+ SkCanvas* skCanvas() { return m_skCanvas.get(); }
+ WebRect canvasRect() { return WebRect(0, 0, 400, 400); }
+
+private:
+ OwnPtr<SkCanvas> m_skCanvas;
+};
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectPresentAfterOpaquePaint)
+{
+ PaintFillOpaque fillOpaque;
+ TestLayerPainterChromium painter(fillOpaque);
+
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ WebRect opaqueRect;
+ delegate.paintContents(skCanvas(), canvasRect(), opaqueRect);
+ EXPECT_EQ_RECT(WebRect(0, 0, 400, 400), opaqueRect);
+}
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentAfterNonOpaquePaint)
+{
+ PaintFillAlpha fillAlpha;
+ TestLayerPainterChromium painter(fillAlpha);
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ WebRect opaqueRect;
+ delegate.paintContents(skCanvas(), canvasRect(), opaqueRect);
+ EXPECT_EQ_RECT(WebRect(0, 0, 0, 0), opaqueRect);
+}
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentForOpaqueLayerWithOpaquePaint)
+{
+ PaintFillOpaque fillOpaque;
+ TestLayerPainterChromium painter(fillOpaque);
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ delegate.setOpaque(true);
+
+ WebRect opaqueRect;
+ delegate.paintContents(skCanvas(), canvasRect(), opaqueRect);
+ EXPECT_EQ_RECT(WebRect(0, 0, 0, 0), opaqueRect);
+}
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentForOpaqueLayerWithNonOpaquePaint)
+{
+ PaintFillOpaque fillAlpha;
+ TestLayerPainterChromium painter(fillAlpha);
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ delegate.setOpaque(true);
+
+ WebRect opaqueRect;
+ delegate.paintContents(skCanvas(), canvasRect(), opaqueRect);
+ EXPECT_EQ_RECT(WebRect(0, 0, 0, 0), opaqueRect);
+}
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testPartialOpaqueRectNoTransform)
+{
+ IntRect partialRect(100, 200, 50, 75);
+ PaintFillPartialOpaque fillPartial(partialRect);
+ TestLayerPainterChromium painter(fillPartial);
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ WebRect opaqueRect;
+ delegate.paintContents(skCanvas(), canvasRect(), opaqueRect);
+ EXPECT_EQ_RECT(WebRect(partialRect.x(), partialRect.y(), partialRect.width(), partialRect.height()), opaqueRect);
+}
+
+TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testPartialOpaqueRectTranslation)
+{
+ IntRect partialRect(100, 200, 50, 75);
+ PaintFillPartialOpaque fillPartial(partialRect);
+ TestLayerPainterChromium painter(fillPartial);
+ OpaqueRectTrackingContentLayerDelegate delegate(&painter);
+
+ WebRect opaqueRect;
+ WebRect contentRect(11, 12, 389, 388);
+ delegate.paintContents(skCanvas(), contentRect, opaqueRect);
+ EXPECT_EQ_RECT(WebRect(partialRect.x(), partialRect.y(), partialRect.width(), partialRect.height()), opaqueRect);
+}
+
+} // namespace
diff --git a/Source/WebKit/chromium/tests/ScrollAnimatorNoneTest.cpp b/Source/WebKit/chromium/tests/ScrollAnimatorNoneTest.cpp
index 0827267ed..6c6c359a9 100644
--- a/Source/WebKit/chromium/tests/ScrollAnimatorNoneTest.cpp
+++ b/Source/WebKit/chromium/tests/ScrollAnimatorNoneTest.cpp
@@ -110,7 +110,7 @@ TEST(ScrollAnimatorEnabled, Enabled)
MockScrollAnimatorNone scrollAnimatorNone(&scrollableArea);
EXPECT_CALL(scrollableArea, scrollSize(_)).Times(AtLeast(1)).WillRepeatedly(Return(1000));
- EXPECT_CALL(scrollableArea, setScrollOffset(_)).Times(3);
+ EXPECT_CALL(scrollableArea, setScrollOffset(_)).Times(4);
scrollAnimatorNone.scroll(HorizontalScrollbar, ScrollByLine, 100, 1);
EXPECT_NE(100, scrollAnimatorNone.currentX());
@@ -125,6 +125,12 @@ TEST(ScrollAnimatorEnabled, Enabled)
scrollAnimatorNone.reset();
scrollAnimatorNone.scroll(HorizontalScrollbar, ScrollByPixel, 4, 25);
+ EXPECT_NE(100, scrollAnimatorNone.currentX());
+ EXPECT_NE(0, scrollAnimatorNone.currentX());
+ EXPECT_EQ(0, scrollAnimatorNone.currentY());
+ scrollAnimatorNone.reset();
+
+ scrollAnimatorNone.scroll(HorizontalScrollbar, ScrollByPrecisePixel, 4, 25);
EXPECT_EQ(100, scrollAnimatorNone.currentX());
EXPECT_NE(0, scrollAnimatorNone.currentX());
EXPECT_EQ(0, scrollAnimatorNone.currentY());
diff --git a/Source/WebKit/chromium/tests/ScrollbarLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/ScrollbarLayerChromiumTest.cpp
index 5bf990cde..d2cd9befc 100644
--- a/Source/WebKit/chromium/tests/ScrollbarLayerChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/ScrollbarLayerChromiumTest.cpp
@@ -100,7 +100,7 @@ TEST(ScrollbarLayerChromiumTest, resolveScrollLayerPointer)
layerTreeRoot->addChild(child1);
layerTreeRoot->addChild(child2);
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, 0);
CCLayerImpl* ccChild1 = ccLayerTreeRoot->children()[0].get();
CCScrollbarLayerImpl* ccChild2 = static_cast<CCScrollbarLayerImpl*>(ccLayerTreeRoot->children()[1].get());
@@ -116,7 +116,7 @@ TEST(ScrollbarLayerChromiumTest, resolveScrollLayerPointer)
layerTreeRoot->addChild(child1);
layerTreeRoot->addChild(child2);
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, 0);
CCScrollbarLayerImpl* ccChild1 = static_cast<CCScrollbarLayerImpl*>(ccLayerTreeRoot->children()[0].get());
CCLayerImpl* ccChild2 = ccLayerTreeRoot->children()[1].get();
diff --git a/Source/WebKit/chromium/tests/TextureCopierTest.cpp b/Source/WebKit/chromium/tests/TextureCopierTest.cpp
index 17173c0a5..d71b8ce45 100644
--- a/Source/WebKit/chromium/tests/TextureCopierTest.cpp
+++ b/Source/WebKit/chromium/tests/TextureCopierTest.cpp
@@ -54,6 +54,7 @@ TEST(TextureCopierTest, testDrawArraysCopy)
GraphicsContext3D::Attributes attrs;
RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new MockContext()), GraphicsContext3D::RenderDirectlyToHostWindow);
MockContext& mockContext = *static_cast<MockContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()));
+ RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
{
InSequence sequence;
@@ -79,7 +80,7 @@ TEST(TextureCopierTest, testDrawArraysCopy)
int destTextureId = 2;
IntSize size(256, 128);
OwnPtr<AcceleratedTextureCopier> copier(AcceleratedTextureCopier::create(context));
- copier->copyTexture(context.get(), sourceTextureId, destTextureId, size);
+ copier->copyTexture(ccContext.get(), sourceTextureId, destTextureId, size);
}
} // namespace
diff --git a/Source/WebKit/chromium/tests/TextureLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TextureLayerChromiumTest.cpp
index b60017fd9..d0cc3d96f 100644
--- a/Source/WebKit/chromium/tests/TextureLayerChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/TextureLayerChromiumTest.cpp
@@ -43,7 +43,7 @@ namespace {
class MockCCLayerTreeHost : public CCLayerTreeHost {
public:
MockCCLayerTreeHost()
- : CCLayerTreeHost(&m_fakeClient, CCSettings())
+ : CCLayerTreeHost(&m_fakeClient, CCLayerTreeSettings())
{
initialize();
}
diff --git a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp
index 80b099f19..5e301d8eb 100644
--- a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp
+++ b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp
@@ -673,12 +673,13 @@ TEST(TiledLayerChromiumTest, invalidateFromPrepare)
FakeTextureCopier fakeCopier;
FakeTextureUploader fakeUploader;
RefPtr<GraphicsContext3D> context = createCompositorMockGraphicsContext3D(GraphicsContext3D::Attributes());
+ RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
// The tile size is 100x100, so this invalidates and then paints two tiles.
layer->setBounds(IntSize(100, 200));
layer->invalidateRect(IntRect(0, 0, 100, 200));
layer->updateLayerRect(updater, IntRect(0, 0, 100, 200), 0);
- updater.update(context.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
+ updater.update(ccContext.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
layer->pushPropertiesTo(layerImpl.get());
// We should have both tiles on the impl side.
@@ -691,7 +692,7 @@ TEST(TiledLayerChromiumTest, invalidateFromPrepare)
// Invoke updateLayerRect again. As the layer is valid updateLayerRect shouldn't be invoked on
// the LayerTextureUpdater.
layer->updateLayerRect(updater, IntRect(0, 0, 100, 200), 0);
- updater.update(context.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
+ updater.update(ccContext.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
EXPECT_EQ(0, layer->fakeLayerTextureUpdater()->prepareCount());
layer->invalidateRect(IntRect(0, 0, 50, 50));
@@ -699,12 +700,12 @@ TEST(TiledLayerChromiumTest, invalidateFromPrepare)
layer->fakeLayerTextureUpdater()->setRectToInvalidate(IntRect(25, 25, 50, 50), layer.get());
layer->fakeLayerTextureUpdater()->clearPrepareCount();
layer->updateLayerRect(updater, IntRect(0, 0, 100, 200), 0);
- updater.update(context.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
+ updater.update(ccContext.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount());
layer->fakeLayerTextureUpdater()->clearPrepareCount();
// The layer should still be invalid as updateLayerRect invoked invalidate.
layer->updateLayerRect(updater, IntRect(0, 0, 100, 200), 0);
- updater.update(context.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
+ updater.update(ccContext.get(), &fakeAllocator, &fakeCopier, &fakeUploader, 1000);
EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount());
}
@@ -796,7 +797,7 @@ TEST(TiledLayerChromiumTest, skipsDrawGetsReset)
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient;
- OwnPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCSettings());
+ OwnPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCLayerTreeSettings());
// Create two 300 x 300 tiled layers.
IntSize contentBounds(300, 300);
@@ -872,10 +873,12 @@ TEST(TiledLayerChromiumTest, hugeLayerUpdateCrash)
TEST(TiledLayerChromiumTest, partialUpdates)
{
- CCSettings settings;
- settings.maxPartialTextureUpdates = 4;
// Initialize without threading support.
WebKit::WebCompositor::initialize(0);
+
+ CCLayerTreeSettings settings;
+ settings.maxPartialTextureUpdates = 4;
+
FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient;
OwnPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, settings);
diff --git a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp
index 098dd2731..08597f1dc 100644
--- a/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp
+++ b/Source/WebKit/chromium/tests/TreeSynchronizerTest.cpp
@@ -120,22 +120,23 @@ private:
bool m_synchronizedAnimations;
};
-void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
+void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer, CCLayerTreeHostImpl* hostImpl)
{
ASSERT_TRUE(layer);
ASSERT_TRUE(ccLayer);
EXPECT_EQ(layer->id(), ccLayer->id());
+ EXPECT_EQ(ccLayer->layerTreeHostImpl(), hostImpl);
EXPECT_EQ(layer->nonFastScrollableRegion(), ccLayer->nonFastScrollableRegion());
ASSERT_EQ(!!layer->maskLayer(), !!ccLayer->maskLayer());
if (layer->maskLayer())
- expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer());
+ expectTreesAreIdentical(layer->maskLayer(), ccLayer->maskLayer(), hostImpl);
ASSERT_EQ(!!layer->replicaLayer(), !!ccLayer->replicaLayer());
if (layer->replicaLayer())
- expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer());
+ expectTreesAreIdentical(layer->replicaLayer(), ccLayer->replicaLayer(), hostImpl);
const Vector<RefPtr<LayerChromium> >& layerChildren = layer->children();
const Vector<OwnPtr<CCLayerImpl> >& ccLayerChildren = ccLayer->children();
@@ -143,7 +144,7 @@ void expectTreesAreIdentical(LayerChromium* layer, CCLayerImpl* ccLayer)
ASSERT_EQ(layerChildren.size(), ccLayerChildren.size());
for (size_t i = 0; i < layerChildren.size(); ++i)
- expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get());
+ expectTreesAreIdentical(layerChildren[i].get(), ccLayerChildren[i].get(), hostImpl);
}
// Attempts to synchronizes a null tree. This should not crash, and should
@@ -152,7 +153,7 @@ TEST(TreeSynchronizerTest, syncNullTree)
{
DebugScopedSetImplThread impl;
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(0, nullptr);
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(0, nullptr, 0);
EXPECT_TRUE(!ccLayerTreeRoot.get());
}
@@ -161,13 +162,17 @@ TEST(TreeSynchronizerTest, syncNullTree)
TEST(TreeSynchronizerTest, syncSimpleTreeFromEmpty)
{
DebugScopedSetImplThread impl;
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
}
// Constructs a very simple tree and synchronizes it attempting to reuse some layers
@@ -176,12 +181,15 @@ TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Add a new layer to the LayerChromium side
layerTreeRoot->children()[0]->addChild(MockLayerChromium::create(&ccLayerDestructionList));
@@ -190,8 +198,8 @@ TEST(TreeSynchronizerTest, syncSimpleTreeReusingLayers)
int secondCCLayerId = ccLayerTreeRoot->children()[1]->id();
// Synchronize again. After the sync the trees should be equivalent and we should have created and destroyed one CCLayerImpl.
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ASSERT_EQ(1u, ccLayerDestructionList.size());
EXPECT_EQ(secondCCLayerId, ccLayerDestructionList[0]);
@@ -203,21 +211,24 @@ TEST(TreeSynchronizerTest, syncSimpleTreeAndTrackStackingOrderChange)
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
// Set up the tree and sync once. child2 needs to be synced here, too, even though we
// remove it to set up the intended scenario.
RefPtr<LayerChromium> layerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
RefPtr<LayerChromium> child2 = MockLayerChromium::create(&ccLayerDestructionList);
layerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
layerTreeRoot->addChild(child2);
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ccLayerTreeRoot->resetAllChangeTrackingForSubtree();
// re-insert the layer and sync again.
child2->removeFromParent();
layerTreeRoot->addChild(child2);
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Check that the impl thread properly tracked the change.
EXPECT_FALSE(ccLayerTreeRoot->layerPropertyChanged());
@@ -228,6 +239,10 @@ TEST(TreeSynchronizerTest, syncSimpleTreeAndTrackStackingOrderChange)
TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
{
DebugScopedSetImplThread impl;
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
@@ -242,8 +257,8 @@ TEST(TreeSynchronizerTest, syncSimpleTreeAndProperties)
IntSize secondChildBounds = IntSize(25, 53);
layerTreeRoot->children()[1]->setBounds(secondChildBounds);
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Check that the property values we set on the LayerChromium tree are reflected in the CCLayerImpl tree.
FloatPoint rootCCLayerPosition = ccLayerTreeRoot->position();
@@ -262,6 +277,9 @@ TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
// Set up a tree with this sort of structure:
// root --- A --- B ---+--- C
// |
@@ -279,8 +297,8 @@ TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
layerB->addChild(MockLayerChromium::create(&ccLayerDestructionList));
RefPtr<LayerChromium> layerD = layerB->children()[1].get();
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Now restructure the tree to look like this:
// root --- D ---+--- A
@@ -297,8 +315,8 @@ TEST(TreeSynchronizerTest, reuseCCLayersAfterStructuralChange)
layerC->addChild(layerB);
// After another synchronize our trees should match and we should not have destroyed any CCLayerImpls
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
EXPECT_EQ(0u, ccLayerDestructionList.size());
}
@@ -309,6 +327,9 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
DebugScopedSetImplThread impl;
Vector<int> ccLayerDestructionList;
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> oldLayerTreeRoot = MockLayerChromium::create(&ccLayerDestructionList);
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
oldLayerTreeRoot->addChild(MockLayerChromium::create(&ccLayerDestructionList));
@@ -317,16 +338,16 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
int oldTreeFirstChildLayerId = oldLayerTreeRoot->children()[0]->id();
int oldTreeSecondChildLayerId = oldLayerTreeRoot->children()[1]->id();
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), nullptr);
- expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(oldLayerTreeRoot.get(), nullptr, hostImpl.get());
+ expectTreesAreIdentical(oldLayerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove all children on the LayerChromium side.
oldLayerTreeRoot->removeAllChildren();
// Synchronize again. After the sync all CCLayerImpls from the old tree should be deleted.
RefPtr<LayerChromium> newLayerTreeRoot = LayerChromium::create();
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(newLayerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(newLayerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
ASSERT_EQ(3u, ccLayerDestructionList.size());
EXPECT_TRUE(ccLayerDestructionList.contains(oldTreeRootLayerId));
@@ -338,6 +359,10 @@ TEST(TreeSynchronizerTest, syncSimpleTreeThenDestroy)
TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
{
DebugScopedSetImplThread impl;
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
layerTreeRoot->addChild(LayerChromium::create());
layerTreeRoot->addChild(LayerChromium::create());
@@ -357,29 +382,33 @@ TEST(TreeSynchronizerTest, syncMaskReplicaAndReplicaMaskLayers)
replicaLayerWithMask->setMaskLayer(replicaMaskLayer.get());
layerTreeRoot->children()[2]->setReplicaLayer(replicaLayerWithMask.get());
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the mask layer.
layerTreeRoot->children()[0]->setMaskLayer(0);
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the replica layer.
layerTreeRoot->children()[1]->setReplicaLayer(0);
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
// Remove the replica mask.
replicaLayerWithMask->setMaskLayer(0);
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
- expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
+ expectTreesAreIdentical(layerTreeRoot.get(), ccLayerTreeRoot.get(), hostImpl.get());
}
TEST(TreeSynchronizerTest, synchronizeAnimations)
{
DebugScopedSetImplThread impl;
+
+ CCLayerTreeSettings settings;
+ OwnPtr<CCLayerTreeHostImpl> hostImpl = CCLayerTreeHostImpl::create(settings, 0);
+
RefPtr<LayerChromium> layerTreeRoot = LayerChromium::create();
FakeLayerAnimationControllerClient dummy;
@@ -387,8 +416,8 @@ TEST(TreeSynchronizerTest, synchronizeAnimations)
EXPECT_FALSE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
- OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr);
- ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release());
+ OwnPtr<CCLayerImpl> ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), nullptr, hostImpl.get());
+ ccLayerTreeRoot = TreeSynchronizer::synchronizeTrees(layerTreeRoot.get(), ccLayerTreeRoot.release(), hostImpl.get());
EXPECT_TRUE(static_cast<FakeLayerAnimationController*>(layerTreeRoot->layerAnimationController())->synchronizedAnimations());
}
diff --git a/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp b/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp
index 92f006184..d5b68a867 100644
--- a/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp
+++ b/Source/WebKit/chromium/tests/WebCompositorInputHandlerImplTest.cpp
@@ -202,14 +202,14 @@ TEST_F(WebCompositorInputHandlerImplTest, gestureScrollStarted)
m_inputHandler->handleInputEvent(gesture);
}
-TEST_F(WebCompositorInputHandlerImplTest, gestureScrollFailed)
+TEST_F(WebCompositorInputHandlerImplTest, gestureScrollOnMainThread)
{
// We should send all events to the widget for this gesture.
m_expectedDisposition = DidNotHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(::testing::_, ::testing::_))
- .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
+ .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollOnMainThread));
gesture.type = WebInputEvent::GestureScrollBegin;
m_inputHandler->handleInputEvent(gesture);
@@ -306,7 +306,7 @@ TEST_F(WebCompositorInputHandlerImplTest, gestureFlingFailed)
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
+ .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollOnMainThread));
gesture.type = WebInputEvent::GestureFlingStart;
m_inputHandler->handleInputEvent(gesture);
@@ -387,7 +387,7 @@ TEST_F(WebCompositorInputHandlerImplTest, gestureFlingAnimates)
// transferred to the main thread.
EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
+ .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollOnMainThread));
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::_)).Times(0);
EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd()).Times(0);
@@ -469,7 +469,7 @@ TEST_F(WebCompositorInputHandlerImplTest, gestureFlingTransferResets)
// transferred to the main thread.
EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
+ .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollOnMainThread));
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::_)).Times(0);
EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd()).Times(0);
@@ -546,7 +546,7 @@ TEST_F(WebCompositorInputHandlerImplTest, gestureFlingTransferResets)
// Then abort the second fling.
EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
+ .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollOnMainThread));
EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::_)).Times(0);
EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd()).Times(0);
diff --git a/Source/WebKit/chromium/tests/WebFrameTest.cpp b/Source/WebKit/chromium/tests/WebFrameTest.cpp
index 4aa905c78..40705808d 100644
--- a/Source/WebKit/chromium/tests/WebFrameTest.cpp
+++ b/Source/WebKit/chromium/tests/WebFrameTest.cpp
@@ -36,6 +36,7 @@
#include "FrameTestHelpers.h"
#include "FrameView.h"
#include "ResourceError.h"
+#include "WebDataSource.h"
#include "WebDocument.h"
#include "WebFindOptions.h"
#include "WebFormElement.h"
@@ -225,13 +226,12 @@ TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag)
int viewportHeight = 480;
FixedLayoutTestWebViewClient client;
- client.m_screenInfo.horizontalDPI = 160;
+ client.m_screenInfo.horizontalDPI = 320;
client.m_windowRect = WebRect(0, 0, viewportWidth, viewportHeight);
WebView* webView = static_cast<WebView*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client));
webView->settings()->setViewportEnabled(true);
- webView->settings()->setDefaultDeviceScaleFactor(2);
webView->enableFixedLayoutMode(true);
webView->resize(WebSize(viewportWidth, viewportHeight));
webView->layout();
@@ -397,6 +397,28 @@ TEST_F(WebFrameTest, ReloadDoesntSetRedirect)
webkit_support::ServeAsynchronousMockedRequests();
}
+TEST_F(WebFrameTest, IframeRedirect)
+{
+ registerMockedHttpURLLoad("iframe_redirect.html");
+ registerMockedHttpURLLoad("visible_iframe.html");
+
+ WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframe_redirect.html", true);
+ webkit_support::RunAllPendingMessages(); // Queue the iframe.
+ webkit_support::ServeAsynchronousMockedRequests(); // Load the iframe.
+
+ WebFrame* iframe = webView->findFrameByName(WebString::fromUTF8("ifr"));
+ ASSERT_TRUE(iframe);
+ WebDataSource* iframeDataSource = iframe->dataSource();
+ ASSERT_TRUE(iframeDataSource);
+ WebVector<WebURL> redirects;
+ iframeDataSource->redirectChain(redirects);
+ ASSERT_EQ(2U, redirects.size());
+ EXPECT_EQ(GURL("about:blank"), GURL(redirects[0]));
+ EXPECT_EQ(GURL("http://www.test.com/visible_iframe.html"), GURL(redirects[1]));
+
+ webView->close();
+}
+
TEST_F(WebFrameTest, ClearFocusedNodeTest)
{
registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
diff --git a/Source/WebKit/chromium/tests/WebLayerTest.cpp b/Source/WebKit/chromium/tests/WebLayerTest.cpp
index 8fc7c93bd..bc4929311 100644
--- a/Source/WebKit/chromium/tests/WebLayerTest.cpp
+++ b/Source/WebKit/chromium/tests/WebLayerTest.cpp
@@ -65,7 +65,7 @@ public:
class MockWebContentLayerClient : public WebContentLayerClient {
public:
- MOCK_METHOD2(paintContents, void(WebCanvas*, const WebRect& clip));
+ MOCK_METHOD3(paintContents, void(WebCanvas*, const WebRect& clip, WebRect& opaque));
};
class WebLayerTest : public Test {
@@ -175,7 +175,7 @@ TEST_F(WebLayerTest, Client)
// Content layer.
MockWebContentLayerClient contentClient;
- EXPECT_CALL(contentClient, paintContents(_, _)).Times(AnyNumber());
+ EXPECT_CALL(contentClient, paintContents(_, _, _)).Times(AnyNumber());
EXPECT_CALL(m_client, scheduleComposite()).Times(AnyNumber());
WebContentLayer contentLayer = WebContentLayer::create(&contentClient);
m_rootLayer.addChild(contentLayer);
@@ -209,7 +209,7 @@ TEST_F(WebLayerTest, Hierarchy)
EXPECT_TRUE(layer2.parent().isNull());
MockWebContentLayerClient contentClient;
- EXPECT_CALL(contentClient, paintContents(_, _)).Times(AnyNumber());
+ EXPECT_CALL(contentClient, paintContents(_, _, _)).Times(AnyNumber());
WebContentLayer contentLayer = WebContentLayer::create(&contentClient);
WebExternalTextureLayer textureLayer = WebExternalTextureLayer::create();
diff --git a/Source/WebKit/chromium/tests/data/iframe_redirect.html b/Source/WebKit/chromium/tests/data/iframe_redirect.html
new file mode 100644
index 000000000..8176253ea
--- /dev/null
+++ b/Source/WebKit/chromium/tests/data/iframe_redirect.html
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <iframe id='ifr'>
+ </iframe>
+ <script>
+ var ifr = document.getElementById('ifr');
+ ifr.contentWindow.document.location = "visible_iframe.html";
+ </script>
+ </body>
+</html>