Changeset 35545 in webkit


Ignore:
Timestamp:
Aug 4, 2008 6:54:46 PM (16 years ago)
Author:
dino@apple.com
Message:

2008-08-04 Dean Jackson <dino@apple.com>

Reviewed by Dave Hyatt.

Improve AnimationController
https://bugs.webkit.org/show_bug.cgi?id=19938

  • Transition class is now called Animation
  • new state-based AnimationController that can support CSS Animations
  • add support for -webkit-transition-delay
  • remove -webkit-transition-repeat-count (since it never existed officially)
  • updates the -webkit-transition shorthand to reflect removing repeat count
  • updates the Transition class so that properties can be shared with animations
  • adds a "now" keyword for -webkit-transition-delay
  • adds a new change type for style (changed by animation)
  • adds new event names (although they are not dispatched yet)
  • makes text stroke and text fill colors returned by RenderStyle const

Tests:

  • manual-tests/transition-left.html
  • manual-tests/transition-delay.html
  • manual-tests/transition-timing-functions.html
  • css/CSSComputedStyleDeclaration.cpp:
  • css/CSSParser.cpp:
  • css/CSSParser.h:
  • css/CSSPropertyNames.in:
  • css/CSSStyleSelector.cpp:
  • css/CSSStyleSelector.h:
  • css/CSSTimingFunctionValue.h:
  • css/CSSValue.h:
  • css/CSSValueKeywords.in:
  • css/WebKitCSSTransformValue.cpp:
  • dom/Document.cpp:
  • dom/Document.h:
  • dom/Element.cpp:
  • dom/EventNames.h:
  • dom/Node.cpp:
  • dom/Node.h:
  • history/CachedPage.cpp:
  • page/AnimationController.cpp:
  • page/AnimationController.h:
  • page/Frame.cpp:
  • rendering/RenderObject.cpp:
  • rendering/RenderWidget.cpp:
  • rendering/style/RenderStyle.cpp:
  • rendering/style/RenderStyle.h:
Location:
trunk
Files:
3 added
28 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r35541 r35545  
     12008-08-04  Dean Jackson  <dino@apple.com>
     2
     3        Reviewed by Dave Hyatt
     4
     5        Update expected computed style results for the following bug
     6        Improve AnimationController
     7        https://bugs.webkit.org/show_bug.cgi?id=19938
     8
     9        * fast/css/computed-style-expected.txt:
     10        * fast/css/computed-style-without-renderer-expected.txt:
     11        * svg/css/getComputedStyle-basic-expected.txt:
     12
    1132008-08-04  Sam Weinig  <sam@webkit.org>
    214
  • trunk/LayoutTests/fast/css/computed-style-expected.txt

    r35239 r35545  
    139139-webkit-transform-origin-x: 392px;
    140140-webkit-transform-origin-y: 288px;
     141-webkit-transition-delay: 0s;
     142-webkit-transition-duration: 0s;
     143-webkit-transition-property: all;
     144-webkit-transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
    141145-webkit-user-drag: auto;
    142146-webkit-user-modify: read-only;
  • trunk/LayoutTests/fast/css/computed-style-without-renderer-expected.txt

    r35239 r35545  
    138138    -webkit-transform-origin-x: 50%
    139139    -webkit-transform-origin-y: 50%
     140    -webkit-transition-delay: 0s
     141    -webkit-transition-duration: 0s
     142    -webkit-transition-property: all
     143    -webkit-transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1)
    140144    -webkit-user-drag: auto
    141145    -webkit-user-modify: read-only
  • trunk/LayoutTests/svg/css/getComputedStyle-basic-expected.txt

    r35307 r35545  
    275275rect: style.getPropertyValue(-webkit-transform-origin-y) : 0px
    276276rect: style.getPropertyCSSValue(-webkit-transform-origin-y) : [object CSSPrimitiveValue]
     277rect: style.getPropertyValue(-webkit-transition-delay) : 0s
     278rect: style.getPropertyCSSValue(-webkit-transition-delay) : [object CSSValueList]
     279rect: style.getPropertyValue(-webkit-transition-duration) : 0s
     280rect: style.getPropertyCSSValue(-webkit-transition-duration) : [object CSSValueList]
     281rect: style.getPropertyValue(-webkit-transition-property) : all
     282rect: style.getPropertyCSSValue(-webkit-transition-property) : [object CSSValueList]
     283rect: style.getPropertyValue(-webkit-transition-timing-function) : cubic-bezier(0.25, 0.1, 0.25, 1)
     284rect: style.getPropertyCSSValue(-webkit-transition-timing-function) : [object CSSValueList]
    277285rect: style.getPropertyValue(-webkit-user-drag) : auto
    278286rect: style.getPropertyCSSValue(-webkit-user-drag) : [object CSSPrimitiveValue]
     
    643651g: style.getPropertyValue(-webkit-transform-origin-y) : 0px
    644652g: style.getPropertyCSSValue(-webkit-transform-origin-y) : [object CSSPrimitiveValue]
     653g: style.getPropertyValue(-webkit-transition-delay) : 0s
     654g: style.getPropertyCSSValue(-webkit-transition-delay) : [object CSSValueList]
     655g: style.getPropertyValue(-webkit-transition-duration) : 0s
     656g: style.getPropertyCSSValue(-webkit-transition-duration) : [object CSSValueList]
     657g: style.getPropertyValue(-webkit-transition-property) : all
     658g: style.getPropertyCSSValue(-webkit-transition-property) : [object CSSValueList]
     659g: style.getPropertyValue(-webkit-transition-timing-function) : cubic-bezier(0.25, 0.1, 0.25, 1)
     660g: style.getPropertyCSSValue(-webkit-transition-timing-function) : [object CSSValueList]
    645661g: style.getPropertyValue(-webkit-user-drag) : auto
    646662g: style.getPropertyCSSValue(-webkit-user-drag) : [object CSSPrimitiveValue]
  • trunk/WebCore/ChangeLog

    r35544 r35545  
    1 2008-05-12  Mike Belshe  <mike@belshe.com>
    2 
    3         Reviewed by Antti.
    4        
    5         Currently we create two copies of script in the HTMLTokenizer.
    6         One copy gets passed into the javascript engine, the other gets
    7         stored in the DOM.  Modify the HTMLParser so that it does not
    8         chunk the string into it's normal 64K chunks for script code,
    9         and modify the HTMLTokenizer to pass that same string into the
    10         JS engine.  On some sites (e.g. GMail), which have hundreds of
    11         KB of inline JS, this saves more than a MB of RAM to run the page.
    12         (Strings use 16bit strings, so 600KB of JS code == 1.2MB of memory)
    13 
    14         * html\HTMLParser.cpp
    15         * html\HTMLTokenizer.cpp
     12008-08-04  Dean Jackson  <dino@apple.com>
     2
     3        Reviewed by Dave Hyatt.
     4
     5        Improve AnimationController
     6        https://bugs.webkit.org/show_bug.cgi?id=19938
     7
     8        - Transition class is now called Animation
     9        - new state-based AnimationController that can support CSS Animations
     10        - add support for -webkit-transition-delay
     11        - remove -webkit-transition-repeat-count (since it never existed officially)
     12        - updates the -webkit-transition shorthand to reflect removing repeat count
     13        - updates the Transition class so that properties can be shared with animations
     14        - adds a "now" keyword for -webkit-transition-delay
     15        - adds a new change type for style (changed by animation)
     16        - adds new event names (although they are not dispatched yet)
     17        - makes text stroke and text fill colors returned by RenderStyle const
     18
     19        Tests:
     20        - manual-tests/transition-left.html
     21        - manual-tests/transition-delay.html
     22        - manual-tests/transition-timing-functions.html
     23
     24        * css/CSSComputedStyleDeclaration.cpp:
     25        * css/CSSParser.cpp:
     26        * css/CSSParser.h:
     27        * css/CSSPropertyNames.in:
     28        * css/CSSStyleSelector.cpp:
     29        * css/CSSStyleSelector.h:
     30        * css/CSSTimingFunctionValue.h:
     31        * css/CSSValue.h:
     32        * css/CSSValueKeywords.in:
     33        * css/WebKitCSSTransformValue.cpp:
     34        * dom/Document.cpp:
     35        * dom/Document.h:
     36        * dom/Element.cpp:
     37        * dom/EventNames.h:
     38        * dom/Node.cpp:
     39        * dom/Node.h:
     40        * history/CachedPage.cpp:
     41        * page/AnimationController.cpp:
     42        * page/AnimationController.h:
     43        * page/Frame.cpp:
     44        * rendering/RenderObject.cpp:
     45        * rendering/RenderWidget.cpp:
     46        * rendering/style/RenderStyle.cpp:
     47        * rendering/style/RenderStyle.h:
    1648
    17492008-08-04  Sam Weinig  <sam@webkit.org>
  • trunk/WebCore/css/CSSComputedStyleDeclaration.cpp

    r35240 r35545  
    3030#include "CSSPropertyNames.h"
    3131#include "CSSReflectValue.h"
     32#include "CSSTimingFunctionValue.h"
    3233#include "CSSValueList.h"
    3334#include "CachedImage.h"
     
    188189    CSSPropertyWebkitTransformOriginX,
    189190    CSSPropertyWebkitTransformOriginY,
     191    CSSPropertyWebkitTransitionDelay,
     192    CSSPropertyWebkitTransitionDuration,
     193    CSSPropertyWebkitTransitionProperty,
     194    CSSPropertyWebkitTransitionTimingFunction,
    190195    CSSPropertyWebkitUserDrag,
    191196    CSSPropertyWebkitUserModify,
     
    10561061            else
    10571062                return CSSPrimitiveValue::create(style->transformOriginY());
     1063        case CSSPropertyWebkitTransitionDelay: {
     1064            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
     1065            const AnimationList* t = style->transitions();
     1066            if (t) {
     1067                for (size_t i = 0; i < t->size(); ++i)
     1068                    list->append(CSSPrimitiveValue::create((*t)[i]->delay(), CSSPrimitiveValue::CSS_S));
     1069            }
     1070            else
     1071                list->append(CSSPrimitiveValue::create(RenderStyle::initialDelay(), CSSPrimitiveValue::CSS_S));
     1072            return list.release();
     1073        }
     1074        case CSSPropertyWebkitTransitionDuration: {
     1075            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
     1076            const AnimationList* t = style->transitions();
     1077            if (t) {
     1078                for (size_t i = 0; i < t->size(); ++i)
     1079                    list->append(CSSPrimitiveValue::create((*t)[i]->duration(), CSSPrimitiveValue::CSS_S));
     1080            }
     1081            else
     1082                list->append(CSSPrimitiveValue::create(RenderStyle::initialDuration(), CSSPrimitiveValue::CSS_S));
     1083            return list.release();
     1084        }
     1085        case CSSPropertyWebkitTransitionTimingFunction: {
     1086            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
     1087            const AnimationList* t = style->transitions();
     1088            if (t) {
     1089                for (size_t i = 0; i < t->size(); ++i) {
     1090                    const TimingFunction& tf = (*t)[i]->timingFunction();
     1091                    list->append(CSSTimingFunctionValue::create(tf.x1(), tf.y1(), tf.x2(), tf.y2()));
     1092                }
     1093            }
     1094            else {
     1095                const TimingFunction& tf = RenderStyle::initialTimingFunction();
     1096                list->append(CSSTimingFunctionValue::create(tf.x1(), tf.y1(), tf.x2(), tf.y2()));
     1097            }
     1098            return list.release();
     1099        }
     1100        case CSSPropertyWebkitTransitionProperty: {
     1101            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
     1102            const AnimationList* t = style->transitions();
     1103            if (t) {
     1104                for (size_t i = 0; i < t->size(); ++i) {
     1105                    int prop = (*t)[i]->property();
     1106                    const char* name;
     1107                    if (prop == cAnimateNone)
     1108                        name = "none";
     1109                    else if (prop == cAnimateAll)
     1110                        name = "all";
     1111                    else
     1112                        name = getPropertyName(static_cast<CSSPropertyID>(prop));
     1113                    list->append(CSSPrimitiveValue::create(name, CSSPrimitiveValue::CSS_STRING));
     1114                }
     1115            }
     1116            else
     1117                list->append(CSSPrimitiveValue::create("all", CSSPrimitiveValue::CSS_STRING));
     1118            return list.release();
     1119        }
    10581120        case CSSPropertyBackground:
    10591121        case CSSPropertyBorder:
     
    11131175        case CSSPropertyWebkitPaddingStart:
    11141176        case CSSPropertyWebkitTextStroke:
    1115         case CSSPropertyWebkitTransition:
    1116         case CSSPropertyWebkitTransitionDuration:
    1117         case CSSPropertyWebkitTransitionProperty:
    1118         case CSSPropertyWebkitTransitionRepeatCount:
    1119         case CSSPropertyWebkitTransitionTimingFunction:
    11201177            // FIXME: The above are unimplemented.
    11211178            break;
  • trunk/WebCore/css/CSSParser.cpp

    r35414 r35545  
    12951295        return false;
    12961296    }
     1297    case CSSPropertyWebkitTransitionDelay:
    12971298    case CSSPropertyWebkitTransitionDuration:
    1298     case CSSPropertyWebkitTransitionRepeatCount:
    12991299    case CSSPropertyWebkitTransitionTimingFunction:
    13001300    case CSSPropertyWebkitTransitionProperty: {
     
    17101710bool CSSParser::parseTransitionShorthand(bool important)
    17111711{
    1712     const int properties[] = { CSSPropertyWebkitTransitionProperty, CSSPropertyWebkitTransitionDuration,
    1713                                CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitTransitionRepeatCount };
     1712    const int properties[] = { CSSPropertyWebkitTransitionProperty,
     1713                               CSSPropertyWebkitTransitionDuration,
     1714                               CSSPropertyWebkitTransitionTimingFunction };
    17141715    const int numProperties = sizeof(properties) / sizeof(properties[0]);
    17151716   
     
    22072208}
    22082209
    2209 PassRefPtr<CSSValue> CSSParser::parseTransitionDuration()
     2210PassRefPtr<CSSValue> CSSParser::parseDelay()
    22102211{
    22112212    CSSParserValue* value = m_valueList->current();
     2213    if (value->id == CSSValueNow)
     2214        return CSSPrimitiveValue::createIdentifier(value->id);
    22122215    if (validUnit(value, FTime, m_strict))
    22132216        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
     
    22152218}
    22162219
    2217 PassRefPtr<CSSValue> CSSParser::parseTransitionRepeatCount()
     2220PassRefPtr<CSSValue> CSSParser::parseDuration()
    22182221{
    22192222    CSSParserValue* value = m_valueList->current();
    2220     if (value->id == CSSValueInfinite)
    2221         return CSSPrimitiveValue::createIdentifier(value->id);
    2222     if (validUnit(value, FInteger|FNonNeg, m_strict))
     2223    if (validUnit(value, FTime|FNonNeg, m_strict))
    22232224        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
    22242225    return 0;
     
    22432244}
    22442245
    2245 PassRefPtr<CSSValue> CSSParser::parseTransitionTimingFunction()
     2246PassRefPtr<CSSValue> CSSParser::parseTimingFunction()
    22462247{
    22472248    CSSParserValue* value = m_valueList->current();
     
    23072308        else {
    23082309            switch (propId) {
    2309                 case CSSPropertyWebkitTransitionDuration:
    2310                     currValue = parseTransitionDuration();
     2310                case CSSPropertyWebkitTransitionDelay:
     2311                    currValue = parseDelay();
    23112312                    if (currValue)
    23122313                        m_valueList->next();
    23132314                    break;
    2314                 case CSSPropertyWebkitTransitionRepeatCount:
    2315                     currValue = parseTransitionRepeatCount();
     2315                case CSSPropertyWebkitTransitionDuration:
     2316                    currValue = parseDuration();
    23162317                    if (currValue)
    23172318                        m_valueList->next();
    23182319                    break;
    23192320                case CSSPropertyWebkitTransitionTimingFunction:
    2320                     currValue = parseTransitionTimingFunction();
     2321                    currValue = parseTimingFunction();
    23212322                    if (currValue)
    23222323                        m_valueList->next();
     
    39083909    // The transform is a list of functional primitives that specify transform operations.
    39093910    // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
    3910     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
     3911    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
    39113912    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
    39123913        if (value->unit != CSSParserValue::Function || !value->function)
  • trunk/WebCore/css/CSSParser.h

    r35414 r35545  
    8585
    8686        void addTransitionValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval);
    87         PassRefPtr<CSSValue> parseTransitionDuration();
    88         PassRefPtr<CSSValue> parseTransitionRepeatCount();
    89         PassRefPtr<CSSValue> parseTransitionTimingFunction();
     87
     88        PassRefPtr<CSSValue> parseDelay();
     89        PassRefPtr<CSSValue> parseDuration();
     90        PassRefPtr<CSSValue> parseTimingFunction();
     91        PassRefPtr<CSSValue> parseTransitionProperty();
     92
    9093        bool parseTimingFunctionValue(CSSParserValueList*& args, double& result);
    91         PassRefPtr<CSSValue> parseTransitionProperty();
    9294        bool parseTransitionProperty(int propId, RefPtr<CSSValue>&);
    9395        bool parseTransitionShorthand(bool important);
  • trunk/WebCore/css/CSSPropertyNames.in

    r35414 r35545  
    143143z-index
    144144zoom
    145 -webkit-transition
    146 -webkit-transition-duration
    147 -webkit-transition-property
    148 -webkit-transition-repeat-count
    149 -webkit-transition-timing-function
    150145-webkit-appearance
    151146-webkit-background-clip
     
    226221-webkit-transform-origin-x
    227222-webkit-transform-origin-y
     223-webkit-transition
     224-webkit-transition-delay
     225-webkit-transition-duration
     226-webkit-transition-property
     227-webkit-transition-timing-function
    228228-webkit-user-drag
    229229-webkit-user-modify
  • trunk/WebCore/css/CSSStyleSelector.cpp

    r35438 r35545  
    185185#define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
    186186if (isInherit) { \
    187     Transition* currChild = m_style->accessTransitions(); \
    188     Transition* prevChild = 0; \
    189     const Transition* currParent = m_parentStyle->transitions(); \
    190     while (currParent && currParent->is##Prop##Set()) { \
    191         if (!currChild) { \
    192             /* Need to make a new layer.*/ \
    193             currChild = new Transition(); \
    194             prevChild->setNext(currChild); \
    195         } \
    196         currChild->set##Prop(currParent->prop()); \
    197         prevChild = currChild; \
    198         currChild = prevChild->next(); \
    199         currParent = currParent->next(); \
     187    AnimationList* list = m_style->accessTransitions(); \
     188    const AnimationList* parentList = m_parentStyle->transitions(); \
     189    size_t i = 0; \
     190    for ( ; i < parentList->size() && (*parentList)[i]->is##Prop##Set(); ++i) { \
     191        if (list->size() <= i) \
     192            list->append(Animation::create()); \
     193        (*list)[i]->set##Prop((*parentList)[i]->prop()); \
    200194    } \
    201195    \
    202     while (currChild) { \
    203         /* Reset any remaining layers to not have the property set. */ \
    204         currChild->clear##Prop(); \
    205         currChild = currChild->next(); \
    206     } \
    207 } else if (isInitial) { \
    208     Transition* currChild = m_style->accessTransitions(); \
    209     currChild->set##Prop(RenderStyle::initialTransition##Prop()); \
    210     for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
    211         currChild->clear##Prop(); \
     196    /* Reset any remaining layers to not have the property set. */ \
     197    for ( ; i < list->size(); ++i) \
     198        (*list)[i]->clear##Prop(); \
     199} \
     200if (isInitial) { \
     201    AnimationList* list = m_style->accessTransitions(); \
     202    (*list)[0]->set##Prop(RenderStyle::initial##Prop()); \
     203    for (size_t i = 1; i < list->size(); ++i) \
     204        (*list)[0]->clear##Prop(); \
    212205}
    213206
     
    216209if (isInherit || isInitial) \
    217210    return; \
    218 Transition* currChild = m_style->accessTransitions(); \
    219 Transition* prevChild = 0; \
     211AnimationList* list = m_style->accessTransitions(); \
     212size_t childIndex = 0; \
    220213if (value->isValueList()) { \
    221214    /* Walk each value and put it into a layer, creating new layers as needed. */ \
    222215    CSSValueList* valueList = static_cast<CSSValueList*>(value); \
    223216    for (unsigned int i = 0; i < valueList->length(); i++) { \
    224         if (!currChild) { \
    225             /* Need to make a new layer to hold this value */ \
    226             currChild = new Transition(); \
    227             prevChild->setNext(currChild); \
    228         } \
    229         mapTransition##Prop(currChild, valueList->itemWithoutBoundsCheck(i)); \
    230         prevChild = currChild; \
    231         currChild = currChild->next(); \
     217        if (childIndex <= list->size()) \
     218            list->append(Animation::create()); \
     219        map##Prop((*list)[childIndex].get(), valueList->itemWithoutBoundsCheck(i)); \
     220        ++childIndex; \
    232221    } \
    233222} else { \
    234     mapTransition##Prop(currChild, value); \
    235     currChild = currChild->next(); \
     223    if (list->isEmpty()) \
     224        list->append(Animation::create()); \
     225    map##Prop((*list)[childIndex].get(), value); \
     226    childIndex = 1; \
    236227} \
    237 while (currChild) { \
     228for ( ; childIndex < list->size(); ++childIndex) { \
    238229    /* Reset all remaining layers to not have the property set. */ \
    239     currChild->clear##Prop(); \
    240     currChild = currChild->next(); \
    241 } }
     230    (*list)[childIndex]->clear##Prop(); \
     231} \
     232}
    242233
    243234#define HANDLE_INHERIT_COND(propID, prop, Prop) \
     
    47594750            m_style->inheritTransitions(m_parentStyle->transitions());
    47604751        return;
     4752    case CSSPropertyWebkitTransitionDelay:
     4753        HANDLE_TRANSITION_VALUE(delay, Delay, value)
     4754        return;
    47614755    case CSSPropertyWebkitTransitionDuration:
    47624756        HANDLE_TRANSITION_VALUE(duration, Duration, value)
    47634757        return;
    4764     case CSSPropertyWebkitTransitionRepeatCount:
    4765         HANDLE_TRANSITION_VALUE(repeatCount, RepeatCount, value)
     4758    case CSSPropertyWebkitTransitionProperty:
     4759        HANDLE_TRANSITION_VALUE(property, Property, value)
    47664760        return;
    47674761    case CSSPropertyWebkitTransitionTimingFunction:
    47684762        HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value)
    4769         return;
    4770     case CSSPropertyWebkitTransitionProperty:
    4771         HANDLE_TRANSITION_VALUE(property, Property, value)
    47724763        return;
    47734764    case CSSPropertyInvalid:
     
    50115002}
    50125003
    5013 void CSSStyleSelector::mapTransitionDuration(Transition* transition, CSSValue* value)
     5004void CSSStyleSelector::mapDuration(Animation* transition, CSSValue* value)
    50145005{
    50155006    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
    5016         transition->setDuration(RenderStyle::initialTransitionDuration());
     5007        transition->setDuration(RenderStyle::initialDuration());
    50175008        return;
    50185009    }
     
    50235014    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
    50245015    if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
    5025         transition->setDuration(int(1000*primitiveValue->getFloatValue()));
     5016        transition->setDuration(primitiveValue->getFloatValue());
    50265017    else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
    5027         transition->setDuration(int(primitiveValue->getFloatValue()));
    5028 }
    5029 
    5030 void CSSStyleSelector::mapTransitionRepeatCount(Transition* transition, CSSValue* value)
     5018        transition->setDuration(primitiveValue->getFloatValue()/1000.0f);
     5019}
     5020
     5021void CSSStyleSelector::mapDelay(Animation* transition, CSSValue* value)
    50315022{
    50325023    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
    5033         transition->setRepeatCount(RenderStyle::initialTransitionRepeatCount());
    5034         return;
    5035     }
    5036 
    5037     if (!value->isPrimitiveValue())
    5038         return;
     5024        transition->setDelay(RenderStyle::initialDelay());
     5025        return;
     5026    }
    50395027
    50405028    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
    5041     if (primitiveValue->getIdent() == CSSValueInfinite)
    5042         transition->setRepeatCount(-1);
    5043     else
    5044         transition->setRepeatCount(int(primitiveValue->getFloatValue()));
    5045 }
    5046 
    5047 void CSSStyleSelector::mapTransitionTimingFunction(Transition* transition, CSSValue* value)
     5029    if (primitiveValue->getIdent() == CSSValueNow)
     5030        transition->setDelay(0);
     5031    else {
     5032        if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
     5033            transition->setDelay(primitiveValue->getFloatValue());
     5034        else
     5035            transition->setDelay(primitiveValue->getFloatValue()/1000.0f);
     5036    }
     5037}
     5038
     5039void CSSStyleSelector::mapTimingFunction(Animation* transition, CSSValue* value)
    50485040{
    50495041    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
    5050         transition->setTimingFunction(RenderStyle::initialTransitionTimingFunction());
    5051         return;
    5052     }
    5053 
     5042        transition->setTimingFunction(RenderStyle::initialTimingFunction());
     5043        return;
     5044    }
     5045   
    50545046    if (value->isPrimitiveValue()) {
    50555047        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
     
    50735065        return;
    50745066    }
    5075 
    5076     if (value->isTransitionTimingFunctionValue()) {
     5067   
     5068    if (value->isTimingFunctionValue()) {
    50775069        CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value);
    50785070        transition->setTimingFunction(TimingFunction(CubicBezierTimingFunction, timingFunction->x1(), timingFunction->y1(), timingFunction->x2(), timingFunction->y2()));
     
    50805072}
    50815073
    5082 void CSSStyleSelector::mapTransitionProperty(Transition* transition, CSSValue* value)
     5074void CSSStyleSelector::mapProperty(Animation* transition, CSSValue* value)
    50835075{
    50845076    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
    5085         transition->setProperty(RenderStyle::initialTransitionProperty());
     5077        transition->setProperty(RenderStyle::initialProperty());
    50865078        return;
    50875079    }
     
    50915083
    50925084    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
    5093     transition->setProperty(primitiveValue->getIdent());
     5085    transition->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent()));
    50945086}
    50955087
  • trunk/WebCore/css/CSSStyleSelector.h

    r35414 r35545  
    206206        void mapFillYPosition(FillLayer*, CSSValue*);
    207207
    208         void mapTransitionDuration(Transition*, CSSValue*);
    209         void mapTransitionRepeatCount(Transition*, CSSValue*);
    210         void mapTransitionTimingFunction(Transition*, CSSValue*);
    211         void mapTransitionProperty(Transition*, CSSValue*);
     208        void mapDelay(Animation*, CSSValue*);
     209        void mapDuration(Animation*, CSSValue*);
     210        void mapTimingFunction(Animation*, CSSValue*);
     211        void mapProperty(Animation*, CSSValue*);
    212212
    213213        void mapNinePieceImage(CSSValue*, NinePieceImage&);
  • trunk/WebCore/css/CSSTimingFunctionValue.h

    r34627 r35545  
    5555    }
    5656
    57     virtual bool isTransitionTimingFunctionValue() { return true; }
     57    virtual bool isTimingFunctionValue() { return true; }
    5858   
    5959    double m_x1;
  • trunk/WebCore/css/CSSValue.h

    r34666 r35545  
    5353    virtual bool isImplicitInitialValue() const { return false; }
    5454    virtual bool isPrimitiveValue() const { return false; }
    55     virtual bool isTransitionTimingFunctionValue() { return false; }
     55    virtual bool isTimingFunctionValue() { return false; }
    5656    virtual bool isValueList() { return false; }
    5757
  • trunk/WebCore/css/CSSValueKeywords.in

    r34910 r35545  
    564564
    565565#
     566# CSS_PROP__WEBKIT_TRANSITION_DELAY
     567#
     568now
     569
     570#
    566571# CSS_PROP__WEBKIT_TRANSITION_TIMING_FUNCTION
    567572#
  • trunk/WebCore/dom/Document.cpp

    r35478 r35545  
    2525#include "Document.h"
    2626
     27#include "AnimationController.h"
    2728#include "AXObjectCache.h"
    2829#include "CDATASection.h"
     
    11631164    if (hasChangedChild())
    11641165        recalcStyle(NoChange);
     1166   
     1167    // tell the animation controller that the style is available and it can start animations
     1168    if (m_frame)
     1169        m_frame->animation()->styleAvailable();
    11651170}
    11661171
  • trunk/WebCore/dom/Document.h

    r35172 r35545  
    751751    void updateFocusAppearanceSoon();
    752752    void cancelFocusAppearanceUpdate();
    753    
     753       
    754754    // FF method for accessing the selection added for compatability.
    755755    DOMSelection* getSelection() const;
     
    10471047    bool m_inLowBandwidthDisplay;
    10481048#endif
     1049
    10491050};
    10501051
  • trunk/WebCore/dom/Element.cpp

    r35332 r35545  
    786786        }
    787787
    788         if (ch != NoChange)
     788        if (ch != NoChange) {
    789789            setRenderStyle(newStyle);
    790         else if (changed() && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
     790        } else if (changed() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
    791791            // Although no change occurred, we use the new style so that the cousin style sharing code won't get
    792792            // fooled into believing this style is the same.  This is only necessary if the document actually uses
     
    797797            else
    798798                setRenderStyle(newStyle);
    799         }
     799        } else if (styleChangeType() == AnimationStyleChange)
     800             setRenderStyle(newStyle);
    800801
    801802        newStyle->deref(document()->renderArena());
    802803
    803804        if (change != Force) {
    804             if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() == FullStyleChange)
     805            if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange)
    805806                change = Force;
    806807            else
  • trunk/WebCore/dom/EventNames.h

    r34775 r35545  
    120120    macro(stalled) \
    121121    \
     122    macro(webkitAnimationEnd) \
     123    macro(webkitAnimationStart) \
     124    macro(webkitAnimationIteration) \
     125    \
     126    macro(webkitTransitionEnd) \
     127    \
    122128// end of DOM_EVENT_NAMES_FOR_EACH
    123129
  • trunk/WebCore/dom/Node.cpp

    r35478 r35545  
    413413        return;
    414414
    415     if (!(changeType == InlineStyleChange && m_styleChange == FullStyleChange))
     415    if (!(changeType == InlineStyleChange && (m_styleChange == FullStyleChange || m_styleChange == AnimationStyleChange)))
    416416        m_styleChange = changeType;
    417417
  • trunk/WebCore/dom/Node.h

    r35332 r35545  
    6262typedef int ExceptionCode;
    6363
    64 enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange };
     64enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange, AnimationStyleChange };
    6565
    6666const unsigned short DOCUMENT_POSITION_EQUIVALENT = 0x00;
  • trunk/WebCore/history/CachedPage.cpp

    r35478 r35545  
    123123#endif
    124124
    125     mainFrame->animation()->resumeAnimations();
     125    mainFrame->animation()->resumeAnimations(m_document.get());
    126126
    127127    mainFrame->eventHandler()->setMousePressNode(mousePressNode());
  • trunk/WebCore/page/AnimationController.cpp

    r35207 r35545  
    3131
    3232#include "CSSPropertyNames.h"
     33#include "CString.h"
    3334#include "Document.h"
     35#include "EventNames.h"
    3436#include "FloatConversion.h"
    3537#include "Frame.h"
     
    4446static const double cAnimationTimerDelay = 0.025;
    4547
     48static void setChanged(Node* node)
     49{
     50    ASSERT(!node || (node->document() && !node->document()->inPageCache()));
     51    node->setChanged(AnimationStyleChange);
     52}
     53
    4654// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
    4755// animation, the more precision we need in the timing function result to avoid ugly discontinuities.
     
    5664}
    5765
    58 class CompositeImplicitAnimation;
    59 
    60 class ImplicitAnimation : public Noncopyable {
     66class CompositeAnimation;
     67class AnimationBase;
     68
     69class AnimationTimerBase {
    6170public:
    62     ImplicitAnimation(const Transition*);
    63     ~ImplicitAnimation();
    64 
    65     void animate(CompositeImplicitAnimation*, RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle, RenderStyle*& animatedStyle);
    66 
    67     void reset(RenderObject*, RenderStyle* from, RenderStyle* to);
    68    
    69     double progress() const;
    70 
     71    AnimationTimerBase(AnimationBase* anim)
     72    : m_timer(this, &AnimationTimerBase::timerFired)
     73    , m_anim(anim)
     74    {
     75        m_timer.startOneShot(0);
     76    }
     77    virtual ~AnimationTimerBase()
     78    {
     79    }
     80   
     81    void startTimer(double timeout=0)
     82    {
     83        m_timer.startOneShot(timeout);
     84    }
     85   
     86    void cancelTimer()
     87    {
     88        m_timer.stop();
     89    }
     90   
     91    virtual void timerFired(Timer<AnimationTimerBase>*) = 0;
     92   
     93private:
     94    Timer<AnimationTimerBase> m_timer;
     95   
     96protected:
     97    AnimationBase* m_anim;
     98};
     99
     100class AnimationEventDispatcher : public AnimationTimerBase {
     101public:
     102    AnimationEventDispatcher(AnimationBase* anim)
     103    : AnimationTimerBase(anim)
     104    , m_property(CSSPropertyInvalid)
     105    , m_reset(false)
     106    , m_elapsedTime(-1)
     107    {
     108    }
     109   
     110    virtual ~AnimationEventDispatcher()
     111    {
     112    }
     113   
     114    void startTimer(Element* element, const AtomicString& name, int property, bool reset,
     115                    const AtomicString& eventType, double elapsedTime)
     116    {
     117        m_element = element;
     118        m_name = name;
     119        m_property = property;
     120        m_reset = reset;
     121        m_eventType = eventType;
     122        m_elapsedTime = elapsedTime;
     123        AnimationTimerBase::startTimer();
     124    }
     125   
     126    virtual void timerFired(Timer<AnimationTimerBase>*);
     127   
     128private:
     129    RefPtr<Element> m_element;
     130    AtomicString m_name;
     131    int m_property;
     132    bool m_reset;
     133    AtomicString m_eventType;
     134    double m_elapsedTime;
     135};
     136
     137class AnimationTimerCallback : public AnimationTimerBase {
     138public:
     139    AnimationTimerCallback(AnimationBase* anim)
     140    : AnimationTimerBase(anim)
     141    , m_elapsedTime(0)
     142    { }
     143    virtual ~AnimationTimerCallback() { }
     144   
     145    virtual void timerFired(Timer<AnimationTimerBase>*);
     146   
     147    void startTimer(double timeout, const AtomicString& eventType, double elapsedTime)
     148    {
     149        m_eventType = eventType;
     150        m_elapsedTime = elapsedTime;
     151        AnimationTimerBase::startTimer(timeout);
     152    }
     153   
     154private:
     155    AtomicString m_eventType;
     156    double m_elapsedTime;
     157};
     158
     159class ImplicitAnimation;
     160class AnimationControllerPrivate;
     161
     162// A CompositeAnimation represents a collection of animations that
     163// are running, such as a number of properties transitioning at once.
     164
     165class CompositeAnimation : public Noncopyable {
     166public:
     167    CompositeAnimation(AnimationControllerPrivate* animationController)
     168    : m_suspended(false)
     169    , m_animationController(animationController)
     170    , m_numStyleAvailableWaiters(0)
     171    { }
     172   
     173    ~CompositeAnimation()
     174    {
     175        deleteAllValues(m_transitions);
     176    }
     177   
     178    RenderStyle* animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
     179   
     180    void setAnimating(bool inAnimating);
     181    bool animating();
     182   
     183    bool hasAnimationForProperty(int prop) const { return m_transitions.contains(prop); }
     184   
     185    void setTransitionStartTime(int property, double t);
     186   
     187    void resetTransitions(RenderObject*);
     188    void resetAnimations(RenderObject*);
     189   
     190    void cleanupFinishedAnimations(RenderObject*);
     191   
     192    void suspendAnimations();
     193    void resumeAnimations();
     194    bool suspended() const      { return m_suspended; }
     195   
     196    void overrideImplicitAnimations(int property);
     197    void resumeOverriddenImplicitAnimations(int property);
     198   
     199    void styleAvailable();
     200   
     201    bool isAnimatingProperty(int property) const;
     202   
     203    void setWaitingForStyleAvailable(bool waiting);
     204protected:
     205    void updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle);
     206   
     207private:
     208    typedef HashMap<int, ImplicitAnimation*> CSSPropertyTransitionsMap;
     209   
     210    CSSPropertyTransitionsMap   m_transitions;
     211    bool                        m_suspended;
     212    AnimationControllerPrivate* m_animationController;
     213    uint32_t                    m_numStyleAvailableWaiters;
     214};
     215
     216class AnimationBase : public Noncopyable {
     217public:
     218    AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim);   
     219    virtual ~AnimationBase()
     220    {
     221        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
     222            m_compAnim->setWaitingForStyleAvailable(false);
     223    }
     224   
     225    RenderObject* renderer() const { return m_object; }
     226    double startTime() const { return m_startTime; }
     227    double duration() const  { return m_animation->duration(); }
     228   
     229    void cancelTimers()
     230    {
     231        m_animationTimerCallback.cancelTimer();
     232        m_animationEventDispatcher.cancelTimer();
     233    }
     234   
     235    // Animations and Transitions go through the states below. When entering the STARTED state
     236    // the animation is started. This may or may not require deferred response from the animator.
     237    // If so, we stay in this state until that response is received (and it returns the start time).
     238    // Otherwise, we use the current time as the start time and go immediately to the LOOPING or
     239    // ENDING state.
     240    enum AnimState {
     241        STATE_NEW,                      // animation just created, animation not running yet
     242        STATE_START_WAIT_TIMER,         // start timer running, waiting for fire
     243        STATE_START_WAIT_STYLE_AVAILABLE,   // waiting for style setup so we can start animations
     244        STATE_START_WAIT_RESPONSE,      // animation started, waiting for response
     245        STATE_LOOPING,                  // response received, animation running, loop timer running, waiting for fire
     246        STATE_ENDING,                   // response received, animation running, end timer running, waiting for fire
     247        STATE_PAUSED_WAIT_TIMER,        // animation in pause mode when animation started
     248        STATE_PAUSED_WAIT_RESPONSE,     // animation paused when in STARTING state
     249        STATE_PAUSED_RUN,               // animation paused when in LOOPING or ENDING state
     250        STATE_DONE                      // end timer fired, animation finished and removed
     251    };
     252   
     253    enum AnimStateInput {
     254        STATE_INPUT_MAKE_NEW,           // reset back to new from any state
     255        STATE_INPUT_START_ANIMATION,    // animation requests a start
     256        STATE_INPUT_RESTART_ANIMATION,  // force a restart from any state
     257        STATE_INPUT_START_TIMER_FIRED,  // start timer fired
     258        STATE_INPUT_STYLE_AVAILABLE,        // style is setup, ready to start animating
     259        STATE_INPUT_START_TIME_SET,     // m_startTime was set
     260        STATE_INPUT_LOOP_TIMER_FIRED,   // loop timer fired
     261        STATE_INPUT_END_TIMER_FIRED,    // end timer fired
     262        STATE_INPUT_PAUSE_OVERRIDE,     // pause an animation due to override
     263        STATE_INPUT_RESUME_OVERRIDE,    // resume an overridden animation
     264        STATE_INPUT_PLAY_STATE_RUNNING, // play state paused -> running
     265        STATE_INPUT_PLAY_STATE_PAUSED,  // play state running -> paused
     266        STATE_INPUT_END_ANIMATION       // force an end from any state
     267    };
     268   
     269    // Called when animation is in NEW state to start animation
     270    void updateStateMachine(AnimStateInput input, double param);
     271   
     272    // Animation has actually started, at passed time
     273    // This is a callback and is only received when RenderObject::startAnimation() or RenderObject::startTransition()
     274    // returns true. If RenderObject::
     275    void onAnimationStartResponse(double startTime);
     276   
     277    // Called to change to or from paused state
     278    void updatePlayState(bool running);
     279    bool playStatePlaying() const { return m_animation; }
     280   
     281    bool waitingToStart() const { return m_animState == STATE_NEW || m_animState == STATE_START_WAIT_TIMER; }
     282    bool preactive() const
     283    { return m_animState == STATE_NEW ||
     284             m_animState == STATE_START_WAIT_TIMER ||
     285             m_animState == STATE_START_WAIT_STYLE_AVAILABLE ||
     286             m_animState == STATE_START_WAIT_RESPONSE;
     287    }
     288    bool postactive() const { return m_animState == STATE_DONE; }
     289    bool active() const { return !postactive() && !preactive(); }
     290    bool running() const { return !isnew() && !postactive(); }
     291    bool paused() const { return m_pauseTime >= 0; }
     292    bool isnew() const { return m_animState == STATE_NEW; }
     293    bool waitingForStartTime() const { return m_animState == STATE_START_WAIT_RESPONSE; }
     294    bool waitingForStyleAvailable() const { return m_animState == STATE_START_WAIT_STYLE_AVAILABLE; }
     295    bool waitingForEndEvent() const  { return m_waitingForEndEvent; }
     296   
     297    // "animating" means that something is running that requires a timer to keep firing
     298    // (e.g. a software animation)
     299    void setAnimating(bool inAnimating = true) { m_animating = inAnimating; }
     300    bool animating() const { return m_animating; }
     301   
     302    double progress(double scale, double offset) const;
     303   
     304    virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle,
     305                         const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle) { }
     306    virtual void reset(RenderObject* renderer, const RenderStyle* from = 0, const RenderStyle* to = 0) { }
     307   
     308    virtual bool shouldFireEvents() const { return false; }
     309   
     310    void animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime);
     311    void animationEventDispatcherFired(Element* element, const AtomicString& name, int property, bool reset,
     312                                       const AtomicString& eventType, double elapsedTime);
     313   
     314    bool animationsMatch(const Animation* anim) const { return m_animation->animationsMatch(anim); }
     315   
     316    void setAnimation(const Animation* anim) { m_animation = const_cast<Animation*>(anim); }
     317   
     318    // Return true if this animation is overridden. This will only be the case for
     319    // ImplicitAnimations and is used to determine whether or not we should force
     320    // set the start time. If an animation is overridden, it will probably not get
     321    // back the START_TIME event.
     322    virtual bool overridden() const { return false; }
     323   
     324    // Does this animation/transition involve the given property?
     325    virtual bool affectsProperty(int property) const { return false; }
     326    bool isAnimatingProperty(int property) const
     327    {
     328        return (!waitingToStart() && !postactive()) && affectsProperty(property);
     329    }
     330       
     331protected:
     332    Element* elementForEventDispatch()
     333    {
     334        if (m_object->node() && m_object->node()->isElementNode())
     335            return static_cast<Element*>(m_object->node());
     336        return 0;
     337    }
     338   
     339    virtual void overrideAnimations() { }
     340    virtual void resumeOverriddenAnimations() { }
     341   
     342    CompositeAnimation* compositeAnimation() { return m_compAnim; }
     343   
     344    // These are called when the corresponding timer fires so subclasses can do any extra work
     345    virtual void onAnimationStart(double elapsedTime) { }
     346    virtual void onAnimationIteration(double elapsedTime) { }
     347    virtual void onAnimationEnd(double elapsedTime) { }
     348    virtual bool startAnimation(double beginTime) { return false; }
     349    virtual void endAnimation(bool reset) { }
     350   
     351    void primeEventTimers();
     352   
     353protected:
     354    AnimState m_animState;
     355    int m_iteration;
     356   
     357    bool m_animating;       // transition/animation requires continual timer firing
     358    bool m_waitedForResponse;
     359    double m_startTime;
     360    double m_pauseTime;
     361    RenderObject*   m_object;
     362   
     363    AnimationTimerCallback m_animationTimerCallback;
     364    AnimationEventDispatcher m_animationEventDispatcher;
     365    RefPtr<Animation> m_animation;
     366    CompositeAnimation* m_compAnim;
     367    bool m_waitingForEndEvent;
     368};
     369
     370class ImplicitAnimation : public AnimationBase {
     371public:
     372    ImplicitAnimation(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
     373    : AnimationBase(transition, renderer, compAnim)
     374    , m_property(transition->property())
     375    , m_overridden(false)
     376    , m_fromStyle(0)
     377    , m_toStyle(0)
     378    {
     379    }
     380   
     381    virtual ~ImplicitAnimation()
     382    {
     383        ASSERT(!m_fromStyle && !m_toStyle);
     384       
     385        // If we were waiting for an end event, we need to finish the animation to make sure no old
     386        // animations stick around in the lower levels
     387        if (waitingForEndEvent() && m_object)
     388            ASSERT(0);
     389       
     390        // Do the cleanup here instead of in the base class so the specialized methods get called
     391        if (!postactive())
     392            updateStateMachine(STATE_INPUT_END_ANIMATION, -1);     
     393    }
     394   
    71395    int property() const { return m_property; }
    72396   
    73     bool finished() const { return m_finished; }
    74     void setFinished(bool f) { m_finished = f; }
    75    
    76     bool stale() const { return m_stale; }
    77     void setStale() { m_stale = true; }
    78 
     397    virtual void onAnimationEnd(double inElapsedTime);
     398    virtual bool startAnimation(double beginTime);
     399    virtual void endAnimation(bool reset);
     400   
     401    virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle,
     402                         const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle);
     403    virtual void reset(RenderObject* renderer, const RenderStyle* from = 0, const RenderStyle* to = 0);
     404   
     405    void setOverridden(bool b);
     406    virtual bool overridden() const { return m_overridden; }
     407   
     408    virtual bool shouldFireEvents() const { return true; }
     409   
     410    virtual bool affectsProperty(int property) const;
     411   
     412    bool hasStyle() const { return m_fromStyle && m_toStyle; }
     413   
     414    bool isTargetPropertyEqual(int prop, RenderStyle* targetStyle);
     415
     416    void blendPropertyValueInStyle(int prop, RenderStyle* currentStyle);
     417   
     418protected:
     419    bool shouldSendEventForListener(Document::ListenerType inListenerType)
     420    {
     421        return m_object->document()->hasListenerType(inListenerType);
     422    }
     423   
     424    bool sendTransitionEvent(const AtomicString& inEventType, double inElapsedTime);
     425   
    79426private:
     427    int m_property;
     428    bool m_overridden;
     429   
    80430    // The two styles that we are blending.
    81431    RenderStyle* m_fromStyle;
    82432    RenderStyle* m_toStyle;
    83 
    84     int m_property;
    85     TimingFunction m_function;
    86     double m_duration;
    87 
    88     int m_repeatCount;
    89     int m_iteration;
    90    
    91     bool m_finished;   
    92     double m_startTime;
    93     bool m_paused;
    94     double m_pauseTime;
    95    
    96     bool m_stale;
    97433};
    98434
    99 class CompositeImplicitAnimation : public Noncopyable {
    100 public:
    101     ~CompositeImplicitAnimation() { deleteAllValues(m_animations); }
    102 
    103     RenderStyle* animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
    104 
    105     bool animating() const;
    106 
    107     void reset(RenderObject*);
    108 
    109 private:
    110     HashMap<int, ImplicitAnimation*> m_animations;
    111 };
    112 
    113 ImplicitAnimation::ImplicitAnimation(const Transition* transition)
    114 : m_fromStyle(0)
    115 , m_toStyle(0)
    116 , m_property(transition->property())
    117 , m_function(transition->timingFunction())
    118 , m_duration(transition->duration() / 1000.0)
    119 , m_repeatCount(transition->repeatCount())
     435void AnimationTimerCallback::timerFired(Timer<AnimationTimerBase>*)
     436{
     437    m_anim->animationTimerCallbackFired(m_eventType, m_elapsedTime);
     438}
     439
     440void AnimationEventDispatcher::timerFired(Timer<AnimationTimerBase>*)
     441{
     442    m_anim->animationEventDispatcherFired(m_element.get(), m_name, m_property, m_reset, m_eventType, m_elapsedTime);
     443}
     444   
     445AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
     446: m_animState(STATE_NEW)
    120447, m_iteration(0)
    121 , m_finished(false)
    122 , m_startTime(currentTime())
    123 , m_paused(false)
    124 , m_pauseTime(m_startTime)
    125 , m_stale(false)
    126 {
    127 }
    128 
    129 ImplicitAnimation::~ImplicitAnimation()
    130 {
    131     ASSERT(!m_fromStyle && !m_toStyle);
    132 }
    133 
    134 void ImplicitAnimation::reset(RenderObject* renderer, RenderStyle* from, RenderStyle* to)
    135 {
    136     setFinished(false);
    137 
    138     if (m_fromStyle)
    139         m_fromStyle->deref(renderer->renderArena());
    140     if (m_toStyle)
    141         m_toStyle->deref(renderer->renderArena());
    142     m_fromStyle = from;
    143     if (m_fromStyle)
    144         m_fromStyle->ref();
    145     m_toStyle = to;
    146     if (m_toStyle)
    147         m_toStyle->ref();
    148     if (from || to)
    149         m_startTime = currentTime();
     448, m_animating(false)
     449, m_waitedForResponse(false)
     450, m_startTime(0)
     451, m_pauseTime(-1)
     452, m_object(renderer)
     453, m_animationTimerCallback(const_cast<AnimationBase*>(this))
     454, m_animationEventDispatcher(const_cast<AnimationBase*>(this))
     455, m_animation(const_cast<Animation*>(transition))
     456, m_compAnim(compAnim)
     457, m_waitingForEndEvent(false)
     458{
     459}
     460
     461void AnimationBase::updateStateMachine(AnimStateInput input, double param)
     462{
     463    // if we get a RESTART then we force a new animation, regardless of state
     464    if (input == STATE_INPUT_MAKE_NEW) {
     465        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
     466            m_compAnim->setWaitingForStyleAvailable(false);
     467        m_animState = STATE_NEW;
     468        m_startTime = 0;
     469        m_pauseTime = -1;
     470        m_waitedForResponse = false;
     471        endAnimation(false);
     472        return;
     473    }
     474    else if (input == STATE_INPUT_RESTART_ANIMATION) {
     475        cancelTimers();
     476        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
     477            m_compAnim->setWaitingForStyleAvailable(false);
     478        m_animState = STATE_NEW;
     479        m_startTime = 0;
     480        m_pauseTime = -1;
     481        endAnimation(false);
    150482       
    151     // If we are stale, attempt to update to a new transition using the new |to| style.  If we are able to find a new transition,
    152     // then we will unmark ourselves for death.
    153     if (stale() && from && to) {
    154          for (const Transition* transition = to->transitions(); transition; transition = transition->next()) {
    155             if (m_property != transition->property())
    156                 continue;
    157             int duration = transition->duration();
    158             int repeatCount = transition->repeatCount();
    159             if (duration && repeatCount) {
    160                 m_duration = duration / 1000.0;
    161                 m_repeatCount = repeatCount;
    162                 m_stale = false;
    163                 break;
     483        if (!paused())
     484            updateStateMachine(STATE_INPUT_START_ANIMATION, -1);
     485        return;
     486    }
     487    else if (input == STATE_INPUT_END_ANIMATION) {
     488        cancelTimers();
     489        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
     490            m_compAnim->setWaitingForStyleAvailable(false);
     491        m_animState = STATE_DONE;
     492        endAnimation(true);
     493        return;
     494    }
     495    else if (input == STATE_INPUT_PAUSE_OVERRIDE) {
     496        if (m_animState == STATE_START_WAIT_RESPONSE) {
     497            // If we are in the WAIT_RESPONSE state, the animation will get canceled before
     498            // we get a response, so move to the next state
     499            endAnimation(false);
     500            updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
     501        }
     502        return;
     503    }
     504    else if (input == STATE_INPUT_RESUME_OVERRIDE) {
     505        if (m_animState == STATE_LOOPING || m_animState == STATE_ENDING) {
     506            // Start the animation
     507            startAnimation(m_startTime);
     508        }
     509        return;
     510    }
     511   
     512    // execute state machine
     513    switch(m_animState) {
     514        case STATE_NEW:
     515            ASSERT(input == STATE_INPUT_START_ANIMATION || input == STATE_INPUT_PLAY_STATE_RUNNING || input == STATE_INPUT_PLAY_STATE_PAUSED);
     516            if (input == STATE_INPUT_START_ANIMATION || input == STATE_INPUT_PLAY_STATE_RUNNING) {
     517                // Set the start timer to the initial delay (0 if no delay)
     518                m_waitedForResponse = false;
     519                m_animState = STATE_START_WAIT_TIMER;
     520                m_animationTimerCallback.startTimer(m_animation->delay(), EventNames::webkitAnimationStartEvent, m_animation->delay());
    164521            }
    165         }
    166     }
    167    
    168     // If we did not find a new transition, then mark ourselves as being finished so that we can be removed.
    169     if (stale())
    170         setFinished(true);
    171 }
    172 
    173 double ImplicitAnimation::progress() const
    174 {
    175     double elapsedTime = currentTime() - m_startTime;
    176    
    177     if (m_finished || !m_duration || elapsedTime >= m_duration)
     522            break;
     523        case STATE_START_WAIT_TIMER:
     524            ASSERT(input == STATE_INPUT_START_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
     525           
     526            if (input == STATE_INPUT_START_TIMER_FIRED) {
     527                ASSERT(param >= 0);
     528                // Start timer has fired, tell the animation to start and wait for it to respond with start time
     529                m_animState = STATE_START_WAIT_STYLE_AVAILABLE;
     530                m_compAnim->setWaitingForStyleAvailable(true);
     531               
     532                // Trigger a render so we can start the animation
     533                setChanged(m_object->element());
     534                m_object->animation()->startUpdateRenderingDispatcher();
     535            }
     536            else {
     537                ASSERT(running());
     538                // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
     539                m_pauseTime = currentTime();
     540                cancelTimers();
     541                m_animState = STATE_PAUSED_WAIT_TIMER;
     542            }
     543            break;
     544        case STATE_START_WAIT_STYLE_AVAILABLE:
     545            ASSERT(input == STATE_INPUT_STYLE_AVAILABLE || input == STATE_INPUT_PLAY_STATE_PAUSED);
     546           
     547            m_compAnim->setWaitingForStyleAvailable(false);
     548           
     549            if (input == STATE_INPUT_STYLE_AVAILABLE) {
     550                // Start timer has fired, tell the animation to start and wait for it to respond with start time
     551                m_animState = STATE_START_WAIT_RESPONSE;
     552               
     553                overrideAnimations();
     554               
     555                // Send start event, if needed
     556                onAnimationStart(0.0f); // the elapsedTime is always 0 here
     557               
     558                // Start the animation
     559                if (overridden() || !startAnimation(0)) {
     560                    // We're not going to get a startTime callback, so fire the start time here
     561                    m_animState = STATE_START_WAIT_RESPONSE;
     562                    updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
     563                }
     564                else
     565                    m_waitedForResponse = true;
     566            }
     567            else {
     568                ASSERT(running());
     569                // We're waiting for the a notification that the style has been setup. If we're asked to wait
     570                // at this point, the style must have been processed, so we can deal with this like we would
     571                // for WAIT_RESPONSE, except that we don't need to do an endAnimation().
     572                m_pauseTime = 0;
     573                m_animState = STATE_START_WAIT_RESPONSE;
     574            }
     575            break;
     576        case STATE_START_WAIT_RESPONSE:
     577            ASSERT(input == STATE_INPUT_START_TIME_SET || input == STATE_INPUT_PLAY_STATE_PAUSED);
     578           
     579            if (input == STATE_INPUT_START_TIME_SET) {
     580                ASSERT(param >= 0);
     581                // We have a start time, set it, unless the startTime is already set
     582                if (m_startTime <= 0)
     583                    m_startTime = param;
     584               
     585                // Decide when the end or loop event needs to fire
     586                primeEventTimers();
     587               
     588                // Trigger a render so we can start the animation
     589                setChanged(m_object->element());
     590                m_object->animation()->startUpdateRenderingDispatcher();
     591            }
     592            else {
     593                // We are pausing while waiting for a start response. Cancel the animation and wait. When
     594                // we unpause, we will act as though the start timer just fired
     595                m_pauseTime = 0;
     596                endAnimation(false);
     597                m_animState = STATE_PAUSED_WAIT_RESPONSE;
     598            }
     599            break;
     600        case STATE_LOOPING:
     601            ASSERT(input == STATE_INPUT_LOOP_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
     602           
     603            if (input == STATE_INPUT_LOOP_TIMER_FIRED) {
     604                ASSERT(param >= 0);
     605                // Loop timer fired, loop again or end.
     606                onAnimationIteration(param);
     607                primeEventTimers();
     608            }
     609            else {
     610                // We are pausing while running. Cancel the animation and wait
     611                m_pauseTime = currentTime();
     612                cancelTimers();
     613                endAnimation(false);
     614                m_animState = STATE_PAUSED_RUN;
     615            }
     616            break;
     617        case STATE_ENDING:
     618            ASSERT(input == STATE_INPUT_END_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
     619           
     620            if (input == STATE_INPUT_END_TIMER_FIRED) {
     621                ASSERT(param >= 0);
     622                // End timer fired, finish up
     623                onAnimationEnd(param);
     624               
     625                resumeOverriddenAnimations();
     626               
     627                // Fire off another style change so we can set the final value
     628                setChanged(m_object->element());
     629                m_animState = STATE_DONE;
     630                m_object->animation()->startUpdateRenderingDispatcher();
     631                // |this| may be deleted here when we've been called from timerFired()
     632            }
     633            else {
     634                // We are pausing while running. Cancel the animation and wait
     635                m_pauseTime = currentTime();
     636                cancelTimers();
     637                endAnimation(false);
     638                m_animState = STATE_PAUSED_RUN;
     639            }
     640            // |this| may be deleted here
     641            break;
     642        case STATE_PAUSED_WAIT_TIMER:
     643            ASSERT(input == STATE_INPUT_PLAY_STATE_RUNNING);
     644            ASSERT(!running());
     645            // Update the times
     646            m_startTime += currentTime() - m_pauseTime;
     647            m_pauseTime = -1;
     648           
     649            // we were waiting for the start timer to fire, go back and wait again
     650            m_animState = STATE_NEW;
     651            updateStateMachine(STATE_INPUT_START_ANIMATION, 0);
     652            break;
     653        case STATE_PAUSED_WAIT_RESPONSE:
     654        case STATE_PAUSED_RUN:
     655            // We treat these two cases the same. The only difference is that, when we are in the WAIT_RESPONSE
     656            // state, we don't yet have a valid startTime, so we send 0 to startAnimation. When the START_TIME
     657            // event comes in qnd we were in the RUN state, we will notice that we have already set the
     658            // startTime and will ignore it.
     659            ASSERT(input == STATE_INPUT_PLAY_STATE_RUNNING);
     660            ASSERT(!running());
     661            // Update the times
     662            if (m_animState == STATE_PAUSED_RUN)
     663                m_startTime += currentTime() - m_pauseTime;
     664            else
     665                m_startTime = 0;
     666            m_pauseTime = -1;
     667           
     668            // We were waiting for a begin time response from the animation, go back and wait again
     669            m_animState = STATE_START_WAIT_RESPONSE;
     670           
     671            // Start the animation
     672            if (overridden() || !startAnimation(m_startTime)) {
     673                // We're not going to get a startTime callback, so fire the start time here
     674                updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
     675            }
     676            else
     677                m_waitedForResponse = true;
     678            break;
     679        case STATE_DONE:
     680            // We're done. Stay in this state until we are deleted
     681            break;
     682    }
     683    // |this| may be deleted here if we came out of STATE_ENDING when we've been called from timerFired()
     684}
     685   
     686void AnimationBase::animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime)
     687{
     688    ASSERT(m_object->document() && !m_object->document()->inPageCache());
     689   
     690    // FIXME: use an enum
     691    if (eventType == EventNames::webkitAnimationStartEvent)
     692        updateStateMachine(STATE_INPUT_START_TIMER_FIRED, elapsedTime);
     693    else if (eventType == EventNames::webkitAnimationIterationEvent)
     694        updateStateMachine(STATE_INPUT_LOOP_TIMER_FIRED, elapsedTime);
     695    else if (eventType == EventNames::webkitAnimationEndEvent) {
     696        updateStateMachine(STATE_INPUT_END_TIMER_FIRED, elapsedTime);
     697        // |this| may be deleted here
     698    }
     699}
     700
     701void AnimationBase::animationEventDispatcherFired(Element* element, const AtomicString& name, int property,
     702                                                  bool reset, const AtomicString& eventType, double elapsedTime)
     703{
     704    m_waitingForEndEvent = false;
     705   
     706    // Keep an atomic string on the stack to keep it alive until we exit this method
     707    // (since dispatching the event may cause |this| to be deleted, therefore removing
     708    // the last ref to the atomic string).
     709    AtomicString animName(name);
     710    AtomicString animEventType(eventType);
     711    // Make sure the element sticks around too
     712    RefPtr<Element> elementRetainer(element);
     713   
     714    ASSERT(!element || (element->document() && !element->document()->inPageCache()));
     715    if (!element)
     716        return;
     717}
     718
     719void AnimationBase::updatePlayState(bool run)
     720{
     721    if (paused() == run || isnew())
     722        updateStateMachine(run ? STATE_INPUT_PLAY_STATE_RUNNING : STATE_INPUT_PLAY_STATE_PAUSED, -1);
     723}
     724
     725double AnimationBase::progress(double scale, double offset) const
     726{
     727    if (preactive())
     728        return 0;
     729   
     730    double elapsedTime = running() ? (currentTime() - m_startTime) : (m_pauseTime - m_startTime);
     731    if (running() && elapsedTime < 0)
     732        return 0;
     733   
     734    double dur = m_animation->duration();
     735   
     736    if (postactive() || !m_animation->duration() || elapsedTime >= dur)
    178737        return 1.0;
    179 
    180     if (m_function.type() == LinearTimingFunction)
    181         return elapsedTime / m_duration;
     738   
     739    // Compute the fractional time, taking into account direction.
     740    // There is no need to worry about iterations, we assume that we would have
     741    // short circuited above if we were done
     742    double t = elapsedTime / m_animation->duration();
     743    int i = (int) t;
     744    t -= i;
     745   
     746    if (scale != 1 || offset != 0)
     747        t = (t - offset) * scale;
     748   
     749    if (m_animation->timingFunction().type() == LinearTimingFunction)
     750        return t;
    182751   
    183752    // Cubic bezier.
    184     return solveCubicBezierFunction(m_function.x1(), m_function.y1(),
    185                                     m_function.x2(), m_function.y2(),
    186                                     elapsedTime / m_duration, m_duration);
     753    double tt = solveCubicBezierFunction(m_animation->timingFunction().x1(),
     754                                         m_animation->timingFunction().y1(),
     755                                         m_animation->timingFunction().x2(),
     756                                         m_animation->timingFunction().y2(),
     757                                         t, m_animation->duration());
     758    return tt;
     759}
     760
     761void AnimationBase::primeEventTimers()
     762{
     763    // Decide when the end or loop event needs to fire
     764    double ct = currentTime();
     765    const double elapsedDuration = ct - m_startTime;
     766    ASSERT(elapsedDuration >= 0);
     767   
     768    double totalDuration = m_animation->duration();
     769    double durationLeft = 0;
     770    double nextIterationTime = totalDuration;
     771    if (totalDuration < 0 || elapsedDuration < totalDuration) {
     772        durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
     773        nextIterationTime = elapsedDuration + durationLeft;
     774    }
     775   
     776    // At this point, we may have 0 durationLeft, if we've gotten the event late and we are already
     777    // past totalDuration. In this case we still fire an end timer before processing the end.
     778    // This defers the call to sendAnimationEvents to avoid re-entrant calls that destroy
     779    // the RenderObject, and therefore |this| before we're done with it.
     780    if (totalDuration < 0 || nextIterationTime < totalDuration) {
     781        // We are not at the end yet, send a loop event
     782        ASSERT(nextIterationTime > 0);
     783        m_animState = STATE_LOOPING;
     784        m_animationTimerCallback.startTimer(durationLeft, EventNames::webkitAnimationIterationEvent, nextIterationTime);
     785    }
     786    else {
     787        // We are at the end, send an end event
     788        m_animState = STATE_ENDING;
     789        m_animationTimerCallback.startTimer(durationLeft, EventNames::webkitAnimationEndEvent, nextIterationTime);
     790    }
    187791}
    188792
     
    224828
    225829    ASSERT(from && to);
    226     return new ShadowData(blendFunc(from->x, to->x, progress), blendFunc(from->y, to->y, progress), blendFunc(from->blur, to->blur, progress), blendFunc(from->color, to->color, progress));
     830    return new ShadowData(blendFunc(from->x, to->x, progress), blendFunc(from->y, to->y, progress),
     831                          blendFunc(from->blur, to->blur, progress), blendFunc(from->color, to->color, progress));
    227832}
    228833
     
    238843        TransformOperation* toOp = i < toSize ? to[i].get() : 0;
    239844        TransformOperation* blendedOp = toOp ? toOp->blend(fromOp, progress) : fromOp->blend(0, progress, true);
    240         result.append(blendedOp);
     845        if (blendedOp)
     846            result.append(blendedOp);
    241847    }
    242848    return result;
     
    255861}
    256862
    257 #define BLEND(prop, getter, setter) \
    258     if (m_property == prop && m_toStyle->getter() != targetStyle->getter()) {\
    259         reset(renderer, currentStyle, targetStyle); \
    260         if (stale()) \
    261             return; \
    262     } \
    263     if (m_property == cAnimateAll || m_property == prop) { \
    264         if (m_fromStyle->getter() != m_toStyle->getter()) {\
    265             setFinished(false); \
    266             if (!animatedStyle) \
    267                 animatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle); \
    268             animatedStyle->setter(blendFunc(m_fromStyle->getter(), m_toStyle->getter(), progress()));\
    269             if (m_property == prop) \
    270                 return; \
    271         }\
    272     }\
    273 
    274 #define BLEND_MAYBE_INVALID_COLOR(prop, getter, setter) \
    275     if (m_property == prop && m_toStyle->getter() != targetStyle->getter()) { \
    276         reset(renderer, currentStyle, targetStyle); \
    277         if (stale()) \
    278             return; \
    279     } \
    280     if (m_property == cAnimateAll || m_property == prop) { \
    281         Color fromColor = m_fromStyle->getter(); \
    282         Color toColor = m_toStyle->getter(); \
    283         if (fromColor.isValid() || toColor.isValid()) { \
    284             if (!fromColor.isValid()) \
    285                 fromColor = m_fromStyle->color(); \
    286             if (!toColor.isValid()) \
    287                 toColor = m_toStyle->color(); \
    288             if (fromColor != toColor) {\
    289                 setFinished(false); \
    290                 if (!animatedStyle) \
    291                     animatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle); \
    292                 animatedStyle->setter(blendFunc(fromColor, toColor, progress()));\
    293                 if (m_property == prop) \
    294                     return; \
    295             }\
    296         }\
    297     }\
    298 
    299 #define BLEND_SHADOW(prop, getter, setter) \
    300     if (m_property == prop && (!m_toStyle->getter() || !targetStyle->getter() || *m_toStyle->getter() != *targetStyle->getter())) { \
    301         reset(renderer, currentStyle, targetStyle); \
    302         if (stale()) \
    303             return; \
    304     } \
    305     if (m_property == cAnimateAll || m_property == prop) { \
    306         if (m_fromStyle->getter() && m_toStyle->getter() && *m_fromStyle->getter() != *m_toStyle->getter()) {\
    307             setFinished(false); \
    308             if (!animatedStyle) \
    309                 animatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle); \
    310             animatedStyle->setter(blendFunc(m_fromStyle->getter(), m_toStyle->getter(), progress()));\
    311             if (m_property == prop) \
    312                 return; \
    313         }\
    314     }
    315 
    316 void ImplicitAnimation::animate(CompositeImplicitAnimation* animation, RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle, RenderStyle*& animatedStyle)
    317 {
    318     // FIXME: If we have no transition-property, then the only way to tell if our goal state changed is to check
    319     // every single animatable property.  For now we'll just diff the styles to ask that question,
    320     // but we should really exclude non-animatable properties.
    321     if (!m_toStyle || (m_property == cAnimateAll && targetStyle->diff(m_toStyle))) {
    322         reset(renderer, currentStyle, targetStyle);
    323         if (stale())
    324             return;
    325     }
    326 
    327     // FIXME: Blow up shorthands so that they can be honored.
    328     setFinished(true);
    329     BLEND(CSSPropertyLeft, left, setLeft);
    330     BLEND(CSSPropertyRight, right, setRight);
    331     BLEND(CSSPropertyTop, top, setTop);
    332     BLEND(CSSPropertyBottom, bottom, setBottom);
    333     BLEND(CSSPropertyWidth, width, setWidth);
    334     BLEND(CSSPropertyHeight, height, setHeight);
    335     BLEND(CSSPropertyBorderLeftWidth, borderLeftWidth, setBorderLeftWidth);
    336     BLEND(CSSPropertyBorderRightWidth, borderRightWidth, setBorderRightWidth);
    337     BLEND(CSSPropertyBorderTopWidth, borderTopWidth, setBorderTopWidth);
    338     BLEND(CSSPropertyBorderBottomWidth, borderBottomWidth, setBorderBottomWidth);
    339     BLEND(CSSPropertyMarginLeft, marginLeft, setMarginLeft);
    340     BLEND(CSSPropertyMarginRight, marginRight, setMarginRight);
    341     BLEND(CSSPropertyMarginTop, marginTop, setMarginTop);
    342     BLEND(CSSPropertyMarginBottom, marginBottom, setMarginBottom);
    343     BLEND(CSSPropertyPaddingLeft, paddingLeft, setPaddingLeft);
    344     BLEND(CSSPropertyPaddingRight, paddingRight, setPaddingRight);
    345     BLEND(CSSPropertyPaddingTop, paddingTop, setPaddingTop);
    346     BLEND(CSSPropertyPaddingBottom, paddingBottom, setPaddingBottom);
    347     BLEND(CSSPropertyOpacity, opacity, setOpacity);
    348     BLEND(CSSPropertyColor, color, setColor);
    349     BLEND(CSSPropertyBackgroundColor, backgroundColor, setBackgroundColor);
    350     BLEND_MAYBE_INVALID_COLOR(CSSPropertyWebkitColumnRuleColor, columnRuleColor, setColumnRuleColor);
    351     BLEND(CSSPropertyWebkitColumnRuleWidth, columnRuleWidth, setColumnRuleWidth);
    352     BLEND(CSSPropertyWebkitColumnGap, columnGap, setColumnGap);
    353     BLEND(CSSPropertyWebkitColumnCount, columnCount, setColumnCount);
    354     BLEND(CSSPropertyWebkitColumnWidth, columnWidth, setColumnWidth);
    355     BLEND_MAYBE_INVALID_COLOR(CSSPropertyWebkitTextStrokeColor, textStrokeColor, setTextStrokeColor);
    356     BLEND_MAYBE_INVALID_COLOR(CSSPropertyWebkitTextFillColor, textFillColor, setTextFillColor);
    357     BLEND(CSSPropertyWebkitBorderHorizontalSpacing, horizontalBorderSpacing, setHorizontalBorderSpacing);
    358     BLEND(CSSPropertyWebkitBorderVerticalSpacing, verticalBorderSpacing, setVerticalBorderSpacing);
    359     BLEND_MAYBE_INVALID_COLOR(CSSPropertyBorderLeftColor, borderLeftColor, setBorderLeftColor);
    360     BLEND_MAYBE_INVALID_COLOR(CSSPropertyBorderRightColor, borderRightColor, setBorderRightColor);
    361     BLEND_MAYBE_INVALID_COLOR(CSSPropertyBorderTopColor, borderTopColor, setBorderTopColor);
    362     BLEND_MAYBE_INVALID_COLOR(CSSPropertyBorderBottomColor, borderBottomColor, setBorderBottomColor);
    363     BLEND(CSSPropertyZIndex, zIndex, setZIndex);
    364     BLEND(CSSPropertyLineHeight, lineHeight, setLineHeight);
    365     BLEND_MAYBE_INVALID_COLOR(CSSPropertyOutlineColor, outlineColor, setOutlineColor);
    366     BLEND(CSSPropertyOutlineOffset, outlineOffset, setOutlineOffset);
    367     BLEND(CSSPropertyOutlineWidth, outlineWidth, setOutlineWidth);
    368     BLEND(CSSPropertyLetterSpacing, letterSpacing, setLetterSpacing);
    369     BLEND(CSSPropertyWordSpacing, wordSpacing, setWordSpacing);
    370     BLEND_SHADOW(CSSPropertyWebkitBoxShadow, boxShadow, setBoxShadow);
    371     BLEND_SHADOW(CSSPropertyTextShadow, textShadow, setTextShadow);
    372     BLEND(CSSPropertyWebkitTransform, transform, setTransform);
    373     BLEND(CSSPropertyWebkitTransformOriginX, transformOriginX, setTransformOriginX);
    374     BLEND(CSSPropertyWebkitTransformOriginY, transformOriginY, setTransformOriginY);
    375     BLEND(CSSPropertyWebkitBorderTopLeftRadius, borderTopLeftRadius, setBorderTopLeftRadius);
    376     BLEND(CSSPropertyWebkitBorderTopRightRadius, borderTopRightRadius, setBorderTopRightRadius);
    377     BLEND(CSSPropertyWebkitBorderBottomLeftRadius, borderBottomLeftRadius, setBorderBottomLeftRadius);
    378     BLEND(CSSPropertyWebkitBorderBottomRightRadius, borderBottomRightRadius, setBorderBottomRightRadius);
    379     BLEND(CSSPropertyVisibility, visibility, setVisibility);
    380     BLEND(CSSPropertyZoom, zoom, setZoom);
    381 }
    382 
    383 RenderStyle* CompositeImplicitAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
    384 {
    385     const Transition* currentTransitions = currentStyle->transitions();
    386     const Transition* targetTransitions = targetStyle->transitions();
    387     bool transitionsChanged = m_animations.isEmpty() || (currentTransitions != targetTransitions && !(currentTransitions && targetTransitions && *currentTransitions == *targetTransitions));
    388 
    389     if (transitionsChanged) {
    390         HashMap<int, ImplicitAnimation*>::iterator end = m_animations.end();
    391          
    392         for (HashMap<int, ImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it)
    393             // Mark any running animations as stale if the set of transitions changed.  Stale animations continue
    394             // to blend on a timer, and then remove themselves when finished.
    395             it->second->setStale();
    396 
    397         // If our transitions changed we need to add new animations for any transitions that
    398         // don't exist yet.  If a new transition conflicts with a currently running stale transition, then we will not add it.
    399         // The stale transition is responsible for updating itself to the new transition if it ever gets reset or finishes.
    400         for (const Transition* transition = targetTransitions; transition; transition = transition->next()) {
    401             int property = transition->property();
    402             int duration = transition->duration();
    403             int repeatCount = transition->repeatCount();
    404             if (property && duration && repeatCount && !m_animations.contains(property)) {
    405                 ImplicitAnimation* animation = new ImplicitAnimation(transition);
    406                 m_animations.set(property, animation);
    407             }
    408         }
    409     }
    410 
    411     // Now that we have animation objects ready, let them know about the new goal state.  We want them
    412     // to fill in a RenderStyle*& only if needed.
    413     RenderStyle* result = 0;
    414     HashMap<int, ImplicitAnimation*>::iterator end = m_animations.end();
    415     Vector<int> obsoleteTransitions;
    416    
    417     // Look at the "all" animation first.
    418     ImplicitAnimation* allAnimation = m_animations.get(cAnimateAll);
    419     if (allAnimation) {
    420         allAnimation->animate(this, renderer, currentStyle, targetStyle, result);
    421 
    422         // If the animation is done and we are marked as stale, then we can be removed after the
    423         // iteration of the hashmap is finished.
    424         if (allAnimation->finished() && allAnimation->stale())
    425             obsoleteTransitions.append(cAnimateAll);
    426     }
    427    
    428     // Now look at the specialized animations.
    429     for (HashMap<int, ImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
    430         // Skip over the "all" animation, since we animated it already.
    431         if (it->second->property() == cAnimateAll)
    432             continue;
     863class PropertyWrapperBase {
     864public:
     865    PropertyWrapperBase(int prop)
     866    : m_prop(prop)
     867    { }
     868    virtual ~PropertyWrapperBase() { }
     869    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const=0;
     870    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const=0;
     871   
     872    int property() const { return m_prop; }
     873   
     874private:
     875    int m_prop;
     876};
     877
     878template <typename T>
     879class PropertyWrapperGetter : public PropertyWrapperBase {
     880public:
     881    PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const)
     882    : PropertyWrapperBase(prop)
     883    , m_getter(getter)
     884    { }
     885   
     886    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
     887    {
     888        return (a->*m_getter)() == (b->*m_getter)();
     889    }
     890   
     891protected:
     892    T (RenderStyle::*m_getter)() const;
     893};
     894
     895template <typename T>
     896class PropertyWrapper : public PropertyWrapperGetter<T> {
     897public:
     898    PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
     899    : PropertyWrapperGetter<T>(prop, getter)
     900    , m_setter(setter)
     901    { }
     902   
     903    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
     904    {
     905        (dst->*m_setter)(blendFunc((a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), prog));
     906    }
     907   
     908protected:
     909    void (RenderStyle::*m_setter)(T);
     910};
     911
     912class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> {
     913public:
     914    PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
     915    : PropertyWrapperGetter<ShadowData*>(prop, getter)
     916    , m_setter(setter)
     917    { }
     918   
     919    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
     920    {
     921        ShadowData* shadowa = (a->*m_getter)();
     922        ShadowData* shadowb = (b->*m_getter)();
    433923       
    434         it->second->animate(this, renderer, currentStyle, targetStyle, result);
    435 
    436         // If the animation is done and we are marked as stale, then we can be removed after the
    437         // iteration of the hashmap is finished.
    438         if (it->second->finished() && it->second->stale())
    439             obsoleteTransitions.append(it->second->property());
    440 
    441     }
    442    
    443     // Now cull out any stale animations that are finished.
    444     for (unsigned i = 0; i < obsoleteTransitions.size(); ++i) {
    445         ImplicitAnimation* animation = m_animations.take(obsoleteTransitions[i]);
    446         animation->reset(renderer, 0, 0);
    447         delete animation;
    448     }
    449 
    450     if (result)
    451         return result;
    452 
    453     return targetStyle;
    454 }
    455 
    456 bool CompositeImplicitAnimation::animating() const
    457 {
    458     HashMap<int, ImplicitAnimation*>::const_iterator end = m_animations.end();
    459     for (HashMap<int, ImplicitAnimation*>::const_iterator it = m_animations.begin(); it != end; ++it)
    460         if (!it->second->finished())
    461             return true;
    462     return false;
    463 }
    464 
    465 void CompositeImplicitAnimation::reset(RenderObject* renderer)
    466 {
    467     HashMap<int, ImplicitAnimation*>::const_iterator end = m_animations.end();
    468     for (HashMap<int, ImplicitAnimation*>::const_iterator it = m_animations.begin(); it != end; ++it)
    469         it->second->reset(renderer, 0, 0);
    470 }
     924        if (!shadowa && shadowb || shadowa && !shadowb)
     925            return false;
     926        if (shadowa && shadowb && (*shadowa != *shadowb))
     927            return false;
     928        return true;
     929    }
     930   
     931    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
     932    {
     933        ShadowData* shadowa = (a->*m_getter)();
     934        ShadowData* shadowb = (b->*m_getter)();
     935        ShadowData defaultShadowData(0, 0, 0, Color::transparent);
     936       
     937        if (!shadowa)
     938            shadowa = &defaultShadowData;
     939        if (!shadowb)
     940            shadowb = &defaultShadowData;
     941       
     942        (dst->*m_setter)(blendFunc(shadowa, shadowb, prog), false);
     943    }
     944   
     945private:
     946    void (RenderStyle::*m_setter)(ShadowData*, bool);
     947};
     948
     949class PropertyWrapperIntSize : public PropertyWrapperGetter<IntSize> {
     950public:
     951    PropertyWrapperIntSize(int prop, IntSize (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const IntSize&))
     952    : PropertyWrapperGetter<IntSize>(prop, getter)
     953    , m_setter(setter)
     954    { }
     955   
     956    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
     957    {
     958        IntSize sizea = (a->*m_getter)();
     959        IntSize sizeb = (b->*m_getter)();
     960       
     961        return (sizea == sizeb);
     962    }
     963   
     964    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
     965    {
     966        IntSize sizea = (a->*m_getter)();
     967        IntSize sizeb = (b->*m_getter)();
     968               
     969        (dst->*m_setter)(blendFunc(sizea, sizeb, prog));
     970    }
     971   
     972private:
     973    void (RenderStyle::*m_setter)(const IntSize&);
     974};
     975
     976class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
     977public:
     978    PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
     979    : PropertyWrapperBase(prop)
     980    , m_getter(getter)
     981    , m_setter(setter)
     982    { }
     983   
     984    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
     985    {
     986        Color fromColor = (a->*m_getter)();
     987        Color toColor = (b->*m_getter)();
     988        if (!fromColor.isValid())
     989            fromColor = a->color();
     990        if (!toColor.isValid())
     991            toColor = b->color();
     992       
     993        return fromColor == toColor;
     994    }
     995   
     996    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
     997    {
     998        Color fromColor = (a->*m_getter)();
     999        Color toColor = (b->*m_getter)();
     1000        if (!fromColor.isValid())
     1001            fromColor = a->color();
     1002        if (!toColor.isValid())
     1003            toColor = b->color();
     1004        (dst->*m_setter)(blendFunc(fromColor, toColor, prog));
     1005    }
     1006   
     1007private:
     1008    const Color& (RenderStyle::*m_getter)() const;
     1009    void (RenderStyle::*m_setter)(const Color&);
     1010};
    4711011
    4721012class AnimationControllerPrivate {
     
    4741014    AnimationControllerPrivate(Frame*);
    4751015    ~AnimationControllerPrivate();
    476 
    477     CompositeImplicitAnimation* get(RenderObject*, RenderStyle*);
     1016   
     1017    CompositeAnimation* accessCompositeAnimation(RenderObject*);
    4781018    bool clear(RenderObject*);
    4791019   
    480     void timerFired(Timer<AnimationControllerPrivate>*);
    481     void updateTimer();
    482 
    483     bool hasImplicitAnimations() const { return !m_animations.isEmpty(); }
    484 
     1020    void animationTimerFired(Timer<AnimationControllerPrivate>*);
     1021    void updateAnimationTimer();
     1022   
     1023    void updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*);
     1024    void startUpdateRenderingDispatcher();
     1025   
     1026    bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
     1027   
     1028    void suspendAnimations(Document* document);
     1029    void resumeAnimations(Document* document);
     1030   
     1031    void styleAvailable();
     1032   
     1033    bool isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const;
     1034   
     1035    static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b);
     1036    static int getPropertyAtIndex(int i);
     1037    static int getNumProperties() { return gPropertyWrappers->size(); }
     1038   
     1039    // Return true if we need to start software animation timers
     1040    static bool blendProperties(int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog);
     1041   
     1042    void setWaitingForStyleAvailable(bool waiting) { if (waiting) m_numStyleAvailableWaiters++; else m_numStyleAvailableWaiters--; }
     1043   
    4851044private:
    486     HashMap<RenderObject*, CompositeImplicitAnimation*> m_animations;
    487     Timer<AnimationControllerPrivate> m_timer;
     1045    static void ensurePropertyMap();
     1046   
     1047    typedef HashMap<RenderObject*, CompositeAnimation*> RenderObjectAnimationMap;
     1048   
     1049    RenderObjectAnimationMap m_compositeAnimations;
     1050    Timer<AnimationControllerPrivate> m_animationTimer;
     1051    Timer<AnimationControllerPrivate> m_updateRenderingDispatcher;
    4881052    Frame* m_frame;
     1053    uint32_t m_numStyleAvailableWaiters;
     1054   
     1055    static Vector<PropertyWrapperBase*>* gPropertyWrappers;
     1056    static int gPropertyWrapperMap[numCSSProperties];
    4891057};
    4901058
     1059Vector<PropertyWrapperBase*>* AnimationControllerPrivate::gPropertyWrappers = 0;
     1060int AnimationControllerPrivate::gPropertyWrapperMap[];
     1061
    4911062AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
    492     : m_timer(this, &AnimationControllerPrivate::timerFired)
    493     , m_frame(frame)
    494 {
     1063: m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
     1064, m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired)
     1065, m_frame(frame)
     1066, m_numStyleAvailableWaiters(0)
     1067{
     1068    ensurePropertyMap();
    4951069}
    4961070
    4971071AnimationControllerPrivate::~AnimationControllerPrivate()
    4981072{
    499     deleteAllValues(m_animations);
    500 }
    501 
    502 CompositeImplicitAnimation* AnimationControllerPrivate::get(RenderObject* renderer, RenderStyle* targetStyle)
    503 {
    504     CompositeImplicitAnimation* animation = m_animations.get(renderer);
    505     if (!animation && targetStyle->transitions()) {
    506         animation = new CompositeImplicitAnimation();
    507         m_animations.set(renderer, animation);
     1073    deleteAllValues(m_compositeAnimations);
     1074}
     1075
     1076// static
     1077void AnimationControllerPrivate::ensurePropertyMap()
     1078{
     1079    // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
     1080    if (gPropertyWrappers == 0) {
     1081        gPropertyWrappers = new Vector<PropertyWrapperBase*>();
     1082       
     1083        // build the list of property wrappers to do the comparisons and blends
     1084        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
     1085        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
     1086        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
     1087        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
     1088        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
     1089        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
     1090        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
     1091        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
     1092        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
     1093        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
     1094        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
     1095        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
     1096        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
     1097        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
     1098        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
     1099        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
     1100        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
     1101        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
     1102        gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
     1103        gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
     1104        gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
     1105        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
     1106        gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
     1107        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
     1108        gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
     1109        gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
     1110        gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
     1111        gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
     1112        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
     1113        gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
     1114        gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
     1115        gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
     1116        gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
     1117        gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
     1118        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
     1119        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
     1120        gPropertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
     1121        gPropertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
     1122        gPropertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
     1123        gPropertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
     1124        gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
     1125        gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom));
     1126       
     1127        // FIXME: these might be invalid colors, need to check for that
     1128        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor));
     1129        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor));
     1130        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor));
     1131        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor));
     1132        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor));
     1133        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor));
     1134        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor));
     1135        gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor));
     1136       
     1137        // These are for shadows
     1138        gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
     1139        gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
     1140       
     1141        // Make sure unused slots have a value
     1142        for (unsigned int i = 0; i < (unsigned int) numCSSProperties; ++i)
     1143            gPropertyWrapperMap[i] = CSSPropertyInvalid;
     1144       
     1145        size_t n = gPropertyWrappers->size();
     1146        for (unsigned int i = 0; i < n; ++i) {
     1147            ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
     1148            gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
     1149        }
     1150    }
     1151}
     1152
     1153// static
     1154bool AnimationControllerPrivate::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b)
     1155{
     1156    if (prop == cAnimateAll) {
     1157        size_t n = gPropertyWrappers->size();
     1158        for (unsigned int i = 0; i < n; ++i) {
     1159            if (!(*gPropertyWrappers)[i]->equals(a, b))
     1160                return false;
     1161        }
     1162    }
     1163    else {
     1164        int propIndex = prop - firstCSSProperty;
     1165       
     1166        if (propIndex >= 0 && propIndex < numCSSProperties) {
     1167            int i = gPropertyWrapperMap[propIndex];
     1168            return (i >= 0) ? (*gPropertyWrappers)[i]->equals(a, b) : true;
     1169        }
     1170    }
     1171    return true;
     1172}
     1173
     1174// static
     1175int AnimationControllerPrivate::getPropertyAtIndex(int i)
     1176{
     1177    if (i < 0 || i >= (int) gPropertyWrappers->size())
     1178        return CSSPropertyInvalid;
     1179       
     1180    return (*gPropertyWrappers)[i]->property();
     1181}
     1182   
     1183// static - return true if we need to start software animation timers
     1184bool AnimationControllerPrivate::blendProperties(int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog)
     1185{
     1186    if (prop == cAnimateAll) {
     1187        bool needsTimer = false;
     1188   
     1189        size_t n = gPropertyWrappers->size();
     1190        for (unsigned int i = 0; i < n; ++i) {
     1191            PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
     1192            if (!wrapper->equals(a, b)) {
     1193                wrapper->blend(dst, a, b, prog);
     1194                needsTimer = true;
     1195            }
     1196        }
     1197        return needsTimer;
     1198    }
     1199   
     1200    int propIndex = prop - firstCSSProperty;
     1201    if (propIndex >= 0 && propIndex < numCSSProperties) {
     1202        int i = gPropertyWrapperMap[propIndex];
     1203        if (i >= 0) {
     1204            PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
     1205            wrapper->blend(dst, a, b, prog);
     1206            return true;
     1207        }
     1208    }
     1209   
     1210    return false;
     1211}
     1212
     1213CompositeAnimation* AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
     1214{
     1215    CompositeAnimation* animation = m_compositeAnimations.get(renderer);
     1216    if (!animation) {
     1217        animation = new CompositeAnimation(this);
     1218        m_compositeAnimations.set(renderer, animation);
    5081219    }
    5091220    return animation;
     
    5121223bool AnimationControllerPrivate::clear(RenderObject* renderer)
    5131224{
    514     CompositeImplicitAnimation* animation = m_animations.take(renderer);
     1225    // Return false if we didn't do anything OR we are suspended (so we don't try to
     1226    // do a setChanged() when suspended
     1227    CompositeAnimation* animation = m_compositeAnimations.take(renderer);
    5151228    if (!animation)
    5161229        return false;
    517     animation->reset(renderer);
     1230    animation->resetTransitions(renderer);
     1231    bool wasSuspended = animation->suspended();
    5181232    delete animation;
    519     return true;
    520 }
    521 
    522 void AnimationControllerPrivate::updateTimer()
     1233    return !wasSuspended;
     1234}
     1235
     1236void AnimationControllerPrivate::styleAvailable()
     1237{
     1238    if (m_numStyleAvailableWaiters == 0)
     1239        return;
     1240   
     1241    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     1242    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin();
     1243         it != animationsEnd; ++it) {
     1244        it->second->styleAvailable();
     1245    }
     1246}
     1247
     1248void AnimationControllerPrivate::updateAnimationTimer()
    5231249{
    5241250    bool animating = false;
    525     HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator end = m_animations.end();
    526     for (HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
    527         if (it->second->animating()) {
     1251   
     1252    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     1253    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin();
     1254         it != animationsEnd; ++it) {
     1255        CompositeAnimation* compAnim = it->second;
     1256        if (!compAnim->suspended() && compAnim->animating()) {
    5281257            animating = true;
    5291258            break;
     
    5321261   
    5331262    if (animating) {
    534         if (!m_timer.isActive())
    535             m_timer.startRepeating(cAnimationTimerDelay);
    536     } else if (m_timer.isActive())
    537         m_timer.stop();
    538 }
    539 
    540 void AnimationControllerPrivate::timerFired(Timer<AnimationControllerPrivate>* timer)
     1263        if (!m_animationTimer.isActive())
     1264            m_animationTimer.startRepeating(cAnimationTimerDelay);
     1265    } else if (m_animationTimer.isActive())
     1266        m_animationTimer.stop();
     1267}
     1268
     1269void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*)
     1270{
     1271    if (m_frame && m_frame->document()) {
     1272        m_frame->document()->updateRendering();
     1273    }
     1274}
     1275
     1276void AnimationControllerPrivate::startUpdateRenderingDispatcher()
     1277{
     1278    if (!m_updateRenderingDispatcher.isActive()) {
     1279        m_updateRenderingDispatcher.startOneShot(0);
     1280    }
     1281}
     1282
     1283void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>* timer)
    5411284{
    5421285    // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
    5431286    // updateRendering.  It will then call back to us with new information.
    5441287    bool animating = false;
    545     HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator end = m_animations.end();
    546     for (HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
    547         if (it->second->animating()) {
     1288    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     1289    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin();
     1290         it != animationsEnd; ++it) {
     1291        RenderObject* renderer = it->first;
     1292        CompositeAnimation* compAnim = it->second;
     1293        if (!compAnim->suspended() && compAnim->animating()) {
    5481294            animating = true;
    549             it->first->element()->setChanged();
     1295            compAnim->setAnimating(false);
     1296            setChanged(renderer->element());
    5501297        }
    5511298    }
     
    5531300    m_frame->document()->updateRendering();
    5541301   
    555     updateTimer();
    556 }
     1302    updateAnimationTimer();
     1303}
     1304
     1305bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const
     1306{
     1307    CompositeAnimation* animation = m_compositeAnimations.get(obj);
     1308    if (!animation) return false;
     1309   
     1310    return animation->isAnimatingProperty(property);
     1311}
     1312
     1313void AnimationControllerPrivate::suspendAnimations(Document* document)
     1314{
     1315    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     1316    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin();
     1317         it != animationsEnd; ++it) {
     1318        RenderObject* renderer = it->first;
     1319        CompositeAnimation* compAnim = it->second;
     1320        if (renderer->document() == document)
     1321            compAnim->suspendAnimations();
     1322    }
     1323   
     1324    updateAnimationTimer();
     1325}
     1326
     1327void AnimationControllerPrivate::resumeAnimations(Document* document)
     1328{
     1329    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     1330    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin();
     1331         it != animationsEnd; ++it) {
     1332        RenderObject* renderer = it->first;
     1333        CompositeAnimation* compAnim = it->second;
     1334        if (renderer->document() == document)
     1335            compAnim->resumeAnimations();
     1336    }
     1337   
     1338    updateAnimationTimer();
     1339}
     1340
     1341void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
     1342{
     1343    // If currentStyle is null, we don't do transitions
     1344    if (!currentStyle || !targetStyle->transitions())
     1345        return;
     1346       
     1347    // Check to see if we need to update the active transitions
     1348    for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
     1349        const Animation* anim = (*targetStyle->transitions())[i].get();
     1350        double duration = anim->duration();
     1351        double delay = anim->delay();
     1352
     1353        // If this is an empty transition, skip it
     1354        if (duration == 0 && delay <= 0)
     1355            continue;
     1356         
     1357        int prop = anim->property();
     1358        bool all = prop == cAnimateAll;
     1359       
     1360        // Handle both the 'all' and single property cases. For the single prop case, we make only one pass
     1361        // through the loop
     1362        for (int i = 0; ; ++i) {
     1363            if (all) {
     1364                if (i >= AnimationControllerPrivate::getNumProperties())
     1365                    break;
     1366                // get the next prop
     1367                prop = AnimationControllerPrivate::getPropertyAtIndex(i);
     1368            }
     1369
     1370            // See if there is a current transition for this prop
     1371            ImplicitAnimation* implAnim = m_transitions.get(prop);
     1372            bool equal = true;
     1373           
     1374            if (implAnim) {
     1375                // There is one, has our target changed?
     1376                if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
     1377                    // It has changed - toss it and start over
     1378                    // Opacity is special since it can pop in and out of RenderLayers. We need to compute
     1379                    // the blended opacity value between the previous from and to styles and put that in the currentStyle, which
     1380                    // will become the new fromStyle. This is changing a const RenderStyle, but we know what we are doing, really :-)
     1381                    if (prop == CSSPropertyOpacity) {
     1382                        // get the blended value of opacity into the currentStyle (which will be the new fromStyle)
     1383                        implAnim->blendPropertyValueInStyle(CSSPropertyOpacity, currentStyle);
     1384                    }
     1385
     1386                    implAnim->reset(renderer);
     1387                    delete implAnim;
     1388                    m_transitions.remove(prop);
     1389                    equal = false;
     1390                }
     1391            }
     1392            else
     1393                // See if we need to start a new transition
     1394                equal = AnimationControllerPrivate::propertiesEqual(prop, currentStyle, targetStyle);
     1395           
     1396            if (!equal) {
     1397                // AAdd the new transition
     1398                ImplicitAnimation* animation = new ImplicitAnimation(const_cast<Animation*>(anim), renderer, this);
     1399                m_transitions.set(prop, animation);
     1400            }
     1401           
     1402            // We only need one pass for the single prop case
     1403            if (!all)
     1404                break;
     1405        }
     1406    }
     1407}
     1408
     1409RenderStyle* CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
     1410{
     1411    RenderStyle* resultStyle = 0;
     1412   
     1413    // We don't do any transitions if we don't have a currentStyle (on startup)
     1414    updateTransitions(renderer, currentStyle, targetStyle);
     1415   
     1416    if (currentStyle) {
     1417        // Now that we have transition objects ready, let them know about the new goal state.  We want them
     1418        // to fill in a RenderStyle*& only if needed.
     1419        CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1420        for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1421            ImplicitAnimation*  anim = it->second;
     1422            if (anim) {
     1423                anim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
     1424            }
     1425        }
     1426    }
     1427   
     1428    cleanupFinishedAnimations(renderer);
     1429   
     1430    return resultStyle ? resultStyle : targetStyle;
     1431}
     1432
     1433// "animating" means that something is running that requires the timer to keep firing
     1434// (e.g. a transition)
     1435void CompositeAnimation::setAnimating(bool inAnimating)
     1436{
     1437    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1438    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1439        ImplicitAnimation*  transition = it->second;
     1440        transition->setAnimating(inAnimating);
     1441    }
     1442}
     1443
     1444bool CompositeAnimation::animating()
     1445{
     1446    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1447    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1448        ImplicitAnimation*  transition = it->second;
     1449        if (transition && transition->animating() && transition->running())
     1450            return true;
     1451    }
     1452    return false;
     1453}
     1454
     1455void CompositeAnimation::resetTransitions(RenderObject* renderer)
     1456{
     1457    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1458    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1459        ImplicitAnimation*  transition = it->second;
     1460        transition->reset(renderer);
     1461        delete transition;
     1462    }
     1463    m_transitions.clear();
     1464}
     1465
     1466void CompositeAnimation::cleanupFinishedAnimations(RenderObject* renderer)
     1467{
     1468    if (suspended())
     1469        return;
     1470   
     1471    // Make a list of transitions to be deleted
     1472    Vector<int> finishedTransitions;
     1473    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1474
     1475    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1476        ImplicitAnimation* anim = it->second;
     1477        if (!anim)
     1478            continue;
     1479        if (anim->postactive() && !anim->waitingForEndEvent())
     1480            finishedTransitions.append(anim->property());
     1481    }
     1482   
     1483    // Delete them
     1484    for (Vector<int>::iterator it = finishedTransitions.begin(); it != finishedTransitions.end(); ++it) {
     1485        ImplicitAnimation* anim = m_transitions.get(*it);
     1486        if (anim) {
     1487            anim->reset(renderer);
     1488            delete anim;
     1489        }
     1490        m_transitions.remove(*it);
     1491    }
     1492}
     1493
     1494void CompositeAnimation::setTransitionStartTime(int property, double t)
     1495{
     1496    // Set the start time for given property transition
     1497    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1498    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1499        ImplicitAnimation* anim = it->second;
     1500        if (anim && anim->waitingForStartTime() &&
     1501                    (anim->property() == property || anim->property() == cAnimateAll))
     1502            anim->updateStateMachine(AnimationBase::STATE_INPUT_START_TIME_SET, t);
     1503    }
     1504}
     1505
     1506void CompositeAnimation::suspendAnimations()
     1507{
     1508    if (m_suspended)
     1509        return;
     1510   
     1511    m_suspended = true;
     1512
     1513    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1514    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1515        ImplicitAnimation* anim = it->second;
     1516        if (anim && anim->hasStyle()) {
     1517            anim->updatePlayState(false);
     1518        }
     1519    }
     1520}
     1521
     1522void CompositeAnimation::resumeAnimations()
     1523{
     1524    if (!m_suspended)
     1525        return;
     1526   
     1527    m_suspended = false;
     1528
     1529    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1530    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1531        ImplicitAnimation* anim = it->second;
     1532        if (anim && anim->hasStyle()) {
     1533            anim->updatePlayState(true);
     1534        }
     1535    }
     1536}
     1537
     1538void CompositeAnimation::overrideImplicitAnimations(int property)
     1539{
     1540    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1541    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1542        ImplicitAnimation* anim = it->second;
     1543        if (anim && (anim->property() == property || anim->property() == cAnimateAll))
     1544            anim->setOverridden(true);
     1545    }
     1546}
     1547
     1548void CompositeAnimation::resumeOverriddenImplicitAnimations(int property)
     1549{
     1550    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1551    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1552        ImplicitAnimation* anim = it->second;
     1553        if (anim && (anim->property() == property || anim->property() == cAnimateAll))
     1554            anim->setOverridden(false);
     1555    }
     1556}
     1557
     1558void CompositeAnimation::styleAvailable()
     1559{
     1560    if (m_numStyleAvailableWaiters == 0)
     1561        return;
     1562   
     1563    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1564    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1565        ImplicitAnimation* anim = it->second;
     1566        if (anim && anim->waitingForStyleAvailable())
     1567            anim->updateStateMachine(AnimationBase::STATE_INPUT_STYLE_AVAILABLE, -1);
     1568    }
     1569}
     1570
     1571bool CompositeAnimation::isAnimatingProperty(int property) const
     1572{
     1573    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     1574    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
     1575        ImplicitAnimation* anim = it->second;
     1576        if (anim && anim->isAnimatingProperty(property))
     1577            return true;
     1578    }
     1579    return false;
     1580}
     1581
     1582void ImplicitAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle,
     1583                                const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle)
     1584{
     1585    if (paused())
     1586        return;
     1587   
     1588    // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
     1589    // If so, send back the targetStyle (it will get tossed later)
     1590    if (postactive()) {
     1591        if (!ioAnimatedStyle)
     1592            ioAnimatedStyle = const_cast<RenderStyle*>(targetStyle);
     1593        return;
     1594    }
     1595
     1596    // Reset to start the transition if we are new
     1597    if (isnew())
     1598        reset(renderer, currentStyle, targetStyle);
     1599   
     1600    // Run a cycle of animation.
     1601    // We know we will need a new render style, so make one if needed
     1602    if (!ioAnimatedStyle)
     1603        ioAnimatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle);
     1604   
     1605    double prog = progress(1, 0);
     1606    bool needsAnim = AnimationControllerPrivate::blendProperties(m_property, ioAnimatedStyle, m_fromStyle, m_toStyle, prog);
     1607    if (needsAnim)
     1608        setAnimating();
     1609}
     1610
     1611bool ImplicitAnimation::startAnimation(double beginTime)
     1612{
     1613    return false;
     1614}
     1615
     1616void ImplicitAnimation::endAnimation(bool reset)
     1617{
     1618}
     1619
     1620void ImplicitAnimation::onAnimationEnd(double inElapsedTime)
     1621{
     1622    // we're converting the animation into a transition here
     1623    if (!sendTransitionEvent(EventNames::webkitTransitionEndEvent, inElapsedTime)) {
     1624        // we didn't dispatch an event, which would call endAnimation(), so we'll just end
     1625        // it here.
     1626        endAnimation(true);
     1627    }
     1628}
     1629
     1630bool ImplicitAnimation::sendTransitionEvent(const AtomicString& inEventType, double inElapsedTime)
     1631{
     1632    return false; // didn't dispatch an event
     1633}
     1634
     1635void ImplicitAnimation::reset(RenderObject* renderer, const RenderStyle* from /* = 0 */, const RenderStyle* to /* = 0 */)
     1636{
     1637    ASSERT((!m_toStyle && !to) || m_toStyle != to);
     1638    ASSERT((!m_fromStyle && !from) || m_fromStyle != from);
     1639    if (m_fromStyle)
     1640        m_fromStyle->deref(renderer->renderArena());
     1641    if (m_toStyle)
     1642        m_toStyle->deref(renderer->renderArena());
     1643   
     1644    m_fromStyle = const_cast<RenderStyle*>(from);   // it is read-only, other than the ref
     1645    if (m_fromStyle)
     1646        m_fromStyle->ref();
     1647   
     1648    m_toStyle = const_cast<RenderStyle*>(to);       // it is read-only, other than the ref
     1649    if (m_toStyle)
     1650        m_toStyle->ref();
     1651   
     1652    // restart the transition
     1653    if (from && to)
     1654        updateStateMachine(STATE_INPUT_RESTART_ANIMATION, -1);
     1655}
     1656
     1657void ImplicitAnimation::setOverridden(bool b)
     1658{
     1659    if (b != m_overridden) {
     1660        m_overridden = b;
     1661        updateStateMachine(m_overridden ? STATE_INPUT_PAUSE_OVERRIDE : STATE_INPUT_RESUME_OVERRIDE, -1);
     1662    }
     1663}
     1664
     1665bool ImplicitAnimation::affectsProperty(int property) const
     1666{
     1667    return m_property == property ||
     1668    (m_property == cAnimateAll && !AnimationControllerPrivate::propertiesEqual(property, m_fromStyle, m_toStyle));
     1669}
     1670
     1671bool ImplicitAnimation::isTargetPropertyEqual(int prop, RenderStyle* targetStyle)
     1672{
     1673    return AnimationControllerPrivate::propertiesEqual(prop, m_toStyle, targetStyle);
     1674}
     1675
     1676void ImplicitAnimation::blendPropertyValueInStyle(int prop, RenderStyle* currentStyle)
     1677{
     1678    double prog = progress(1, 0);
     1679    AnimationControllerPrivate::blendProperties(prop, currentStyle, m_fromStyle, m_toStyle, prog);
     1680}   
    5571681
    5581682AnimationController::AnimationController(Frame* frame)
    559 :m_data(new AnimationControllerPrivate(frame))
    560 {
    561 
     1683: m_data(new AnimationControllerPrivate(frame))
     1684{
     1685   
    5621686}
    5631687
     
    5671691}
    5681692
    569 void AnimationController::cancelImplicitAnimations(RenderObject* renderer)
    570 {
    571     if (!m_data->hasImplicitAnimations())
     1693void AnimationController::cancelAnimations(RenderObject* renderer)
     1694{
     1695    if (!m_data->hasAnimations())
    5721696        return;
    573 
     1697   
    5741698    if (m_data->clear(renderer))
    575         renderer->element()->setChanged();
    576 }
    577 
    578 RenderStyle* AnimationController::updateImplicitAnimations(RenderObject* renderer, RenderStyle* newStyle)
    579 {
     1699        setChanged(renderer->element());
     1700}
     1701
     1702RenderStyle* AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
     1703{   
     1704    // don't do anything if we're in the cache
     1705    if (!renderer->document() || renderer->document()->inPageCache())
     1706        return newStyle;
     1707   
     1708    RenderStyle* oldStyle = renderer->style();
     1709   
     1710    if ((!oldStyle || !oldStyle->transitions()) && !newStyle->transitions())
     1711        return newStyle;
     1712   
     1713    RenderStyle* blendedStyle = newStyle;
     1714   
    5801715    // Fetch our current set of implicit animations from a hashtable.  We then compare them
    5811716    // against the animations in the style and make sure we're in sync.  If destination values
     
    5831718    // a new style.
    5841719    ASSERT(renderer->element()); // FIXME: We do not animate generated content yet.
    585 
    586     CompositeImplicitAnimation* animation = m_data->get(renderer, newStyle);
    587     if (!animation && !newStyle->transitions())
    588         return newStyle;
    589 
    590     RenderStyle* blendedStyle = animation->animate(renderer, renderer->style(), newStyle);
    591     m_data->updateTimer();
    592 
     1720   
     1721    CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer);
     1722    blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
     1723   
     1724    m_data->updateAnimationTimer();
     1725   
    5931726    if (blendedStyle != newStyle) {
    594         // Do some of the work that CSSStyleSelector::adjustRenderStyle() does, to impose rules
    595         // like opacity creating stacking context.
     1727        // If the animations/transitions change opacity or transform, we neeed to update
     1728        // the style to impose the stacking rules. Note that this is also
     1729        // done in CSSStyleSelector::adjustRenderStyle().
    5961730        if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
    5971731            blendedStyle->setZIndex(0);
    5981732    }
    599 
    6001733    return blendedStyle;
    6011734}
    6021735
    603 void AnimationController::suspendAnimations()
    604 {
    605     // FIXME: Walk the whole hashtable and call pause on each animation.
    606     // Kill our timer.
    607 }
    608 
    609 void AnimationController::resumeAnimations()
    610 {
    611     // FIXME: Walk the whole hashtable and call resume on each animation.
    612     // Start our timer.
    613 }
    614 
    615 }
     1736bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const
     1737{
     1738    return m_data->isAnimatingPropertyOnRenderer(obj, property);
     1739}
     1740
     1741void AnimationController::suspendAnimations(Document* document)
     1742{
     1743#ifdef DEBUG_STATE_MACHINE
     1744    fprintf(stderr, "AnimationController %p suspendAnimations for document %p\n", this, document);
     1745#endif
     1746    m_data->suspendAnimations(document);
     1747}
     1748
     1749void AnimationController::resumeAnimations(Document* document)
     1750{
     1751#ifdef DEBUG_STATE_MACHINE
     1752    fprintf(stderr, "AnimationController %p resumeAnimations for document %p\n", this, document);
     1753#endif
     1754    m_data->resumeAnimations(document);
     1755}
     1756
     1757void AnimationController::startUpdateRenderingDispatcher()
     1758{
     1759    m_data->startUpdateRenderingDispatcher();
     1760}
     1761
     1762void AnimationController::styleAvailable()
     1763{
     1764    m_data->styleAvailable();
     1765}
     1766
     1767void CompositeAnimation::setWaitingForStyleAvailable(bool waiting)
     1768{
     1769    if (waiting)
     1770        m_numStyleAvailableWaiters++;
     1771    else
     1772        m_numStyleAvailableWaiters--;
     1773    m_animationController->setWaitingForStyleAvailable(waiting);
     1774}
     1775   
     1776}
  • trunk/WebCore/page/AnimationController.h

    r29663 r35545  
    3030#define AnimationController_h
    3131
     32#include "CSSPropertyNames.h"
     33
    3234namespace WebCore {
    3335
    3436class AnimationControllerPrivate;
     37class Document;
    3538class Frame;
    3639class RenderObject;
     
    4346    ~AnimationController();
    4447   
    45     void cancelImplicitAnimations(RenderObject*);
    46     RenderStyle* updateImplicitAnimations(RenderObject*, RenderStyle* newStyle);
     48    void cancelAnimations(RenderObject*);
     49    RenderStyle* updateAnimations(RenderObject*, RenderStyle* newStyle);
    4750   
    48     void suspendAnimations();
    49     void resumeAnimations();
     51    bool isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const;
     52   
     53    void suspendAnimations(Document* document);
     54    void resumeAnimations(Document* document);
     55    void updateAnimationTimer();
     56   
     57    void startUpdateRenderingDispatcher();
     58   
     59    void styleAvailable();
    5060   
    5161private:
    5262    AnimationControllerPrivate* m_data;
     63   
    5364};
    5465
  • trunk/WebCore/page/Frame.cpp

    r35499 r35545  
    14831483            if (document && document->renderer() && document->renderer()->hasLayer())
    14841484                document->renderer()->layer()->suspendMarquees();
    1485             view->frame()->animation()->suspendAnimations();
     1485            view->frame()->animation()->suspendAnimations(document);
    14861486            view->frame()->eventHandler()->stopAutoscrollTimer();
    14871487        }
  • trunk/WebCore/rendering/RenderObject.cpp

    r35433 r35545  
    21572157{
    21582158    if (!isText() && m_style && style)
    2159         style = animation()->updateImplicitAnimations(this, style);
     2159        style = animation()->updateAnimations(this, style);
    21602160
    21612161    setStyle(style);
     
    25362536        document()->axObjectCache()->remove(this);
    25372537
    2538     animation()->cancelImplicitAnimations(this);
     2538    animation()->cancelAnimations(this);
    25392539
    25402540    // By default no ref-counting. RenderWidget::destroy() doesn't call
  • trunk/WebCore/rendering/RenderWidget.cpp

    r34589 r35545  
    7373    // both RenderBox::destroy() and RenderObject::destroy().
    7474    // Fix originally made for <rdar://problem/4228818>.
    75     animation()->cancelImplicitAnimations(this);
     75    animation()->cancelAnimations(this);
    7676
    7777    if (RenderView* v = view())
  • trunk/WebCore/rendering/style/RenderStyle.cpp

    r35238 r35545  
    665665}
    666666
    667 Transition::Transition()
    668     : m_duration(RenderStyle::initialTransitionDuration())
    669     , m_repeatCount(RenderStyle::initialTransitionRepeatCount())
    670     , m_timingFunction(RenderStyle::initialTransitionTimingFunction())
    671     , m_property(RenderStyle::initialTransitionProperty())
     667Animation::Animation()
     668    : m_duration(RenderStyle::initialDuration())
     669    , m_timingFunction(RenderStyle::initialTimingFunction())
     670    , m_delay(RenderStyle::initialDelay())
     671    , m_property(RenderStyle::initialProperty())
    672672    , m_durationSet(false)
    673     , m_repeatCountSet(false)
    674673    , m_timingFunctionSet(false)
     674    , m_delaySet(false)
    675675    , m_propertySet(false)
    676     , m_next(0)
    677 {
    678 }
    679 
    680 Transition::Transition(const Transition& o)
    681     : m_duration(o.m_duration)
    682     , m_repeatCount(o.m_repeatCount)
     676{
     677}
     678
     679Animation::Animation(const Animation& o)
     680    : RefCounted<Animation>()
     681    , m_duration(o.m_duration)
    683682    , m_timingFunction(o.m_timingFunction)
     683    , m_delay(o.m_delay)
    684684    , m_property(o.m_property)
    685685    , m_durationSet(o.m_durationSet)
    686     , m_repeatCountSet(o.m_repeatCountSet)
    687686    , m_timingFunctionSet(o.m_timingFunctionSet)
     687    , m_delaySet(o.m_delaySet)
    688688    , m_propertySet(o.m_propertySet)
    689     , m_next(o.m_next ? new Transition(*o.m_next) : 0)
    690 {
    691 }
    692 
    693 Transition::~Transition()
    694 {
    695     delete m_next;
    696 }
    697 
    698 Transition& Transition::operator=(const Transition& o)
    699 {
    700     if (m_next != o.m_next) {
    701         delete m_next;
    702         m_next = o.m_next ? new Transition(*o.m_next) : 0;
    703     }
    704 
     689{
     690}
     691
     692Animation& Animation::operator=(const Animation& o)
     693{
     694    m_delay = o.m_delay;
    705695    m_duration = o.m_duration;
    706     m_repeatCount = o.m_repeatCount;
    707696    m_timingFunction = o.m_timingFunction;
    708697    m_property = o.m_property;
    709698
     699    m_delaySet = o.m_delaySet;
    710700    m_durationSet = o.m_durationSet;
    711     m_repeatCountSet = o.m_repeatCountSet;
    712701    m_timingFunctionSet = o.m_timingFunctionSet;
    713702    m_propertySet = o.m_propertySet;
     
    716705}
    717706
    718 bool Transition::operator==(const Transition& o) const
    719 {
    720     return m_duration == o.m_duration && m_repeatCount == o.m_repeatCount && m_timingFunction == o.m_timingFunction &&
    721            m_property == o.m_property && m_durationSet == o.m_durationSet && m_repeatCountSet == o.m_repeatCountSet &&
    722            m_timingFunctionSet == o.m_timingFunctionSet && m_propertySet == o.m_propertySet &&
    723            ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
    724 }
    725 
    726 void Transition::fillUnsetProperties()
    727 {
    728     Transition* curr;
    729     for (curr = this; curr && curr->isDurationSet(); curr = curr->next()) { }
    730     if (curr && curr != this) {
    731         // We need to fill in the remaining values with the pattern specified.
    732         for (Transition* pattern = this; curr; curr = curr->next()) {
    733             curr->m_duration = pattern->m_duration;
    734             pattern = pattern->next();
    735             if (pattern == curr || !pattern)
    736                 pattern = this;
    737         }
    738     }
    739    
    740     for (curr = this; curr && curr->isRepeatCountSet(); curr = curr->next()) { }
    741     if (curr && curr != this) {
    742         // We need to fill in the remaining values with the pattern specified.
    743         for (Transition* pattern = this; curr; curr = curr->next()) {
    744             curr->m_repeatCount = pattern->m_repeatCount;
    745             pattern = pattern->next();
    746             if (pattern == curr || !pattern)
    747                 pattern = this;
    748         }
    749     }
    750    
    751     for (curr = this; curr && curr->isTimingFunctionSet(); curr = curr->next()) { }
    752     if (curr && curr != this) {
    753         // We need to fill in the remaining values with the pattern specified.
    754         for (Transition* pattern = this; curr; curr = curr->next()) {
    755             curr->m_timingFunction = pattern->m_timingFunction;
    756             pattern = pattern->next();
    757             if (pattern == curr || !pattern)
    758                 pattern = this;
    759         }
    760     }
    761 
    762     for (curr = this; curr && curr->isPropertySet(); curr = curr->next()) { }
    763     if (curr && curr != this) {
    764         // We need to fill in the remaining values with the pattern specified.
    765         for (Transition* pattern = this; curr; curr = curr->next()) {
    766             curr->m_property = pattern->m_property;
    767             pattern = pattern->next();
    768             if (pattern == curr || !pattern)
    769                 pattern = this;
    770         }
    771     }
     707bool Animation::animationsMatch(const Animation* o) const
     708{
     709    if (!o)
     710        return false;
     711   
     712    bool result = m_duration == o->m_duration &&
     713                  m_timingFunction == o->m_timingFunction &&
     714                  m_delay == o->m_delay &&
     715                  m_property == o->m_property &&
     716                  m_durationSet == o->m_durationSet &&
     717                  m_timingFunctionSet == o->m_timingFunctionSet &&
     718                  m_delaySet == o->m_delaySet &&
     719                  m_propertySet == o->m_propertySet;
     720   
     721    return result;
     722}
     723
     724#define FILL_UNSET_PROPERTY(test, propGet, propSet) \
     725for (i = 0; i < size() && (*this)[i]->test(); ++i) { } \
     726if (i < size() && i != 0) { \
     727    for (size_t j = 0; i < size(); ++i, ++j) \
     728        (*this)[i]->propSet((*this)[j]->propGet()); \
     729}
     730
     731void AnimationList::fillUnsetProperties()
     732{
     733    size_t i;
     734    FILL_UNSET_PROPERTY(isDelaySet, delay, setDelay);
     735    FILL_UNSET_PROPERTY(isDurationSet, duration, setDuration);
     736    FILL_UNSET_PROPERTY(isTimingFunctionSet, timingFunction, setTimingFunction);
     737    FILL_UNSET_PROPERTY(isPropertySet, property, setProperty);
     738}
     739
     740bool AnimationList::operator==(const AnimationList& o) const
     741{
     742    if (size() != o.size())
     743        return false;
     744    for (size_t i = 0; i < size(); ++i)
     745        if (*at(i) != *o.at(i))
     746            return false;
     747    return true;
    772748}
    773749
     
    785761    , m_borderFit(RenderStyle::initialBorderFit())
    786762    , m_boxShadow(0)
    787     , m_transition(0)
     763    , m_transitions(0)
    788764    , m_mask(FillLayer(MaskFillLayer))
    789765#if ENABLE(XBL)
     
    812788    , m_boxShadow(o.m_boxShadow ? new ShadowData(*o.m_boxShadow) : 0)
    813789    , m_boxReflect(o.m_boxReflect)
    814     , m_transition(o.m_transition ? new Transition(*o.m_transition) : 0)
     790    , m_transitions(o.m_transitions ? new AnimationList(*o.m_transitions) : 0)
    815791    , m_mask(o.m_mask)
    816792    , m_maskBoxImage(o.m_maskBoxImage)
     
    826802    delete m_counterDirectives;
    827803    delete m_boxShadow;
    828     delete m_transition;
    829804#if ENABLE(XBL)
    830805    delete bindingURI;
     
    897872bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInheritedData& o) const
    898873{
    899     if (!m_transition && o.m_transition || m_transition && !o.m_transition)
    900         return false;
    901     if (m_transition && o.m_transition && (*m_transition != *o.m_transition))
     874    if (!m_transitions && o.m_transitions || m_transitions && !o.m_transitions)
     875        return false;
     876    if (m_transitions && o.m_transitions && (*m_transitions != *o.m_transitions))
    902877        return false;
    903878    return true;
     
    14951470    // so they don't need to cause any repaint or layout.
    14961471
    1497     // Transitions don't need to be checked either.  We always set the new style on the RenderObject, so we will get a chance to fire off
     1472    // Animations don't need to be checked either.  We always set the new style on the RenderObject, so we will get a chance to fire off
    14981473    // the resulting transition properly.
    14991474    return Equal;
     
    18711846void RenderStyle::adjustTransitions()
    18721847{
    1873     if (transitions()) {
    1874         if (transitions()->isEmpty()) {
    1875             clearTransitions();
    1876             return;
     1848    AnimationList* transitionList = rareNonInheritedData->m_transitions;
     1849    if (!transitionList)
     1850        return;
     1851   
     1852    if (transitionList->size() == 0) {
     1853        clearTransitions();
     1854        return;
     1855    }
     1856
     1857    // get rid of empty transitions and anything beyond them
     1858    for (size_t i = 0; i < transitionList->size(); ++i) {
     1859        if ((*transitionList)[i]->isEmpty()) {
     1860            transitionList->resize(i);
     1861            break;
    18771862        }
    1878 
    1879         Transition* next;
    1880         for (Transition* p = accessTransitions(); p; p = next) {
    1881             next = p->m_next;
    1882             if (next && next->isEmpty()) {
    1883                 delete next;
    1884                 p->m_next = 0;
    1885                 break;
     1863    }
     1864
     1865    if (transitionList->size() == 0) {
     1866        clearTransitions();
     1867        return;
     1868    }
     1869
     1870    // Repeat patterns into layers that don't have some properties set.
     1871    transitionList->fillUnsetProperties();
     1872       
     1873    // Make sure there are no duplicate properties. This is an O(n^2) algorithm
     1874    // but the lists tend to be very short, so it is probably ok
     1875    for (size_t i = 0; i < transitionList->size(); ++i) {
     1876        for (size_t j = i+1; j < transitionList->size(); ++j) {
     1877            if ((*transitionList)[i]->property() == (*transitionList)[j]->property()) {
     1878                // toss i
     1879                transitionList->remove(i);
     1880                j = i;
    18861881            }
    18871882        }
    1888    
    1889         // Repeat patterns into layers that don't have some properties set.
    1890         accessTransitions()->fillUnsetProperties();
    1891     }
    1892 }
    1893 
    1894 Transition* RenderStyle::accessTransitions()
    1895 {
    1896     Transition* layer = rareNonInheritedData.access()->m_transition;
    1897     if (!layer)
    1898         rareNonInheritedData.access()->m_transition = new Transition();
    1899     return rareNonInheritedData->m_transition;
    1900 }
    1901 
    1902 }
     1883    }
     1884}
     1885
     1886AnimationList* RenderStyle::accessTransitions()
     1887{
     1888    AnimationList* list = rareNonInheritedData.access()->m_transitions;
     1889    if (!list)
     1890        rareNonInheritedData.access()->m_transitions = new AnimationList();
     1891    return rareNonInheritedData->m_transitions;
     1892}
     1893
     1894}
  • trunk/WebCore/rendering/style/RenderStyle.h

    r35026 r35545  
    12581258};
    12591259
    1260 struct Transition {
    1261 public:
    1262     Transition();
    1263     ~Transition();
    1264 
    1265     Transition* next() const { return m_next; }
    1266     Transition* next() { return m_next; }
    1267 
     1260class Animation : public RefCounted<Animation> {
     1261public:
     1262
     1263    static PassRefPtr<Animation> create() { return adoptRef(new Animation); };
     1264   
     1265    bool isDelaySet() const { return m_delaySet; }
    12681266    bool isDurationSet() const { return m_durationSet; }
    1269     bool isRepeatCountSet() const { return m_repeatCountSet; }
    12701267    bool isTimingFunctionSet() const { return m_timingFunctionSet; }
    12711268    bool isPropertySet() const { return m_propertySet; }
    1272    
    1273     bool isEmpty() const { return !m_durationSet && !m_repeatCountSet && !m_timingFunctionSet && !m_propertySet; }
     1269
     1270    bool isEmpty() const
     1271    {
     1272        return (!m_durationSet && !m_delaySet && !m_timingFunctionSet && !m_propertySet);
     1273    }
     1274
     1275    bool isEmptyOrZeroDuration() const
     1276    {
     1277        return isEmpty() || (m_duration == 0 && m_delay <= 0);
     1278    }
     1279
     1280    void clearDelay() { m_delaySet = false; }
    12741281    void clearDuration() { m_durationSet = false; }
    1275     void clearRepeatCount() { m_repeatCountSet = false; }
    12761282    void clearTimingFunction() { m_timingFunctionSet = false; }
     1283
    12771284    void clearProperty() { m_propertySet = false; }
    12781285
    1279     int duration() const { return m_duration; }
    1280     int repeatCount() const { return m_repeatCount; }
     1286    double delay() const { return m_delay; }
     1287    double duration() const { return m_duration; }
    12811288    const TimingFunction& timingFunction() const { return m_timingFunction; }
    12821289    int property() const { return m_property; }
    1283    
    1284     void setDuration(int d) { m_duration = d; m_durationSet = true; }
    1285     void setRepeatCount(int c) { m_repeatCount = c; m_repeatCountSet = true; }
     1290
     1291    void setDelay(double c) { m_delay = c; m_delaySet = true; }
     1292    void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; }
    12861293    void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; }
    12871294    void setProperty(int t) { m_property = t; m_propertySet = true; }
    12881295
    1289     void setNext(Transition* n) { if (m_next != n) { delete m_next; m_next = n; } }
    1290 
    1291     Transition& operator=(const Transition& o);   
    1292     Transition(const Transition& o);
    1293 
    1294     bool operator==(const Transition& o) const;
    1295     bool operator!=(const Transition& o) const {
    1296         return !(*this == o);
    1297     }
    1298 
     1296    Animation& operator=(const Animation& o);
     1297
     1298    // return true if all members of this class match (excluding m_next)
     1299    bool animationsMatch(const Animation* t) const;
     1300
     1301    // return true every Animation in the chain (defined by m_next) match
     1302    bool operator==(const Animation& o) const { return animationsMatch(&o); }
     1303    bool operator!=(const Animation& o) const { return !(*this == o); }
     1304
     1305private:
     1306    Animation();
     1307    Animation(const Animation& o);
     1308   
     1309    double m_duration;
     1310    TimingFunction m_timingFunction;
     1311    double m_delay;
     1312    int m_property;
     1313
     1314    bool m_durationSet       : 1;
     1315    bool m_timingFunctionSet : 1;
     1316    bool m_delaySet          : 1;
     1317    bool m_propertySet       : 1;
     1318};
     1319
     1320class AnimationList : public Vector<RefPtr<Animation> >
     1321{
     1322public:
    12991323    void fillUnsetProperties();
    1300 
    1301     int m_duration;
    1302     int m_repeatCount;
    1303     TimingFunction m_timingFunction;
    1304     int m_property;
    1305 
    1306     bool m_durationSet;
    1307     bool m_repeatCountSet;
    1308     bool m_timingFunctionSet;
    1309     bool m_propertySet;
    1310 
    1311     Transition* m_next;
    1312 };
     1324    bool operator==(const AnimationList& o) const;
     1325};   
     1326
    13131327
    13141328class StyleReflection : public RefCounted<StyleReflection> {
     
    13901404    RefPtr<StyleReflection> m_boxReflect;
    13911405
    1392     Transition* m_transition;
     1406    AnimationList* m_transitions;
    13931407
    13941408    FillLayer m_mask;
     
    20312045    }
    20322046    ShadowData* textShadow() const { return rareInheritedData->textShadow; }
    2033     Color textStrokeColor() const { return rareInheritedData->textStrokeColor; }
     2047    const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; }
    20342048    float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
    2035     Color textFillColor() const { return rareInheritedData->textFillColor; }
     2049    const Color& textFillColor() const { return rareInheritedData->textFillColor; }
    20362050    float opacity() const { return rareNonInheritedData->opacity; }
    20372051    EAppearance appearance() const { return static_cast<EAppearance>(rareNonInheritedData->m_appearance); }
     
    20882102
    20892103    // Apple-specific property getter methods
    2090     Transition* accessTransitions();
    2091     const Transition* transitions() const { return rareNonInheritedData->m_transition; }
     2104    AnimationList* accessTransitions();
     2105    const AnimationList* transitions() const { return rareNonInheritedData->m_transitions; }
     2106    bool hasTransitions() const { return rareNonInheritedData->m_transitions && rareNonInheritedData->m_transitions->size() > 0; }
     2107
    20922108    int lineClamp() const { return rareNonInheritedData->lineClamp; }
    20932109    bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
     
    23512367    void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); }
    23522368    // End CSS3 Setters
    2353    
     2369
    23542370    // Apple-specific property setters
    2355     void clearTransitions() { delete rareNonInheritedData.access()->m_transition; rareNonInheritedData.access()->m_transition = 0; }
    2356     void inheritTransitions(const Transition* parent) { clearTransitions(); if (parent) rareNonInheritedData.access()->m_transition = new Transition(*parent); }
     2371    void clearTransitions()
     2372    {
     2373        if (rareNonInheritedData.access()->m_transitions) {
     2374            delete rareNonInheritedData.access()->m_transitions;
     2375            rareNonInheritedData.access()->m_transitions = 0;
     2376        }
     2377    }
     2378
     2379    void inheritTransitions(const AnimationList* parent) { clearTransitions(); if (parent) rareNonInheritedData.access()->m_transitions = new AnimationList(*parent); }
    23572380    void adjustTransitions();
    23582381    void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
     
    25122535   
    25132536    // Keep these at the end.
    2514     static int initialTransitionDuration() { return 0; }
    2515     static int initialTransitionRepeatCount() { return 1; }
    2516     static TimingFunction initialTransitionTimingFunction() { return TimingFunction(); }
    2517     static int initialTransitionProperty() { return cAnimateAll; }
     2537    static float initialDelay() { return 0; }
     2538    static double initialDuration() { return 0; }
     2539    static TimingFunction initialTimingFunction() { return TimingFunction(); }
     2540    static int initialProperty() { return cAnimateAll; }
    25182541    static int initialLineClamp() { return -1; }
    25192542    static bool initialTextSizeAdjust() { return true; }
Note: See TracChangeset for help on using the changeset viewer.