Index: third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp |
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp |
index 8e99446dee9e8ad1b9c2214f17fc9ed79f334952..876af2617177ad9d74a69e597814cd2b4b90b662 100644 |
--- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp |
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp |
@@ -42,11 +42,16 @@ |
#include "core/animation/animatable/AnimatableTransform.h" |
#include "core/animation/animatable/AnimatableValueTestHelper.h" |
#include "core/dom/Document.h" |
+#include "core/layout/LayoutBox.h" |
#include "core/layout/LayoutObject.h" |
+#include "core/loader/EmptyClients.h" |
+#include "core/paint/PaintLayer.h" |
#include "core/testing/DummyPageHolder.h" |
#include "platform/geometry/FloatBox.h" |
#include "platform/geometry/IntSize.h" |
#include "platform/graphics/filters/FilterOperations.h" |
+#include "platform/graphics/paint/PaintArtifact.h" |
+#include "platform/graphics/test/FakeGraphicsLayerFactory.h" |
#include "platform/transforms/TransformOperations.h" |
#include "platform/transforms/TranslateTransformOperation.h" |
#include "public/platform/WebCompositorAnimation.h" |
@@ -65,6 +70,64 @@ using ::testing::Ref; |
using ::testing::Return; |
using ::testing::_; |
+class MockChromeClient : public EmptyChromeClient { |
+public: |
+ MockChromeClient() {} |
+ GraphicsLayerFactory* graphicsLayerFactory() const override |
+ { |
+ return FakeGraphicsLayerFactory::instance(); |
+ } |
+}; |
+ |
+ |
+class LayoutObjectProxy : public LayoutBox { |
+public: |
+ static LayoutObjectProxy* create(ContainerNode* node) |
+ { |
+ return new LayoutObjectProxy(node); |
+ } |
+ |
+ static void dispose(LayoutObjectProxy* proxy) |
+ { |
+ proxy->destroy(); |
+ } |
+ |
+ const char* name() const override { return nullptr; } |
+ |
+ void createCompositedLayer(WebCompositorSupportMock& compositorSupport) |
+ { |
+ RefPtr<ComputedStyle> computedStyle = ComputedStyle::create(); |
+ styleWillChange(StyleDifference(), *computedStyle.get()); |
+ setStyle(computedStyle); |
+ styleDidChange(StyleDifference(), nullptr); |
+ |
+ m_contentLayer = new WebContentLayerMock(); |
+ EXPECT_CALL(compositorSupport, createContentLayer(_)).WillOnce(Return(m_contentLayer)); |
+ |
+ DisableCompositingQueryAsserts disabler; |
+ layer()->ensureCompositedLayerMapping(); |
+ } |
+ |
+ WebContentLayerMock* contentLayer() const |
+ { |
+ return m_contentLayer; |
+ } |
+ |
+private: |
+ explicit LayoutObjectProxy(ContainerNode* node) |
+ : LayoutBox(node) |
+ { |
+ } |
+ |
+ PaintLayerType layerTypeRequired() const override |
+ { |
+ return NormalPaintLayer; |
+ } |
+ |
+ WebContentLayerMock* m_contentLayer; |
+}; |
+ |
+ |
class AnimationCompositorAnimationsTest : public AnimationCompositorAnimationsTestBase { |
protected: |
RefPtr<TimingFunction> m_linearTimingFunction; |
@@ -82,11 +145,14 @@ protected: |
RefPtrWillBePersistent<Document> m_document; |
RefPtrWillBePersistent<Element> m_element; |
Persistent<AnimationTimeline> m_timeline; |
+ OwnPtrWillBePersistent<MockChromeClient> m_chromeClient; |
OwnPtr<DummyPageHolder> m_pageHolder; |
WebCompositorSupportMock m_mockCompositor; |
virtual void SetUp() |
{ |
+ m_chromeClient = adoptPtrWillBeNoop(new MockChromeClient); |
+ |
AnimationCompositorAnimationsTestBase::SetUp(); |
setCompositorForTesting(m_mockCompositor); |
@@ -111,7 +177,12 @@ protected: |
EXPECT_CALL(m_mockCompositor, createAnimationTimeline()) |
.WillOnce(Return(new WebCompositorAnimationTimelineMock())); |
} |
- m_pageHolder = DummyPageHolder::create(); |
+ |
+ Page::PageClients clients; |
+ fillWithEmptyClients(clients); |
+ clients.chromeClient = m_chromeClient.get(); |
+ m_pageHolder = DummyPageHolder::create(IntSize(), &clients); |
+ |
m_document = &m_pageHolder->document(); |
m_document->animationClock().resetTimeForTesting(); |
@@ -264,27 +335,38 @@ public: |
m_document->compositorPendingAnimations().update(false); |
m_timeline->serviceAnimations(TimingUpdateForAnimationFrame); |
} |
-}; |
-class LayoutObjectProxy : public LayoutObject { |
-public: |
- static LayoutObjectProxy* create(Node* node) |
+ PassOwnPtr<WebCompositorAnimationMock> preCommit(LayoutObjectProxy* layoutObject, Animation* animation) |
{ |
- return new LayoutObjectProxy(node); |
- } |
+ WebFloatAnimationCurveMock* mockCurvePtr = new WebFloatAnimationCurveMock; |
+ ExpectationSet usesMockCurve; |
+ EXPECT_CALL(m_mockCompositor, createFloatAnimationCurve()) |
+ .WillOnce(Return(mockCurvePtr)); |
- static void dispose(LayoutObjectProxy* proxy) |
- { |
- proxy->destroy(); |
- } |
+ OwnPtr<WebCompositorAnimationMock> mockAnimationPtr = adoptPtr(new WebCompositorAnimationMock(WebCompositorAnimation::TargetPropertyOpacity)); |
+ EXPECT_CALL(m_mockCompositor, createAnimation(Ref(*mockCurvePtr), WebCompositorAnimation::TargetPropertyOpacity, _, _)) |
+ .WillOnce(Return(mockAnimationPtr.get())); |
- const char* name() const override { return nullptr; } |
- void layout() override { } |
+ const int animationId = 1; |
+ EXPECT_CALL(*mockAnimationPtr.get(), id()).WillRepeatedly(Return(animationId)); |
-private: |
- explicit LayoutObjectProxy(Node* node) |
- : LayoutObject(node) |
- { |
+ if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()) { |
+ EXPECT_TRUE(m_timeline->compositorTimeline()); |
+ EXPECT_CALL(m_mockCompositor, createAnimationPlayer()) |
+ .WillOnce(Return(new WebCompositorAnimationPlayerMock())); |
+ } else { |
+ EXPECT_CALL(layoutObject->contentLayer()->layerMock(), addAnimation(_)).WillRepeatedly(Return(true)); |
+ } |
+ |
+ const int compositorGroup = 1; |
+ DisableCompositingQueryAsserts disabler; |
+ EXPECT_TRUE(animation->preCommit(compositorGroup, true)); |
+ |
+ if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()) |
+ EXPECT_TRUE(animation->compositorPlayer()); |
+ |
+ EXPECT_TRUE(animation->hasActiveAnimationsOnCompositor()); |
+ return mockAnimationPtr.release(); |
} |
}; |
@@ -1175,12 +1257,51 @@ TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationWithTiming |
result[0].clear(); |
} |
+TEST_F(AnimationCompositorAnimationsTest, CancelCompositorAnimationIfAnimationDisposed) |
+{ |
+ RefPtrWillBePersistent<Element> element = m_document->createElement("shared", ASSERT_NO_EXCEPTION); |
+ |
+ LayoutObjectProxy* layoutObject = LayoutObjectProxy::create(element.get()); |
+ element->setLayoutObject(layoutObject); |
+ layoutObject->createCompositedLayer(m_mockCompositor); |
+ |
+ AnimatableValueKeyframeVector keyFrames; |
+ keyFrames.append(createDefaultKeyframe(CSSPropertyOpacity, EffectModel::CompositeReplace, 0.0).get()); |
+ keyFrames.append(createDefaultKeyframe(CSSPropertyOpacity, EffectModel::CompositeReplace, 1.0).get()); |
+ EffectModel* animationEffect = AnimatableValueKeyframeEffectModel::create(keyFrames); |
+ |
+ Timing timing; |
+ timing.iterationDuration = 1.f; |
+ |
+ KeyframeEffect* keyframeEffect = KeyframeEffect::create(element.get(), animationEffect, timing); |
+ Animation* animation = m_timeline->play(keyframeEffect); |
+ EXPECT_TRUE(animation->isCandidateForAnimationOnCompositor()); |
+ |
+ OwnPtr<WebCompositorAnimationMock> compositorAnimation = preCommit(layoutObject, animation); |
+ |
+ animation->dispose(); |
+ animation->cancelAnimationOnCompositor(); |
+ |
+ EXPECT_FALSE(animation->hasActiveAnimationsOnCompositor()); |
+ |
+ simulateFrame(0); |
+ EXPECT_EQ(1U, element->elementAnimations()->animations().size()); |
+ simulateFrame(1.); |
+ |
+ element->setLayoutObject(nullptr); |
+ LayoutObjectProxy::dispose(layoutObject); |
+ |
+ Heap::collectAllGarbage(); |
+ EXPECT_TRUE(element->elementAnimations()->animations().isEmpty()); |
+} |
+ |
TEST_F(AnimationCompositorAnimationsTest, CancelIncompatibleCompositorAnimations) |
{ |
RefPtrWillBePersistent<Element> element = m_document->createElement("shared", ASSERT_NO_EXCEPTION); |
LayoutObjectProxy* layoutObject = LayoutObjectProxy::create(element.get()); |
element->setLayoutObject(layoutObject); |
+ layoutObject->createCompositedLayer(m_mockCompositor); |
AnimatableValueKeyframeVector keyFrames; |
keyFrames.append(createDefaultKeyframe(CSSPropertyOpacity, EffectModel::CompositeReplace, 0.0).get()); |
@@ -1194,18 +1315,15 @@ TEST_F(AnimationCompositorAnimationsTest, CancelIncompatibleCompositorAnimations |
// The first animation for opacity is ok to run on compositor. |
KeyframeEffect* keyframeEffect1 = KeyframeEffect::create(element.get(), animationEffect1, timing); |
Animation* animation1 = m_timeline->play(keyframeEffect1); |
- EXPECT_TRUE(CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(timing, *element.get(), animation1, *animationEffect1, 1)); |
+ EXPECT_TRUE(animation1->isCandidateForAnimationOnCompositor()); |
- // simulate KeyframeEffect::maybeStartAnimationOnCompositor |
- Vector<int> compositorAnimationIds; |
- compositorAnimationIds.append(1); |
- keyframeEffect1->setCompositorAnimationIdsForTesting(compositorAnimationIds); |
- EXPECT_TRUE(animation1->hasActiveAnimationsOnCompositor()); |
+ OwnPtr<WebCompositorAnimationMock> compositorAnimation = preCommit(layoutObject, animation1); |
// The second animation for opacity is not ok to run on compositor. |
KeyframeEffect* keyframeEffect2 = KeyframeEffect::create(element.get(), animationEffect2, timing); |
Animation* animation2 = m_timeline->play(keyframeEffect2); |
EXPECT_FALSE(CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(timing, *element.get(), animation2, *animationEffect2, 1)); |
+ EXPECT_FALSE(animation2->isCandidateForAnimationOnCompositor()); |
EXPECT_FALSE(animation2->hasActiveAnimationsOnCompositor()); |
// A fallback to blink implementation needed, so cancel all compositor-side opacity animations for this element. |