void KeyframeEffectModelBase::ensureKeyframeGroups() const
{
    if (m_keyframeGroups)
        return;

    m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap);
    const KeyframeVector keyframes = normalizedKeyframes(getFrames());
    for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyframeIter != keyframes.end(); ++keyframeIter) {
        const Keyframe* keyframe = keyframeIter->get();
        PropertySet keyframeProperties = keyframe->properties();
        for (PropertySet::const_iterator propertyIter = keyframeProperties.begin(); propertyIter != keyframeProperties.end(); ++propertyIter) {
            CSSPropertyID property = *propertyIter;
            ASSERT_WITH_MESSAGE(!isExpandedShorthand(property), "Web Animations: Encountered shorthand CSS property (%d) in normalized keyframes.", property);
            KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property);
            PropertySpecificKeyframeGroup* group;
            if (groupIter == m_keyframeGroups->end())
                group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new PropertySpecificKeyframeGroup)).storedValue->value.get();
            else
                group = groupIter->value.get();

            group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property));
        }
    }

    // Add synthetic keyframes.
    for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
        iter->value->addSyntheticKeyframeIfRequired(this);
        iter->value->removeRedundantKeyframes();
    }
}
void KeyframeEffectModelBase::ensureKeyframeGroups() const
{
    if (m_keyframeGroups)
        return;

    m_keyframeGroups = adoptPtr(new KeyframeGroupMap);
    RefPtr<TimingFunction> zeroOffsetEasing = m_defaultKeyframeEasing;
    for (const auto& keyframe : normalizedKeyframes(getFrames())) {
        if (keyframe->offset() == 0)
            zeroOffsetEasing = &keyframe->easing();

        for (const PropertyHandle& property : keyframe->properties()) {
            KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property);
            PropertySpecificKeyframeGroup* group;
            if (groupIter == m_keyframeGroups->end())
                group = m_keyframeGroups->add(property, adoptPtr(new PropertySpecificKeyframeGroup)).storedValue->value.get();
            else
                group = groupIter->value.get();

            group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property));
        }
    }

    // Add synthetic keyframes.
    m_hasSyntheticKeyframes = false;
    for (const auto& entry : *m_keyframeGroups) {
        if (entry.value->addSyntheticKeyframeIfRequired(zeroOffsetEasing))
            m_hasSyntheticKeyframes = true;

        entry.value->removeRedundantKeyframes();
    }
}
TEST_F(KeyframeEffectModelTest, EvenlyDistributed3)
{
    KeyframeVector keyframes(12);
    keyframes[0] = AnimatableValueKeyframe::create();
    keyframes[0]->setOffset(0);
    keyframes[1] = AnimatableValueKeyframe::create();
    keyframes[2] = AnimatableValueKeyframe::create();
    keyframes[3] = AnimatableValueKeyframe::create();
    keyframes[4] = AnimatableValueKeyframe::create();
    keyframes[4]->setOffset(0.5);
    keyframes[5] = AnimatableValueKeyframe::create();
    keyframes[6] = AnimatableValueKeyframe::create();
    keyframes[7] = AnimatableValueKeyframe::create();
    keyframes[7]->setOffset(0.8);
    keyframes[8] = AnimatableValueKeyframe::create();
    keyframes[9] = AnimatableValueKeyframe::create();
    keyframes[10] = AnimatableValueKeyframe::create();
    keyframes[11] = AnimatableValueKeyframe::create();

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(12U, result.size());
    EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
    EXPECT_DOUBLE_EQ(0.125, result[1]->offset());
    EXPECT_DOUBLE_EQ(0.25, result[2]->offset());
    EXPECT_DOUBLE_EQ(0.375, result[3]->offset());
    EXPECT_DOUBLE_EQ(0.5, result[4]->offset());
    EXPECT_DOUBLE_EQ(0.6, result[5]->offset());
    EXPECT_DOUBLE_EQ(0.7, result[6]->offset());
    EXPECT_DOUBLE_EQ(0.8, result[7]->offset());
    EXPECT_DOUBLE_EQ(0.85, result[8]->offset());
    EXPECT_DOUBLE_EQ(0.9, result[9]->offset());
    EXPECT_DOUBLE_EQ(0.95, result[10]->offset());
    EXPECT_DOUBLE_EQ(1.0, result[11]->offset());
}
TEST_F(KeyframeEffectModelTest, LastOne)
{
    KeyframeEffectModel::KeyframeVector keyframes(3);
    keyframes[0] = Keyframe::create();
    keyframes[0]->setOffset(-1);
    keyframes[1] = Keyframe::create();
    keyframes[2] = Keyframe::create();
    keyframes[2]->setOffset(2);

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(1U, result.size());
    EXPECT_DOUBLE_EQ(1.0, result[0]->offset());
}
TEST_F(KeyframeEffectModelTest, NotLooselySorted)
{
    KeyframeEffectModel::KeyframeVector keyframes(4);
    keyframes[0] = Keyframe::create();
    keyframes[1] = Keyframe::create();
    keyframes[1]->setOffset(9);
    keyframes[2] = Keyframe::create();
    keyframes[3] = Keyframe::create();
    keyframes[3]->setOffset(1);

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(0U, result.size());
}
TEST_F(KeyframeEffectModelTest, FirstZero)
{
    KeyframeEffectModel::KeyframeVector keyframes(3);
    keyframes[0] = Keyframe::create();
    keyframes[0]->setOffset(-1);
    keyframes[1] = Keyframe::create();
    keyframes[2] = Keyframe::create();
    keyframes[2]->setOffset(0.25);

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(2U, result.size());
    EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
    EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
}
TEST_F(KeyframeEffectModelTest, EvenlyDistributed1)
{
    KeyframeVector keyframes(5);
    keyframes[0] = AnimatableValueKeyframe::create();
    keyframes[0]->setOffset(0.125);
    keyframes[1] = AnimatableValueKeyframe::create();
    keyframes[2] = AnimatableValueKeyframe::create();
    keyframes[3] = AnimatableValueKeyframe::create();
    keyframes[4] = AnimatableValueKeyframe::create();
    keyframes[4]->setOffset(0.625);

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(5U, result.size());
    EXPECT_DOUBLE_EQ(0.125, result[0]->offset());
    EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
    EXPECT_DOUBLE_EQ(0.375, result[2]->offset());
    EXPECT_DOUBLE_EQ(0.5, result[3]->offset());
    EXPECT_DOUBLE_EQ(0.625, result[4]->offset());
}
TEST_F(KeyframeEffectModelTest, EvenlyDistributed2)
{
    KeyframeEffectModel::KeyframeVector keyframes(8);
    keyframes[0] = Keyframe::create();
    keyframes[0]->setOffset(-0.1);
    keyframes[1] = Keyframe::create();
    keyframes[2] = Keyframe::create();
    keyframes[3] = Keyframe::create();
    keyframes[4] = Keyframe::create();
    keyframes[4]->setOffset(0.75);
    keyframes[5] = Keyframe::create();
    keyframes[6] = Keyframe::create();
    keyframes[7] = Keyframe::create();
    keyframes[7]->setOffset(1.1);

    const KeyframeVector result = normalizedKeyframes(keyframes);
    EXPECT_EQ(6U, result.size());
    EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
    EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
    EXPECT_DOUBLE_EQ(0.5, result[2]->offset());
    EXPECT_DOUBLE_EQ(0.75, result[3]->offset());
    EXPECT_DOUBLE_EQ(0.875, result[4]->offset());
    EXPECT_DOUBLE_EQ(1.0, result[5]->offset());
}