Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/animation/KeyframeEffectModel.h"
     33 
     34 #include "core/StylePropertyShorthand.h"
     35 #include "core/animation/AnimationNode.h"
     36 #include "platform/geometry/FloatBox.h"
     37 #include "platform/transforms/TransformationMatrix.h"
     38 #include "wtf/text/StringHash.h"
     39 
     40 namespace blink {
     41 
     42 PropertySet KeyframeEffectModelBase::properties() const
     43 {
     44     PropertySet result;
     45     if (!m_keyframes.size()) {
     46         return result;
     47     }
     48     result = m_keyframes[0]->properties();
     49     for (size_t i = 1; i < m_keyframes.size(); i++) {
     50         PropertySet extras = m_keyframes[i]->properties();
     51         for (PropertySet::const_iterator it = extras.begin(); it != extras.end(); ++it) {
     52             result.add(*it);
     53         }
     54     }
     55     return result;
     56 }
     57 
     58 PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > KeyframeEffectModelBase::sample(int iteration, double fraction, double iterationDuration) const
     59 {
     60     ASSERT(iteration >= 0);
     61     ASSERT(!isNull(fraction));
     62     ensureKeyframeGroups();
     63     ensureInterpolationEffect();
     64 
     65     return m_interpolationEffect->getActiveInterpolations(fraction, iterationDuration);
     66 }
     67 
     68 KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes)
     69 {
     70     double lastOffset = 0;
     71     KeyframeVector result;
     72     result.reserveCapacity(keyframes.size());
     73 
     74     for (size_t i = 0; i < keyframes.size(); ++i) {
     75         double offset = keyframes[i]->offset();
     76         if (!isNull(offset)) {
     77             ASSERT(offset >= 0);
     78             ASSERT(offset <= 1);
     79             ASSERT(offset >= lastOffset);
     80             lastOffset = offset;
     81         }
     82         result.append(keyframes[i]->clone());
     83     }
     84 
     85     if (result.isEmpty()) {
     86         return result;
     87     }
     88 
     89     if (isNull(result.last()->offset()))
     90         result.last()->setOffset(1);
     91 
     92     if (result.size() > 1 && isNull(result[0]->offset()))
     93         result[0]->setOffset(0);
     94 
     95     size_t lastIndex = 0;
     96     lastOffset = result[0]->offset();
     97     for (size_t i = 1; i < result.size(); ++i) {
     98         double offset = result[i]->offset();
     99         if (!isNull(offset)) {
    100             for (size_t j = 1; j < i - lastIndex; ++j)
    101                 result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex));
    102             lastIndex = i;
    103             lastOffset = offset;
    104         }
    105     }
    106 
    107     return result;
    108 }
    109 
    110 
    111 void KeyframeEffectModelBase::ensureKeyframeGroups() const
    112 {
    113     if (m_keyframeGroups)
    114         return;
    115 
    116     m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap);
    117     const KeyframeVector keyframes = normalizedKeyframes(getFrames());
    118     for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyframeIter != keyframes.end(); ++keyframeIter) {
    119         const Keyframe* keyframe = keyframeIter->get();
    120         PropertySet keyframeProperties = keyframe->properties();
    121         for (PropertySet::const_iterator propertyIter = keyframeProperties.begin(); propertyIter != keyframeProperties.end(); ++propertyIter) {
    122             CSSPropertyID property = *propertyIter;
    123             ASSERT_WITH_MESSAGE(!isExpandedShorthand(property), "Web Animations: Encountered shorthand CSS property (%d) in normalized keyframes.", property);
    124             KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property);
    125             PropertySpecificKeyframeGroup* group;
    126             if (groupIter == m_keyframeGroups->end())
    127                 group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new PropertySpecificKeyframeGroup)).storedValue->value.get();
    128             else
    129                 group = groupIter->value.get();
    130 
    131             group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property));
    132         }
    133     }
    134 
    135     // Add synthetic keyframes.
    136     for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
    137         iter->value->addSyntheticKeyframeIfRequired(this);
    138         iter->value->removeRedundantKeyframes();
    139     }
    140 }
    141 
    142 void KeyframeEffectModelBase::ensureInterpolationEffect(Element* element) const
    143 {
    144     if (m_interpolationEffect)
    145         return;
    146     m_interpolationEffect = InterpolationEffect::create();
    147 
    148     for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
    149         const PropertySpecificKeyframeVector& keyframes = iter->value->keyframes();
    150         ASSERT(keyframes[0]->composite() == AnimationEffect::CompositeReplace);
    151         for (size_t i = 0; i < keyframes.size() - 1; i++) {
    152             ASSERT(keyframes[i + 1]->composite() == AnimationEffect::CompositeReplace);
    153             double applyFrom = i ? keyframes[i]->offset() : (-std::numeric_limits<double>::infinity());
    154             double applyTo = i == keyframes.size() - 2 ? std::numeric_limits<double>::infinity() : keyframes[i + 1]->offset();
    155             if (applyTo == 1)
    156                 applyTo = std::numeric_limits<double>::infinity();
    157 
    158             m_interpolationEffect->addInterpolation(keyframes[i]->createInterpolation(iter->key, keyframes[i + 1].get(), element),
    159                 &keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i + 1]->offset(), applyFrom, applyTo);
    160         }
    161     }
    162 }
    163 
    164 bool KeyframeEffectModelBase::isReplaceOnly()
    165 {
    166     ensureKeyframeGroups();
    167     for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
    168         const PropertySpecificKeyframeVector& keyframeVector = iter->value->keyframes();
    169         for (size_t i = 0; i < keyframeVector.size(); ++i) {
    170             if (keyframeVector[i]->composite() != AnimationEffect::CompositeReplace)
    171                 return false;
    172         }
    173     }
    174     return true;
    175 }
    176 
    177 void KeyframeEffectModelBase::trace(Visitor* visitor)
    178 {
    179     visitor->trace(m_keyframes);
    180     visitor->trace(m_interpolationEffect);
    181 #if ENABLE_OILPAN
    182     visitor->trace(m_keyframeGroups);
    183 #endif
    184     AnimationEffect::trace(visitor);
    185 }
    186 
    187 Keyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation composite)
    188     : m_offset(offset)
    189     , m_easing(easing)
    190     , m_composite(composite)
    191 {
    192 }
    193 
    194 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> keyframe)
    195 {
    196     ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->offset());
    197     m_keyframes.append(keyframe);
    198 }
    199 
    200 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::removeRedundantKeyframes()
    201 {
    202     // As an optimization, removes keyframes in the following categories, as
    203     // they will never be used by sample().
    204     // - End keyframes with the same offset as their neighbor
    205     // - Interior keyframes with the same offset as both their neighbors
    206     // Note that synthetic keyframes must be added before this method is
    207     // called.
    208     ASSERT(m_keyframes.size() >= 2);
    209     for (int i = m_keyframes.size() - 1; i >= 0; --i) {
    210         double offset = m_keyframes[i]->offset();
    211         bool hasSameOffsetAsPreviousNeighbor = !i || m_keyframes[i - 1]->offset() == offset;
    212         bool hasSameOffsetAsNextNeighbor = i == static_cast<int>(m_keyframes.size() - 1) || m_keyframes[i + 1]->offset() == offset;
    213         if (hasSameOffsetAsPreviousNeighbor && hasSameOffsetAsNextNeighbor)
    214             m_keyframes.remove(i);
    215     }
    216     ASSERT(m_keyframes.size() >= 2);
    217 }
    218 
    219 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired(const KeyframeEffectModelBase* context)
    220 {
    221     ASSERT(!m_keyframes.isEmpty());
    222     if (m_keyframes.first()->offset() != 0.0)
    223         m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, nullptr));
    224     if (m_keyframes.last()->offset() != 1.0)
    225         appendKeyframe(m_keyframes.last()->neutralKeyframe(1, nullptr));
    226 }
    227 
    228 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::trace(Visitor* visitor)
    229 {
    230 #if ENABLE(OILPAN)
    231     visitor->trace(m_keyframes);
    232 #endif
    233 }
    234 
    235 } // namespace
    236