Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2000 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2000 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2000 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      6  * Copyright (C) 2006 Graham Dennis (graham.dennis (at) gmail.com)
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  *
     23  */
     24 
     25 #ifndef TimingFunction_h
     26 #define TimingFunction_h
     27 
     28 #include "RuntimeEnabledFeatures.h"
     29 #include "platform/animation/AnimationUtilities.h" // For blend()
     30 #include "platform/animation/UnitBezier.h"
     31 #include "wtf/OwnPtr.h"
     32 #include "wtf/PassOwnPtr.h"
     33 #include "wtf/PassRefPtr.h"
     34 #include "wtf/RefCounted.h"
     35 #include "wtf/StdLibExtras.h"
     36 #include "wtf/Vector.h"
     37 #include <algorithm>
     38 
     39 
     40 namespace WebCore {
     41 
     42 class TimingFunction : public RefCounted<TimingFunction> {
     43 public:
     44 
     45     enum Type {
     46         LinearFunction, CubicBezierFunction, StepsFunction, ChainedFunction
     47     };
     48 
     49     virtual ~TimingFunction() { }
     50 
     51     Type type() const { return m_type; }
     52 
     53     // Evaluates the timing function at the given fraction. The accuracy parameter provides a hint as to the required
     54     // accuracy and is not guaranteed.
     55     virtual double evaluate(double fraction, double accuracy) const = 0;
     56 
     57 protected:
     58     TimingFunction(Type type)
     59         : m_type(type)
     60     {
     61     }
     62 
     63 private:
     64     Type m_type;
     65 };
     66 
     67 class LinearTimingFunction : public TimingFunction {
     68 public:
     69     static PassRefPtr<LinearTimingFunction> create()
     70     {
     71         return adoptRef(new LinearTimingFunction);
     72     }
     73 
     74     ~LinearTimingFunction() { }
     75 
     76     virtual double evaluate(double fraction, double) const
     77     {
     78         ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1));
     79         ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Timing function behavior outside the range [0, 1] is not yet specified");
     80         return fraction;
     81     }
     82 
     83 private:
     84     LinearTimingFunction()
     85         : TimingFunction(LinearFunction)
     86     {
     87     }
     88 };
     89 
     90 
     91 // Forward declare so we can friend it below. Don't use in production code!
     92 class ChainedTimingFunctionTestHelper;
     93 
     94 class CubicBezierTimingFunction : public TimingFunction {
     95 public:
     96     enum SubType {
     97         Ease,
     98         EaseIn,
     99         EaseOut,
    100         EaseInOut,
    101         Custom
    102     };
    103 
    104     static PassRefPtr<CubicBezierTimingFunction> create(double x1, double y1, double x2, double y2)
    105     {
    106         return adoptRef(new CubicBezierTimingFunction(Custom, x1, y1, x2, y2));
    107     }
    108 
    109     static CubicBezierTimingFunction* preset(SubType subType)
    110     {
    111         switch (subType) {
    112         case Ease:
    113             {
    114                 DEFINE_STATIC_REF(CubicBezierTimingFunction, ease, (adoptRef(new CubicBezierTimingFunction(Ease, 0.25, 0.1, 0.25, 1.0))));
    115                 return ease;
    116             }
    117         case EaseIn:
    118             {
    119                 DEFINE_STATIC_REF(CubicBezierTimingFunction, easeIn, (adoptRef(new CubicBezierTimingFunction(EaseIn, 0.42, 0.0, 1.0, 1.0))));
    120                 return easeIn;
    121             }
    122         case EaseOut:
    123             {
    124                 DEFINE_STATIC_REF(CubicBezierTimingFunction, easeOut, (adoptRef(new CubicBezierTimingFunction(EaseOut, 0.0, 0.0, 0.58, 1.0))));
    125                 return easeOut;
    126             }
    127         case EaseInOut:
    128             {
    129                 DEFINE_STATIC_REF(CubicBezierTimingFunction, easeInOut, (adoptRef(new CubicBezierTimingFunction(EaseInOut, 0.42, 0.0, 0.58, 1.0))));
    130                 return easeInOut;
    131             }
    132         default:
    133             ASSERT_NOT_REACHED();
    134             return 0;
    135         }
    136     }
    137 
    138     ~CubicBezierTimingFunction() { }
    139 
    140     virtual double evaluate(double fraction, double accuracy) const
    141     {
    142         ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1));
    143         ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Timing function behavior outside the range [0, 1] is not yet specified");
    144         if (!m_bezier)
    145             m_bezier = adoptPtr(new UnitBezier(m_x1, m_y1, m_x2, m_y2));
    146         return m_bezier->solve(fraction, accuracy);
    147     }
    148 
    149     double x1() const { return m_x1; }
    150     double y1() const { return m_y1; }
    151     double x2() const { return m_x2; }
    152     double y2() const { return m_y2; }
    153 
    154     SubType subType() const { return m_subType; }
    155 
    156 private:
    157     explicit CubicBezierTimingFunction(SubType subType, double x1, double y1, double x2, double y2)
    158         : TimingFunction(CubicBezierFunction)
    159         , m_x1(x1)
    160         , m_y1(y1)
    161         , m_x2(x2)
    162         , m_y2(y2)
    163         , m_subType(subType)
    164     {
    165     }
    166 
    167     double m_x1;
    168     double m_y1;
    169     double m_x2;
    170     double m_y2;
    171     SubType m_subType;
    172     mutable OwnPtr<UnitBezier> m_bezier;
    173 };
    174 
    175 class StepsTimingFunction : public TimingFunction {
    176 public:
    177     enum SubType {
    178         Start,
    179         End,
    180         Custom
    181     };
    182 
    183     static PassRefPtr<StepsTimingFunction> create(int steps, bool stepAtStart)
    184     {
    185         return adoptRef(new StepsTimingFunction(Custom, steps, stepAtStart));
    186     }
    187 
    188     static StepsTimingFunction* preset(SubType subType)
    189     {
    190         switch (subType) {
    191         case Start:
    192             {
    193                 DEFINE_STATIC_REF(StepsTimingFunction, start, (adoptRef(new StepsTimingFunction(Start, 1, true))));
    194                 return start;
    195             }
    196         case End:
    197             {
    198                 DEFINE_STATIC_REF(StepsTimingFunction, end, (adoptRef(new StepsTimingFunction(End, 1, false))));
    199                 return end;
    200             }
    201         default:
    202             ASSERT_NOT_REACHED();
    203             return 0;
    204         }
    205     }
    206 
    207 
    208     ~StepsTimingFunction() { }
    209 
    210     virtual double evaluate(double fraction, double) const
    211     {
    212         ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1));
    213         ASSERT_WITH_MESSAGE(!RuntimeEnabledFeatures::webAnimationsCSSEnabled() || (fraction >= 0 && fraction <= 1), "Web Animations not yet implemented: Timing function behavior outside the range [0, 1] is not yet specified");
    214         return std::min(1.0, (floor(m_steps * fraction) + m_stepAtStart) / m_steps);
    215     }
    216 
    217     int numberOfSteps() const { return m_steps; }
    218     bool stepAtStart() const { return m_stepAtStart; }
    219 
    220     SubType subType() const { return m_subType; }
    221 
    222 private:
    223     StepsTimingFunction(SubType subType, int steps, bool stepAtStart)
    224         : TimingFunction(StepsFunction)
    225         , m_steps(steps)
    226         , m_stepAtStart(stepAtStart)
    227         , m_subType(subType)
    228     {
    229     }
    230 
    231     int m_steps;
    232     bool m_stepAtStart;
    233     SubType m_subType;
    234 };
    235 
    236 class ChainedTimingFunction : public TimingFunction {
    237 public:
    238     static PassRefPtr<ChainedTimingFunction> create()
    239     {
    240         return adoptRef(new ChainedTimingFunction);
    241     }
    242 
    243     void appendSegment(double upperBound, TimingFunction* timingFunction)
    244     {
    245         double max = m_segments.isEmpty() ? 0 : m_segments.last().max();
    246         ASSERT(upperBound > max);
    247         m_segments.append(Segment(max, upperBound, timingFunction));
    248     }
    249     virtual double evaluate(double fraction, double accuracy) const
    250     {
    251         ASSERT_WITH_MESSAGE(fraction >= 0 && fraction <= 1, "Web Animations not yet implemented: Timing function behavior outside the range [0, 1] is not yet specified");
    252         ASSERT(!m_segments.isEmpty());
    253         ASSERT(m_segments.last().max() == 1);
    254         size_t i = 0;
    255         const Segment* segment = &m_segments[i++];
    256         while (fraction >= segment->max() && i < m_segments.size()) {
    257             segment = &m_segments[i++];
    258         }
    259         return segment->evaluate(fraction, accuracy);
    260     }
    261 
    262 private:
    263     class Segment {
    264     public:
    265         Segment(double min, double max, TimingFunction* timingFunction)
    266             : m_min(min)
    267             , m_max(max)
    268             , m_timingFunction(timingFunction)
    269         { ASSERT(timingFunction); }
    270 
    271         double max() const { return m_max; }
    272         double evaluate(double fraction, double accuracy) const
    273         {
    274             return scaleFromLocal(m_timingFunction->evaluate(scaleToLocal(fraction), accuracy));
    275         }
    276 
    277     private:
    278         double scaleToLocal(double x) const { return (x - m_min) / (m_max - m_min); }
    279         double scaleFromLocal(double x) const { return blend(m_min, m_max, x); }
    280 
    281         double m_min;
    282         double m_max;
    283         RefPtr<TimingFunction> m_timingFunction;
    284 
    285         // FIXME: Come up with a public API for the segments and remove this.
    286         friend class CompositorAnimationsImpl;
    287         friend class CompositorAnimations;
    288 
    289         // Allow the compositor to reverse the timing function.
    290         friend class CompositorAnimationsTimingFunctionReverser;
    291 
    292         // Allow PrintTo/operator== of the segments. Can be removed once
    293         // ChainedTimingFunction has a public API for segments.
    294         friend class ChainedTimingFunctionTestHelper;
    295     };
    296 
    297     ChainedTimingFunction()
    298         : TimingFunction(ChainedFunction)
    299     {
    300         ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
    301     }
    302 
    303     Vector<Segment> m_segments;
    304 
    305     // FIXME: Come up with a public API for the segments and remove this.
    306     friend class CompositorAnimationsImpl;
    307     friend class CompositorAnimations;
    308 
    309     // Allow the compositor to reverse the timing function.
    310     friend class CompositorAnimationsTimingFunctionReverser;
    311 
    312     // Allow PrintTo/operator== of the segments. Can be removed once
    313     // ChainedTimingFunction has a public API for segments.
    314     friend class ChainedTimingFunctionTestHelper;
    315 };
    316 
    317 #define DEFINE_TIMING_FUNCTION_TYPE_CASTS(typeName) \
    318     DEFINE_TYPE_CASTS( \
    319         typeName##TimingFunction, TimingFunction, value, \
    320         value->type() == TimingFunction::typeName##Function, \
    321         value.type() == TimingFunction::typeName##Function)
    322 
    323 DEFINE_TIMING_FUNCTION_TYPE_CASTS(Linear);
    324 DEFINE_TIMING_FUNCTION_TYPE_CASTS(CubicBezier);
    325 DEFINE_TIMING_FUNCTION_TYPE_CASTS(Steps);
    326 DEFINE_TIMING_FUNCTION_TYPE_CASTS(Chained);
    327 
    328 } // namespace WebCore
    329 
    330 #endif // TimingFunction_h
    331