diff options
Diffstat (limited to 'Source/WebKit/chromium/tests')
21 files changed, 1766 insertions, 137 deletions
diff --git a/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp b/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp index 11a88784b..bbea971dd 100644 --- a/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp +++ b/Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp @@ -33,8 +33,11 @@ #include "cc/CCMathUtil.h" #include "cc/CCSingleThreadProxy.h" #include <gtest/gtest.h> +#include <public/WebFilterOperation.h> +#include <public/WebFilterOperations.h> using namespace WebCore; +using namespace WebKit; using namespace WTF; using namespace WebKitTests; @@ -364,8 +367,8 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBlurredSurface) OwnPtr<CCLayerImpl> root = createAndSetUpTestTreeWithOneSurface(); CCLayerImpl* child = root->children()[0].get(); - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(5, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(5)); int outsetTop, outsetRight, outsetBottom, outsetLeft; filters.getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft); root->setFilters(filters); @@ -391,8 +394,11 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild) CCLayerImpl* child1 = root->children()[0].get(); CCLayerImpl* child2 = root->children()[1].get(); - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(2, WebCore::Fixed), FilterOperation::BLUR)); + // Allow us to set damage on child1 too. + child1->setDrawsContent(true); + + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(2)); int outsetTop, outsetRight, outsetBottom, outsetLeft; filters.getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft); child1->setBackgroundFilters(filters); @@ -432,7 +438,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild) expectedDamageRect.expand(outsetLeft, outsetTop); EXPECT_FLOAT_RECT_EQ(expectedDamageRect, rootDamageRect); - // CASE 3: Setting this update rect outside the contentBounds of the blurred + // CASE 3: Setting this update rect outside the blurred contentBounds of the blurred // child1 will not cause it to be expanded. root->setUpdateRect(FloatRect(30, 30, 2, 2)); @@ -444,7 +450,22 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild) expectedDamageRect = FloatRect(30, 30, 2, 2); EXPECT_FLOAT_RECT_EQ(expectedDamageRect, rootDamageRect); - // CASE 4: Setting the update rect on child2, which is above child1, will + // 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. + root->setUpdateRect(FloatRect(99, 99, 1, 1)); + + emulateDrawingOneFrame(root.get()); + + rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect(); + // Damage on the root should be: position of updateRect (99, 99), expanded + // by the blurring on child1, but since it is 1 pixel outside the layer, the + // expanding should be reduced by 1. + expectedDamageRect = FloatRect(99, 99, 1, 1); + expectedDamageRect.move(-outsetLeft + 1, -outsetTop + 1); + expectedDamageRect.expand(outsetLeft + outsetRight - 1, outsetTop + outsetBottom - 1); + EXPECT_FLOAT_RECT_EQ(expectedDamageRect, rootDamageRect); + + // 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. child2->setUpdateRect(FloatRect(0, 0, 1, 1)); @@ -454,6 +475,19 @@ TEST_F(CCDamageTrackerTest, verifyDamageForBackgroundBlurredChild) // Damage on child2 should be: position of updateRect offset by the child's position (11, 11), and not expanded by anything. expectedDamageRect = FloatRect(11, 11, 1, 1); EXPECT_FLOAT_RECT_EQ(expectedDamageRect, rootDamageRect); + + // 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. + child1->setUpdateRect(FloatRect(0, 0, 1, 1)); + + emulateDrawingOneFrame(root.get()); + + rootDamageRect = root->renderSurface()->damageTracker()->currentDamageRect(); + // Damage on child1 should be: position of updateRect offset by the child's position (100, 100), and expanded by the damage. + expectedDamageRect = FloatRect(100, 100, 1, 1); + expectedDamageRect.move(-outsetLeft, -outsetTop); + expectedDamageRect.expand(outsetLeft + outsetRight, outsetTop + outsetBottom); + EXPECT_FLOAT_RECT_EQ(expectedDamageRect, rootDamageRect); } TEST_F(CCDamageTrackerTest, verifyDamageForAddingAndRemovingLayer) @@ -1018,7 +1052,7 @@ TEST_F(CCDamageTrackerTest, verifyDamageForEmptyLayerList) ASSERT_TRUE(root->renderSurface() == root->targetRenderSurface()); CCRenderSurface* targetSurface = root->renderSurface(); targetSurface->clearLayerList(); - targetSurface->damageTracker()->updateDamageTrackingState(targetSurface->layerList(), targetSurface->owningLayerId(), false, IntRect(), 0, FilterOperations()); + targetSurface->damageTracker()->updateDamageTrackingState(targetSurface->layerList(), targetSurface->owningLayerId(), false, IntRect(), 0, WebFilterOperations()); FloatRect damageRect = targetSurface->damageTracker()->currentDamageRect(); EXPECT_TRUE(damageRect.isEmpty()); diff --git a/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp index 1d5409f98..827194bbc 100644 --- a/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp @@ -747,4 +747,32 @@ TEST(CCLayerAnimationControllerTest, AbortAGroupedAnimation) EXPECT_EQ(0.75, dummy.opacity()); } +TEST(CCLayerAnimationControllerTest, ForceSyncWhenSynchronizedStartTimeNeeded) +{ + FakeLayerAnimationControllerClient dummyImpl; + OwnPtr<CCLayerAnimationController> controllerImpl(CCLayerAnimationController::create(&dummyImpl)); + OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)); + FakeLayerAnimationControllerClient dummy; + OwnPtr<CCLayerAnimationController> controller( + CCLayerAnimationController::create(&dummy)); + + OwnPtr<CCActiveAnimation> toAdd(createActiveAnimation(adoptPtr(new FakeFloatTransition(2, 0, 1)), 0, CCActiveAnimation::Opacity)); + toAdd->setNeedsSynchronizedStartTime(true); + controller->add(toAdd.release()); + + controller->animate(0, 0); + EXPECT_TRUE(controller->hasActiveAnimation()); + CCActiveAnimation* activeAnimation = controller->getActiveAnimation(0, CCActiveAnimation::Opacity); + EXPECT_TRUE(activeAnimation); + EXPECT_TRUE(activeAnimation->needsSynchronizedStartTime()); + + controller->setForceSync(); + + controller->pushAnimationUpdatesTo(controllerImpl.get()); + + activeAnimation = controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity); + EXPECT_TRUE(activeAnimation); + EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, activeAnimation->runState()); +} + } // namespace diff --git a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp index 36c1082b7..f5259e1cf 100644 --- a/Source/WebKit/chromium/tests/CCLayerImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerImplTest.cpp @@ -29,7 +29,10 @@ #include "cc/CCSingleThreadProxy.h" #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <public/WebFilterOperation.h> +#include <public/WebFilterOperations.h> +using namespace WebKit; using namespace WebCore; namespace { @@ -85,8 +88,8 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly) Color arbitraryColor = Color(10, 20, 30); TransformationMatrix arbitraryTransform; arbitraryTransform.scale3d(0.1, 0.2, 0.3); - FilterOperations arbitraryFilters; - arbitraryFilters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); + WebFilterOperations arbitraryFilters; + arbitraryFilters.append(WebFilterOperation::createOpacityFilter(0.5)); // Changing these properties affects the entire subtree of layers. EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->setAnchorPoint(arbitraryFloatPoint)); diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp index d243aee4a..17e570199 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp @@ -581,6 +581,37 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForTransparentChild) EXPECT_EQ(parent->drawableContentRect(), IntRect()); } +TEST(CCLayerTreeHostCommonTest, verifyForceRenderSurface) +{ + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> renderSurface1 = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent()); + renderSurface1->setForceRenderSurface(true); + + const TransformationMatrix identityMatrix; + setLayerPropertiesForTesting(renderSurface1.get(), identityMatrix, identityMatrix, FloatPoint::zero(), FloatPoint::zero(), IntSize(10, 10), false); + setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, FloatPoint::zero(), FloatPoint::zero(), IntSize(10, 10), false); + + parent->createRenderSurface(); + parent->setClipRect(IntRect(0, 0, 10, 10)); + parent->addChild(renderSurface1); + renderSurface1->addChild(child); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(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); + EXPECT_FALSE(renderSurface1->renderSurface()); + EXPECT_EQ(renderSurfaceLayerList.size(), 0U); +} + TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces) { // The entire subtree of layers that are outside the clipRect should be culled away, @@ -700,6 +731,78 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfacesCrashRepro) EXPECT_EQ(child->id(), renderSurfaceLayerList[1]->id()); } +TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsSurfaceWithoutVisibleContent) +{ + // When a renderSurface has a clipRect, it is used to clip the contentRect + // of the surface. When the renderSurface is animating its transforms, then + // the contentRect's position in the clipRect is not defined on the main + // thread, and its contentRect should not be clipped. + + // The test tree is set up as follows: + // - parent is a container layer that masksToBounds=true to cause clipping. + // - child is a renderSurface, which has a clipRect set to the bounds of the parent. + // - grandChild is a renderSurface, and the only visible content in child. It is positioned outside of the clipRect from parent. + + // In this configuration, grandChild should be outside the clipped + // contentRect of the child, making grandChild not appear in the + // renderSurfaceLayerList. However, when we place an animation on the child, + // this clipping should be avoided and we should keep the grandChild + // in the renderSurfaceLayerList. + + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromium> child = LayerChromium::create(); + RefPtr<LayerChromium> grandChild = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> leafNode = adoptRef(new LayerChromiumWithForcedDrawsContent()); + parent->addChild(child); + child->addChild(grandChild); + grandChild->addChild(leafNode); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(20, 20), false); + setLayerPropertiesForTesting(grandChild.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(200, 200), IntSize(10, 10), false); + setLayerPropertiesForTesting(leafNode.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(10, 10), false); + + parent->setMasksToBounds(true); + child->setOpacity(0.4f); + grandChild->setOpacity(0.4f); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->createRenderSurface(); + renderSurfaceLayerList.append(parent.get()); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(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()); + EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id()); + + // Now put an animating transform on child. + addAnimatedTransformToController(*child->layerAnimationController(), 10, 30, 0); + + parent->clearRenderSurface(); + child->clearRenderSurface(); + grandChild->clearRenderSurface(); + renderSurfaceLayerList.clear(); + dummyLayerList.clear(); + + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + parent->createRenderSurface(); + renderSurfaceLayerList.append(parent.get()); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(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()); + EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id()); + EXPECT_EQ(child->id(), renderSurfaceLayerList[1]->id()); + EXPECT_EQ(grandChild->id(), renderSurfaceLayerList[2]->id()); +} + TEST(CCLayerTreeHostCommonTest, verifyClipRectIsPropagatedCorrectlyToLayers) { // Verify that layers get the appropriate clipRects when their parent masksToBounds is true. @@ -874,8 +977,9 @@ TEST(CCLayerTreeHostCommonTest, verifyAnimationsForRenderSurfaceHierarchy) TransformationMatrix sublayerTransform; sublayerTransform.scale3d(10.0, 1.0, 1.0); - // In combination with descendantDrawsContent, an animated transform forces the layer to have a new renderSurface. + // In combination with descendantDrawsContent and masksToBounds, an animated transform forces the layer to have a new renderSurface. addAnimatedTransformToController(*renderSurface2->layerAnimationController(), 10, 30, 0); + renderSurface2->setMasksToBounds(true); // Also put transform animations on grandChildOfRoot, and grandChildOfRS2 addAnimatedTransformToController(*grandChildOfRoot->layerAnimationController(), 10, 30, 0); @@ -1238,9 +1342,208 @@ TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForPerspectiveUnprojection) EXPECT_INT_RECT_EQ(expected, actual); } -TEST(CCLayerTreeHostCommonTest, verifyBackFaceCulling) +TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithoutPreserves3d) { - // Verify that layers are appropriately culled when their back face is showing and they are not double sided. + // Verify the behavior of back-face culling when there are no preserve-3d layers. Note + // that 3d transforms still apply in this case, but they are "flattened" to each + // parent layer according to current W3C spec. + + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChild = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChild = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChildOfFrontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChildOfFrontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChildOfBackFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChildOfBackFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + + parent->createRenderSurface(); + parent->addChild(frontFacingChild); + parent->addChild(backFacingChild); + parent->addChild(frontFacingSurface); + parent->addChild(backFacingSurface); + frontFacingSurface->addChild(frontFacingChildOfFrontFacingSurface); + frontFacingSurface->addChild(backFacingChildOfFrontFacingSurface); + backFacingSurface->addChild(frontFacingChildOfBackFacingSurface); + backFacingSurface->addChild(backFacingChildOfBackFacingSurface); + + // Nothing is double-sided + frontFacingChild->setDoubleSided(false); + backFacingChild->setDoubleSided(false); + frontFacingSurface->setDoubleSided(false); + backFacingSurface->setDoubleSided(false); + frontFacingChildOfFrontFacingSurface->setDoubleSided(false); + backFacingChildOfFrontFacingSurface->setDoubleSided(false); + frontFacingChildOfBackFacingSurface->setDoubleSided(false); + backFacingChildOfBackFacingSurface->setDoubleSided(false); + + TransformationMatrix backfaceMatrix; + backfaceMatrix.translate(50, 50); + backfaceMatrix.rotate3d(0, 1, 0, 180); + backfaceMatrix.translate(-50, -50); + + // Having a descendant and opacity will force these to have render surfaces. + frontFacingSurface->setOpacity(0.5f); + backFacingSurface->setOpacity(0.5f); + + // Nothing preserves 3d. According to current W3C CSS Transforms spec, these layers + // should blindly use their own local transforms to determine back-face culling. + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingChild.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChild.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingChildOfFrontFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChildOfFrontFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingChildOfBackFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChildOfBackFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + parent->renderSurface()->setContentRect(IntRect(IntPoint(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent.get()); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + // Verify which renderSurfaces were created. + EXPECT_FALSE(frontFacingChild->renderSurface()); + EXPECT_FALSE(backFacingChild->renderSurface()); + EXPECT_TRUE(frontFacingSurface->renderSurface()); + EXPECT_TRUE(backFacingSurface->renderSurface()); + EXPECT_FALSE(frontFacingChildOfFrontFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingChildOfFrontFacingSurface->renderSurface()); + EXPECT_FALSE(frontFacingChildOfBackFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingChildOfBackFacingSurface->renderSurface()); + + // Verify the renderSurfaceLayerList. + ASSERT_EQ(3u, renderSurfaceLayerList.size()); + EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->id()); + // Even though the back facing surface LAYER gets culled, the other descendants should still be added, so the SURFACE should not be culled. + EXPECT_EQ(backFacingSurface->id(), renderSurfaceLayerList[2]->id()); + + // Verify root surface's layerList. + ASSERT_EQ(3u, renderSurfaceLayerList[0]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingChild->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[0]->id()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[1]->id()); + EXPECT_EQ(backFacingSurface->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[2]->id()); + + // Verify frontFacingSurface's layerList. + ASSERT_EQ(2u, renderSurfaceLayerList[1]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[0]->id()); + EXPECT_EQ(frontFacingChildOfFrontFacingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[1]->id()); + + // Verify backFacingSurface's layerList; its own layer should be culled from the surface list. + ASSERT_EQ(1u, renderSurfaceLayerList[2]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingChildOfBackFacingSurface->id(), renderSurfaceLayerList[2]->renderSurface()->layerList()[0]->id()); +} + +TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3d) +{ + // Verify the behavior of back-face culling when preserves-3d transform style is used. + + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChild = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChild = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChildOfFrontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChildOfFrontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingChildOfBackFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingChildOfBackFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> dummyReplicaLayer1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> dummyReplicaLayer2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + + parent->createRenderSurface(); + parent->addChild(frontFacingChild); + parent->addChild(backFacingChild); + parent->addChild(frontFacingSurface); + parent->addChild(backFacingSurface); + frontFacingSurface->addChild(frontFacingChildOfFrontFacingSurface); + frontFacingSurface->addChild(backFacingChildOfFrontFacingSurface); + backFacingSurface->addChild(frontFacingChildOfBackFacingSurface); + backFacingSurface->addChild(backFacingChildOfBackFacingSurface); + + // Nothing is double-sided + frontFacingChild->setDoubleSided(false); + backFacingChild->setDoubleSided(false); + frontFacingSurface->setDoubleSided(false); + backFacingSurface->setDoubleSided(false); + frontFacingChildOfFrontFacingSurface->setDoubleSided(false); + backFacingChildOfFrontFacingSurface->setDoubleSided(false); + frontFacingChildOfBackFacingSurface->setDoubleSided(false); + backFacingChildOfBackFacingSurface->setDoubleSided(false); + + TransformationMatrix backfaceMatrix; + backfaceMatrix.translate(50, 50); + backfaceMatrix.rotate3d(0, 1, 0, 180); + backfaceMatrix.translate(-50, -50); + + // Opacity will not force creation of renderSurfaces in this case because of the + // preserve-3d transform style. Instead, an example of when a surface would be + // created with preserve-3d is when there is a replica layer. + frontFacingSurface->setReplicaLayer(dummyReplicaLayer1.get()); + backFacingSurface->setReplicaLayer(dummyReplicaLayer2.get()); + + // Each surface creates its own new 3d rendering context (as defined by W3C spec). + // According to current W3C CSS Transforms spec, layers in a 3d rendering context + // should use the transform with respect to that context. This 3d rendering context + // occurs when (a) parent's transform style is flat and (b) the layer's transform + // style is preserve-3d. + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); // parent transform style is flat. + setLayerPropertiesForTesting(frontFacingChild.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChild.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); // surface transform style is preserve-3d. + setLayerPropertiesForTesting(backFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); // surface transform style is preserve-3d. + setLayerPropertiesForTesting(frontFacingChildOfFrontFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChildOfFrontFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(frontFacingChildOfBackFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(backFacingChildOfBackFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + parent->renderSurface()->setContentRect(IntRect(IntPoint(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent.get()); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + // Verify which renderSurfaces were created. + EXPECT_FALSE(frontFacingChild->renderSurface()); + EXPECT_FALSE(backFacingChild->renderSurface()); + EXPECT_TRUE(frontFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingSurface->renderSurface()); + EXPECT_FALSE(frontFacingChildOfFrontFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingChildOfFrontFacingSurface->renderSurface()); + EXPECT_FALSE(frontFacingChildOfBackFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingChildOfBackFacingSurface->renderSurface()); + + // Verify the renderSurfaceLayerList. The back-facing surface should be culled. + ASSERT_EQ(2u, renderSurfaceLayerList.size()); + EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->id()); + + // Verify root surface's layerList. + ASSERT_EQ(2u, renderSurfaceLayerList[0]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingChild->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[0]->id()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[1]->id()); + + // Verify frontFacingSurface's layerList. + ASSERT_EQ(2u, renderSurfaceLayerList[1]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[0]->id()); + EXPECT_EQ(frontFacingChildOfFrontFacingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[1]->id()); +} + +TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithAnimatingTransforms) +{ + // Verify that layers are appropriately culled when their back face is showing and + // they are not double sided, while animations are going on. // // Layers that are animating do not get culled on the main thread, as their transforms should be // treated as "unknown" so we can not be sure that their back face is really showing. @@ -1273,15 +1576,16 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCulling) backfaceMatrix.rotate3d(0, 1, 0, 180); backfaceMatrix.translate(-50, -50); - // Having a descendent, and animating transforms, will make the animatingSurface own a render surface. + // Having a descendant that draws, masksToBounds, and animating transforms, will make the animatingSurface own a render surface. addAnimatedTransformToController(*animatingSurface->layerAnimationController(), 10, 30, 0); + animatingSurface->setMasksToBounds(true); // This is just an animating layer, not a surface. addAnimatedTransformToController(*animatingChild->layerAnimationController(), 10, 30, 0); - setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); setLayerPropertiesForTesting(child.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); setLayerPropertiesForTesting(animatingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); - setLayerPropertiesForTesting(childOfAnimatingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(childOfAnimatingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); setLayerPropertiesForTesting(animatingChild.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); @@ -1318,11 +1622,74 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCulling) EXPECT_FALSE(child2->visibleLayerRect().isEmpty()); - // But if the back face is visible, then the visibleLayerRect should be empty. - EXPECT_TRUE(animatingChild->visibleLayerRect().isEmpty()); - EXPECT_TRUE(animatingSurface->visibleLayerRect().isEmpty()); - // And any layers in the subtree should not be considered visible either. - EXPECT_TRUE(childOfAnimatingSurface->visibleLayerRect().isEmpty()); + // The animating layers should have a visibleLayerRect that represents the area of the front face that is within the viewport. + EXPECT_EQ(animatingChild->visibleLayerRect(), IntRect(IntPoint(), animatingChild->contentBounds())); + EXPECT_EQ(animatingSurface->visibleLayerRect(), IntRect(IntPoint(), animatingSurface->contentBounds())); + // And layers in the subtree of the animating layer should have valid visibleLayerRects also. + EXPECT_EQ(childOfAnimatingSurface->visibleLayerRect(), IntRect(IntPoint(), childOfAnimatingSurface->contentBounds())); +} + +TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3dForFlatteningSurface) +{ + // Verify the behavior of back-face culling for a renderSurface that is created + // when it flattens its subtree, and its parent has preserves-3d. + + const TransformationMatrix identityMatrix; + RefPtr<LayerChromium> parent = LayerChromium::create(); + RefPtr<LayerChromiumWithForcedDrawsContent> frontFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> backFacingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> child1 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + RefPtr<LayerChromiumWithForcedDrawsContent> child2 = adoptRef(new LayerChromiumWithForcedDrawsContent()); + + parent->createRenderSurface(); + parent->addChild(frontFacingSurface); + parent->addChild(backFacingSurface); + frontFacingSurface->addChild(child1); + backFacingSurface->addChild(child2); + + // RenderSurfaces are not double-sided + frontFacingSurface->setDoubleSided(false); + backFacingSurface->setDoubleSided(false); + + TransformationMatrix backfaceMatrix; + backfaceMatrix.translate(50, 50); + backfaceMatrix.rotate3d(0, 1, 0, 180); + backfaceMatrix.translate(-50, -50); + + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true); // parent transform style is preserve3d. + setLayerPropertiesForTesting(frontFacingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); // surface transform style is flat. + setLayerPropertiesForTesting(backFacingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); // surface transform style is flat. + setLayerPropertiesForTesting(child1.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false); + + Vector<RefPtr<LayerChromium> > renderSurfaceLayerList; + Vector<RefPtr<LayerChromium> > dummyLayerList; + int dummyMaxTextureSize = 512; + parent->renderSurface()->setContentRect(IntRect(IntPoint(), parent->bounds())); + parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds())); + renderSurfaceLayerList.append(parent.get()); + + CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize); + + // Verify which renderSurfaces were created. + EXPECT_TRUE(frontFacingSurface->renderSurface()); + EXPECT_FALSE(backFacingSurface->renderSurface()); // because it should be culled + EXPECT_FALSE(child1->renderSurface()); + EXPECT_FALSE(child2->renderSurface()); + + // Verify the renderSurfaceLayerList. The back-facing surface should be culled. + ASSERT_EQ(2u, renderSurfaceLayerList.size()); + EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->id()); + + // Verify root surface's layerList. + ASSERT_EQ(1u, renderSurfaceLayerList[0]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[0]->id()); + + // Verify frontFacingSurface's layerList. + ASSERT_EQ(2u, renderSurfaceLayerList[1]->renderSurface()->layerList().size()); + EXPECT_EQ(frontFacingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[0]->id()); + EXPECT_EQ(child1->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[1]->id()); } // FIXME: diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp index 77a3b8264..9e28a5b82 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp @@ -31,7 +31,6 @@ #include "CCTiledLayerTestCommon.h" #include "CompositorFakeWebGraphicsContext3D.h" #include "ContentLayerChromium.h" -#include "FilterOperations.h" #include "GraphicsContext3DPrivate.h" #include "LayerChromium.h" #include "TextureManager.h" @@ -49,8 +48,12 @@ #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> using namespace WebCore; @@ -79,7 +82,9 @@ public: virtual void updateAnimations(double monotonicTime) { } virtual void layout() { } virtual void didRecreateContext(bool succeded) { } + virtual void didCommit() { } virtual void didCommitAndDrawFrame() { } + virtual void scheduleComposite() { } // Implementation of CCLayerAnimationDelegate virtual void notifyAnimationStarted(double time) { } @@ -131,6 +136,11 @@ protected: 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) @@ -239,6 +249,10 @@ public: { } + virtual void didBeginFrame() OVERRIDE + { + } + virtual void updateAnimations(double monotonicTime) OVERRIDE { m_testHooks->updateAnimations(monotonicTime); @@ -264,8 +278,13 @@ public: return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow); } + virtual void willCommit() OVERRIDE + { + } + virtual void didCommit() OVERRIDE { + m_testHooks->didCommit(); } virtual void didCommitAndDrawFrame() OVERRIDE @@ -284,6 +303,7 @@ public: virtual void scheduleComposite() OVERRIDE { + m_testHooks->scheduleComposite(); } private: @@ -367,10 +387,22 @@ protected: CCLayerTreeHostTest() : m_beginning(false) , m_endWhenBeginReturns(false) - , m_timedOut(false) { } + , m_timedOut(false) + , m_finished(false) + , m_scheduled(false) + , m_started(false) + { } 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()); @@ -380,8 +412,12 @@ protected: 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(); } @@ -389,8 +425,12 @@ protected: 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); } @@ -398,8 +438,12 @@ protected: 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); } @@ -407,8 +451,12 @@ protected: 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(); @@ -418,26 +466,38 @@ protected: 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_layerTreeHost) - test->m_layerTreeHost->acquireLayerTextures(); + 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(); } @@ -445,8 +505,12 @@ protected: 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); } @@ -454,12 +518,26 @@ protected: 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) @@ -547,6 +625,9 @@ 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; @@ -565,6 +646,7 @@ void CCLayerTreeHostTest::doBeginTest() rootLayer->setLayerTreeHost(m_layerTreeHost.get()); m_layerTreeHost->setSurfaceReady(); + m_started = true; m_beginning = true; beginTest(); m_beginning = false; @@ -574,6 +656,8 @@ void CCLayerTreeHostTest::doBeginTest() 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)); @@ -856,7 +940,6 @@ TEST_F(CCLayerTreeHostTestSetNeedsRedraw, runMultiThread) } // If the layerTreeHost says it can't draw, then we should not try to draw. -// FIXME: Make this run in single threaded mode too. http://crbug.com/127481 class CCLayerTreeHostTestCanDrawBlocksDrawing : public CCLayerTreeHostTestThreadOnly { public: CCLayerTreeHostTestCanDrawBlocksDrawing() @@ -866,6 +949,7 @@ public: virtual void beginTest() { + postSetNeedsCommitToMainThread(); } virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) @@ -883,7 +967,7 @@ public: } } - virtual void didCommitAndDrawFrame() + virtual void didCommit() { m_numCommits++; if (m_numCommits == 1) { @@ -893,10 +977,10 @@ public: OwnArrayPtr<char> pixels(adoptArrayPtr(new char[4])); m_layerTreeHost->compositeAndReadback(static_cast<void*>(pixels.get()), IntRect(0, 0, 1, 1)); } else if (m_numCommits == 2) { + m_layerTreeHost->setNeedsRedraw(); m_layerTreeHost->setNeedsCommit(); - m_layerTreeHost->finishAllRendering(); + } else endTest(); - } } virtual void afterTest() @@ -907,10 +991,7 @@ private: int m_numCommits; }; -TEST_F(CCLayerTreeHostTestCanDrawBlocksDrawing, runMultiThread) -{ - runTestThreaded(); -} +SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestCanDrawBlocksDrawing) // beginLayerWrite should prevent draws from executing until a commit occurs class CCLayerTreeHostTestWriteLayersRedraw : public CCLayerTreeHostTestThreadOnly { @@ -930,8 +1011,8 @@ public: virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) { - EXPECT_EQ(1, impl->sourceFrameNumber()); m_numDraws++; + EXPECT_EQ(m_numDraws, m_numCommits); } virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*) @@ -942,7 +1023,6 @@ public: virtual void afterTest() { - EXPECT_EQ(0, m_numDraws); EXPECT_EQ(1, m_numCommits); } @@ -1148,7 +1228,10 @@ public: postAddAnimationToMainThread(); } - virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime) + // Use willAnimateLayers to set visible false before the animation runs and + // causes a commit, so we block the second visible animate in single-thread + // mode. + virtual void willAnimateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime) { if (m_numAnimates < 2) { if (!m_numAnimates) { @@ -1185,7 +1268,10 @@ public: virtual void animateLayers(CCLayerTreeHostImpl* layerTreeHostImpl, double monotonicTime) { - const CCFloatAnimationCurve* curve = m_layerTreeHost->rootLayer()->layerAnimationController()->getActiveAnimation(0, CCActiveAnimation::Opacity)->curve()->toFloatAnimationCurve(); + const CCActiveAnimation* animation = m_layerTreeHost->rootLayer()->layerAnimationController()->getActiveAnimation(0, CCActiveAnimation::Opacity); + if (!animation) + return; + const CCFloatAnimationCurve* curve = animation->curve()->toFloatAnimationCurve(); float startOpacity = curve->getValue(0); float endOpacity = curve->getValue(curve->duration()); float linearlyInterpolatedOpacity = 0.25 * endOpacity + 0.75 * startOpacity; @@ -1353,11 +1439,11 @@ public: root->setMaxScrollPosition(IntSize(100, 100)); root->scrollBy(m_scrollAmount); - if (impl->frameNumber() == 1) { + if (!impl->sourceFrameNumber()) { EXPECT_EQ(root->scrollPosition(), m_initialScroll); EXPECT_EQ(root->scrollDelta(), m_scrollAmount); postSetNeedsCommitToMainThread(); - } else if (impl->frameNumber() == 2) { + } else if (impl->sourceFrameNumber() == 1) { EXPECT_EQ(root->scrollPosition(), m_secondScroll); EXPECT_EQ(root->scrollDelta(), m_scrollAmount); endTest(); @@ -1420,21 +1506,25 @@ public: root->setScrollable(true); root->setMaxScrollPosition(IntSize(100, 100)); - if (impl->frameNumber() == 1) { + if (!impl->sourceFrameNumber() && impl->frameNumber() == 1) { + // First draw after first commit. EXPECT_EQ(root->scrollDelta(), IntSize()); root->scrollBy(m_scrollAmount); EXPECT_EQ(root->scrollDelta(), m_scrollAmount); EXPECT_EQ(root->scrollPosition(), m_initialScroll); postSetNeedsRedrawToMainThread(); - } else if (impl->frameNumber() == 2) { + } else if (!impl->sourceFrameNumber() && impl->frameNumber() == 2) { + // Second draw after first commit. EXPECT_EQ(root->scrollDelta(), m_scrollAmount); root->scrollBy(m_scrollAmount); EXPECT_EQ(root->scrollDelta(), m_scrollAmount + m_scrollAmount); EXPECT_EQ(root->scrollPosition(), m_initialScroll); postSetNeedsCommitToMainThread(); - } else if (impl->frameNumber() == 3) { + } else if (impl->sourceFrameNumber() == 1) { + // Third or later draw after second commit. + EXPECT_GE(impl->frameNumber(), 3); EXPECT_EQ(root->scrollDelta(), IntSize()); EXPECT_EQ(root->scrollPosition(), m_initialScroll + m_scrollAmount + m_scrollAmount); endTest(); @@ -1495,6 +1585,113 @@ TEST_F(CCLayerTreeHostTestCommit, runTest) runTest(true); } +class CCLayerTreeHostTestVisibilityAndAllocationControlDrawing : public CCLayerTreeHostTest { +public: + + CCLayerTreeHostTestVisibilityAndAllocationControlDrawing() { } + + virtual void beginTest() + { + postSetNeedsCommitToMainThread(); + } + + virtual void didCommitAndDrawFrame() + { + int lastFrame = m_layerTreeHost->frameNumber() - 1; + + // These frames should draw. + switch (lastFrame) { + case 0: + // Set the tree invisible, this should not draw. + m_layerTreeHost->setVisible(false); + break; + case 2: + // Set the tree invisible and give a non-visible allocation, this + // should not draw. + m_layerTreeHost->setVisible(false); + m_layerTreeHost->setContentsMemoryAllocationLimitBytes(0); + break; + case 5: + // Give a memory allocation not for display, but while we are + // visible. This should not be used and we should remain + // ready for display and it should draw. + m_layerTreeHost->setContentsMemoryAllocationLimitBytes(0); + break; + case 6: + endTest(); + break; + + default: + ASSERT_NOT_REACHED(); + } + } + + virtual void didCommit() + { + int lastFrame = m_layerTreeHost->frameNumber() - 1; + + // These frames should not draw. + switch (lastFrame) { + case 1: + // Set the tree visible, this should draw. + m_layerTreeHost->setVisible(true); + break; + case 3: + // Set visible without giving a visible memory allocation, this + // shouldn't make the impl side ready for display, so it should + // not draw. + m_layerTreeHost->setVisible(true); + break; + case 4: + // Now give a memory allocation for display, this should draw. + m_layerTreeHost->setContentsMemoryAllocationLimitBytes(1); + break; + } + } + + virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl) + { + switch (impl->sourceFrameNumber()) { + case 0: + // The host starts out visible and able to display before we do any commit. + EXPECT_TRUE(impl->visible()); + EXPECT_TRUE(impl->sourceFrameCanBeDrawn()); + break; + case 1: + // We still have a memory allocation for display. + EXPECT_FALSE(impl->visible()); + EXPECT_TRUE(impl->sourceFrameCanBeDrawn()); + break; + case 2: + EXPECT_TRUE(impl->visible()); + EXPECT_TRUE(impl->sourceFrameCanBeDrawn()); + break; + case 3: + EXPECT_FALSE(impl->visible()); + EXPECT_FALSE(impl->sourceFrameCanBeDrawn()); + break; + case 4: + EXPECT_TRUE(impl->visible()); + EXPECT_FALSE(impl->sourceFrameCanBeDrawn()); + break; + case 5: + EXPECT_TRUE(impl->visible()); + EXPECT_TRUE(impl->sourceFrameCanBeDrawn()); + break; + case 6: + EXPECT_TRUE(impl->visible()); + EXPECT_TRUE(impl->sourceFrameCanBeDrawn()); + break; + } + } + + virtual void afterTest() + { + } +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestVisibilityAndAllocationControlDrawing) + // Verifies that startPageScaleAnimation events propagate correctly from CCLayerTreeHost to // CCLayerTreeHostImpl in the MT compositor. class CCLayerTreeHostTestStartPageScaleAnimation : public CCLayerTreeHostTest { @@ -1542,9 +1739,8 @@ public: virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl* impl) { impl->processScrollDeltas(); - // We get one commit before the first draw, and the animation doesn't happen until the second draw, - // so results available on the third commit. - if (impl->frameNumber() == 2) { + // We get one commit before the first draw, and the animation doesn't happen until the second draw. + if (impl->sourceFrameNumber() == 1) { EXPECT_EQ(1.25, impl->pageScale()); endTest(); } else @@ -1699,53 +1895,6 @@ TEST_F(CCLayerTreeHostTestOpacityChange, runMultiThread) runTest(true); } -class CCLayerTreeHostTestSetViewportSize : public CCLayerTreeHostTest { -public: - - CCLayerTreeHostTestSetViewportSize() - : m_numCommits(0) - , m_numDraws(0) - { - } - - virtual void beginTest() - { - IntSize viewportSize(10, 10); - layerTreeHost()->setViewportSize(viewportSize); - - CCTextureUpdater updater; - layerTreeHost()->updateLayers(updater); - - EXPECT_EQ(viewportSize, layerTreeHost()->viewportSize()); - EXPECT_EQ(TextureManager::highLimitBytes(viewportSize), layerTreeHost()->contentsTextureManager()->maxMemoryLimitBytes()); - EXPECT_EQ(TextureManager::reclaimLimitBytes(viewportSize), layerTreeHost()->contentsTextureManager()->preferredMemoryLimitBytes()); - - // setViewportSize() should not call TextureManager::setMaxMemoryLimitBytes() or TextureManager::setPreferredMemoryLimitBytes() - // if the viewport size is not changed. - IntSize fakeSize(5, 5); - layerTreeHost()->contentsTextureManager()->setMaxMemoryLimitBytes(TextureManager::highLimitBytes(fakeSize)); - layerTreeHost()->contentsTextureManager()->setPreferredMemoryLimitBytes(TextureManager::reclaimLimitBytes(fakeSize)); - layerTreeHost()->setViewportSize(viewportSize); - EXPECT_EQ(TextureManager::highLimitBytes(fakeSize), layerTreeHost()->contentsTextureManager()->maxMemoryLimitBytes()); - EXPECT_EQ(TextureManager::reclaimLimitBytes(fakeSize), layerTreeHost()->contentsTextureManager()->preferredMemoryLimitBytes()); - - endTest(); - } - - virtual void afterTest() - { - } - -private: - int m_numCommits; - int m_numDraws; -}; - -TEST_F(CCLayerTreeHostTestSetViewportSize, runSingleThread) -{ - runTest(false); -} - class MockContentLayerDelegate : public ContentLayerDelegate { public: bool drawsContent() const { return true; } @@ -2373,8 +2522,8 @@ public: setTestLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); { - FilterOperations filters; - filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createOpacityFilter(0.5)); child->setFilters(filters); } @@ -2401,8 +2550,8 @@ public: setTestLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true); { - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Percent), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(10)); child->setFilters(filters); } @@ -2580,15 +2729,15 @@ public: root->setMaxScrollPosition(IntSize(100, 100)); // Check that a fractional scroll delta is correctly accumulated over multiple commits. - if (impl->frameNumber() == 1) { + if (!impl->sourceFrameNumber()) { EXPECT_EQ(root->scrollPosition(), IntPoint(0, 0)); EXPECT_EQ(root->scrollDelta(), FloatSize(0, 0)); postSetNeedsCommitToMainThread(); - } else if (impl->frameNumber() == 2) { + } else if (impl->sourceFrameNumber() == 1) { EXPECT_EQ(root->scrollPosition(), flooredIntPoint(m_scrollAmount)); EXPECT_EQ(root->scrollDelta(), FloatSize(fmod(m_scrollAmount.width(), 1), 0)); postSetNeedsCommitToMainThread(); - } else if (impl->frameNumber() == 3) { + } else if (impl->sourceFrameNumber() == 2) { EXPECT_EQ(root->scrollPosition(), flooredIntPoint(m_scrollAmount + m_scrollAmount)); EXPECT_EQ(root->scrollDelta(), FloatSize(fmod(2 * m_scrollAmount.width(), 1), 0)); endTest(); @@ -2614,4 +2763,55 @@ TEST_F(CCLayerTreeHostTestFractionalScroll, runMultiThread) runTestThreaded(); } +class CCLayerTreeHostTestFinishAllRendering : public CCLayerTreeHostTest { +public: + CCLayerTreeHostTestFinishAllRendering() + : m_once(false) + , m_mutex() + , m_drawCount(0) + { + } + + virtual void beginTest() + { + m_layerTreeHost->setNeedsRedraw(); + } + + virtual void didCommitAndDrawFrame() + { + if (m_once) + return; + m_once = true; + m_layerTreeHost->setNeedsRedraw(); + m_layerTreeHost->acquireLayerTextures(); + { + Locker<Mutex> lock(m_mutex); + m_drawCount = 0; + } + m_layerTreeHost->finishAllRendering(); + { + Locker<Mutex> lock(m_mutex); + EXPECT_EQ(0, m_drawCount); + } + endTest(); + } + + virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl) + { + Locker<Mutex> lock(m_mutex); + ++m_drawCount; + } + + virtual void afterTest() + { + } +private: + + bool m_once; + Mutex m_mutex; + int m_drawCount; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestFinishAllRendering) + } // namespace diff --git a/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp index 891c305b0..976dc3f29 100644 --- a/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp +++ b/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp @@ -28,7 +28,6 @@ #include "CCAnimationTestCommon.h" #include "CCOcclusionTrackerTestCommon.h" -#include "FilterOperations.h" #include "LayerChromium.h" #include "Region.h" #include "TransformationMatrix.h" @@ -37,11 +36,13 @@ #include "cc/CCLayerImpl.h" #include "cc/CCLayerTreeHostCommon.h" #include "cc/CCSingleThreadProxy.h" - #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <public/WebFilterOperation.h> +#include <public/WebFilterOperations.h> using namespace WebCore; +using namespace WebKit; using namespace WebKitTests; #define EXPECT_EQ_RECT(a, b) \ @@ -199,8 +200,8 @@ protected: typename Types::LayerType* createSurface(typename Types::LayerType* parent, const TransformationMatrix& transform, const FloatPoint& position, const IntSize& bounds) { typename Types::LayerType* layer = createLayer(parent, transform, position, bounds); - FilterOperations filters; - filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createGrayscaleFilter(0.5)); layer->setFilters(filters); return layer; } @@ -246,8 +247,8 @@ protected: typename Types::ContentLayerType* createDrawingSurface(typename Types::LayerType* parent, const TransformationMatrix& transform, const FloatPoint& position, const IntSize& bounds, bool opaque) { typename Types::ContentLayerType* layer = createDrawingLayer(parent, transform, position, bounds, opaque); - FilterOperations filters; - filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createGrayscaleFilter(0.5)); layer->setFilters(filters); return layer; } @@ -1221,16 +1222,16 @@ protected: typename Types::ContentLayerType* opaqueLayer = this->createDrawingLayer(parent, layerTransform, FloatPoint(30, 30), IntSize(500, 500), true); typename Types::ContentLayerType* opacityLayer = this->createDrawingLayer(parent, layerTransform, FloatPoint(30, 30), IntSize(500, 500), true); - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Percent), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(10)); blurLayer->setFilters(filters); - filters.operations().clear(); - filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE)); + filters.clear(); + filters.append(WebFilterOperation::createGrayscaleFilter(0.5)); opaqueLayer->setFilters(filters); - filters.operations().clear(); - filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY)); + filters.clear(); + filters.append(WebFilterOperation::createOpacityFilter(0.5)); opacityLayer->setFilters(filters); this->calcDrawEtc(parent); @@ -2495,8 +2496,8 @@ protected: typename Types::LayerType* occludingLayer5 = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(250, 50), IntSize(50, 50), true); // Filters make the layer own a surface. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(10)); filteredSurface->setBackgroundFilters(filters); // Save the distance of influence for the blur effect. @@ -2616,8 +2617,8 @@ protected: typename Types::LayerType* occludingLayerAbove = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(100, 100), IntSize(50, 50), true); // Filters make the layers own surfaces. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(3, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(3)); filteredSurface1->setBackgroundFilters(filters); filteredSurface2->setBackgroundFilters(filters); @@ -2681,8 +2682,8 @@ protected: typename Types::LayerType* occludingLayer5 = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(250, 50), IntSize(50, 50), true); // Filters make the layer own a surface. This filter is large enough that it goes outside the bottom of the clippingSurface. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(12, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(12)); filteredSurface->setBackgroundFilters(filters); // Save the distance of influence for the blur effect. @@ -2804,8 +2805,8 @@ protected: this->createReplicaLayer(filteredSurface, this->identityMatrix, FloatPoint(300, 0), IntSize()); // Filters make the layer own a surface. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(3, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(3)); filteredSurface->setBackgroundFilters(filters); this->calcDrawEtc(parent); @@ -2853,8 +2854,8 @@ protected: typename Types::LayerType* aboveReplicaLayer = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(200, 50), IntSize(50, 50), true); // Filters make the layer own a surface. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(3, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(3)); filteredSurface->setBackgroundFilters(filters); this->calcDrawEtc(parent); @@ -2903,8 +2904,8 @@ protected: typename Types::LayerType* besideReplicaLayer = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(200, 40), IntSize(10, 10), true); // Filters make the layer own a surface. - FilterOperations filters; - filters.operations().append(BlurFilterOperation::create(Length(3, WebCore::Fixed), FilterOperation::BLUR)); + WebFilterOperations filters; + filters.append(WebFilterOperation::createBlurFilter(3)); filteredSurface->setBackgroundFilters(filters); // Save the distance of influence for the blur effect. diff --git a/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h index 513fd0cbc..992509c4f 100755 --- a/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h +++ b/Source/WebKit/chromium/tests/FakeCCLayerTreeHostClient.h @@ -35,6 +35,7 @@ namespace WebCore { class FakeCCLayerTreeHostClient : public CCLayerTreeHostClient { public: virtual void willBeginFrame() OVERRIDE { } + virtual void didBeginFrame() OVERRIDE { } virtual void updateAnimations(double monotonicFrameBeginTime) OVERRIDE { } virtual void layout() OVERRIDE { } virtual void applyScrollAndScale(const IntSize& scrollDelta, float pageScale) OVERRIDE { } @@ -44,6 +45,7 @@ public: 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 { } diff --git a/Source/WebKit/chromium/tests/FilterOperationsTest.cpp b/Source/WebKit/chromium/tests/FilterOperationsTest.cpp new file mode 100644 index 000000000..8a3c5d8a1 --- /dev/null +++ b/Source/WebKit/chromium/tests/FilterOperationsTest.cpp @@ -0,0 +1,93 @@ +/* + * 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 "FilterOperations.h" + +#include <gtest/gtest.h> +#include <public/WebFilterOperation.h> +#include <public/WebFilterOperations.h> + +using namespace WebCore; +using namespace WebKit; + +namespace { + +TEST(FilterOperationsTest, getOutsetsBlur) +{ + FilterOperations ops; + ops.operations().append(BlurFilterOperation::create(Length(20.0, WebCore::Fixed), FilterOperation::BLUR)); + EXPECT_TRUE(ops.hasOutsets()); + int top, right, bottom, left; + top = right = bottom = left = 0; + ops.getOutsets(top, right, bottom, left); + EXPECT_EQ(57, top); + EXPECT_EQ(57, right); + EXPECT_EQ(57, bottom); + EXPECT_EQ(57, left); +} + +TEST(FilterOperationsTest, getOutsetsDropShadow) +{ + FilterOperations ops; + ops.operations().append(DropShadowFilterOperation::create(IntPoint(3, 8), 20, Color(1, 2, 3), FilterOperation::DROP_SHADOW)); + EXPECT_TRUE(ops.hasOutsets()); + int top, right, bottom, left; + top = right = bottom = left = 0; + ops.getOutsets(top, right, bottom, left); + EXPECT_EQ(49, top); + EXPECT_EQ(60, right); + EXPECT_EQ(65, bottom); + EXPECT_EQ(54, left); +} + +TEST(WebFilterOperationsTest, getOutsetsBlur) +{ + WebFilterOperations ops; + ops.append(WebFilterOperation::createBlurFilter(20)); + int top, right, bottom, left; + top = right = bottom = left = 0; + ops.getOutsets(top, right, bottom, left); + EXPECT_EQ(57, top); + EXPECT_EQ(57, right); + EXPECT_EQ(57, bottom); + EXPECT_EQ(57, left); +} + +TEST(WebFilterOperationsTest, getOutsetsDropShadow) +{ + WebFilterOperations ops; + ops.append(WebFilterOperation::createDropShadowFilter(WebPoint(3, 8), 20, 0)); + int top, right, bottom, left; + top = right = bottom = left = 0; + ops.getOutsets(top, right, bottom, left); + EXPECT_EQ(49, top); + EXPECT_EQ(60, right); + EXPECT_EQ(65, bottom); + EXPECT_EQ(54, left); +} + +} + diff --git a/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp index 39ad32621..b7aa85746 100644 --- a/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/GraphicsLayerChromiumTest.cpp @@ -28,6 +28,7 @@ #include "CCAnimationTestCommon.h" #include "GraphicsLayer.h" +#include "LayerChromium.h" #include <gtest/gtest.h> #include <wtf/PassOwnPtr.h> diff --git a/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp b/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp new file mode 100644 index 000000000..6c78aa53c --- /dev/null +++ b/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp @@ -0,0 +1,107 @@ +/* + * 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 "IDBFactoryBackendImpl.h" +#include "IDBFakeBackingStore.h" +#include "SecurityOrigin.h" +#include <gtest/gtest.h> +#include <wtf/Vector.h> + +#if ENABLE(INDEXED_DATABASE) + +using namespace WebCore; + +namespace { + +class MockIDBCallbacks : public IDBCallbacks { +public: + MockIDBCallbacks() : m_wasErrorCalled(false) { } + + virtual ~MockIDBCallbacks() + { + EXPECT_TRUE(m_wasErrorCalled); + } + virtual void onError(PassRefPtr<IDBDatabaseError>) + { + m_wasErrorCalled = true; + } + virtual void onSuccess(PassRefPtr<DOMStringList>) { } + virtual void onSuccess(PassRefPtr<IDBCursorBackendInterface>) { } + virtual void onSuccess(PassRefPtr<IDBDatabaseBackendInterface>) + { + EXPECT_TRUE(false); + } + virtual void onSuccess(PassRefPtr<IDBKey>) { } + virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>) { } + virtual void onSuccess(PassRefPtr<SerializedScriptValue>) { } + virtual void onSuccessWithContinuation() { } + virtual void onSuccessWithPrefetch(const Vector<RefPtr<IDBKey> >&, const Vector<RefPtr<IDBKey> >&, const Vector<RefPtr<SerializedScriptValue> >&) { } + virtual void onBlocked() { } +private: + bool m_wasErrorCalled; +}; + +class FailingBackingStore : public IDBFakeBackingStore { +public: + virtual ~FailingBackingStore() { } + static PassRefPtr<IDBBackingStore> open() + { + return adoptRef(new FailingBackingStore); + } + virtual bool createIDBDatabaseMetaData(const String&, const String&, int64_t&) + { + return false; + } +}; + +class FailingIDBFactoryBackendImpl : public IDBFactoryBackendImpl { +public: + virtual ~FailingIDBFactoryBackendImpl() { } + static PassRefPtr<FailingIDBFactoryBackendImpl> create() + { + return adoptRef(new FailingIDBFactoryBackendImpl); + } + virtual void removeIDBDatabaseBackend(const WTF::String &) { } + +protected: + virtual PassRefPtr<IDBBackingStore> openBackingStore(PassRefPtr<SecurityOrigin> prpOrigin, const String& dataDir) + { + return FailingBackingStore::open(); + } +}; + +TEST(IDBAbortTest, TheTest) +{ + RefPtr<IDBFactoryBackendImpl> factory = FailingIDBFactoryBackendImpl::create(); + const String& name = "db name"; + MockIDBCallbacks callbacks; + RefPtr<SecurityOrigin> origin = SecurityOrigin::create("http", "localhost", 81); + factory->open(name, &callbacks, origin, 0 /*Frame*/, String() /*path*/); +} + +} // namespace + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp b/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp index d60295a5f..c1351850d 100644 --- a/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp +++ b/Source/WebKit/chromium/tests/IDBBindingUtilitiesTest.cpp @@ -41,10 +41,8 @@ namespace { PassRefPtr<IDBKey> checkKeyFromValueAndKeyPathInternal(SerializedScriptValue* value, const String& keyPath) { - Vector<String> idbKeyPath; - IDBKeyPathParseError parseError; - IDBParseKeyPath(keyPath, idbKeyPath, parseError); - EXPECT_EQ(IDBKeyPathParseErrorNone, parseError); + IDBKeyPath idbKeyPath(keyPath); + EXPECT_TRUE(idbKeyPath.isValid()); return createIDBKeyFromSerializedValueAndKeyPath(value, idbKeyPath); } @@ -56,10 +54,8 @@ void checkKeyPathNullValue(SerializedScriptValue* value, const String& keyPath) PassRefPtr<SerializedScriptValue> injectKey(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath) { - Vector<String> idbKeyPath; - IDBKeyPathParseError parseError; - IDBParseKeyPath(keyPath, idbKeyPath, parseError); - EXPECT_EQ(IDBKeyPathParseErrorNone, parseError); + IDBKeyPath idbKeyPath(keyPath); + EXPECT_TRUE(idbKeyPath.isValid()); return injectIDBKeyIntoSerializedValue(key, value, idbKeyPath); } diff --git a/Source/WebKit/chromium/tests/IDBFakeBackingStore.h b/Source/WebKit/chromium/tests/IDBFakeBackingStore.h new file mode 100644 index 000000000..ed894cb19 --- /dev/null +++ b/Source/WebKit/chromium/tests/IDBFakeBackingStore.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBFakeBackingStore_h +#define IDBFakeBackingStore_h + +#include "IDBBackingStore.h" + +namespace WebCore { + +class IDBFakeBackingStore : public IDBBackingStore { +public: + virtual void getDatabaseNames(Vector<String>& foundNames) OVERRIDE { } + virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) OVERRIDE { return false; } + virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId) OVERRIDE { return true; } + virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version) OVERRIDE { return false; } + virtual bool deleteDatabase(const String& name) OVERRIDE { return false; } + + virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<IDBKeyPath>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) OVERRIDE { } + virtual bool createObjectStore(int64_t databaseId, const String& name, const IDBKeyPath& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId) OVERRIDE { return false; } + virtual void deleteObjectStore(int64_t databaseId, int64_t objectStoreId) OVERRIDE { } + + virtual PassRefPtr<ObjectStoreRecordIdentifier> createInvalidRecordIdentifier() OVERRIDE { return PassRefPtr<ObjectStoreRecordIdentifier>(); } + + virtual String getObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey&) OVERRIDE { return String(); } + virtual bool putObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey&, const String& value, ObjectStoreRecordIdentifier*) OVERRIDE { return false; } + virtual void clearObjectStore(int64_t databaseId, int64_t objectStoreId) OVERRIDE { } + virtual void deleteObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const ObjectStoreRecordIdentifier*) OVERRIDE { } + virtual int64_t nextAutoIncrementNumber(int64_t databaseId, int64_t objectStoreId) OVERRIDE { return 0.0; } + virtual bool keyExistsInObjectStore(int64_t databaseId, int64_t objectStoreId, const IDBKey&, ObjectStoreRecordIdentifier* foundRecordIdentifier) OVERRIDE { return false; } + + virtual bool forEachObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, ObjectStoreRecordCallback&) OVERRIDE { return false; } + + virtual void getIndexes(int64_t databaseId, int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<IDBKeyPath>& foundKeyPaths, Vector<bool>& foundUniqueFlags, Vector<bool>& foundMultiEntryFlags) OVERRIDE { } + virtual bool createIndex(int64_t databaseId, int64_t objectStoreId, const String& name, const IDBKeyPath& keyPath, bool isUnique, bool isMultiEntry, int64_t& indexId) OVERRIDE { return false; } + virtual void deleteIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId) OVERRIDE { } + virtual bool putIndexDataForRecord(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&, const ObjectStoreRecordIdentifier*) OVERRIDE { return false; } + virtual bool deleteIndexDataForRecord(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const ObjectStoreRecordIdentifier*) OVERRIDE { return false; } + virtual String getObjectViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&) OVERRIDE { return String(); } + virtual PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&) OVERRIDE { return PassRefPtr<IDBKey>(); } + virtual bool keyExistsInIndex(int64_t databaseid, int64_t objectStoreId, int64_t indexId, const IDBKey& indexKey, RefPtr<IDBKey>& foundPrimaryKey) OVERRIDE { return false; } + + virtual PassRefPtr<Cursor> openObjectStoreCursor(int64_t databaseId, int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction) OVERRIDE { return PassRefPtr<Cursor>(); } + virtual PassRefPtr<Cursor> openIndexKeyCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange*, IDBCursor::Direction) OVERRIDE { return PassRefPtr<Cursor>(); } + virtual PassRefPtr<Cursor> openIndexCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange*, IDBCursor::Direction) OVERRIDE { return PassRefPtr<Cursor>(); } + + virtual PassRefPtr<Transaction> createTransaction() OVERRIDE { return PassRefPtr<Transaction>(); } +}; + +} // namespace WebCore + +#endif // IDBFakeBackingStore_h diff --git a/Source/WebKit/chromium/tests/IDBKeyPathTest.cpp b/Source/WebKit/chromium/tests/IDBKeyPathTest.cpp index e2fdaebc2..7d662c009 100644 --- a/Source/WebKit/chromium/tests/IDBKeyPathTest.cpp +++ b/Source/WebKit/chromium/tests/IDBKeyPathTest.cpp @@ -37,6 +37,10 @@ namespace { void checkKeyPath(const String& keyPath, const Vector<String>& expected, int parserError) { + IDBKeyPath idbKeyPath(keyPath); + ASSERT_EQ(idbKeyPath.type(), IDBKeyPath::StringType); + ASSERT_EQ(idbKeyPath.isValid(), (parserError == IDBKeyPathParseErrorNone)); + IDBKeyPathParseError error; Vector<String> keyPathElements; IDBParseKeyPath(keyPath, keyPathElements, error); diff --git a/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp b/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp index eb9962d58..8f5b8ef01 100644 --- a/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp +++ b/Source/WebKit/chromium/tests/IDBLevelDBCodingTest.cpp @@ -30,6 +30,7 @@ #if USE(LEVELDB) #include "IDBKey.h" +#include "IDBKeyPath.h" #include "LevelDBSlice.h" #include <gtest/gtest.h> #include <wtf/Vector.h> @@ -418,6 +419,133 @@ TEST(IDBLevelDBCodingTest, EncodeDecodeIDBKey) EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey)); } +TEST(IDBLevelDBCodingTest, EncodeIDBKeyPath) +{ + const unsigned char kIDBKeyPathTypeCodedByte1 = 0; + const unsigned char kIDBKeyPathTypeCodedByte2 = 0; + { + IDBKeyPath keyPath; + EXPECT_EQ(keyPath.type(), IDBKeyPath::NullType); + Vector<char> v = encodeIDBKeyPath(keyPath); + EXPECT_EQ(v.size(), 3U); + EXPECT_EQ(v[0], kIDBKeyPathTypeCodedByte1); + EXPECT_EQ(v[1], kIDBKeyPathTypeCodedByte2); + EXPECT_EQ(v[2], IDBKeyPath::NullType); + } + + { + Vector<String> testCases; + testCases.append(""); + testCases.append("foo"); + testCases.append("foo.bar"); + + for (size_t i = 0; i < testCases.size(); ++i) { + IDBKeyPath keyPath = IDBKeyPath(testCases[i]); + Vector<char> v = encodeIDBKeyPath(keyPath); + EXPECT_EQ(v.size(), encodeStringWithLength(testCases[i]).size() + 3); + const char* p = v.data(); + const char* limit = v.data() + v.size(); + EXPECT_EQ(*p++, kIDBKeyPathTypeCodedByte1); + EXPECT_EQ(*p++, kIDBKeyPathTypeCodedByte2); + EXPECT_EQ(*p++, IDBKeyPath::StringType); + String string; + p = decodeStringWithLength(p, limit, string); + EXPECT_EQ(string, testCases[i]); + EXPECT_EQ(p, limit); + } + } + + { + Vector<String> testCase; + testCase.append(""); + testCase.append("foo"); + testCase.append("foo.bar"); + + IDBKeyPath keyPath(testCase); + EXPECT_EQ(keyPath.type(), IDBKeyPath::ArrayType); + Vector<char> v = encodeIDBKeyPath(keyPath); + const char* p = v.data(); + const char* limit = v.data() + v.size(); + EXPECT_EQ(*p++, kIDBKeyPathTypeCodedByte1); + EXPECT_EQ(*p++, kIDBKeyPathTypeCodedByte2); + EXPECT_EQ(*p++, IDBKeyPath::ArrayType); + int64_t count; + p = decodeVarInt(p, limit, count); + EXPECT_EQ(count, static_cast<int64_t>(testCase.size())); + for (size_t i = 0; i < static_cast<size_t>(count); ++i) { + String string; + p = decodeStringWithLength(p, limit, string); + EXPECT_EQ(string, testCase[i]); + } + EXPECT_EQ(p, limit); + } +} + +TEST(IDBLevelDBCodingTest, DecodeIDBKeyPath) +{ + const unsigned char kIDBKeyPathTypeCodedByte1 = 0; + const unsigned char kIDBKeyPathTypeCodedByte2 = 0; + { + // Legacy encoding of string key paths. + Vector<String> testCases; + testCases.append(""); + testCases.append("foo"); + testCases.append("foo.bar"); + + for (size_t i = 0; i < testCases.size(); ++i) { + Vector<char> v = encodeString(testCases[i]); + IDBKeyPath keyPath = decodeIDBKeyPath(v.data(), v.data() + v.size()); + EXPECT_EQ(keyPath.type(), IDBKeyPath::StringType); + EXPECT_EQ(testCases[i], keyPath.string()); + } + } + { + Vector<char> v; + v.append(kIDBKeyPathTypeCodedByte1); + v.append(kIDBKeyPathTypeCodedByte2); + v.append(IDBKeyPath::NullType); + IDBKeyPath keyPath = decodeIDBKeyPath(v.data(), v.data() + v.size()); + EXPECT_EQ(keyPath.type(), IDBKeyPath::NullType); + EXPECT_TRUE(keyPath.isNull()); + } + { + Vector<String> testCases; + testCases.append(""); + testCases.append("foo"); + testCases.append("foo.bar"); + + for (size_t i = 0; i < testCases.size(); ++i) { + Vector<char> v; + v.append(kIDBKeyPathTypeCodedByte1); + v.append(kIDBKeyPathTypeCodedByte2); + v.append(IDBKeyPath::StringType); + v.append(encodeStringWithLength(testCases[i])); + IDBKeyPath keyPath = decodeIDBKeyPath(v.data(), v.data() + v.size()); + EXPECT_EQ(keyPath.type(), IDBKeyPath::StringType); + EXPECT_EQ(testCases[i], keyPath.string()); + } + } + { + Vector<String> testCase; + testCase.append(""); + testCase.append("foo"); + testCase.append("foo.bar"); + + Vector<char> v; + v.append(kIDBKeyPathTypeCodedByte1); + v.append(kIDBKeyPathTypeCodedByte2); + v.append(IDBKeyPath::ArrayType); + v.append(encodeVarInt(testCase.size())); + for (size_t i = 0; i < testCase.size(); ++i) + v.append(encodeStringWithLength(testCase[i])); + IDBKeyPath keyPath = decodeIDBKeyPath(v.data(), v.data() + v.size()); + EXPECT_EQ(keyPath.type(), IDBKeyPath::ArrayType); + EXPECT_EQ(keyPath.array().size(), testCase.size()); + for (size_t i = 0; i < testCase.size(); ++i) + EXPECT_EQ(keyPath.array()[i], testCase[i]); + } +} + TEST(IDBLevelDBCodingTest, ExtractAndCompareIDBKeys) { Vector<RefPtr<IDBKey> > keys; diff --git a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp index a93eac7fa..491d48db5 100644 --- a/Source/WebKit/chromium/tests/LayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/LayerChromiumTest.cpp @@ -522,6 +522,7 @@ TEST_F(LayerChromiumTest, checkPropertyChangeCausesCorrectBehavior) EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDoubleSided(false)); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDebugName("Test Layer")); EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setDrawCheckerboardForMissingTiles(!testLayer->drawCheckerboardForMissingTiles())); + EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setForceRenderSurface(true)); // The above tests should not have caused a change to the needsDisplay flag. EXPECT_FALSE(testLayer->needsDisplay()); diff --git a/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp index 721f1fabb..eb2c07512 100644 --- a/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp +++ b/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp @@ -724,7 +724,7 @@ TEST(PlatformContextSkiaTest, UnboundedDrawsAreClipped) context.setStrokeStyle(SolidStroke); // Make skia unable to compute fast bounds for our paths. - Vector<float> dashArray; + DashArray dashArray; dashArray.append(1); dashArray.append(0); context.setLineDash(dashArray, 0); @@ -771,7 +771,7 @@ TEST(PlatformContextSkiaTest, PreserveOpaqueOnlyMattersForFirstLayer) context.setStrokeStyle(SolidStroke); // Make skia unable to compute fast bounds for our paths. - Vector<float> dashArray; + DashArray dashArray; dashArray.append(1); dashArray.append(0); context.setLineDash(dashArray, 0); diff --git a/Source/WebKit/chromium/tests/WebFrameTest.cpp b/Source/WebKit/chromium/tests/WebFrameTest.cpp index 74251f3e8..a6ab77fc1 100644 --- a/Source/WebKit/chromium/tests/WebFrameTest.cpp +++ b/Source/WebKit/chromium/tests/WebFrameTest.cpp @@ -34,11 +34,13 @@ #include "Frame.h" #include "FrameTestHelpers.h" +#include "FrameView.h" #include "ResourceError.h" #include "WebDocument.h" #include "WebFindOptions.h" #include "WebFormElement.h" #include "WebFrameClient.h" +#include "WebFrameImpl.h" #include "WebRange.h" #include "WebScriptSource.h" #include "WebSearchableFormData.h" @@ -243,6 +245,43 @@ TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag) // Force the layout to happen before leaving the test. webView->mainFrame()->contentAsText(1024).utf8(); } + +TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumPageScale) +{ + registerMockedHttpURLLoad("fixed_layout.html"); + + FixedLayoutTestWebViewClient client; + client.m_screenInfo.horizontalDPI = 160; + int viewportWidth = 640; + int viewportHeight = 480; + client.m_windowRect = WebRect(0, 0, viewportWidth, viewportHeight); + + // Make sure we initialize to minimum scale, even if the window size + // only becomes available after the load begins. + WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client)); + webViewImpl->enableFixedLayoutMode(true); + webViewImpl->settings()->setViewportEnabled(true); + webViewImpl->resize(WebSize(viewportWidth, viewportHeight)); + + int defaultFixedLayoutWidth = 980; + float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth; + EXPECT_EQ(minimumPageScaleFactor, webViewImpl->pageScaleFactor()); + + // Assume the user has pinch zoomed to page scale factor 2. + float userPinchPageScaleFactor = 2; + webViewImpl->setPageScaleFactorPreservingScrollOffset(userPinchPageScaleFactor); + webViewImpl->mainFrameImpl()->frameView()->layout(); + + // Make sure we don't reset to initial scale if the page continues to load. + bool isNewNavigation; + webViewImpl->didCommitLoad(&isNewNavigation, false); + webViewImpl->didChangeContentsSize(); + EXPECT_EQ(userPinchPageScaleFactor, webViewImpl->pageScaleFactor()); + + // Make sure we don't reset to initial scale if the viewport size changes. + webViewImpl->resize(WebSize(viewportWidth, viewportHeight + 100)); + EXPECT_EQ(userPinchPageScaleFactor, webViewImpl->pageScaleFactor()); +} #endif #if ENABLE(GESTURE_EVENTS) diff --git a/Source/WebKit/chromium/tests/WebLayerTest.cpp b/Source/WebKit/chromium/tests/WebLayerTest.cpp index 7c0831f90..8fc7c93bd 100644 --- a/Source/WebKit/chromium/tests/WebLayerTest.cpp +++ b/Source/WebKit/chromium/tests/WebLayerTest.cpp @@ -53,10 +53,12 @@ public: MOCK_METHOD0(scheduleComposite, void()); virtual void updateAnimations(double frameBeginTime) { } + virtual void didBeginFrame() { } virtual void layout() { } virtual void applyScrollAndScale(const WebSize& scrollDelta, float scaleFactor) { } virtual WebGraphicsContext3D* createContext3D() { return CompositorFakeWebGraphicsContext3D::create(WebGraphicsContext3D::Attributes()).leakPtr(); } virtual void didRebindGraphicsContext(bool success) { } + virtual void willCommit() { } virtual void didCommitAndDrawFrame() { } virtual void didCompleteSwapBuffers() { } }; diff --git a/Source/WebKit/chromium/tests/WebLayerTreeViewTest.cpp b/Source/WebKit/chromium/tests/WebLayerTreeViewTest.cpp new file mode 100644 index 000000000..2df259f76 --- /dev/null +++ b/Source/WebKit/chromium/tests/WebLayerTreeViewTest.cpp @@ -0,0 +1,220 @@ +/* + * 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 "platform/WebLayerTreeView.h" + +#include "CompositorFakeWebGraphicsContext3D.h" +#include "WebCompositor.h" +#include "public/WebLayer.h" +#include "public/WebLayerTreeViewClient.h" +#include "public/WebThread.h" +#include <gmock/gmock.h> +#include <public/Platform.h> + +using namespace WebKit; +using testing::Mock; +using testing::Test; + +namespace { + +class MockWebLayerTreeViewClient : public WebLayerTreeViewClient { +public: + virtual void scheduleComposite() OVERRIDE { } + virtual void updateAnimations(double frameBeginTime) OVERRIDE { } + MOCK_METHOD0(willBeginFrame, void()); + MOCK_METHOD0(didBeginFrame, void()); + virtual void layout() OVERRIDE { } + virtual void applyScrollAndScale(const WebSize& scrollDelta, float scaleFactor) OVERRIDE { } + virtual WebGraphicsContext3D* createContext3D() OVERRIDE { return CompositorFakeWebGraphicsContext3D::create(WebGraphicsContext3D::Attributes()).leakPtr(); } + virtual void didRebindGraphicsContext(bool success) OVERRIDE { } + MOCK_METHOD0(willCommit, void()); + MOCK_METHOD0(didCommit, void()); + virtual void didCommitAndDrawFrame() OVERRIDE { } + virtual void didCompleteSwapBuffers() OVERRIDE { } +}; + +class MockWebLayerTreeViewClientForThreadedTests : public MockWebLayerTreeViewClient { +public: + virtual void didBeginFrame() OVERRIDE + { + WebKit::Platform::current()->currentThread()->exitRunLoop(); + MockWebLayerTreeViewClient::didBeginFrame(); + } +}; + +class WebLayerTreeViewTestBase : public Test { +protected: + virtual void initializeCompositor() = 0; + virtual WebLayerTreeViewClient* client() = 0; + +public: + virtual void SetUp() + { + initializeCompositor(); + m_rootLayer = WebLayer::create(); + EXPECT_TRUE(m_view.initialize(client(), m_rootLayer, WebLayerTreeView::Settings())); + m_view.setSurfaceReady(); + } + + virtual void TearDown() + { + Mock::VerifyAndClearExpectations(client()); + + m_view.setRootLayer(0); + m_rootLayer.reset(); + m_view.reset(); + WebKit::WebCompositor::shutdown(); + } + +protected: + WebLayer m_rootLayer; + WebLayerTreeView m_view; +}; + +class WebLayerTreeViewSingleThreadTest : public WebLayerTreeViewTestBase { +protected: + void composite() + { + m_view.composite(); + } + + virtual void initializeCompositor() OVERRIDE + { + WebKit::WebCompositor::initialize(0); + } + + virtual WebLayerTreeViewClient* client() OVERRIDE + { + return &m_client; + } + + MockWebLayerTreeViewClient m_client; +}; + +class CancelableTaskWrapper : public RefCounted<CancelableTaskWrapper> { + class Task : public WebThread::Task { + public: + Task(CancelableTaskWrapper* cancelableTask) + : m_cancelableTask(cancelableTask) + { + } + + private: + virtual void run() OVERRIDE + { + m_cancelableTask->runIfNotCanceled(); + } + + RefPtr<CancelableTaskWrapper> m_cancelableTask; + }; + +public: + CancelableTaskWrapper(PassOwnPtr<WebThread::Task> task) + : m_task(task) + { + } + + void cancel() + { + m_task.clear(); + } + + WebThread::Task* createTask() + { + ASSERT(m_task); + return new Task(this); + } + + void runIfNotCanceled() + { + if (!m_task) + return; + m_task->run(); + m_task.clear(); + } + +private: + OwnPtr<WebThread::Task> m_task; +}; + +class WebLayerTreeViewThreadedTest : public WebLayerTreeViewTestBase { +protected: + class TimeoutTask : public WebThread::Task { + virtual void run() OVERRIDE + { + WebKit::Platform::current()->currentThread()->exitRunLoop(); + } + }; + + void composite() + { + m_view.setNeedsRedraw(); + RefPtr<CancelableTaskWrapper> timeoutTask = adoptRef(new CancelableTaskWrapper(adoptPtr(new TimeoutTask()))); + WebKit::Platform::current()->currentThread()->postDelayedTask(timeoutTask->createTask(), 5000); + WebKit::Platform::current()->currentThread()->enterRunLoop(); + timeoutTask->cancel(); + m_view.finishAllRendering(); + } + + virtual void initializeCompositor() OVERRIDE + { + m_webThread = adoptPtr(WebKit::Platform::current()->createThread("WebLayerTreeViewTest")); + WebCompositor::initialize(m_webThread.get()); + } + + virtual WebLayerTreeViewClient* client() OVERRIDE + { + return &m_client; + } + + MockWebLayerTreeViewClientForThreadedTests m_client; + OwnPtr<WebThread> m_webThread; +}; + +TEST_F(WebLayerTreeViewSingleThreadTest, InstrumentationCallbacks) +{ + ::testing::InSequence dummy; + + EXPECT_CALL(m_client, willCommit()); + EXPECT_CALL(m_client, didCommit()); + EXPECT_CALL(m_client, didBeginFrame()); + + composite(); +} + +TEST_F(WebLayerTreeViewThreadedTest, InstrumentationCallbacks) +{ + ::testing::InSequence dummy; + + EXPECT_CALL(m_client, willBeginFrame()); + EXPECT_CALL(m_client, willCommit()); + EXPECT_CALL(m_client, didCommit()); + EXPECT_CALL(m_client, didBeginFrame()); + + composite(); +} + +} // namespace diff --git a/Source/WebKit/chromium/tests/WebTransformationMatrixTest.cpp b/Source/WebKit/chromium/tests/WebTransformationMatrixTest.cpp index af291698a..2888e0d7c 100644 --- a/Source/WebKit/chromium/tests/WebTransformationMatrixTest.cpp +++ b/Source/WebKit/chromium/tests/WebTransformationMatrixTest.cpp @@ -24,9 +24,11 @@ #include "config.h" -#include "../../../../Platform/chromium/public/WebTransformationMatrix.h" +#include <public/WebTransformationMatrix.h> +#include "CCLayerTreeTestCommon.h" #include <gtest/gtest.h> +#include <wtf/MathExtras.h> #define EXPECT_ROW1_EQ(a, b, c, d, matrix) \ EXPECT_FLOAT_EQ((a), (matrix).m11()); \ @@ -74,6 +76,7 @@ EXPECT_NEAR((d), (matrix).m43(), (errorThreshold)); #define ERROR_THRESHOLD 1e-14 +#define LOOSE_ERROR_THRESHOLD 1e-7 using namespace WebKit; @@ -926,7 +929,7 @@ TEST(WebTransformationMatrixTest, verifyIsIdentityOrTranslation) EXPECT_FALSE(A.isIdentityOrTranslation()); } -TEST(WebTransformationMatrixTest, isIntegerTranslation) +TEST(WebTransformationMatrixTest, verifyIsIntegerTranslation) { WebTransformationMatrix A; @@ -953,4 +956,329 @@ TEST(WebTransformationMatrixTest, isIntegerTranslation) EXPECT_TRUE(A.isIntegerTranslation()); } +TEST(WebTransformationMatrixTest, verifyBlendForTranslation) +{ + WebTransformationMatrix from; + from.translate3d(100, 200, 100); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.translate3d(200, 100, 300); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + to.makeIdentity(); + to.translate3d(200, 100, 300); + to.blend(from, 0.25); + EXPECT_ROW1_EQ(1, 0, 0, 125, to); + EXPECT_ROW2_EQ(0, 1, 0, 175, to); + EXPECT_ROW3_EQ(0, 0, 1, 150, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.translate3d(200, 100, 300); + to.blend(from, 0.5); + EXPECT_ROW1_EQ(1, 0, 0, 150, to); + EXPECT_ROW2_EQ(0, 1, 0, 150, to); + EXPECT_ROW3_EQ(0, 0, 1, 200, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.translate3d(200, 100, 300); + to.blend(from, 1); + EXPECT_ROW1_EQ(1, 0, 0, 200, to); + EXPECT_ROW2_EQ(0, 1, 0, 100, to); + EXPECT_ROW3_EQ(0, 0, 1, 300, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForScale) +{ + WebTransformationMatrix from; + from.scale3d(100, 200, 100); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.scale3d(200, 100, 300); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + to.makeIdentity(); + to.scale3d(200, 100, 300); + to.blend(from, 0.25); + EXPECT_ROW1_EQ(125, 0, 0, 0, to); + EXPECT_ROW2_EQ(0, 175, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 150, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.scale3d(200, 100, 300); + to.blend(from, 0.5); + EXPECT_ROW1_EQ(150, 0, 0, 0, to); + EXPECT_ROW2_EQ(0, 150, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 200, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.scale3d(200, 100, 300); + to.blend(from, 1); + EXPECT_ROW1_EQ(200, 0, 0, 0, to); + EXPECT_ROW2_EQ(0, 100, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 300, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForSkewX) +{ + WebTransformationMatrix from; + from.skewX(0); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.skewX(45); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + to.makeIdentity(); + to.skewX(45); + to.blend(from, 0.5); + EXPECT_ROW1_EQ(1, 0.5, 0, 0, to); + EXPECT_ROW2_EQ(0, 1, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.skewX(45); + to.blend(from, 0.25); + EXPECT_ROW1_EQ(1, 0.25, 0, 0, to); + EXPECT_ROW2_EQ(0, 1, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.skewX(45); + to.blend(from, 1); + EXPECT_ROW1_EQ(1, 1, 0, 0, to); + EXPECT_ROW2_EQ(0, 1, 0, 0, to); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForSkewY) +{ + // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix is + // inherently underconstrained, and so it does not always compute the originally + // intended skew parameters. The current implementation uses QR decomposition, which + // decomposes the shear into a rotation + non-uniform scale. + // + // It is unlikely that the decomposition implementation will need to change very + // often, so to get any test coverage, the compromise is to verify the exact matrix + // that the blend() operation produces. + // + // This problem also potentially exists for skewX, but the current QR decomposition + // implementation just happens to decompose those test matrices intuitively. + + WebTransformationMatrix from; + from.skewY(0); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.skewY(45); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + to.makeIdentity(); + to.skewY(45); + to.blend(from, 0.25); + EXPECT_ROW1_NEAR(1.0823489449280947471976333, 0.0464370719145053845178239, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0.2152925909665224513123150, 0.9541702441750861130032035, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.skewY(45); + to.blend(from, 0.5); + EXPECT_ROW1_NEAR(1.1152212925809066312865525, 0.0676495144007326631996335, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0.4619397844342648662419037, 0.9519009045724774464858342, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + // Unfortunately, this case suffers from uncomfortably large precision error. + to.makeIdentity(); + to.skewY(45); + to.blend(from, 1); + EXPECT_ROW1_NEAR(1, 0, 0, 0, to, LOOSE_ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(1, 1, 0, 0, to, LOOSE_ERROR_THRESHOLD); + EXPECT_ROW3_EQ(0, 0, 1, 0, to); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForRotationAboutX) +{ + // Even though blending uses quaternions, axis-aligned rotations should blend the same + // with quaternions or Euler angles. So we can test rotation blending by comparing + // against manually specified matrices from Euler angles. + + WebTransformationMatrix from; + from.rotate3d(1, 0, 0, 0); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.rotate3d(1, 0, 0, 90); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + double expectedRotationAngle = 22.5 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(1, 0, 0, 90); + to.blend(from, 0.25); + EXPECT_ROW1_NEAR(1, 0, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, cos(expectedRotationAngle), -sin(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, sin(expectedRotationAngle), cos(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + expectedRotationAngle = 45.0 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(1, 0, 0, 90); + to.blend(from, 0.5); + EXPECT_ROW1_NEAR(1, 0, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, cos(expectedRotationAngle), -sin(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, sin(expectedRotationAngle), cos(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.rotate3d(1, 0, 0, 90); + to.blend(from, 1); + EXPECT_ROW1_NEAR(1, 0, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, 0, -1, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, 1, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForRotationAboutY) +{ + WebTransformationMatrix from; + from.rotate3d(0, 1, 0, 0); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.rotate3d(0, 1, 0, 90); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + double expectedRotationAngle = 22.5 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(0, 1, 0, 90); + to.blend(from, 0.25); + EXPECT_ROW1_NEAR(cos(expectedRotationAngle), 0, sin(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, 1, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(-sin(expectedRotationAngle), 0, cos(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + expectedRotationAngle = 45.0 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(0, 1, 0, 90); + to.blend(from, 0.5); + EXPECT_ROW1_NEAR(cos(expectedRotationAngle), 0, sin(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, 1, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(-sin(expectedRotationAngle), 0, cos(expectedRotationAngle), 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.rotate3d(0, 1, 0, 90); + to.blend(from, 1); + EXPECT_ROW1_NEAR(0, 0, 1, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(0, 1, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(-1, 0, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + +TEST(WebTransformationMatrixTest, verifyBlendForRotationAboutZ) +{ + WebTransformationMatrix from; + from.rotate3d(0, 0, 1, 0); + + WebTransformationMatrix to; + + to.makeIdentity(); + to.rotate3d(0, 0, 1, 90); + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + double expectedRotationAngle = 22.5 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(0, 0, 1, 90); + to.blend(from, 0.25); + EXPECT_ROW1_NEAR(cos(expectedRotationAngle), -sin(expectedRotationAngle), 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(sin(expectedRotationAngle), cos(expectedRotationAngle), 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, 0, 1, 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + expectedRotationAngle = 45.0 * piDouble / 180.0; + to.makeIdentity(); + to.rotate3d(0, 0, 1, 90); + to.blend(from, 0.5); + EXPECT_ROW1_NEAR(cos(expectedRotationAngle), -sin(expectedRotationAngle), 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(sin(expectedRotationAngle), cos(expectedRotationAngle), 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, 0, 1, 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); + + to.makeIdentity(); + to.rotate3d(0, 0, 1, 90); + to.blend(from, 1); + EXPECT_ROW1_NEAR(0, -1, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW2_NEAR(1, 0, 0, 0, to, ERROR_THRESHOLD); + EXPECT_ROW3_NEAR(0, 0, 1, 0, to, ERROR_THRESHOLD); + EXPECT_ROW4_EQ(0, 0, 0, 1, to); +} + + +TEST(WebTransformationMatrixTest, verifyBlendForCompositeTransform) +{ + // Verify that the blending was done with a decomposition in correct order by blending + // a composite transform. + // Using matrix x vector notation (Ax = b, where x is column vector), the ordering should be: + // perspective * translation * rotation * skew * scale + // + // It is not as important (or meaningful) to check intermediate interpolations; order + // of operations will be tested well enough by the end cases that are easier to + // specify. + + WebTransformationMatrix from; + WebTransformationMatrix to; + + WebTransformationMatrix expectedEndOfAnimation; + expectedEndOfAnimation.applyPerspective(1); + expectedEndOfAnimation.translate3d(10, 20, 30); + expectedEndOfAnimation.rotate3d(0, 0, 1, 25); + expectedEndOfAnimation.skewY(45); + expectedEndOfAnimation.scale3d(6, 7, 8); + + to = expectedEndOfAnimation; + to.blend(from, 0); + EXPECT_TRANSFORMATION_MATRIX_EQ(from, to); + + to = expectedEndOfAnimation; + to.blend(from, 1); + + // Recomposing the matrix results in a normalized matrix, so to verify we need to + // normalize the expectedEndOfAnimation before comparing elements. Normalizing means + // dividing everything by expectedEndOfAnimation.m44(). + WebTransformationMatrix normalizedExpectedEndOfAnimation = expectedEndOfAnimation; + WebTransformationMatrix normalizationMatrix; + normalizationMatrix.setM11(1 / expectedEndOfAnimation.m44()); + normalizationMatrix.setM22(1 / expectedEndOfAnimation.m44()); + normalizationMatrix.setM33(1 / expectedEndOfAnimation.m44()); + normalizationMatrix.setM44(1 / expectedEndOfAnimation.m44()); + normalizedExpectedEndOfAnimation.multiply(normalizationMatrix); + + EXPECT_TRANSFORMATION_MATRIX_EQ(normalizedExpectedEndOfAnimation, to); +} + } // namespace diff --git a/Source/WebKit/chromium/tests/data/fixed_layout.html b/Source/WebKit/chromium/tests/data/fixed_layout.html new file mode 100644 index 000000000..a89cecae9 --- /dev/null +++ b/Source/WebKit/chromium/tests/data/fixed_layout.html @@ -0,0 +1 @@ +<body>Ordinary non-mobile page</body> |
