void LinkHighlightImpl::startHighlightAnimationIfNeeded() { if (m_isAnimating) return; m_isAnimating = true; const float startOpacity = 1; // FIXME: Should duration be configurable? const float fadeDuration = 0.1f; const float minPreFadeDuration = 0.1f; m_contentLayer->layer()->setOpacity(startOpacity); std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); const auto easeType = CubicBezierTimingFunction::EaseType::EASE; curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, startOpacity), easeType); // Make sure we have displayed for at least minPreFadeDuration before starting to fade out. float extraDurationRequired = std::max(0.f, minPreFadeDuration - static_cast<float>(monotonicallyIncreasingTime() - m_startTime)); if (extraDurationRequired) curve->addCubicBezierKeyframe(CompositorFloatKeyframe(extraDurationRequired, startOpacity), easeType); // For layout tests we don't fade out. curve->addCubicBezierKeyframe(CompositorFloatKeyframe(fadeDuration + extraDurationRequired, layoutTestMode() ? startOpacity : 0), easeType); std::unique_ptr<CompositorAnimation> animation = CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0); m_contentLayer->layer()->setDrawsContent(true); m_compositorPlayer->addAnimation(animation.release()); invalidate(); m_owningWebViewImpl->scheduleAnimation(); }
// Tests that a float animation with two keyframes works as expected. TEST(WebFloatAnimationCurveTest, TwoFloatKeyframe) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); curve->addKeyframe( CompositorFloatKeyframe(0, 2, *LinearTimingFunction::shared())); curve->addKeyframe( CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared())); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); EXPECT_FLOAT_EQ(4, curve->getValue(1)); EXPECT_FLOAT_EQ(4, curve->getValue(2)); }
// Tests using a linear timing function. TEST(WebFloatAnimationCurveTest, LinearTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); curve->addKeyframe( CompositorFloatKeyframe(0, 0, *LinearTimingFunction::shared())); curve->addKeyframe( CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared())); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(time, curve->getValue(time)); } }
// Tests that a float animation with two keyframes works as expected. TEST(WebFloatAnimationCurveTest, TwoFloatKeyframe) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); curve->add(CompositorFloatKeyframe(0, 2), CompositorAnimationCurve::TimingFunctionTypeLinear); curve->add(CompositorFloatKeyframe(1, 4), CompositorAnimationCurve::TimingFunctionTypeLinear); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); EXPECT_FLOAT_EQ(4, curve->getValue(1)); EXPECT_FLOAT_EQ(4, curve->getValue(2)); }
// Tests using a linear timing function. TEST(WebFloatAnimationCurveTest, LinearTimingFunction) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); curve->add(CompositorFloatKeyframe(0, 0), CompositorAnimationCurve::TimingFunctionTypeLinear); curve->add(CompositorFloatKeyframe(1, 1), CompositorAnimationCurve::TimingFunctionTypeLinear); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(time, curve->getValue(time)); } }
// Tests that the default timing function is indeed ease. TEST(WebFloatAnimationCurveTest, DefaultTimingFunction) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); curve->add(CompositorFloatKeyframe(0, 0)); curve->add(CompositorFloatKeyframe(1, 1), CompositorAnimationCurve::TimingFunctionTypeLinear); scoped_ptr<cc::TimingFunction> timingFunction( cc::EaseTimingFunction::Create()); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(timingFunction->GetValue(time), curve->getValue(time)); } }
// Tests that a cubic bezier timing function works as expected. TEST(WebFloatAnimationCurveTest, CubicBezierTimingFunction) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); curve->add(CompositorFloatKeyframe(0, 0), 0.25, 0, 0.75, 1); curve->add(CompositorFloatKeyframe(1, 1), CompositorAnimationCurve::TimingFunctionTypeLinear); EXPECT_FLOAT_EQ(0, curve->getValue(0)); EXPECT_LT(0, curve->getValue(0.25)); EXPECT_GT(0.25, curve->getValue(0.25)); EXPECT_NEAR(curve->getValue(0.5), 0.5, 0.00015); EXPECT_LT(0.75, curve->getValue(0.75)); EXPECT_GT(1, curve->getValue(0.75)); EXPECT_FLOAT_EQ(1, curve->getValue(1)); }
// Tests that the default timing function is indeed ease. TEST(WebFloatAnimationCurveTest, DefaultTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); curve->addKeyframe(CompositorFloatKeyframe( 0, 0, *CubicBezierTimingFunction::preset( CubicBezierTimingFunction::EaseType::EASE))); curve->addKeyframe( CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared())); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset( CubicBezierTimingFunction::EaseType::EASE)); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(timingFunction->GetValue(time), curve->getValue(time)); } }
// Tests that a cubic bezier timing function works as expected. TEST(WebFloatAnimationCurveTest, CubicBezierTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(0.25, 0, 0.75, 1); curve->addKeyframe(CompositorFloatKeyframe(0, 0, *cubic)); curve->addKeyframe( CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared())); EXPECT_FLOAT_EQ(0, curve->getValue(0)); EXPECT_LT(0, curve->getValue(0.25)); EXPECT_GT(0.25, curve->getValue(0.25)); EXPECT_NEAR(curve->getValue(0.5), 0.5, 0.00015); EXPECT_LT(0.75, curve->getValue(0.75)); EXPECT_GT(1, curve->getValue(0.75)); EXPECT_FLOAT_EQ(1, curve->getValue(1)); }
// Tests that an ease in timing function works as expected. TEST(WebFloatAnimationCurveTest, CustomBezierTimingFunction) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); double x1 = 0.3; double y1 = 0.2; double x2 = 0.8; double y2 = 0.7; curve->add(CompositorFloatKeyframe(0, 0), x1, y1, x2, y2); curve->add(CompositorFloatKeyframe(1, 1), CompositorAnimationCurve::TimingFunctionTypeLinear); scoped_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(timingFunction->GetValue(time), curve->getValue(time)); } }
// Tests that an ease in timing function works as expected. TEST(WebFloatAnimationCurveTest, CustomBezierTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); double x1 = 0.3; double y1 = 0.2; double x2 = 0.8; double y2 = 0.7; RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(x1, y1, x2, y2); curve->addKeyframe(CompositorFloatKeyframe(0, 0, *cubic)); curve->addKeyframe( CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared())); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; EXPECT_FLOAT_EQ(timingFunction->GetValue(time), curve->getValue(time)); } }
TEST_F(GraphicsLayerTest, updateLayerShouldFlattenTransformWithAnimations) { ASSERT_FALSE(m_platformLayer->hasTickingAnimationForTesting()); std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); curve->addKeyframe(CompositorFloatKeyframe( 0.0, 0.0, *CubicBezierTimingFunction::preset( CubicBezierTimingFunction::EaseType::EASE))); std::unique_ptr<CompositorAnimation> floatAnimation( CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0)); int animationId = floatAnimation->id(); std::unique_ptr<CompositorAnimationTimeline> compositorTimeline = CompositorAnimationTimeline::create(); AnimationPlayerForTesting player; layerTreeView()->attachCompositorAnimationTimeline( compositorTimeline->animationTimeline()); compositorTimeline->playerAttached(player); m_platformLayer->setElementId(CompositorElementId(m_platformLayer->id(), 0)); player.compositorPlayer()->attachElement(m_platformLayer->elementId()); ASSERT_TRUE(player.compositorPlayer()->isElementAttached()); player.compositorPlayer()->addAnimation(std::move(floatAnimation)); ASSERT_TRUE(m_platformLayer->hasTickingAnimationForTesting()); m_graphicsLayer->setShouldFlattenTransform(false); m_platformLayer = m_graphicsLayer->platformLayer(); ASSERT_TRUE(m_platformLayer); ASSERT_TRUE(m_platformLayer->hasTickingAnimationForTesting()); player.compositorPlayer()->removeAnimation(animationId); ASSERT_FALSE(m_platformLayer->hasTickingAnimationForTesting()); m_graphicsLayer->setShouldFlattenTransform(true); m_platformLayer = m_graphicsLayer->platformLayer(); ASSERT_TRUE(m_platformLayer); ASSERT_FALSE(m_platformLayer->hasTickingAnimationForTesting()); player.compositorPlayer()->detachElement(); ASSERT_FALSE(player.compositorPlayer()->isElementAttached()); compositorTimeline->playerDestroyed(player); layerTreeView()->detachCompositorAnimationTimeline( compositorTimeline->animationTimeline()); }
// Tests that a float animation with multiple keys at a given time works sanely. TEST(WebFloatAnimationCurveTest, RepeatedFloatKeyTimes) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); curve->addKeyframe( CompositorFloatKeyframe(0, 4, *LinearTimingFunction::shared())); curve->addKeyframe( CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared())); curve->addKeyframe( CompositorFloatKeyframe(1, 6, *LinearTimingFunction::shared())); curve->addKeyframe( CompositorFloatKeyframe(2, 6, *LinearTimingFunction::shared())); EXPECT_FLOAT_EQ(4, curve->getValue(-1)); EXPECT_FLOAT_EQ(4, curve->getValue(0)); EXPECT_FLOAT_EQ(4, curve->getValue(0.5)); // There is a discontinuity at 1. Any value between 4 and 6 is valid. float value = curve->getValue(1); EXPECT_TRUE(value >= 4 && value <= 6); EXPECT_FLOAT_EQ(6, curve->getValue(1.5)); EXPECT_FLOAT_EQ(6, curve->getValue(2)); EXPECT_FLOAT_EQ(6, curve->getValue(3)); }
// Tests that a float animation with multiple keys at a given time works sanely. TEST(WebFloatAnimationCurveTest, RepeatedFloatKeyTimes) { scoped_ptr<CompositorFloatAnimationCurve> curve(new CompositorFloatAnimationCurve); curve->add(CompositorFloatKeyframe(0, 4), CompositorAnimationCurve::TimingFunctionTypeLinear); curve->add(CompositorFloatKeyframe(1, 4), CompositorAnimationCurve::TimingFunctionTypeLinear); curve->add(CompositorFloatKeyframe(1, 6), CompositorAnimationCurve::TimingFunctionTypeLinear); curve->add(CompositorFloatKeyframe(2, 6), CompositorAnimationCurve::TimingFunctionTypeLinear); EXPECT_FLOAT_EQ(4, curve->getValue(-1)); EXPECT_FLOAT_EQ(4, curve->getValue(0)); EXPECT_FLOAT_EQ(4, curve->getValue(0.5)); // There is a discontinuity at 1. Any value between 4 and 6 is valid. float value = curve->getValue(1); EXPECT_TRUE(value >= 4 && value <= 6); EXPECT_FLOAT_EQ(6, curve->getValue(1.5)); EXPECT_FLOAT_EQ(6, curve->getValue(2)); EXPECT_FLOAT_EQ(6, curve->getValue(3)); }
TEST_F(GraphicsLayerTest, updateLayerShouldFlattenTransformWithAnimations) { ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); OwnPtr<CompositorFloatAnimationCurve> curve = adoptPtr(CompositorFactory::current().createFloatAnimationCurve()); curve->add(CompositorFloatKeyframe(0.0, 0.0)); OwnPtr<CompositorAnimation> floatAnimation(adoptPtr(CompositorFactory::current().createAnimation(*curve, CompositorTargetProperty::OPACITY))); int animationId = floatAnimation->id(); OwnPtr<CompositorAnimationTimeline> compositorTimeline = adoptPtr(CompositorFactory::current().createAnimationTimeline()); AnimationPlayerForTesting player; layerTreeView()->attachCompositorAnimationTimeline(compositorTimeline->animationTimeline()); compositorTimeline->playerAttached(player); player.compositorPlayer()->attachLayer(m_platformLayer); ASSERT_TRUE(player.compositorPlayer()->isLayerAttached()); player.compositorPlayer()->addAnimation(floatAnimation.leakPtr()); ASSERT_TRUE(m_platformLayer->hasActiveAnimationForTesting()); m_graphicsLayer->setShouldFlattenTransform(false); m_platformLayer = m_graphicsLayer->platformLayer(); ASSERT_TRUE(m_platformLayer); ASSERT_TRUE(m_platformLayer->hasActiveAnimationForTesting()); player.compositorPlayer()->removeAnimation(animationId); ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); m_graphicsLayer->setShouldFlattenTransform(true); m_platformLayer = m_graphicsLayer->platformLayer(); ASSERT_TRUE(m_platformLayer); ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); player.compositorPlayer()->detachLayer(); ASSERT_FALSE(player.compositorPlayer()->isLayerAttached()); compositorTimeline->playerDestroyed(player); layerTreeView()->detachCompositorAnimationTimeline(compositorTimeline->animationTimeline()); }