View | Details | Raw Unified | Return to bug 19938 | Differences between
and this patch

Collapse All | Expand All

(-)a/WebCore/css/CSSComputedStyleDeclaration.cpp (-5 / +62 lines)
Lines 29-34 Link Here
29
#include "CSSPrimitiveValueMappings.h"
29
#include "CSSPrimitiveValueMappings.h"
30
#include "CSSPropertyNames.h"
30
#include "CSSPropertyNames.h"
31
#include "CSSReflectValue.h"
31
#include "CSSReflectValue.h"
32
#include "CSSTimingFunctionValue.h"
32
#include "CSSValueList.h"
33
#include "CSSValueList.h"
33
#include "CachedImage.h"
34
#include "CachedImage.h"
34
#include "Document.h"
35
#include "Document.h"
Lines 187-192 static const int computedProperties[] = { Link Here
187
    CSSPropertyWebkitTransform,
188
    CSSPropertyWebkitTransform,
188
    CSSPropertyWebkitTransformOriginX,
189
    CSSPropertyWebkitTransformOriginX,
189
    CSSPropertyWebkitTransformOriginY,
190
    CSSPropertyWebkitTransformOriginY,
191
    CSSPropertyWebkitTransitionDelay,
192
    CSSPropertyWebkitTransitionDuration,
193
    CSSPropertyWebkitTransitionProperty,
194
    CSSPropertyWebkitTransitionTimingFunction,
190
    CSSPropertyWebkitUserDrag,
195
    CSSPropertyWebkitUserDrag,
191
    CSSPropertyWebkitUserModify,
196
    CSSPropertyWebkitUserModify,
192
    CSSPropertyWebkitUserSelect,
197
    CSSPropertyWebkitUserSelect,
Lines 1055-1060 PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper Link Here
1055
            }
1060
            }
1056
            else
1061
            else
1057
                return CSSPrimitiveValue::create(style->transformOriginY());
1062
                return CSSPrimitiveValue::create(style->transformOriginY());
1063
        case CSSPropertyWebkitTransitionDelay: {
1064
            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1065
            const Transition* t = style->transitions();
1066
            if (t) {
1067
                for ( ; t; t = t->next())
1068
                    list->append(CSSPrimitiveValue::create(t->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 Transition* t = style->transitions();
1077
            if (t) {
1078
                for ( ; t; t = t->next())
1079
                    list->append(CSSPrimitiveValue::create(t->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 Transition* t = style->transitions();
1088
            if (t) {
1089
                for ( ; t; t = t->next()) {
1090
                    const TimingFunction& tf = t->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 Transition* t = style->transitions();
1103
            if (t) {
1104
                for ( ; t; t = t->next()) {
1105
                    int prop = t->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
        }
1058
        case CSSPropertyBackground:
1120
        case CSSPropertyBackground:
1059
        case CSSPropertyBorder:
1121
        case CSSPropertyBorder:
1060
        case CSSPropertyBorderBottom:
1122
        case CSSPropertyBorderBottom:
Lines 1112-1122 PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper Link Here
1112
        case CSSPropertyWebkitMask:
1174
        case CSSPropertyWebkitMask:
1113
        case CSSPropertyWebkitPaddingStart:
1175
        case CSSPropertyWebkitPaddingStart:
1114
        case CSSPropertyWebkitTextStroke:
1176
        case CSSPropertyWebkitTextStroke:
1115
        case CSSPropertyWebkitTransition:
1116
        case CSSPropertyWebkitTransitionDuration:
1117
        case CSSPropertyWebkitTransitionProperty:
1118
        case CSSPropertyWebkitTransitionRepeatCount:
1119
        case CSSPropertyWebkitTransitionTimingFunction:
1120
            // FIXME: The above are unimplemented.
1177
            // FIXME: The above are unimplemented.
1121
            break;
1178
            break;
1122
#if ENABLE(SVG)
1179
#if ENABLE(SVG)
(-)a/WebCore/css/CSSParser.cpp (-15 / +16 lines)
Lines 1294-1301 bool CSSParser::parseValue(int propId, bool important) Link Here
1294
        }
1294
        }
1295
        return false;
1295
        return false;
1296
    }
1296
    }
1297
    case CSSPropertyWebkitTransitionDelay:
1297
    case CSSPropertyWebkitTransitionDuration:
1298
    case CSSPropertyWebkitTransitionDuration:
1298
    case CSSPropertyWebkitTransitionRepeatCount:
1299
    case CSSPropertyWebkitTransitionTimingFunction:
1299
    case CSSPropertyWebkitTransitionTimingFunction:
1300
    case CSSPropertyWebkitTransitionProperty: {
1300
    case CSSPropertyWebkitTransitionProperty: {
1301
        RefPtr<CSSValue> val;
1301
        RefPtr<CSSValue> val;
Lines 1709-1716 void CSSParser::addTransitionValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> Link Here
1709
1709
1710
bool CSSParser::parseTransitionShorthand(bool important)
1710
bool CSSParser::parseTransitionShorthand(bool important)
1711
{
1711
{
1712
    const int properties[] = { CSSPropertyWebkitTransitionProperty, CSSPropertyWebkitTransitionDuration, 
1712
    const int properties[] = { CSSPropertyWebkitTransitionProperty,
1713
                               CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitTransitionRepeatCount };
1713
                               CSSPropertyWebkitTransitionDuration,
1714
                               CSSPropertyWebkitTransitionTimingFunction };
1714
    const int numProperties = sizeof(properties) / sizeof(properties[0]);
1715
    const int numProperties = sizeof(properties) / sizeof(properties[0]);
1715
    
1716
    
1716
    ShorthandScope scope(this, CSSPropertyWebkitTransition);
1717
    ShorthandScope scope(this, CSSPropertyWebkitTransition);
Lines 2206-2225 bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2, Link Here
2206
    return false;
2207
    return false;
2207
}
2208
}
2208
2209
2209
PassRefPtr<CSSValue> CSSParser::parseTransitionDuration()
2210
PassRefPtr<CSSValue> CSSParser::parseDelay()
2210
{
2211
{
2211
    CSSParserValue* value = m_valueList->current();
2212
    CSSParserValue* value = m_valueList->current();
2213
    if (value->id == CSSValueNow)
2214
        return CSSPrimitiveValue::createIdentifier(value->id);
2212
    if (validUnit(value, FTime, m_strict))
2215
    if (validUnit(value, FTime, m_strict))
2213
        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2216
        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2214
    return 0;
2217
    return 0;
2215
}
2218
}
2216
2219
2217
PassRefPtr<CSSValue> CSSParser::parseTransitionRepeatCount()
2220
PassRefPtr<CSSValue> CSSParser::parseDuration()
2218
{
2221
{
2219
    CSSParserValue* value = m_valueList->current();
2222
    CSSParserValue* value = m_valueList->current();
2220
    if (value->id == CSSValueInfinite)
2223
    if (validUnit(value, FTime|FNonNeg, m_strict))
2221
        return CSSPrimitiveValue::createIdentifier(value->id);
2222
    if (validUnit(value, FInteger|FNonNeg, m_strict))
2223
        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2224
        return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2224
    return 0;
2225
    return 0;
2225
}
2226
}
Lines 2242-2248 bool CSSParser::parseTimingFunctionValue(CSSParserValueList*& args, double& resu Link Here
2242
    return true;
2243
    return true;
2243
}
2244
}
2244
2245
2245
PassRefPtr<CSSValue> CSSParser::parseTransitionTimingFunction()
2246
PassRefPtr<CSSValue> CSSParser::parseTimingFunction()
2246
{
2247
{
2247
    CSSParserValue* value = m_valueList->current();
2248
    CSSParserValue* value = m_valueList->current();
2248
    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut)
2249
    if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut)
Lines 2306-2323 bool CSSParser::parseTransitionProperty(int propId, RefPtr<CSSValue>& result) Link Here
2306
        }
2307
        }
2307
        else {
2308
        else {
2308
            switch (propId) {
2309
            switch (propId) {
2309
                case CSSPropertyWebkitTransitionDuration:
2310
                case CSSPropertyWebkitTransitionDelay:
2310
                    currValue = parseTransitionDuration();
2311
                    currValue = parseDelay();
2311
                    if (currValue)
2312
                    if (currValue)
2312
                        m_valueList->next();
2313
                        m_valueList->next();
2313
                    break;
2314
                    break;
2314
                case CSSPropertyWebkitTransitionRepeatCount:
2315
                case CSSPropertyWebkitTransitionDuration:
2315
                    currValue = parseTransitionRepeatCount();
2316
                    currValue = parseDuration();
2316
                    if (currValue)
2317
                    if (currValue)
2317
                        m_valueList->next();
2318
                        m_valueList->next();
2318
                    break;
2319
                    break;
2319
                case CSSPropertyWebkitTransitionTimingFunction:
2320
                case CSSPropertyWebkitTransitionTimingFunction:
2320
                    currValue = parseTransitionTimingFunction();
2321
                    currValue = parseTimingFunction();
2321
                    if (currValue)
2322
                    if (currValue)
2322
                        m_valueList->next();
2323
                        m_valueList->next();
2323
                    break;
2324
                    break;
Lines 3907-3913 PassRefPtr<CSSValueList> CSSParser::parseTransform() Link Here
3907
3908
3908
    // The transform is a list of functional primitives that specify transform operations.
3909
    // The transform is a list of functional primitives that specify transform operations.
3909
    // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
3910
    // 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();
3911
    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
3912
    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
3912
        if (value->unit != CSSParserValue::Function || !value->function)
3913
        if (value->unit != CSSParserValue::Function || !value->function)
3913
            return 0;
3914
            return 0;
(-)a/WebCore/css/CSSParser.h (-4 / +6 lines)
Lines 84-94 namespace WebCore { Link Here
84
        void addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval);
84
        void addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval);
85
85
86
        void addTransitionValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval);
86
        void addTransitionValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval);
87
        PassRefPtr<CSSValue> parseTransitionDuration();
87
88
        PassRefPtr<CSSValue> parseTransitionRepeatCount();
88
        PassRefPtr<CSSValue> parseDelay();
89
        PassRefPtr<CSSValue> parseTransitionTimingFunction();
89
        PassRefPtr<CSSValue> parseDuration();
90
        bool parseTimingFunctionValue(CSSParserValueList*& args, double& result);
90
        PassRefPtr<CSSValue> parseTimingFunction();
91
        PassRefPtr<CSSValue> parseTransitionProperty();
91
        PassRefPtr<CSSValue> parseTransitionProperty();
92
93
        bool parseTimingFunctionValue(CSSParserValueList*& args, double& result);
92
        bool parseTransitionProperty(int propId, RefPtr<CSSValue>&);
94
        bool parseTransitionProperty(int propId, RefPtr<CSSValue>&);
93
        bool parseTransitionShorthand(bool important);
95
        bool parseTransitionShorthand(bool important);
94
        
96
        
(-)a/WebCore/css/CSSPropertyNames.in (-5 / +5 lines)
Lines 142-152 word-spacing Link Here
142
word-wrap
142
word-wrap
143
z-index
143
z-index
144
zoom
144
zoom
145
-webkit-transition
146
-webkit-transition-duration
147
-webkit-transition-property
148
-webkit-transition-repeat-count
149
-webkit-transition-timing-function
150
-webkit-appearance
145
-webkit-appearance
151
-webkit-background-clip
146
-webkit-background-clip
152
-webkit-background-composite
147
-webkit-background-composite
Lines 225-230 zoom Link Here
225
-webkit-transform-origin
220
-webkit-transform-origin
226
-webkit-transform-origin-x
221
-webkit-transform-origin-x
227
-webkit-transform-origin-y
222
-webkit-transform-origin-y
223
-webkit-transition
224
-webkit-transition-delay
225
-webkit-transition-duration
226
-webkit-transition-property
227
-webkit-transition-timing-function
228
-webkit-user-drag
228
-webkit-user-drag
229
-webkit-user-modify
229
-webkit-user-modify
230
-webkit-user-select
230
-webkit-user-select
(-)a/WebCore/css/CSSStyleSelector.cpp (-38 / +40 lines)
Lines 189-195 if (isInherit) { \ Link Here
189
    const Transition* currParent = m_parentStyle->transitions(); \
189
    const Transition* currParent = m_parentStyle->transitions(); \
190
    while (currParent && currParent->is##Prop##Set()) { \
190
    while (currParent && currParent->is##Prop##Set()) { \
191
        if (!currChild) { \
191
        if (!currChild) { \
192
            /* Need to make a new layer.*/ \
192
            /* Need to make a new transition.*/ \
193
            currChild = new Transition(); \
193
            currChild = new Transition(); \
194
            prevChild->setNext(currChild); \
194
            prevChild->setNext(currChild); \
195
        } \
195
        } \
Lines 200-241 if (isInherit) { \ Link Here
200
    } \
200
    } \
201
    \
201
    \
202
    while (currChild) { \
202
    while (currChild) { \
203
        /* Reset any remaining layers to not have the property set. */ \
203
        /* Reset any remaining transitions to not have the property set. */ \
204
        currChild->clear##Prop(); \
204
        currChild->clear##Prop(); \
205
        currChild = currChild->next(); \
205
        currChild = currChild->next(); \
206
    } \
206
    } \
207
} else if (isInitial) { \
207
    return; \
208
} \
209
if (isInitial) { \
208
    Transition* currChild = m_style->accessTransitions(); \
210
    Transition* currChild = m_style->accessTransitions(); \
209
    currChild->set##Prop(RenderStyle::initialTransition##Prop()); \
211
    currChild->set##Prop(RenderStyle::initial##Prop()); \
210
    for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
212
    for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
211
        currChild->clear##Prop(); \
213
        currChild->clear##Prop(); \
214
    return; \
212
}
215
}
213
216
214
#define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \
217
#define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \
215
HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
218
HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
216
if (isInherit || isInitial) \
217
    return; \
218
Transition* currChild = m_style->accessTransitions(); \
219
Transition* currChild = m_style->accessTransitions(); \
219
Transition* prevChild = 0; \
220
Transition* prevChild = 0; \
220
if (value->isValueList()) { \
221
if (value->isValueList()) { \
221
    /* Walk each value and put it into a layer, creating new layers as needed. */ \
222
    /* Walk each value and put it into a transition, creating new transitions as needed. */ \
222
    CSSValueList* valueList = static_cast<CSSValueList*>(value); \
223
    CSSValueList* valueList = static_cast<CSSValueList*>(value); \
223
    for (unsigned int i = 0; i < valueList->length(); i++) { \
224
    for (unsigned int i = 0; i < valueList->length(); i++) { \
224
        if (!currChild) { \
225
        if (!currChild) { \
225
            /* Need to make a new layer to hold this value */ \
226
        /* Need to make a new transition to hold this value */ \
226
            currChild = new Transition(); \
227
        currChild = new Transition(); \
227
            prevChild->setNext(currChild); \
228
        prevChild->setNext(currChild); \
228
        } \
229
        } \
229
        mapTransition##Prop(currChild, valueList->itemWithoutBoundsCheck(i)); \
230
        map##Prop(currChild, valueList->item(i)); \
230
        prevChild = currChild; \
231
        prevChild = currChild; \
231
        currChild = currChild->next(); \
232
        currChild = currChild->next(); \
232
    } \
233
    } \
233
} else { \
234
} else { \
234
    mapTransition##Prop(currChild, value); \
235
    map##Prop(currChild, value); \
235
    currChild = currChild->next(); \
236
    currChild = currChild->next(); \
236
} \
237
} \
237
while (currChild) { \
238
while (currChild) { \
238
    /* Reset all remaining layers to not have the property set. */ \
239
    /* Reset all remaining transitions to not have the property set. */ \
239
    currChild->clear##Prop(); \
240
    currChild->clear##Prop(); \
240
    currChild = currChild->next(); \
241
    currChild = currChild->next(); \
241
} }
242
} }
Lines 4735-4752 void CSSStyleSelector::applyProperty(int id, CSSValue *value) Link Here
4735
        else if (isInherit)
4736
        else if (isInherit)
4736
            m_style->inheritTransitions(m_parentStyle->transitions());
4737
            m_style->inheritTransitions(m_parentStyle->transitions());
4737
        return;
4738
        return;
4739
    case CSSPropertyWebkitTransitionDelay:
4740
        HANDLE_TRANSITION_VALUE(delay, Delay, value)
4741
        return;
4738
    case CSSPropertyWebkitTransitionDuration:
4742
    case CSSPropertyWebkitTransitionDuration:
4739
        HANDLE_TRANSITION_VALUE(duration, Duration, value)
4743
        HANDLE_TRANSITION_VALUE(duration, Duration, value)
4740
        return;
4744
        return;
4741
    case CSSPropertyWebkitTransitionRepeatCount:
4745
    case CSSPropertyWebkitTransitionProperty:
4742
        HANDLE_TRANSITION_VALUE(repeatCount, RepeatCount, value)
4746
        HANDLE_TRANSITION_VALUE(property, Property, value)
4743
        return;
4747
        return;
4744
    case CSSPropertyWebkitTransitionTimingFunction:
4748
    case CSSPropertyWebkitTransitionTimingFunction:
4745
        HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value)
4749
        HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value)
4746
        return;
4750
        return;
4747
    case CSSPropertyWebkitTransitionProperty:
4748
        HANDLE_TRANSITION_VALUE(property, Property, value)
4749
        return;
4750
    case CSSPropertyInvalid:
4751
    case CSSPropertyInvalid:
4751
        return;
4752
        return;
4752
    case CSSPropertyFontStretch:
4753
    case CSSPropertyFontStretch:
Lines 4987-4996 void CSSStyleSelector::mapFillYPosition(FillLayer* layer, CSSValue* value) Link Here
4987
    layer->setYPosition(l);
4988
    layer->setYPosition(l);
4988
}
4989
}
4989
4990
4990
void CSSStyleSelector::mapTransitionDuration(Transition* transition, CSSValue* value)
4991
void CSSStyleSelector::mapDuration(Transition* transition, CSSValue* value)
4991
{
4992
{
4992
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4993
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4993
        transition->setDuration(RenderStyle::initialTransitionDuration());
4994
        transition->setDuration(RenderStyle::initialDuration());
4994
        return;
4995
        return;
4995
    }
4996
    }
4996
4997
Lines 4999-5033 void CSSStyleSelector::mapTransitionDuration(Transition* transition, CSSValue* v Link Here
4999
5000
5000
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5001
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5001
    if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
5002
    if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
5002
        transition->setDuration(int(1000*primitiveValue->getFloatValue()));
5003
        transition->setDuration(primitiveValue->getFloatValue());
5003
    else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
5004
    else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
5004
        transition->setDuration(int(primitiveValue->getFloatValue()));
5005
        transition->setDuration(primitiveValue->getFloatValue()/1000.0f);
5005
}
5006
}
5006
5007
5007
void CSSStyleSelector::mapTransitionRepeatCount(Transition* transition, CSSValue* value)
5008
void CSSStyleSelector::mapDelay(Transition* transition, CSSValue* value)
5008
{
5009
{
5009
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5010
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5010
        transition->setRepeatCount(RenderStyle::initialTransitionRepeatCount());
5011
        transition->setDelay(RenderStyle::initialDelay());
5011
        return;
5012
        return;
5012
    }
5013
    }
5013
5014
5014
    if (!value->isPrimitiveValue())
5015
        return;
5016
5017
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5015
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5018
    if (primitiveValue->getIdent() == CSSValueInfinite)
5016
    if (primitiveValue->getIdent() == CSSValueNow)
5019
        transition->setRepeatCount(-1);
5017
        transition->setDelay(0);
5020
    else
5018
    else {
5021
        transition->setRepeatCount(int(primitiveValue->getFloatValue()));
5019
        if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
5020
            transition->setDelay(primitiveValue->getFloatValue());
5021
        else
5022
            transition->setDelay(primitiveValue->getFloatValue()/1000.0f);
5023
    }
5022
}
5024
}
5023
5025
5024
void CSSStyleSelector::mapTransitionTimingFunction(Transition* transition, CSSValue* value)
5026
void CSSStyleSelector::mapTimingFunction(Transition* transition, CSSValue* value)
5025
{
5027
{
5026
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5028
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5027
        transition->setTimingFunction(RenderStyle::initialTransitionTimingFunction());
5029
        transition->setTimingFunction(RenderStyle::initialTimingFunction());
5028
        return;
5030
        return;
5029
    }
5031
    }
5030
5032
    
5031
    if (value->isPrimitiveValue()) {
5033
    if (value->isPrimitiveValue()) {
5032
        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5034
        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5033
        switch (primitiveValue->getIdent()) {
5035
        switch (primitiveValue->getIdent()) {
Lines 5049-5065 void CSSStyleSelector::mapTransitionTimingFunction(Transition* transition, CSSVa Link Here
5049
        }
5051
        }
5050
        return;
5052
        return;
5051
    }
5053
    }
5052
5054
    
5053
    if (value->isTransitionTimingFunctionValue()) {
5055
    if (value->isTransitionTimingFunctionValue()) {
5054
        CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value);
5056
        CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value);
5055
        transition->setTimingFunction(TimingFunction(CubicBezierTimingFunction, timingFunction->x1(), timingFunction->y1(), timingFunction->x2(), timingFunction->y2()));
5057
        transition->setTimingFunction(TimingFunction(CubicBezierTimingFunction, timingFunction->x1(), timingFunction->y1(), timingFunction->x2(), timingFunction->y2()));
5056
    }
5058
    }
5057
}
5059
}
5058
5060
5059
void CSSStyleSelector::mapTransitionProperty(Transition* transition, CSSValue* value)
5061
void CSSStyleSelector::mapProperty(Transition* transition, CSSValue* value)
5060
{
5062
{
5061
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5063
    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
5062
        transition->setProperty(RenderStyle::initialTransitionProperty());
5064
        transition->setProperty(RenderStyle::initialProperty());
5063
        return;
5065
        return;
5064
    }
5066
    }
5065
5067
Lines 5067-5073 void CSSStyleSelector::mapTransitionProperty(Transition* transition, CSSValue* v Link Here
5067
        return;
5069
        return;
5068
5070
5069
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5071
    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
5070
    transition->setProperty(primitiveValue->getIdent());
5072
    transition->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent()));
5071
}
5073
}
5072
5074
5073
void CSSStyleSelector::mapNinePieceImage(CSSValue* value, NinePieceImage& image)
5075
void CSSStyleSelector::mapNinePieceImage(CSSValue* value, NinePieceImage& image)
(-)a/WebCore/css/CSSStyleSelector.h (-4 / +4 lines)
Lines 204-213 public: Link Here
204
        void mapFillXPosition(FillLayer*, CSSValue*);
204
        void mapFillXPosition(FillLayer*, CSSValue*);
205
        void mapFillYPosition(FillLayer*, CSSValue*);
205
        void mapFillYPosition(FillLayer*, CSSValue*);
206
206
207
        void mapTransitionDuration(Transition*, CSSValue*);
207
        void mapDelay(Transition*, CSSValue*);
208
        void mapTransitionRepeatCount(Transition*, CSSValue*);
208
        void mapDuration(Transition*, CSSValue*);
209
        void mapTransitionTimingFunction(Transition*, CSSValue*);
209
        void mapTimingFunction(Transition*, CSSValue*);
210
        void mapTransitionProperty(Transition*, CSSValue*);
210
        void mapProperty(Transition*, CSSValue*);
211
211
212
        void mapNinePieceImage(CSSValue*, NinePieceImage&);
212
        void mapNinePieceImage(CSSValue*, NinePieceImage&);
213
213
(-)a/WebCore/css/CSSValueKeywords.in (+5 lines)
Lines 563-568 visual Link Here
563
lines
563
lines
564
564
565
#
565
#
566
# CSS_PROP__WEBKIT_TRANSITION_DELAY
567
#
568
now
569
570
#
566
# CSS_PROP__WEBKIT_TRANSITION_TIMING_FUNCTION
571
# CSS_PROP__WEBKIT_TRANSITION_TIMING_FUNCTION
567
#
572
#
568
ease
573
ease
(-)a/WebCore/css/WebKitCSSTransformValue.cpp (-1 / +1 lines)
Lines 33-39 Link Here
33
namespace WebCore {
33
namespace WebCore {
34
34
35
WebKitCSSTransformValue::WebKitCSSTransformValue(TransformOperationType op)
35
WebKitCSSTransformValue::WebKitCSSTransformValue(TransformOperationType op)
36
    : CSSValueList(false)
36
    : CSSValueList(true)
37
    , m_type(op)
37
    , m_type(op)
38
{
38
{
39
}
39
}
(-)a/WebCore/dom/Document.cpp (+8 lines)
Lines 24-29 Link Here
24
#include "config.h"
24
#include "config.h"
25
#include "Document.h"
25
#include "Document.h"
26
26
27
#include "AnimationController.h"
27
#include "AXObjectCache.h"
28
#include "AXObjectCache.h"
28
#include "CDATASection.h"
29
#include "CDATASection.h"
29
#include "CSSHelper.h"
30
#include "CSSHelper.h"
Lines 297-302 Document::Document(Frame* frame, bool isXHTML) Link Here
297
#if USE(LOW_BANDWIDTH_DISPLAY)
298
#if USE(LOW_BANDWIDTH_DISPLAY)
298
    , m_inLowBandwidthDisplay(false)
299
    , m_inLowBandwidthDisplay(false)
299
#endif
300
#endif
301
    , m_loadComplete(false)
300
{
302
{
301
    m_document.resetSkippingRef(this);
303
    m_document.resetSkippingRef(this);
302
304
Lines 1166-1171 void Document::updateRendering() Link Here
1166
{
1168
{
1167
    if (hasChangedChild())
1169
    if (hasChangedChild())
1168
        recalcStyle(NoChange);
1170
        recalcStyle(NoChange);
1171
    
1172
    // tell the animation controller that the style is available and it can start animations
1173
    if (m_frame)
1174
        m_frame->animation()->styleAvailable();
1169
}
1175
}
1170
1176
1171
void Document::updateDocumentsRendering()
1177
void Document::updateDocumentsRendering()
Lines 1547-1552 void Document::implicitClose() Link Here
1547
    if (f)
1553
    if (f)
1548
        f->loader()->startIconLoader();
1554
        f->loader()->startIconLoader();
1549
1555
1556
    m_loadComplete = true;
1557
1550
    dispatchImageLoadEventsNow();
1558
    dispatchImageLoadEventsNow();
1551
    this->dispatchWindowEvent(loadEvent, false, false);
1559
    this->dispatchWindowEvent(loadEvent, false, false);
1552
    if (f)
1560
    if (f)
(-)a/WebCore/dom/Document.h (+5 lines)
Lines 751-756 public: Link Here
751
    void updateFocusAppearanceSoon();
751
    void updateFocusAppearanceSoon();
752
    void cancelFocusAppearanceUpdate();
752
    void cancelFocusAppearanceUpdate();
753
    
753
    
754
    // for animations to know whether they can run yet or not
755
    bool loadComplete() const { return m_loadComplete; }
756
    
754
    // FF method for accessing the selection added for compatability.
757
    // FF method for accessing the selection added for compatability.
755
    DOMSelection* getSelection() const;
758
    DOMSelection* getSelection() const;
756
    
759
    
Lines 1046-1051 private: Link Here
1046
#if USE(LOW_BANDWIDTH_DISPLAY)
1049
#if USE(LOW_BANDWIDTH_DISPLAY)
1047
    bool m_inLowBandwidthDisplay;
1050
    bool m_inLowBandwidthDisplay;
1048
#endif
1051
#endif
1052
1053
    bool m_loadComplete;    // for animations to know whether or not they can run yet
1049
};
1054
};
1050
1055
1051
inline bool Document::hasElementWithId(AtomicStringImpl* id) const
1056
inline bool Document::hasElementWithId(AtomicStringImpl* id) const
(-)a/WebCore/dom/Element.cpp (-4 / +5 lines)
Lines 784-792 void Element::recalcStyle(StyleChange change) Link Here
784
                newStyle->setChildrenAffectedByDirectAdjacentRules();
784
                newStyle->setChildrenAffectedByDirectAdjacentRules();
785
        }
785
        }
786
786
787
        if (ch != NoChange)
787
        if (ch != NoChange) {
788
            setRenderStyle(newStyle);
788
            setRenderStyle(newStyle);
789
        else if (changed() && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
789
        } else if (changed() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
790
            // Although no change occurred, we use the new style so that the cousin style sharing code won't get
790
            // Although no change occurred, we use the new style so that the cousin style sharing code won't get
791
            // fooled into believing this style is the same.  This is only necessary if the document actually uses
791
            // fooled into believing this style is the same.  This is only necessary if the document actually uses
792
            // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
792
            // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
Lines 795-806 void Element::recalcStyle(StyleChange change) Link Here
795
                renderer()->setStyleInternal(newStyle);
795
                renderer()->setStyleInternal(newStyle);
796
            else
796
            else
797
                setRenderStyle(newStyle);
797
                setRenderStyle(newStyle);
798
        }
798
        } else if (styleChangeType() == AnimationStyleChange)
799
             setRenderStyle(newStyle);
799
800
800
        newStyle->deref(document()->renderArena());
801
        newStyle->deref(document()->renderArena());
801
802
802
        if (change != Force) {
803
        if (change != Force) {
803
            if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() == FullStyleChange)
804
            if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange)
804
                change = Force;
805
                change = Force;
805
            else
806
            else
806
                change = ch;
807
                change = ch;
(-)a/WebCore/dom/EventNames.h (+6 lines)
Lines 119-124 namespace WebCore { namespace EventNames { Link Here
119
    macro(progress) \
119
    macro(progress) \
120
    macro(stalled) \
120
    macro(stalled) \
121
    \
121
    \
122
    macro(webkitAnimationEnd) \
123
    macro(webkitAnimationStart) \
124
    macro(webkitAnimationIteration) \
125
    \
126
    macro(webkitTransitionEnd) \
127
    \
122
// end of DOM_EVENT_NAMES_FOR_EACH
128
// end of DOM_EVENT_NAMES_FOR_EACH
123
129
124
#ifndef DOM_EVENT_NAMES_HIDE_GLOBALS
130
#ifndef DOM_EVENT_NAMES_HIDE_GLOBALS
(-)a/WebCore/dom/Node.cpp (-1 / +1 lines)
Lines 372-378 void Node::setChanged(StyleChangeType changeType) Link Here
372
    if ((changeType != NoStyleChange) && !attached()) // changed compared to what?
372
    if ((changeType != NoStyleChange) && !attached()) // changed compared to what?
373
        return;
373
        return;
374
374
375
    if (!(changeType == InlineStyleChange && m_styleChange == FullStyleChange))
375
    if (!(changeType == InlineStyleChange && (m_styleChange == FullStyleChange || m_styleChange == AnimationStyleChange)))
376
        m_styleChange = changeType;
376
        m_styleChange = changeType;
377
377
378
    if (m_styleChange != NoStyleChange) {
378
    if (m_styleChange != NoStyleChange) {
(-)a/WebCore/dom/Node.h (-1 / +1 lines)
Lines 61-67 struct NodeListsNodeData; Link Here
61
61
62
typedef int ExceptionCode;
62
typedef int ExceptionCode;
63
63
64
enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange };
64
enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange, AnimationStyleChange };
65
65
66
const unsigned short DOCUMENT_POSITION_EQUIVALENT = 0x00;
66
const unsigned short DOCUMENT_POSITION_EQUIVALENT = 0x00;
67
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
67
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
(-)a/WebCore/history/CachedPage.cpp (-1 / +1 lines)
Lines 127-133 void CachedPage::restore(Page* page) Link Here
127
        m_document->accessSVGExtensions()->unpauseAnimations();
127
        m_document->accessSVGExtensions()->unpauseAnimations();
128
#endif
128
#endif
129
129
130
    mainFrame->animation()->resumeAnimations();
130
    mainFrame->animation()->resumeAnimations(m_document.get());
131
131
132
    mainFrame->eventHandler()->setMousePressNode(mousePressNode());
132
    mainFrame->eventHandler()->setMousePressNode(mousePressNode());
133
        
133
        
(-)a/WebCore/page/AnimationController.cpp (-350 / +1536 lines)
Lines 30-36 Link Here
30
#include "AnimationController.h"
30
#include "AnimationController.h"
31
31
32
#include "CSSPropertyNames.h"
32
#include "CSSPropertyNames.h"
33
#include "CString.h"
33
#include "Document.h"
34
#include "Document.h"
35
#include "EventNames.h"
34
#include "FloatConversion.h"
36
#include "FloatConversion.h"
35
#include "Frame.h"
37
#include "Frame.h"
36
#include "RenderObject.h"
38
#include "RenderObject.h"
Lines 43-48 namespace WebCore { Link Here
43
45
44
static const double cAnimationTimerDelay = 0.025;
46
static const double cAnimationTimerDelay = 0.025;
45
47
48
static void setChanged(Node* node)
49
{
50
    ASSERT(!node || (node->document() && !node->document()->inPageCache()));
51
    node->setChanged(AnimationStyleChange);
52
}
53
46
// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
54
// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
47
// animation, the more precision we need in the timing function result to avoid ugly discontinuities.
55
// animation, the more precision we need in the timing function result to avoid ugly discontinuities.
48
static inline double solveEpsilon(double duration) { return 1. / (200. * duration); }
56
static inline double solveEpsilon(double duration) { return 1. / (200. * duration); }
Lines 55-191 static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x Link Here
55
    return bezier.solve(t, solveEpsilon(duration));
63
    return bezier.solve(t, solveEpsilon(duration));
56
}
64
}
57
65
58
class CompositeImplicitAnimation;
66
#pragma mark -
59
67
60
class ImplicitAnimation : public Noncopyable {
68
class CompositeAnimation;
61
public:
69
class AnimationBase;
62
    ImplicitAnimation(const Transition*);
63
    ~ImplicitAnimation();
64
70
65
    void animate(CompositeImplicitAnimation*, RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle, RenderStyle*& animatedStyle);
71
class AnimationTimerBase {
72
public:
73
    AnimationTimerBase(AnimationBase* anim)
74
    : m_timer(this, &AnimationTimerBase::timerFired)
75
    , m_anim(anim)
76
    {
77
        m_timer.startOneShot(0);
78
    }
79
    virtual ~AnimationTimerBase()
80
    {
81
    }
82
    
83
    void startTimer(double timeout=0)
84
    {
85
        m_timer.startOneShot(timeout);
86
    }
87
    
88
    void cancelTimer()
89
    {
90
        m_timer.stop();
91
    }
92
    
93
    virtual void timerFired(Timer<AnimationTimerBase>*) = 0;
94
    
95
private:
96
    Timer<AnimationTimerBase> m_timer;
97
    
98
protected:
99
    AnimationBase* m_anim;
100
};
66
101
67
    void reset(RenderObject*, RenderStyle* from, RenderStyle* to);
102
class AnimationEventDispatcher : public AnimationTimerBase {
103
public:
104
    AnimationEventDispatcher(AnimationBase* anim) 
105
    : AnimationTimerBase(anim)
106
    , m_property(CSSPropertyInvalid)
107
    , m_reset(false)
108
    , m_elapsedTime(-1)
109
    {
110
    }
111
    
112
    virtual ~AnimationEventDispatcher()
113
    {
114
    }
115
    
116
    void startTimer(HTMLElement* element, const AtomicString& name, int property, bool reset, 
117
                    const AtomicString& eventType, double elapsedTime)
118
    {
119
        m_element = element;
120
        m_name = name;
121
        m_property = property;
122
        m_reset = reset;
123
        m_eventType = eventType;
124
        m_elapsedTime = elapsedTime;
125
        AnimationTimerBase::startTimer();
126
    }
127
    
128
    virtual void timerFired(Timer<AnimationTimerBase>*);
68
    
129
    
69
    double progress() const;
130
private:
131
    RefPtr<HTMLElement> m_element;
132
    AtomicString m_name;
133
    int m_property;
134
    bool m_reset;
135
    AtomicString m_eventType;
136
    double m_elapsedTime;
137
};
70
138
71
    int property() const { return m_property; }
139
class AnimationTimerCallback : public AnimationTimerBase {
140
public:
141
    AnimationTimerCallback(AnimationBase* anim) 
142
    : AnimationTimerBase(anim)
143
    , m_elapsedTime(0)
144
    { }
145
    virtual ~AnimationTimerCallback() { }
146
    
147
    virtual void timerFired(Timer<AnimationTimerBase>*);
148
    
149
    void startTimer(double timeout, const AtomicString& eventType, double elapsedTime)
150
    {
151
        m_eventType = eventType;
152
        m_elapsedTime = elapsedTime;
153
        AnimationTimerBase::startTimer(timeout);
154
    }
72
    
155
    
73
    bool finished() const { return m_finished; }
156
private:
74
    void setFinished(bool f) { m_finished = f; }
157
    AtomicString m_eventType;
158
    double m_elapsedTime;
159
};
160
161
#pragma mark -
75
    
162
    
76
    bool stale() const { return m_stale; }
163
class ImplicitAnimation;
77
    void setStale() { m_stale = true; }
164
class AnimationControllerPrivate;
165
166
// A CompositeAnimation represents a collection of animations that
167
// are running, such as a number of properties transitioning at once.
78
168
169
class CompositeAnimation : public Noncopyable {
170
public:
171
    CompositeAnimation(bool suspended, AnimationControllerPrivate* animationController)
172
    : m_suspended(suspended)
173
    , m_animationController(animationController)
174
    , m_numStyleAvailableWaiters(0)
175
    { }
176
    
177
    ~CompositeAnimation()
178
    {
179
        deleteAllValues(m_transitions);
180
    }
181
    
182
    RenderStyle* animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
183
    
184
    void setAnimating(bool inAnimating);
185
    bool animating();
186
    
187
    bool hasAnimationForProperty(int prop) const { return m_transitions.contains(prop); }
188
    
189
    void setTransitionStartTime(int property, double t);
190
    
191
    void resetTransitions(RenderObject*);
192
    void resetAnimations(RenderObject*);
193
    
194
    void cleanupFinishedAnimations(RenderObject*);
195
    
196
    void suspendAnimations();
197
    void resumeAnimations();
198
    bool suspended() const      { return m_suspended; }
199
    
200
    void overrideImplicitAnimations(int property);
201
    void resumeOverriddenImplicitAnimations(int property);
202
    
203
    void styleAvailable();
204
    
205
    bool isAnimatingProperty(int property) const;
206
    
207
    void setWaitingForStyleAvailable(bool waiting);
208
protected:
209
    void updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle);
210
    
79
private:
211
private:
80
    // The two styles that we are blending.
212
    typedef HashMap<int, ImplicitAnimation*> CSSPropertyTransitionsMap;
81
    RenderStyle* m_fromStyle;
213
    
82
    RenderStyle* m_toStyle;
214
    CSSPropertyTransitionsMap   m_transitions;
215
    bool                        m_suspended;
216
    AnimationControllerPrivate* m_animationController;
217
    uint32_t                    m_numStyleAvailableWaiters;
218
};
83
219
84
    int m_property;
220
#pragma mark -
85
    TimingFunction m_function;
86
    double m_duration;
87
221
88
    int m_repeatCount;
222
class AnimationBase : public Noncopyable {
223
public:
224
    AnimationBase(const Transition* transition, RenderObject* renderer, CompositeAnimation* compAnim);    
225
    virtual ~AnimationBase()
226
    {
227
        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
228
            m_compAnim->setWaitingForStyleAvailable(false);
229
    }
230
    
231
    RenderObject* renderer() const { return m_object; }
232
    double startTime() const { return m_startTime; }
233
    double duration() const  { return m_animation->duration(); }
234
    
235
    void cancelTimers()
236
    {
237
        m_animationTimerCallback.cancelTimer();
238
        m_animationEventDispatcher.cancelTimer();
239
    }
240
    
241
    // Animations and Transitions go through the states below. When entering the STARTED state
242
    // the animation is started. This may or may not require deferred response from the animator.
243
    // If so, we stay in this state until that response is received (and it returns the start time).
244
    // Otherwise, we use the current time as the start time and go immediately to the LOOPING or
245
    // ENDING state.
246
    enum AnimState { 
247
        STATE_NEW,                      // animation just created, animation not running yet
248
        STATE_START_WAIT_TIMER,         // start timer running, waiting for fire
249
        STATE_START_WAIT_STYLE_AVAILABLE,   // waiting for style setup so we can start animations
250
        STATE_START_WAIT_RESPONSE,      // animation started, waiting for response
251
        STATE_LOOPING,                  // response received, animation running, loop timer running, waiting for fire
252
        STATE_ENDING,                   // response received, animation running, end timer running, waiting for fire
253
        STATE_PAUSED_WAIT_TIMER,        // animation in pause mode when animation started
254
        STATE_PAUSED_WAIT_RESPONSE,     // animation paused when in STARTING state
255
        STATE_PAUSED_RUN,               // animation paused when in LOOPING or ENDING state
256
        STATE_DONE                      // end timer fired, animation finished and removed
257
    };
258
    
259
    enum AnimStateInput {
260
        STATE_INPUT_MAKE_NEW,           // reset back to new from any state
261
        STATE_INPUT_START_ANIMATION,    // animation requests a start
262
        STATE_INPUT_RESTART_ANIMATION,  // force a restart from any state
263
        STATE_INPUT_START_TIMER_FIRED,  // start timer fired
264
        STATE_INPUT_STYLE_AVAILABLE,        // style is setup, ready to start animating
265
        STATE_INPUT_START_TIME_SET,     // m_startTime was set
266
        STATE_INPUT_LOOP_TIMER_FIRED,   // loop timer fired
267
        STATE_INPUT_END_TIMER_FIRED,    // end timer fired
268
        STATE_INPUT_PAUSE_OVERRIDE,     // pause an animation due to override
269
        STATE_INPUT_RESUME_OVERRIDE,    // resume an overridden animation
270
        STATE_INPUT_PLAY_STATE_RUNNING, // play state paused -> running
271
        STATE_INPUT_PLAY_STATE_PAUSED,  // play state running -> paused
272
        STATE_INPUT_END_ANIMATION       // force an end from any state
273
    };
274
    
275
    // Called when animation is in NEW state to start animation
276
    void updateStateMachine(AnimStateInput input, double param);
277
    
278
    // Animation has actually started, at passed time
279
    // This is a callback and is only received when RenderObject::startAnimation() or RenderObject::startTransition() 
280
    // returns true. If RenderObject::
281
    void onAnimationStartResponse(double startTime);
282
    
283
    // Called to change to or from paused state
284
    void updatePlayState(bool running);
285
    bool playStatePlaying() const { return m_animation; }
286
    
287
    bool waitingToStart() const { return m_animState == STATE_NEW || m_animState == STATE_START_WAIT_TIMER; }
288
    bool preactive() const
289
    { return m_animState == STATE_NEW ||
290
             m_animState == STATE_START_WAIT_TIMER ||
291
             m_animState == STATE_START_WAIT_STYLE_AVAILABLE ||
292
             m_animState == STATE_START_WAIT_RESPONSE;
293
    }
294
    bool postactive() const { return m_animState == STATE_DONE; }
295
    bool active() const { return !postactive() && !preactive(); }
296
    bool running() const { return m_pauseTime < 0; }
297
    bool isnew() const { return m_animState == STATE_NEW; }
298
    bool waitingForStartTime() const { return m_animState == STATE_START_WAIT_RESPONSE; }
299
    bool waitingForStyleAvailable() const { return m_animState == STATE_START_WAIT_STYLE_AVAILABLE; }
300
    bool waitingForEndEvent() const  { return m_waitingForEndEvent; }
301
    
302
    // "animating" means that something is running that requires a timer to keep firing
303
    // (e.g. a software animation)
304
    void setAnimating(bool inAnimating = true) { m_animating = inAnimating; }
305
    bool animating() const { return m_animating; }
306
    
307
    double progress(double scale, double offset) const;
308
    
309
    virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, 
310
                         const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle) { }
311
    virtual void reset(RenderObject* renderer, const RenderStyle* from = 0, const RenderStyle* to = 0) { }
312
    
313
    virtual bool shouldFireEvents() const { return false; }
314
    
315
    void animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime);
316
    void animationEventDispatcherFired(HTMLElement* element, const AtomicString& name, int property, bool reset, 
317
                                       const AtomicString& eventType, double elapsedTime);
318
    
319
    bool animationsMatch(const Transition* anim) const { return m_animation->transitionsMatch(anim); }
320
    
321
    void setAnimation(const Transition* anim) { m_animation = const_cast<Transition*>(anim); }
322
    
323
    // Return true if this animation is overridden. This will only be the case for
324
    // ImplicitAnimations and is used to determine whether or not we should force
325
    // set the start time. If an animation is overridden, it will probably not get
326
    // back the START_TIME event.
327
    virtual bool overridden() const { return false; }
328
    
329
    // Does this animation/transition involve the given property?
330
    virtual bool affectsProperty(int property) const { return false; }
331
    bool isAnimatingProperty(int property) const
332
    {
333
        return (!waitingToStart() && !postactive()) && affectsProperty(property);
334
    }
335
        
336
protected:
337
    HTMLElement* elementForEventDispatch()
338
    {
339
        if (m_object->node() && m_object->node()->isHTMLElement())
340
            return static_cast<HTMLElement*>(m_object->node());
341
        return 0;
342
    }
343
    
344
    virtual void overrideAnimations() { }
345
    virtual void resumeOverriddenAnimations() { }
346
    
347
    CompositeAnimation* compositeAnimation() { return m_compAnim; }
348
    
349
    // These are called when the corresponding timer fires so subclasses can do any extra work
350
    virtual void onAnimationStart(double elapsedTime) { }
351
    virtual void onAnimationIteration(double elapsedTime) { }
352
    virtual void onAnimationEnd(double elapsedTime) { }
353
    virtual bool startAnimation(double beginTime) { return false; }
354
    virtual void endAnimation(bool reset) { }
355
    
356
    void primeEventTimers();
357
    
358
protected:
359
    AnimState m_animState;
89
    int m_iteration;
360
    int m_iteration;
90
    
361
    
91
    bool m_finished;    
362
    bool m_animating;       // transition/animation requires continual timer firing
363
    bool m_waitedForResponse;
92
    double m_startTime;
364
    double m_startTime;
93
    bool m_paused;
94
    double m_pauseTime;
365
    double m_pauseTime;
366
    RenderObject*   m_object;
95
    
367
    
96
    bool m_stale;
368
    AnimationTimerCallback m_animationTimerCallback;
369
    AnimationEventDispatcher m_animationEventDispatcher;
370
    RefPtr<Transition> m_animation;
371
    CompositeAnimation* m_compAnim;
372
    bool m_waitingForEndEvent;
97
};
373
};
98
374
99
class CompositeImplicitAnimation : public Noncopyable {
375
#pragma mark -
100
public:
101
    ~CompositeImplicitAnimation() { deleteAllValues(m_animations); }
102
103
    RenderStyle* animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
104
105
    bool animating() const;
106
376
107
    void reset(RenderObject*);
377
class ImplicitAnimation : public AnimationBase {
378
public:
379
    ImplicitAnimation(const Transition* transition, RenderObject* renderer, CompositeAnimation* compAnim)
380
    : AnimationBase(transition, renderer, compAnim)
381
    , m_property(transition->property())
382
    , m_overridden(false)
383
    , m_fromStyle(0)
384
    , m_toStyle(0)
385
    {
386
    }
387
    
388
    virtual ~ImplicitAnimation()
389
    {
390
        ASSERT(!m_fromStyle && !m_toStyle);
391
        
392
        // If we were waiting for an end event, we need to finish the animation to make sure no old
393
        // animations stick around in the lower levels
394
        if (waitingForEndEvent() && m_object)
395
            ASSERT(0);
396
        
397
        // Do the cleanup here instead of in the base class so the specialized methods get called
398
        if (!postactive())
399
            updateStateMachine(STATE_INPUT_END_ANIMATION, -1);     
400
    }
401
    
402
    int property() const { return m_property; }
403
    
404
    virtual void onAnimationEnd(double inElapsedTime);
405
    virtual bool startAnimation(double beginTime);
406
    virtual void endAnimation(bool reset);
407
    
408
    virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, 
409
                         const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle);
410
    virtual void reset(RenderObject* renderer, const RenderStyle* from = 0, const RenderStyle* to = 0);
411
    
412
    void setOverridden(bool b);
413
    virtual bool overridden() const { return m_overridden; }
414
    
415
    virtual bool shouldFireEvents() const { return true; }
416
    
417
    virtual bool affectsProperty(int property) const;
418
    
419
    bool hasStyle() const { return m_fromStyle && m_toStyle; }
420
    
421
    bool isTargetPropertyEqual(int prop, RenderStyle* targetStyle);
108
422
423
    void blendPropertyValueInStyle(int prop, RenderStyle* currentStyle);
424
    
425
protected:
426
    bool shouldSendEventForListener(Document::ListenerType inListenerType)
427
    {
428
        return m_object->document()->hasListenerType(inListenerType);
429
    }
430
    
431
    bool sendTransitionEvent(const AtomicString& inEventType, double inElapsedTime);
432
    
109
private:
433
private:
110
    HashMap<int, ImplicitAnimation*> m_animations;
434
    int m_property;
435
    bool m_overridden;
436
    
437
    // The two styles that we are blending.
438
    RenderStyle* m_fromStyle;
439
    RenderStyle* m_toStyle;
111
};
440
};
112
441
113
ImplicitAnimation::ImplicitAnimation(const Transition* transition)
442
#pragma mark -
114
: m_fromStyle(0)
443
115
, m_toStyle(0)
444
void AnimationTimerCallback::timerFired(Timer<AnimationTimerBase>*)
116
, m_property(transition->property())
117
, m_function(transition->timingFunction())
118
, m_duration(transition->duration() / 1000.0)
119
, m_repeatCount(transition->repeatCount())
120
, 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
{
445
{
446
    m_anim->animationTimerCallbackFired(m_eventType, m_elapsedTime);
127
}
447
}
128
448
129
ImplicitAnimation::~ImplicitAnimation()
449
void AnimationEventDispatcher::timerFired(Timer<AnimationTimerBase>*)
130
{
450
{
131
    ASSERT(!m_fromStyle && !m_toStyle);
451
    m_anim->animationEventDispatcherFired(m_element.get(), m_name, m_property, m_reset, m_eventType, m_elapsedTime);
132
}
452
}
133
453
134
void ImplicitAnimation::reset(RenderObject* renderer, RenderStyle* from, RenderStyle* to)
454
#pragma mark -
455
456
#pragma mark -
457
    
458
AnimationBase::AnimationBase(const Transition* transition, RenderObject* renderer, CompositeAnimation* compAnim)
459
: m_animState(STATE_NEW)
460
, m_iteration(0)
461
, m_animating(false)
462
, m_waitedForResponse(false)
463
, m_startTime(0)
464
, m_pauseTime(-1)
465
, m_object(renderer)
466
, m_animationTimerCallback(const_cast<AnimationBase*>(this))
467
, m_animationEventDispatcher(const_cast<AnimationBase*>(this))
468
, m_animation(const_cast<Transition*>(transition))
469
, m_compAnim(compAnim)
470
, m_waitingForEndEvent(false)
135
{
471
{
136
    setFinished(false);
472
}
137
473
138
    if (m_fromStyle)
474
void AnimationBase::updateStateMachine(AnimStateInput input, double param)
139
        m_fromStyle->deref(renderer->renderArena());
475
{
140
    if (m_toStyle)
476
    // if we get a RESTART then we force a new animation, regardless of state
141
        m_toStyle->deref(renderer->renderArena());
477
    if (input == STATE_INPUT_MAKE_NEW) {
142
    m_fromStyle = from;
478
        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
143
    if (m_fromStyle)
479
            m_compAnim->setWaitingForStyleAvailable(false);
144
        m_fromStyle->ref();
480
        m_animState = STATE_NEW;
145
    m_toStyle = to;
481
        m_startTime = 0;
146
    if (m_toStyle)
482
        m_pauseTime = -1;
147
        m_toStyle->ref();
483
        m_waitedForResponse = false;
148
    if (from || to)
484
        endAnimation(false);
149
        m_startTime = currentTime();
485
        return;
486
    }
487
    else if (input == STATE_INPUT_RESTART_ANIMATION) {
488
        cancelTimers();
489
        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
490
            m_compAnim->setWaitingForStyleAvailable(false);
491
        m_animState = STATE_NEW;
492
        m_startTime = 0;
493
        m_pauseTime = -1;
494
        endAnimation(false);
150
        
495
        
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,
496
        if (running())
152
    // then we will unmark ourselves for death.
497
            updateStateMachine(STATE_INPUT_START_ANIMATION, -1);
153
    if (stale() && from && to) {
498
        return;
154
         for (const Transition* transition = to->transitions(); transition; transition = transition->next()) {
499
    }
155
            if (m_property != transition->property())
500
    else if (input == STATE_INPUT_END_ANIMATION) {
156
                continue;
501
        cancelTimers();
157
            int duration = transition->duration();
502
        if (m_animState == STATE_START_WAIT_STYLE_AVAILABLE)
158
            int repeatCount = transition->repeatCount();
503
            m_compAnim->setWaitingForStyleAvailable(false);
159
            if (duration && repeatCount) {
504
        m_animState = STATE_DONE;
160
                m_duration = duration / 1000.0;
505
        endAnimation(true);
161
                m_repeatCount = repeatCount;
506
        return;
162
                m_stale = false;
507
    }
163
                break;
508
    else if (input == STATE_INPUT_PAUSE_OVERRIDE) {
164
            }
509
        if (m_animState == STATE_START_WAIT_RESPONSE) {
510
            // If we are in the WAIT_RESPONSE state, the animation will get canceled before 
511
            // we get a response, so move to the next state
512
            endAnimation(false);
513
            updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
514
        }
515
        return;
516
    }
517
    else if (input == STATE_INPUT_RESUME_OVERRIDE) {
518
        if (m_animState == STATE_LOOPING || m_animState == STATE_ENDING) {
519
            // Start the animation
520
            startAnimation(m_startTime);
165
        }
521
        }
522
        return;
523
    }
524
    
525
    // execute state machine
526
    switch(m_animState) {
527
        case STATE_NEW:
528
            ASSERT(input == STATE_INPUT_START_ANIMATION || input == STATE_INPUT_PLAY_STATE_RUNNING || input == STATE_INPUT_PLAY_STATE_PAUSED);
529
            if (input == STATE_INPUT_START_ANIMATION || input == STATE_INPUT_PLAY_STATE_RUNNING) {
530
                // Set the start timer to the initial delay (0 if no delay)
531
                m_waitedForResponse = false;
532
                m_animState = STATE_START_WAIT_TIMER;
533
                m_animationTimerCallback.startTimer(m_animation->delay(), EventNames::webkitAnimationStartEvent, m_animation->delay());
534
            }
535
            break;
536
        case STATE_START_WAIT_TIMER:
537
            ASSERT(input == STATE_INPUT_START_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
538
            
539
            if (input == STATE_INPUT_START_TIMER_FIRED) {
540
                ASSERT(param >= 0);
541
                // Start timer has fired, tell the animation to start and wait for it to respond with start time
542
                m_animState = STATE_START_WAIT_STYLE_AVAILABLE;
543
                m_compAnim->setWaitingForStyleAvailable(true);
544
                
545
                // Trigger a render so we can start the animation
546
                setChanged(m_object->element());
547
                m_object->animation()->startUpdateRenderingDispatcher();
548
            }
549
            else {
550
                ASSERT(running());
551
                // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
552
                m_pauseTime = currentTime();
553
                cancelTimers();
554
                m_animState = STATE_PAUSED_WAIT_TIMER;
555
            }
556
            break;
557
        case STATE_START_WAIT_STYLE_AVAILABLE:
558
            ASSERT(input == STATE_INPUT_STYLE_AVAILABLE || input == STATE_INPUT_PLAY_STATE_PAUSED);
559
            
560
            m_compAnim->setWaitingForStyleAvailable(false);
561
            
562
            if (input == STATE_INPUT_STYLE_AVAILABLE) {
563
                // Start timer has fired, tell the animation to start and wait for it to respond with start time
564
                m_animState = STATE_START_WAIT_RESPONSE;
565
                
566
                overrideAnimations();
567
                
568
                // Send start event, if needed
569
                onAnimationStart(0.0f); // the elapsedTime is always 0 here
570
                
571
                // Start the animation
572
                if (overridden() || !startAnimation(0)) {
573
                    // We're not going to get a startTime callback, so fire the start time here
574
                    m_animState = STATE_START_WAIT_RESPONSE;
575
                    updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
576
                }
577
                else
578
                    m_waitedForResponse = true;
579
            }
580
            else {
581
                ASSERT(running());
582
                // We're waiting for the a notification that the style has been setup. If we're asked to wait
583
                // at this point, the style must have been processed, so we can deal with this like we would
584
                // for WAIT_RESPONSE, except that we don't need to do an endAnimation().
585
                m_pauseTime = 0;
586
                m_animState = STATE_START_WAIT_RESPONSE;
587
            }
588
            break;
589
        case STATE_START_WAIT_RESPONSE:
590
            ASSERT(input == STATE_INPUT_START_TIME_SET || input == STATE_INPUT_PLAY_STATE_PAUSED);
591
            
592
            if (input == STATE_INPUT_START_TIME_SET) {
593
                ASSERT(param >= 0);
594
                // We have a start time, set it, unless the startTime is already set
595
                if (m_startTime <= 0)
596
                    m_startTime = param;
597
                
598
                // Decide when the end or loop event needs to fire
599
                primeEventTimers();
600
                
601
                // Trigger a render so we can start the animation
602
                setChanged(m_object->element());
603
                m_object->animation()->startUpdateRenderingDispatcher();
604
            }
605
            else {
606
                // We are pausing while waiting for a start response. Cancel the animation and wait. When 
607
                // we unpause, we will act as though the start timer just fired
608
                m_pauseTime = 0;
609
                endAnimation(false);
610
                m_animState = STATE_PAUSED_WAIT_RESPONSE;
611
            }
612
            break;
613
        case STATE_LOOPING:
614
            ASSERT(input == STATE_INPUT_LOOP_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
615
            
616
            if (input == STATE_INPUT_LOOP_TIMER_FIRED) {
617
                ASSERT(param >= 0);
618
                // Loop timer fired, loop again or end.
619
                onAnimationIteration(param);
620
                primeEventTimers();
621
            }
622
            else {
623
                // We are pausing while running. Cancel the animation and wait
624
                m_pauseTime = currentTime();
625
                cancelTimers();
626
                endAnimation(false);
627
                m_animState = STATE_PAUSED_RUN;
628
            }
629
            break;
630
        case STATE_ENDING:
631
            ASSERT(input == STATE_INPUT_END_TIMER_FIRED || input == STATE_INPUT_PLAY_STATE_PAUSED);
632
            
633
            if (input == STATE_INPUT_END_TIMER_FIRED) {
634
                ASSERT(param >= 0);
635
                // End timer fired, finish up
636
                onAnimationEnd(param);
637
                
638
                resumeOverriddenAnimations();
639
                
640
                // Fire off another style change so we can set the final value
641
                setChanged(m_object->element());
642
                m_animState = STATE_DONE;
643
                m_object->animation()->startUpdateRenderingDispatcher();
644
                // |this| may be deleted here when we've been called from timerFired()
645
            }
646
            else {
647
                // We are pausing while running. Cancel the animation and wait
648
                m_pauseTime = currentTime();
649
                cancelTimers();
650
                endAnimation(false);
651
                m_animState = STATE_PAUSED_RUN;
652
            }
653
            // |this| may be deleted here
654
            break;
655
        case STATE_PAUSED_WAIT_TIMER:
656
            ASSERT(input == STATE_INPUT_PLAY_STATE_RUNNING);
657
            ASSERT(!running());
658
            // Update the times
659
            m_startTime += currentTime() - m_pauseTime;
660
            m_pauseTime = -1;
661
            
662
            // we were waiting for the start timer to fire, go back and wait again
663
            m_animState = STATE_NEW;
664
            updateStateMachine(STATE_INPUT_START_ANIMATION, 0);
665
            break;
666
        case STATE_PAUSED_WAIT_RESPONSE:
667
        case STATE_PAUSED_RUN:
668
            // We treat these two cases the same. The only difference is that, when we are in the WAIT_RESPONSE
669
            // state, we don't yet have a valid startTime, so we send 0 to startAnimation. When the START_TIME
670
            // event comes in qnd we were in the RUN state, we will notice that we have already set the 
671
            // startTime and will ignore it.
672
            ASSERT(input == STATE_INPUT_PLAY_STATE_RUNNING);
673
            ASSERT(!running());
674
            // Update the times
675
            if (m_animState == STATE_PAUSED_RUN)
676
                m_startTime += currentTime() - m_pauseTime;
677
            else
678
                m_startTime = 0;
679
            m_pauseTime = -1;
680
            
681
            // We were waiting for a begin time response from the animation, go back and wait again
682
            m_animState = STATE_START_WAIT_RESPONSE;
683
            
684
            // Start the animation
685
            if (overridden() || !startAnimation(m_startTime)) {
686
                // We're not going to get a startTime callback, so fire the start time here
687
                updateStateMachine(STATE_INPUT_START_TIME_SET, currentTime());
688
            }
689
            else
690
                m_waitedForResponse = true;
691
            break;
692
        case STATE_DONE:
693
            // We're done. Stay in this state until we are deleted
694
            break;
166
    }
695
    }
696
    // |this| may be deleted here if we came out of STATE_ENDING when we've been called from timerFired()
697
}
698
    
699
void AnimationBase::animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime)
700
{
701
    ASSERT(m_object->document() && !m_object->document()->inPageCache());
167
    
702
    
168
    // If we did not find a new transition, then mark ourselves as being finished so that we can be removed.
703
    // FIXME: use an enum
169
    if (stale())
704
    if (eventType == EventNames::webkitAnimationStartEvent)
170
        setFinished(true);
705
        updateStateMachine(STATE_INPUT_START_TIMER_FIRED, elapsedTime);
706
    else if (eventType == EventNames::webkitAnimationIterationEvent)
707
        updateStateMachine(STATE_INPUT_LOOP_TIMER_FIRED, elapsedTime);
708
    else if (eventType == EventNames::webkitAnimationEndEvent) {
709
        updateStateMachine(STATE_INPUT_END_TIMER_FIRED, elapsedTime);
710
        // |this| may be deleted here
711
    }
171
}
712
}
172
713
173
double ImplicitAnimation::progress() const
714
void AnimationBase::animationEventDispatcherFired(HTMLElement* element, const AtomicString& name, int property, 
715
                                                  bool reset, const AtomicString& eventType, double elapsedTime)
174
{
716
{
175
    double elapsedTime = currentTime() - m_startTime;
717
    m_waitingForEndEvent = false;
176
    
718
    
177
    if (m_finished || !m_duration || elapsedTime >= m_duration)
719
    // Keep an atomic string on the stack to keep it alive until we exit this method
178
        return 1.0;
720
    // (since dispatching the event may cause |this| to be deleted, therefore removing
721
    // the last ref to the atomic string).
722
    AtomicString animName(name);
723
    AtomicString animEventType(eventType);
724
    // Make sure the element sticks around too
725
    RefPtr<HTMLElement> elementRetainer(element);
726
    
727
    ASSERT(!element || (element->document() && !element->document()->inPageCache()));
728
    if (!element)
729
        return;
730
}
731
732
void AnimationBase::updatePlayState(bool run)
733
{
734
    if (running() != run || isnew()) {
735
        updateStateMachine(run ? STATE_INPUT_PLAY_STATE_RUNNING : STATE_INPUT_PLAY_STATE_PAUSED, -1);
736
    }
737
}
179
738
180
    if (m_function.type() == LinearTimingFunction)
739
double AnimationBase::progress(double scale, double offset) const
181
        return elapsedTime / m_duration;
740
{
741
    if (preactive())
742
        return 0;
743
    
744
    double elapsedTime = running() ? (currentTime() - m_startTime) : (m_pauseTime - m_startTime);
745
    if (running() && elapsedTime < 0)
746
        return 0;
747
    
748
    double dur = m_animation->duration();
749
    
750
    if (postactive() || !m_animation->duration() || elapsedTime >= dur)
751
        return 1.0;
752
    
753
    // Compute the fractional time, taking into account direction.
754
    // There is no need to worry about iterations, we assume that we would have 
755
    // short circuited above if we were done
756
    double t = elapsedTime / m_animation->duration();
757
    int i = (int) t;
758
    t -= i;
759
    
760
    if (scale != 1 || offset != 0)
761
        t = (t - offset) * scale;
762
    
763
    if (m_animation->timingFunction().type() == LinearTimingFunction)
764
        return t;
182
    
765
    
183
    // Cubic bezier.
766
    // Cubic bezier.
184
    return solveCubicBezierFunction(m_function.x1(), m_function.y1(), 
767
    double tt = solveCubicBezierFunction(m_animation->timingFunction().x1(), 
185
                                    m_function.x2(), m_function.y2(),
768
                                         m_animation->timingFunction().y1(), 
186
                                    elapsedTime / m_duration, m_duration);
769
                                         m_animation->timingFunction().x2(), 
770
                                         m_animation->timingFunction().y2(),
771
                                         t, m_animation->duration());
772
    return tt;
187
}
773
}
188
774
775
void AnimationBase::primeEventTimers()
776
{
777
    // Decide when the end or loop event needs to fire
778
    double ct = currentTime();
779
    const double elapsedDuration = ct - m_startTime;
780
    ASSERT(elapsedDuration >= 0);
781
    
782
    double totalDuration = m_animation->duration();
783
    double durationLeft = 0;
784
    double nextIterationTime = totalDuration;
785
    if (totalDuration < 0 || elapsedDuration < totalDuration) {
786
        durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
787
        nextIterationTime = elapsedDuration + durationLeft;
788
    }
789
    
790
    // At this point, we may have 0 durationLeft, if we've gotten the event late and we are already
791
    // past totalDuration. In this case we still fire an end timer before processing the end. 
792
    // This defers the call to sendAnimationEvents to avoid re-entrant calls that destroy
793
    // the RenderObject, and therefore |this| before we're done with it.
794
    if (totalDuration < 0 || nextIterationTime < totalDuration) {
795
        // We are not at the end yet, send a loop event
796
        ASSERT(nextIterationTime > 0);
797
        m_animState = STATE_LOOPING;
798
        m_animationTimerCallback.startTimer(durationLeft, EventNames::webkitAnimationIterationEvent, nextIterationTime);
799
    }
800
    else {
801
        // We are at the end, send an end event
802
        m_animState = STATE_ENDING;
803
        m_animationTimerCallback.startTimer(durationLeft, EventNames::webkitAnimationEndEvent, nextIterationTime);
804
    }
805
}
806
807
#pragma mark -
808
189
static inline int blendFunc(int from, int to, double progress)
809
static inline int blendFunc(int from, int to, double progress)
190
{  
810
{  
191
    return int(from + (to - from) * progress);
811
    return int(from + (to - from) * progress);
Lines 223-229 static inline IntSize blendFunc(const IntSize& from, const IntSize& to, double p Link Here
223
static inline ShadowData* blendFunc(const ShadowData* from, const ShadowData* to, double progress)
843
static inline ShadowData* blendFunc(const ShadowData* from, const ShadowData* to, double progress)
224
{  
844
{  
225
    ASSERT(from && to);
845
    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));
846
    return new ShadowData(blendFunc(from->x, to->x, progress), blendFunc(from->y, to->y, progress), 
847
                          blendFunc(from->blur, to->blur, progress), blendFunc(from->color, to->color, progress));
227
}
848
}
228
849
229
static inline TransformOperations blendFunc(const TransformOperations& from, const TransformOperations& to, double progress)
850
static inline TransformOperations blendFunc(const TransformOperations& from, const TransformOperations& to, double progress)
Lines 237-243 static inline TransformOperations blendFunc(const TransformOperations& from, con Link Here
237
        TransformOperation* fromOp = i < fromSize ? from[i].get() : 0;
858
        TransformOperation* fromOp = i < fromSize ? from[i].get() : 0;
238
        TransformOperation* toOp = i < toSize ? to[i].get() : 0;
859
        TransformOperation* toOp = i < toSize ? to[i].get() : 0;
239
        TransformOperation* blendedOp = toOp ? toOp->blend(fromOp, progress) : fromOp->blend(0, progress, true);
860
        TransformOperation* blendedOp = toOp ? toOp->blend(fromOp, progress) : fromOp->blend(0, progress, true);
240
        result.append(blendedOp);
861
        if (blendedOp)
862
            result.append(blendedOp);
241
    }
863
    }
242
    return result;
864
    return result;
243
}
865
}
Lines 254-564 static inline EVisibility blendFunc(EVisibility from, EVisibility to, double pro Link Here
254
    return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
876
    return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
255
}
877
}
256
878
257
#define BLEND(prop, getter, setter) \
879
#pragma mark -
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
880
411
    // Now that we have animation objects ready, let them know about the new goal state.  We want them
881
class PropertyWrapperBase {
412
    // to fill in a RenderStyle*& only if needed.
882
public:
413
    RenderStyle* result = 0;
883
    PropertyWrapperBase(int prop)
414
    HashMap<int, ImplicitAnimation*>::iterator end = m_animations.end();
884
    : m_prop(prop)
415
    Vector<int> obsoleteTransitions;
885
    { }
886
    virtual ~PropertyWrapperBase() { }
887
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const=0;
888
    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const=0;
416
    
889
    
417
    // Look at the "all" animation first.
890
    int property() const { return m_prop; }
418
    ImplicitAnimation* allAnimation = m_animations.get(cAnimateAll);
891
    
419
    if (allAnimation) {
892
private:
420
        allAnimation->animate(this, renderer, currentStyle, targetStyle, result);
893
    int m_prop;
894
};
421
895
422
        // If the animation is done and we are marked as stale, then we can be removed after the
896
template <typename T>
423
        // iteration of the hashmap is finished.
897
class PropertyWrapperGetter : public PropertyWrapperBase {
424
        if (allAnimation->finished() && allAnimation->stale())
898
public:
425
            obsoleteTransitions.append(cAnimateAll);
899
    PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const)
900
    : PropertyWrapperBase(prop)
901
    , m_getter(getter)
902
    { }
903
    
904
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
905
    {
906
        return (a->*m_getter)() == (b->*m_getter)();
426
    }
907
    }
427
    
908
    
428
    // Now look at the specialized animations.
909
protected:
429
    for (HashMap<int, ImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
910
    T (RenderStyle::*m_getter)() const;
430
        // Skip over the "all" animation, since we animated it already.
911
};
431
        if (it->second->property() == cAnimateAll)
432
            continue;
433
        
434
        it->second->animate(this, renderer, currentStyle, targetStyle, result);
435
912
436
        // If the animation is done and we are marked as stale, then we can be removed after the
913
template <typename T>
437
        // iteration of the hashmap is finished.
914
class PropertyWrapper : public PropertyWrapperGetter<T> {
438
        if (it->second->finished() && it->second->stale())
915
public:
439
            obsoleteTransitions.append(it->second->property());
916
    PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
917
    : PropertyWrapperGetter<T>(prop, getter)
918
    , m_setter(setter)
919
    { }
920
    
921
    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
922
    {
923
        (dst->*m_setter)(blendFunc((a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), prog));
924
    }
925
    
926
protected:
927
    void (RenderStyle::*m_setter)(T);
928
};
440
929
930
class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> {
931
public:
932
    PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
933
    : PropertyWrapperGetter<ShadowData*>(prop, getter)
934
    , m_setter(setter)
935
    { }
936
    
937
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
938
    {
939
        ShadowData* shadowa = (a->*m_getter)();
940
        ShadowData* shadowb = (b->*m_getter)();
941
        
942
        if (!shadowa && shadowb || shadowa && !shadowb)
943
            return false;
944
        if (shadowa && shadowb && (*shadowa != *shadowb))
945
            return false;
946
        return true;
441
    }
947
    }
442
    
948
    
443
    // Now cull out any stale animations that are finished.
949
    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
444
    for (unsigned i = 0; i < obsoleteTransitions.size(); ++i) {
950
    {
445
        ImplicitAnimation* animation = m_animations.take(obsoleteTransitions[i]);
951
        ShadowData* shadowa = (a->*m_getter)();
446
        animation->reset(renderer, 0, 0);
952
        ShadowData* shadowb = (b->*m_getter)();
447
        delete animation;
953
        ShadowData defaultShadowData(0, 0, 0, Color::transparent);
954
        
955
        if (!shadowa)
956
            shadowa = &defaultShadowData;
957
        if (!shadowb)
958
            shadowb = &defaultShadowData;
959
        
960
        (dst->*m_setter)(blendFunc(shadowa, shadowb, prog), false);
448
    }
961
    }
962
    
963
private:
964
    void (RenderStyle::*m_setter)(ShadowData*, bool);
965
};
449
966
450
    if (result)
967
class PropertyWrapperIntSize : public PropertyWrapperGetter<IntSize> {
451
        return result;
968
public:
452
969
    PropertyWrapperIntSize(int prop, IntSize (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const IntSize&))
453
    return targetStyle;
970
    : PropertyWrapperGetter<IntSize>(prop, getter)
454
}
971
    , m_setter(setter)
455
972
    { }
456
bool CompositeImplicitAnimation::animating() const
973
    
457
{
974
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
458
    HashMap<int, ImplicitAnimation*>::const_iterator end = m_animations.end();
975
    {
459
    for (HashMap<int, ImplicitAnimation*>::const_iterator it = m_animations.begin(); it != end; ++it)
976
        IntSize sizea = (a->*m_getter)();
460
        if (!it->second->finished())
977
        IntSize sizeb = (b->*m_getter)();
461
            return true;
978
        
462
    return false;
979
        return (sizea == sizeb);
463
}
980
    }
981
    
982
    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
983
    {
984
        IntSize sizea = (a->*m_getter)();
985
        IntSize sizeb = (b->*m_getter)();
986
                
987
        (dst->*m_setter)(blendFunc(sizea, sizeb, prog));
988
    }
989
    
990
private:
991
    void (RenderStyle::*m_setter)(const IntSize&);
992
};
464
993
465
void CompositeImplicitAnimation::reset(RenderObject* renderer)
994
class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
466
{
995
public:
467
    HashMap<int, ImplicitAnimation*>::const_iterator end = m_animations.end();
996
    PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
468
    for (HashMap<int, ImplicitAnimation*>::const_iterator it = m_animations.begin(); it != end; ++it)
997
    : PropertyWrapperBase(prop)
469
        it->second->reset(renderer, 0, 0);
998
    , m_getter(getter)
470
}
999
    , m_setter(setter)
1000
    { }
1001
    
1002
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
1003
    {
1004
        Color fromColor = (a->*m_getter)();
1005
        Color toColor = (b->*m_getter)();
1006
        if (!fromColor.isValid())
1007
            fromColor = a->color();
1008
        if (!toColor.isValid())
1009
            toColor = b->color();
1010
        
1011
        return fromColor == toColor;
1012
    }
1013
    
1014
    virtual void blend(RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog) const
1015
    {
1016
        Color fromColor = (a->*m_getter)();
1017
        Color toColor = (b->*m_getter)();
1018
        if (!fromColor.isValid())
1019
            fromColor = a->color();
1020
        if (!toColor.isValid())
1021
            toColor = b->color();
1022
        (dst->*m_setter)(blendFunc(fromColor, toColor, prog));
1023
    }
1024
    
1025
private:
1026
    const Color& (RenderStyle::*m_getter)() const;
1027
    void (RenderStyle::*m_setter)(const Color&);
1028
};
471
1029
472
class AnimationControllerPrivate {
1030
class AnimationControllerPrivate {
473
public:
1031
public:
474
    AnimationControllerPrivate(Frame*);
1032
    AnimationControllerPrivate(Frame*);
475
    ~AnimationControllerPrivate();
1033
    ~AnimationControllerPrivate();
476
1034
    
477
    CompositeImplicitAnimation* get(RenderObject*, RenderStyle*);
1035
    CompositeAnimation* accessCompositeAnimation(RenderObject*);
478
    bool clear(RenderObject*);
1036
    bool clear(RenderObject*);
479
    
1037
    
480
    void timerFired(Timer<AnimationControllerPrivate>*);
1038
    void animationTimerFired(Timer<AnimationControllerPrivate>*);
481
    void updateTimer();
1039
    void updateAnimationTimer();
482
1040
    
483
    bool hasImplicitAnimations() const { return !m_animations.isEmpty(); }
1041
    void updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*);
484
1042
    void startUpdateRenderingDispatcher();
1043
    
1044
    bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
1045
    
1046
    void suspendAnimations(Document* document);
1047
    void resumeAnimations(Document* document);
1048
    
1049
    void styleAvailable();
1050
    
1051
    bool isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const;
1052
    
1053
    static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b);
1054
    static int getPropertyAtIndex(int i);
1055
    static int getNumProperties() { return g_propertyWrappers->size(); }
1056
    
1057
    // Return true if we need to start software animation timers
1058
    static bool blendProperties(int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog);
1059
    
1060
    void setWaitingForStyleAvailable(bool waiting) { if (waiting) m_numStyleAvailableWaiters++; else m_numStyleAvailableWaiters--; }
1061
    
485
private:
1062
private:
486
    HashMap<RenderObject*, CompositeImplicitAnimation*> m_animations;
1063
    static void ensurePropertyMap();
487
    Timer<AnimationControllerPrivate> m_timer;
1064
    
1065
    typedef HashMap<RenderObject*, CompositeAnimation*> RenderObjectAnimationMap;
1066
    
1067
    RenderObjectAnimationMap m_compositeAnimations;
1068
    Timer<AnimationControllerPrivate> m_animationTimer;
1069
    Timer<AnimationControllerPrivate> m_updateRenderingDispatcher;
488
    Frame* m_frame;
1070
    Frame* m_frame;
1071
    uint32_t m_numStyleAvailableWaiters;
1072
    
1073
    static Vector<PropertyWrapperBase*>* g_propertyWrappers;
1074
    static int g_propertyWrapperMap[numCSSProperties];
489
};
1075
};
490
1076
1077
#pragma mark -
1078
1079
Vector<PropertyWrapperBase*>* AnimationControllerPrivate::g_propertyWrappers = 0;
1080
int AnimationControllerPrivate::g_propertyWrapperMap[];
1081
491
AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
1082
AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
492
    : m_timer(this, &AnimationControllerPrivate::timerFired)
1083
: m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
493
    , m_frame(frame)
1084
, m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired)
1085
, m_frame(frame)
1086
, m_numStyleAvailableWaiters(0)
494
{
1087
{
1088
    ensurePropertyMap();
495
}
1089
}
496
1090
497
AnimationControllerPrivate::~AnimationControllerPrivate()
1091
AnimationControllerPrivate::~AnimationControllerPrivate()
498
{
1092
{
499
    deleteAllValues(m_animations);
1093
    deleteAllValues(m_compositeAnimations);
1094
}
1095
1096
// static
1097
void AnimationControllerPrivate::ensurePropertyMap()
1098
{
1099
    // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
1100
    if (g_propertyWrappers == 0) {
1101
        g_propertyWrappers = new Vector<PropertyWrapperBase*>();
1102
        
1103
        // build the list of property wrappers to do the comparisons and blends
1104
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
1105
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
1106
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
1107
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
1108
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
1109
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
1110
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
1111
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
1112
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
1113
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
1114
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
1115
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
1116
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
1117
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
1118
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
1119
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
1120
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
1121
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
1122
        g_propertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
1123
        g_propertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
1124
        g_propertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
1125
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
1126
        g_propertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
1127
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
1128
        g_propertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
1129
        g_propertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
1130
        g_propertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
1131
        g_propertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
1132
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
1133
        g_propertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
1134
        g_propertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
1135
        g_propertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
1136
        g_propertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
1137
        g_propertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
1138
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
1139
        g_propertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
1140
        g_propertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
1141
        g_propertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
1142
        g_propertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
1143
        g_propertyWrappers->append(new PropertyWrapperIntSize(CSSPropertyWebkitBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
1144
        g_propertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
1145
        g_propertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom));
1146
        
1147
        // FIXME: these might be invalid colors, need to check for that
1148
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor));
1149
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor));
1150
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor));
1151
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor));
1152
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor));
1153
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor));
1154
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor));
1155
        g_propertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor));
1156
        
1157
        // These are for shadows
1158
        g_propertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1159
        g_propertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
1160
        
1161
        // Make sure unused slots have a value
1162
        for (unsigned int i = 0; i < (unsigned int) numCSSProperties; ++i)
1163
            g_propertyWrapperMap[i] = CSSPropertyInvalid;
1164
        
1165
        size_t n = g_propertyWrappers->size();
1166
        for (unsigned int i = 0; i < n; ++i) {
1167
            ASSERT((*g_propertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
1168
            g_propertyWrapperMap[(*g_propertyWrappers)[i]->property() - firstCSSProperty] = i;
1169
        }
1170
    }
1171
}
1172
1173
// static
1174
bool AnimationControllerPrivate::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b)
1175
{
1176
    if (prop == cAnimateAll) {
1177
        size_t n = g_propertyWrappers->size();
1178
        for (unsigned int i = 0; i < n; ++i) {
1179
            if (!(*g_propertyWrappers)[i]->equals(a, b))
1180
                return false;
1181
        }
1182
    }
1183
    else {
1184
        int propIndex = prop - firstCSSProperty;
1185
        
1186
        if (propIndex >= 0 && propIndex < numCSSProperties) {
1187
            int i = g_propertyWrapperMap[propIndex];
1188
            return (i >= 0) ? (*g_propertyWrappers)[i]->equals(a, b) : true;
1189
        }
1190
    }
1191
    return true;
1192
}
1193
1194
// static
1195
int AnimationControllerPrivate::getPropertyAtIndex(int i)
1196
{
1197
    if (i < 0 || i >= (int) g_propertyWrappers->size())
1198
        return CSSPropertyInvalid;
1199
        
1200
    return (*g_propertyWrappers)[i]->property();
1201
}
1202
    
1203
// static - return true if we need to start software animation timers
1204
bool AnimationControllerPrivate::blendProperties(int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double prog)
1205
{
1206
    if (prop == cAnimateAll) {
1207
        bool needsTimer = false;
1208
    
1209
        size_t n = g_propertyWrappers->size();
1210
        for (unsigned int i = 0; i < n; ++i) {
1211
            PropertyWrapperBase* wrapper = (*g_propertyWrappers)[i];
1212
            if (!wrapper->equals(a, b)) {
1213
                wrapper->blend(dst, a, b, prog);
1214
                needsTimer = true;
1215
            }
1216
        }
1217
        return needsTimer;
1218
    }
1219
    
1220
    int propIndex = prop - firstCSSProperty;
1221
    if (propIndex >= 0 && propIndex < numCSSProperties) {
1222
        int i = g_propertyWrapperMap[propIndex];
1223
        if (i >= 0) {
1224
            PropertyWrapperBase* wrapper = (*g_propertyWrappers)[i];
1225
            wrapper->blend(dst, a, b, prog);
1226
            return true;
1227
        }
1228
    }
1229
    
1230
    return false;
500
}
1231
}
501
1232
502
CompositeImplicitAnimation* AnimationControllerPrivate::get(RenderObject* renderer, RenderStyle* targetStyle)
1233
CompositeAnimation* AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
503
{
1234
{
504
    CompositeImplicitAnimation* animation = m_animations.get(renderer);
1235
    CompositeAnimation* animation = m_compositeAnimations.get(renderer);
505
    if (!animation && targetStyle->transitions()) {
1236
    if (!animation) {
506
        animation = new CompositeImplicitAnimation();
1237
        animation = new CompositeAnimation(!renderer->document()->loadComplete(), this);
507
        m_animations.set(renderer, animation);
1238
        m_compositeAnimations.set(renderer, animation);
508
    }
1239
    }
509
    return animation;
1240
    return animation;
510
}
1241
}
511
1242
512
bool AnimationControllerPrivate::clear(RenderObject* renderer)
1243
bool AnimationControllerPrivate::clear(RenderObject* renderer)
513
{
1244
{
514
    CompositeImplicitAnimation* animation = m_animations.take(renderer);
1245
    // Return false if we didn't do anything OR we are suspended (so we don't try to
1246
    // do a setChanged() when suspended
1247
    CompositeAnimation* animation = m_compositeAnimations.take(renderer);
515
    if (!animation)
1248
    if (!animation)
516
        return false;
1249
        return false;
517
    animation->reset(renderer);
1250
    animation->resetTransitions(renderer);
1251
    bool wasSuspended = animation->suspended();
518
    delete animation;
1252
    delete animation;
519
    return true;
1253
    return !wasSuspended;
520
}
1254
}
521
1255
522
void AnimationControllerPrivate::updateTimer()
1256
void AnimationControllerPrivate::styleAvailable()
1257
{
1258
    if (m_numStyleAvailableWaiters == 0)
1259
        return;
1260
    
1261
    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
1262
    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); 
1263
         it != animationsEnd; ++it) {
1264
        it->second->styleAvailable();
1265
    }
1266
}
1267
1268
void AnimationControllerPrivate::updateAnimationTimer()
523
{
1269
{
524
    bool animating = false;
1270
    bool animating = false;
525
    HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator end = m_animations.end();
1271
    
526
    for (HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
1272
    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
527
        if (it->second->animating()) {
1273
    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); 
1274
         it != animationsEnd; ++it) {
1275
        CompositeAnimation* compAnim = it->second;
1276
        if (!compAnim->suspended() && compAnim->animating()) {
528
            animating = true;
1277
            animating = true;
529
            break;
1278
            break;
530
        }
1279
        }
531
    }
1280
    }
532
    
1281
    
533
    if (animating) {
1282
    if (animating) {
534
        if (!m_timer.isActive())
1283
        if (!m_animationTimer.isActive())
535
            m_timer.startRepeating(cAnimationTimerDelay);
1284
            m_animationTimer.startRepeating(cAnimationTimerDelay);
536
    } else if (m_timer.isActive())
1285
    } else if (m_animationTimer.isActive())
537
        m_timer.stop();
1286
        m_animationTimer.stop();
1287
}
1288
1289
void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*)
1290
{
1291
    if (m_frame && m_frame->document()) {
1292
        m_frame->document()->updateRendering();
1293
    }
1294
}
1295
1296
void AnimationControllerPrivate::startUpdateRenderingDispatcher()
1297
{
1298
    if (!m_updateRenderingDispatcher.isActive()) {
1299
        m_updateRenderingDispatcher.startOneShot(0);
1300
    }
538
}
1301
}
539
1302
540
void AnimationControllerPrivate::timerFired(Timer<AnimationControllerPrivate>* timer)
1303
void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>* timer)
541
{
1304
{
542
    // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
1305
    // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
543
    // updateRendering.  It will then call back to us with new information.
1306
    // updateRendering.  It will then call back to us with new information.
544
    bool animating = false;
1307
    bool animating = false;
545
    HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator end = m_animations.end();
1308
    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
546
    for (HashMap<RenderObject*, CompositeImplicitAnimation*>::iterator it = m_animations.begin(); it != end; ++it) {
1309
    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); 
547
        if (it->second->animating()) {
1310
         it != animationsEnd; ++it) {
1311
        RenderObject* renderer = it->first;
1312
        CompositeAnimation* compAnim = it->second;
1313
        if (!compAnim->suspended() && compAnim->animating()) {
548
            animating = true;
1314
            animating = true;
549
            it->first->element()->setChanged();
1315
            compAnim->setAnimating(false);
1316
            setChanged(renderer->element());
550
        }
1317
        }
551
    }
1318
    }
552
    
1319
    
553
    m_frame->document()->updateRendering();
1320
    m_frame->document()->updateRendering();
554
    
1321
    
555
    updateTimer();
1322
    updateAnimationTimer();
556
}
1323
}
557
1324
558
AnimationController::AnimationController(Frame* frame)
1325
bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const
559
:m_data(new AnimationControllerPrivate(frame))
1326
{
1327
    CompositeAnimation* animation = m_compositeAnimations.get(obj);
1328
    if (!animation) return false;
1329
    
1330
    return animation->isAnimatingProperty(property);
1331
}
1332
1333
void AnimationControllerPrivate::suspendAnimations(Document* document)
1334
{
1335
    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
1336
    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); 
1337
         it != animationsEnd; ++it) {
1338
        RenderObject* renderer = it->first;
1339
        CompositeAnimation* compAnim = it->second;
1340
        if (renderer->document() == document)
1341
            compAnim->suspendAnimations();
1342
    }
1343
    
1344
    updateAnimationTimer();
1345
}
1346
1347
void AnimationControllerPrivate::resumeAnimations(Document* document)
1348
{
1349
    RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
1350
    for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); 
1351
         it != animationsEnd; ++it) {
1352
        RenderObject* renderer = it->first;
1353
        CompositeAnimation* compAnim = it->second;
1354
        if (renderer->document() == document)
1355
            compAnim->resumeAnimations();
1356
    }
1357
    
1358
    updateAnimationTimer();
1359
}
1360
1361
#pragma mark -
1362
1363
void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
1364
{
1365
    // If currentStyle is null, we don't do transitions
1366
    if (!currentStyle)
1367
        return;
1368
        
1369
    // Check to see if we need to update the active transitions
1370
    for (const Transition* anim = targetStyle->transitions(); anim; anim = anim->next()) {
1371
        double duration = anim->duration();
1372
        double delay = anim->delay();
1373
1374
        // If this is an empty transition, skip it
1375
        if (duration == 0 && delay <= 0)
1376
            continue;
1377
         
1378
        int prop = anim->property();
1379
        bool all = prop == cAnimateAll;
1380
        
1381
        // Handle both the 'all' and single property cases. For the single prop case, we make only one pass
1382
        // through the loop
1383
        for (int i = 0; ; ++i) {
1384
            if (all) {
1385
                if (i >= AnimationControllerPrivate::getNumProperties())
1386
                    break;
1387
                // get the next prop
1388
                prop = AnimationControllerPrivate::getPropertyAtIndex(i);
1389
            }
1390
1391
            // See if there is a current transition for this prop
1392
            ImplicitAnimation* implAnim = m_transitions.get(prop);
1393
            bool equal = true;
1394
            
1395
            if (implAnim) {
1396
                // There is one, has our target changed?
1397
                if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
1398
                    // It has changed - toss it and start over
1399
                    // Opacity is special since it can pop in and out of RenderLayers. We need to compute
1400
                    // the blended opacity value between the previous from and to styles and put that in the currentStyle, which
1401
                    // will become the new fromStyle. This is changing a const RenderStyle, but we know what we are doing, really :-)
1402
                    if (prop == CSSPropertyOpacity) {
1403
                        // get the blended value of opacity into the currentStyle (which will be the new fromStyle)
1404
                        implAnim->blendPropertyValueInStyle(CSSPropertyOpacity, currentStyle);
1405
                    }
1406
1407
                    implAnim->reset(renderer);
1408
                    delete implAnim;
1409
                    m_transitions.remove(prop);
1410
                    equal = false;
1411
                }
1412
            }
1413
            else
1414
                // See if we need to start a new transition
1415
                equal = AnimationControllerPrivate::propertiesEqual(prop, currentStyle, targetStyle);
1416
            
1417
            if (!equal) {
1418
                // AAdd the new transition
1419
                ImplicitAnimation* animation = new ImplicitAnimation(const_cast<Transition*>(anim), renderer, this);
1420
                m_transitions.set(prop, animation);
1421
            }
1422
            
1423
            // We only need one pass for the single prop case
1424
            if (!all)
1425
                break;
1426
        }
1427
    }
1428
}
1429
1430
RenderStyle* CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
560
{
1431
{
1432
    RenderStyle* resultStyle = 0;
1433
    
1434
    // We don't do any transitions if we don't have a currentStyle (on startup)
1435
    updateTransitions(renderer, currentStyle, targetStyle);
1436
    
1437
    if (currentStyle) {
1438
        // Now that we have transition objects ready, let them know about the new goal state.  We want them
1439
        // to fill in a RenderStyle*& only if needed.
1440
        CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1441
        for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1442
            ImplicitAnimation*  anim = it->second;
1443
            if (anim) {
1444
                anim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
1445
            }
1446
        }
1447
    }
1448
    
1449
    cleanupFinishedAnimations(renderer);
1450
    
1451
    return resultStyle ? resultStyle : targetStyle;
1452
}
1453
1454
// "animating" means that something is running that requires the timer to keep firing
1455
// (e.g. a transition)
1456
void CompositeAnimation::setAnimating(bool inAnimating)
1457
{
1458
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1459
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1460
        ImplicitAnimation*  transition = it->second;
1461
        transition->setAnimating(inAnimating);
1462
    }
1463
}
1464
1465
bool CompositeAnimation::animating()
1466
{
1467
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1468
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1469
        ImplicitAnimation*  transition = it->second;
1470
        if (transition && transition->animating() && transition->running())
1471
            return true;
1472
    }
1473
    return false;
1474
}
1475
1476
void CompositeAnimation::resetTransitions(RenderObject* renderer)
1477
{
1478
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1479
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1480
        ImplicitAnimation*  transition = it->second;
1481
        transition->reset(renderer);
1482
        delete transition;
1483
    }
1484
    m_transitions.clear();
1485
}
1486
1487
void CompositeAnimation::cleanupFinishedAnimations(RenderObject* renderer)
1488
{
1489
    if (suspended())
1490
        return;
1491
    
1492
    // Make a list of transitions to be deleted
1493
    Vector<int> finishedTransitions;
1494
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
561
1495
1496
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1497
        ImplicitAnimation* anim = it->second;
1498
        if (!anim)
1499
            continue;
1500
        if (anim->postactive() && !anim->waitingForEndEvent())
1501
            finishedTransitions.append(anim->property());
1502
    }
1503
    
1504
    // Delete them
1505
    for (Vector<int>::iterator it = finishedTransitions.begin(); it != finishedTransitions.end(); ++it) {
1506
        ImplicitAnimation* anim = m_transitions.get(*it);
1507
        if (anim) {
1508
            anim->reset(renderer);
1509
            delete anim;
1510
        }
1511
        m_transitions.remove(*it);
1512
    }
1513
}
1514
1515
void CompositeAnimation::setTransitionStartTime(int property, double t)
1516
{
1517
    // Set the start time for given property transition
1518
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1519
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1520
        ImplicitAnimation* anim = it->second;
1521
        if (anim && anim->waitingForStartTime() && 
1522
                    (anim->property() == property || anim->property() == cAnimateAll))
1523
            anim->updateStateMachine(AnimationBase::STATE_INPUT_START_TIME_SET, t);
1524
    }
1525
}
1526
1527
void CompositeAnimation::suspendAnimations()
1528
{
1529
    if (m_suspended)
1530
        return;
1531
    
1532
    m_suspended = true;
1533
1534
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1535
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1536
        ImplicitAnimation* anim = it->second;
1537
        if (anim && anim->hasStyle()) {
1538
            anim->updatePlayState(false);
1539
        }
1540
    }
1541
}
1542
1543
void CompositeAnimation::resumeAnimations()
1544
{
1545
    if (!m_suspended)
1546
        return;
1547
    
1548
    m_suspended = false;
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->hasStyle()) {
1554
            anim->updatePlayState(true);
1555
        }
1556
    }
1557
}
1558
1559
void CompositeAnimation::overrideImplicitAnimations(int property)
1560
{
1561
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1562
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1563
        ImplicitAnimation* anim = it->second;
1564
        if (anim && (anim->property() == property || anim->property() == cAnimateAll))
1565
            anim->setOverridden(true);
1566
    }
1567
}
1568
1569
void CompositeAnimation::resumeOverriddenImplicitAnimations(int property)
1570
{
1571
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1572
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1573
        ImplicitAnimation* anim = it->second;
1574
        if (anim && (anim->property() == property || anim->property() == cAnimateAll))
1575
            anim->setOverridden(false);
1576
    }
1577
}
1578
1579
void CompositeAnimation::styleAvailable()
1580
{
1581
    if (m_numStyleAvailableWaiters == 0)
1582
        return;
1583
    
1584
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1585
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1586
        ImplicitAnimation* anim = it->second;
1587
        if (anim && anim->waitingForStyleAvailable())
1588
            anim->updateStateMachine(AnimationBase::STATE_INPUT_STYLE_AVAILABLE, -1);
1589
    }
1590
}
1591
1592
bool CompositeAnimation::isAnimatingProperty(int property) const
1593
{
1594
    CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
1595
    for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
1596
        ImplicitAnimation* anim = it->second;
1597
        if (anim && anim->isAnimatingProperty(property))
1598
            return true;
1599
    }
1600
    return false;
1601
}
1602
1603
#pragma mark -
1604
1605
void ImplicitAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle, 
1606
                                const RenderStyle* targetStyle, RenderStyle*& ioAnimatedStyle)
1607
{
1608
    if (!running() || !m_object->document()->loadComplete())
1609
        return;
1610
    
1611
    // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
1612
    // If so, send back the targetStyle (it will get tossed later)
1613
    if (postactive()) {
1614
        if (!ioAnimatedStyle)
1615
            ioAnimatedStyle = const_cast<RenderStyle*>(targetStyle);
1616
        return;
1617
    }
1618
1619
    // Reset to start the transition if we are new
1620
    if (isnew())
1621
        reset(renderer, currentStyle, targetStyle);
1622
    
1623
    // Run a cycle of animation.
1624
    // We know we will need a new render style, so make one if needed
1625
    if (!ioAnimatedStyle)
1626
        ioAnimatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle);
1627
    
1628
    double prog = progress(1, 0);
1629
    bool needsAnim = AnimationControllerPrivate::blendProperties(m_property, ioAnimatedStyle, m_fromStyle, m_toStyle, prog);
1630
    if (needsAnim)
1631
        setAnimating();
1632
}
1633
1634
bool ImplicitAnimation::startAnimation(double beginTime)
1635
{
1636
    return false;
1637
}
1638
1639
void ImplicitAnimation::endAnimation(bool reset)
1640
{
1641
}
1642
1643
void ImplicitAnimation::onAnimationEnd(double inElapsedTime)
1644
{
1645
    // we're converting the animation into a transition here
1646
    if (!sendTransitionEvent(EventNames::webkitTransitionEndEvent, inElapsedTime)) {
1647
        // we didn't dispatch an event, which would call endAnimation(), so we'll just end
1648
        // it here.
1649
        endAnimation(true);
1650
    }
1651
}
1652
1653
bool ImplicitAnimation::sendTransitionEvent(const AtomicString& inEventType, double inElapsedTime)
1654
{
1655
    return false; // didn't dispatch an event
1656
}
1657
1658
void ImplicitAnimation::reset(RenderObject* renderer, const RenderStyle* from /* = 0 */, const RenderStyle* to /* = 0 */)
1659
{
1660
    ASSERT((!m_toStyle && !to) || m_toStyle != to);
1661
    ASSERT((!m_fromStyle && !from) || m_fromStyle != from);
1662
    if (m_fromStyle)
1663
        m_fromStyle->deref(renderer->renderArena());
1664
    if (m_toStyle)
1665
        m_toStyle->deref(renderer->renderArena());
1666
    
1667
    m_fromStyle = const_cast<RenderStyle*>(from);   // it is read-only, other than the ref
1668
    if (m_fromStyle)
1669
        m_fromStyle->ref();
1670
    
1671
    m_toStyle = const_cast<RenderStyle*>(to);       // it is read-only, other than the ref
1672
    if (m_toStyle)
1673
        m_toStyle->ref();
1674
    
1675
    // restart the transition
1676
    if (from && to)
1677
        updateStateMachine(STATE_INPUT_RESTART_ANIMATION, -1);
1678
}
1679
1680
void ImplicitAnimation::setOverridden(bool b)
1681
{
1682
    if (b != m_overridden) {
1683
        m_overridden = b;
1684
        updateStateMachine(m_overridden ? STATE_INPUT_PAUSE_OVERRIDE : STATE_INPUT_RESUME_OVERRIDE, -1);
1685
    }
1686
}
1687
1688
bool ImplicitAnimation::affectsProperty(int property) const
1689
{
1690
    return m_property == property ||
1691
    (m_property == cAnimateAll && !AnimationControllerPrivate::propertiesEqual(property, m_fromStyle, m_toStyle));
1692
}
1693
1694
bool ImplicitAnimation::isTargetPropertyEqual(int prop, RenderStyle* targetStyle)
1695
{
1696
    return AnimationControllerPrivate::propertiesEqual(prop, m_toStyle, targetStyle);
1697
}
1698
1699
void ImplicitAnimation::blendPropertyValueInStyle(int prop, RenderStyle* currentStyle)
1700
{
1701
    double prog = progress(1, 0);
1702
    AnimationControllerPrivate::blendProperties(prop, currentStyle, m_fromStyle, m_toStyle, prog);
1703
}    
1704
1705
#pragma mark -
1706
1707
AnimationController::AnimationController(Frame* frame)
1708
: m_data(new AnimationControllerPrivate(frame))
1709
{
1710
    
562
}
1711
}
563
1712
564
AnimationController::~AnimationController()
1713
AnimationController::~AnimationController()
Lines 566-615 AnimationController::~AnimationController() Link Here
566
    delete m_data;
1715
    delete m_data;
567
}
1716
}
568
1717
569
void AnimationController::cancelImplicitAnimations(RenderObject* renderer)
1718
void AnimationController::cancelAnimations(RenderObject* renderer)
570
{
1719
{
571
    if (!m_data->hasImplicitAnimations())
1720
    if (!m_data->hasAnimations())
572
        return;
1721
        return;
573
1722
    
574
    if (m_data->clear(renderer))
1723
    if (m_data->clear(renderer))
575
        renderer->element()->setChanged();
1724
        setChanged(renderer->element());
576
}
1725
}
577
1726
578
RenderStyle* AnimationController::updateImplicitAnimations(RenderObject* renderer, RenderStyle* newStyle)
1727
RenderStyle* AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
579
{
1728
{    
1729
    // don't do anything if we're in the cache
1730
    if (!renderer->document() || renderer->document()->inPageCache())
1731
        return newStyle;
1732
    
1733
    RenderStyle* oldStyle = renderer->style();
1734
    
1735
    if ((!oldStyle || !oldStyle->transitions()) && !newStyle->transitions())
1736
        return newStyle;
1737
    
1738
    RenderStyle* blendedStyle = newStyle;
1739
    
580
    // Fetch our current set of implicit animations from a hashtable.  We then compare them
1740
    // Fetch our current set of implicit animations from a hashtable.  We then compare them
581
    // against the animations in the style and make sure we're in sync.  If destination values
1741
    // against the animations in the style and make sure we're in sync.  If destination values
582
    // have changed, we reset the animation.  We then do a blend to get new values and we return
1742
    // have changed, we reset the animation.  We then do a blend to get new values and we return
583
    // a new style.
1743
    // a new style.
584
    ASSERT(renderer->element()); // FIXME: We do not animate generated content yet.
1744
    ASSERT(renderer->element()); // FIXME: We do not animate generated content yet.
585
1745
    
586
    CompositeImplicitAnimation* animation = m_data->get(renderer, newStyle);
1746
    CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer);
587
    if (!animation && !newStyle->transitions())
1747
    blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
588
        return newStyle;
1748
    
589
1749
    m_data->updateAnimationTimer();
590
    RenderStyle* blendedStyle = animation->animate(renderer, renderer->style(), newStyle);
1750
    
591
    m_data->updateTimer();
592
593
    if (blendedStyle != newStyle) {
1751
    if (blendedStyle != newStyle) {
594
        // Do some of the work that CSSStyleSelector::adjustRenderStyle() does, to impose rules
1752
        // If the animations/transitions change opacity or transform, we neeed to update
595
        // like opacity creating stacking context.
1753
        // the style to impose the stacking rules. Note that this is also
1754
        // done in CSSStyleSelector::adjustRenderStyle().
596
        if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
1755
        if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
597
            blendedStyle->setZIndex(0);
1756
            blendedStyle->setZIndex(0);
598
    }
1757
    }
599
600
    return blendedStyle;
1758
    return blendedStyle;
601
}
1759
}
602
1760
603
void AnimationController::suspendAnimations()
1761
bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const
1762
{
1763
    return m_data->isAnimatingPropertyOnRenderer(obj, property);
1764
}
1765
1766
void AnimationController::suspendAnimations(Document* document)
604
{
1767
{
605
    // FIXME: Walk the whole hashtable and call pause on each animation.
1768
#ifdef DEBUG_STATE_MACHINE
606
    // Kill our timer.
1769
    fprintf(stderr, "AnimationController %p suspendAnimations for document %p\n", this, document);
1770
#endif
1771
    m_data->suspendAnimations(document);
607
}
1772
}
608
1773
609
void AnimationController::resumeAnimations()
1774
void AnimationController::resumeAnimations(Document* document)
610
{
1775
{
611
    // FIXME: Walk the whole hashtable and call resume on each animation.
1776
#ifdef DEBUG_STATE_MACHINE
612
    // Start our timer.
1777
    fprintf(stderr, "AnimationController %p resumeAnimations for document %p\n", this, document);
1778
#endif
1779
    m_data->resumeAnimations(document);
613
}
1780
}
614
1781
1782
void AnimationController::startUpdateRenderingDispatcher()
1783
{
1784
    m_data->startUpdateRenderingDispatcher();
1785
}
1786
1787
void AnimationController::styleAvailable()
1788
{
1789
    m_data->styleAvailable();
1790
}
1791
1792
void CompositeAnimation::setWaitingForStyleAvailable(bool waiting)
1793
{
1794
    if (waiting)
1795
        m_numStyleAvailableWaiters++;
1796
    else
1797
        m_numStyleAvailableWaiters--;
1798
    m_animationController->setWaitingForStyleAvailable(waiting);
1799
}
1800
    
615
}
1801
}
(-)a/WebCore/page/AnimationController.h (-4 / +15 lines)
Lines 29-37 Link Here
29
#ifndef AnimationController_h
29
#ifndef AnimationController_h
30
#define AnimationController_h
30
#define AnimationController_h
31
31
32
#include "CSSPropertyNames.h"
33
32
namespace WebCore {
34
namespace WebCore {
33
35
34
class AnimationControllerPrivate;
36
class AnimationControllerPrivate;
37
class Document;
35
class Frame;
38
class Frame;
36
class RenderObject;
39
class RenderObject;
37
class RenderStyle;
40
class RenderStyle;
Lines 42-55 public: Link Here
42
    AnimationController(Frame*);
45
    AnimationController(Frame*);
43
    ~AnimationController();
46
    ~AnimationController();
44
    
47
    
45
    void cancelImplicitAnimations(RenderObject*);
48
    void cancelAnimations(RenderObject*);
46
    RenderStyle* updateImplicitAnimations(RenderObject*, RenderStyle* newStyle);
49
    RenderStyle* updateAnimations(RenderObject*, RenderStyle* newStyle);
50
    
51
    bool isAnimatingPropertyOnRenderer(RenderObject* obj, int property) const;
52
    
53
    void suspendAnimations(Document* document);
54
    void resumeAnimations(Document* document);
55
    void updateAnimationTimer();
47
    
56
    
48
    void suspendAnimations();
57
    void startUpdateRenderingDispatcher();
49
    void resumeAnimations();
58
    
59
    void styleAvailable();
50
    
60
    
51
private:
61
private:
52
    AnimationControllerPrivate* m_data;
62
    AnimationControllerPrivate* m_data;
63
    
53
};
64
};
54
65
55
}
66
}
(-)a/WebCore/page/Frame.cpp (-1 / +1 lines)
Lines 1480-1486 void Frame::clearTimers(FrameView *view, Document *document) Link Here
1480
        if (view->frame()) {
1480
        if (view->frame()) {
1481
            if (document && document->renderer() && document->renderer()->hasLayer())
1481
            if (document && document->renderer() && document->renderer()->hasLayer())
1482
                document->renderer()->layer()->suspendMarquees();
1482
                document->renderer()->layer()->suspendMarquees();
1483
            view->frame()->animation()->suspendAnimations();
1483
            view->frame()->animation()->suspendAnimations(document);
1484
        }
1484
        }
1485
    }
1485
    }
1486
}
1486
}
(-)a/WebCore/rendering/RenderObject.cpp (-2 / +2 lines)
Lines 2156-2162 void RenderObject::handleDynamicFloatPositionChange() Link Here
2156
void RenderObject::setAnimatableStyle(RenderStyle* style)
2156
void RenderObject::setAnimatableStyle(RenderStyle* style)
2157
{
2157
{
2158
    if (!isText() && m_style && style)
2158
    if (!isText() && m_style && style)
2159
        style = animation()->updateImplicitAnimations(this, style);
2159
        style = animation()->updateAnimations(this, style);
2160
2160
2161
    setStyle(style);
2161
    setStyle(style);
2162
}
2162
}
Lines 2535-2541 void RenderObject::destroy() Link Here
2535
    if (AXObjectCache::accessibilityEnabled())
2535
    if (AXObjectCache::accessibilityEnabled())
2536
        document()->axObjectCache()->remove(this);
2536
        document()->axObjectCache()->remove(this);
2537
2537
2538
    animation()->cancelImplicitAnimations(this);
2538
    animation()->cancelAnimations(this);
2539
2539
2540
    // By default no ref-counting. RenderWidget::destroy() doesn't call
2540
    // By default no ref-counting. RenderWidget::destroy() doesn't call
2541
    // this function because it needs to do ref-counting. If anything
2541
    // this function because it needs to do ref-counting. If anything
(-)a/WebCore/rendering/RenderWidget.cpp (-1 / +1 lines)
Lines 72-78 void RenderWidget::destroy() Link Here
72
    // So the code below includes copied and pasted contents of
72
    // So the code below includes copied and pasted contents of
73
    // both RenderBox::destroy() and RenderObject::destroy().
73
    // both RenderBox::destroy() and RenderObject::destroy().
74
    // Fix originally made for <rdar://problem/4228818>.
74
    // Fix originally made for <rdar://problem/4228818>.
75
    animation()->cancelImplicitAnimations(this);
75
    animation()->cancelAnimations(this);
76
76
77
    if (RenderView* v = view())
77
    if (RenderView* v = view())
78
        v->removeWidget(this);
78
        v->removeWidget(this);
(-)a/WebCore/rendering/style/RenderStyle.cpp (-74 / +76 lines)
Lines 665-774 TransformOperation* MatrixTransformOperation::blend(const TransformOperation* fr Link Here
665
}
665
}
666
666
667
Transition::Transition()
667
Transition::Transition()
668
    : m_duration(RenderStyle::initialTransitionDuration())
668
    : m_duration(RenderStyle::initialDuration())
669
    , m_repeatCount(RenderStyle::initialTransitionRepeatCount())
669
    , m_timingFunction(RenderStyle::initialTimingFunction())
670
    , m_timingFunction(RenderStyle::initialTransitionTimingFunction())
670
    , m_delay(RenderStyle::initialDelay())
671
    , m_property(RenderStyle::initialTransitionProperty())
671
    , m_property(RenderStyle::initialProperty())
672
    , m_durationSet(false)
672
    , m_durationSet(false)
673
    , m_repeatCountSet(false)
674
    , m_timingFunctionSet(false)
673
    , m_timingFunctionSet(false)
674
    , m_delaySet(false)
675
    , m_propertySet(false)
675
    , m_propertySet(false)
676
    , m_next(0)
676
    , m_next(0)
677
{
677
{
678
}
678
}
679
679
680
Transition::Transition(const Transition& o)
680
Transition::Transition(const Transition& o)
681
    : m_duration(o.m_duration)
681
    : RefCounted<Transition>()
682
    , m_repeatCount(o.m_repeatCount)
682
    , m_duration(o.m_duration)
683
    , m_timingFunction(o.m_timingFunction)
683
    , m_timingFunction(o.m_timingFunction)
684
    , m_delay(o.m_delay)
684
    , m_property(o.m_property)
685
    , m_property(o.m_property)
685
    , m_durationSet(o.m_durationSet)
686
    , m_durationSet(o.m_durationSet)
686
    , m_repeatCountSet(o.m_repeatCountSet)
687
    , m_timingFunctionSet(o.m_timingFunctionSet)
687
    , m_timingFunctionSet(o.m_timingFunctionSet)
688
    , m_delaySet(o.m_delaySet)
688
    , m_propertySet(o.m_propertySet)
689
    , m_propertySet(o.m_propertySet)
689
    , m_next(o.m_next ? new Transition(*o.m_next) : 0)
690
    , m_next(o.m_next ? new Transition(*(o.m_next.get())) : 0)
690
{
691
{
691
}
692
}
692
693
693
Transition::~Transition()
694
{
695
    delete m_next;
696
}
697
698
Transition& Transition::operator=(const Transition& o)
694
Transition& Transition::operator=(const Transition& o)
699
{
695
{
700
    if (m_next != o.m_next) {
696
    if (m_next != o.m_next) {
701
        delete m_next;
697
        m_next = o.m_next ? new Transition(*(o.m_next.get())) : 0;
702
        m_next = o.m_next ? new Transition(*o.m_next) : 0;
703
    }
698
    }
704
699
700
    m_delay = o.m_delay;
705
    m_duration = o.m_duration;
701
    m_duration = o.m_duration;
706
    m_repeatCount = o.m_repeatCount;
707
    m_timingFunction = o.m_timingFunction;
702
    m_timingFunction = o.m_timingFunction;
708
    m_property = o.m_property;
703
    m_property = o.m_property;
709
704
705
    m_delaySet = o.m_delaySet;
710
    m_durationSet = o.m_durationSet;
706
    m_durationSet = o.m_durationSet;
711
    m_repeatCountSet = o.m_repeatCountSet;
712
    m_timingFunctionSet = o.m_timingFunctionSet;
707
    m_timingFunctionSet = o.m_timingFunctionSet;
713
    m_propertySet = o.m_propertySet;
708
    m_propertySet = o.m_propertySet;
714
709
715
    return *this;
710
    return *this;
716
}
711
}
717
712
718
bool Transition::operator==(const Transition& o) const
713
bool Transition::transitionsMatch(const Transition* o) const
719
{
714
{
720
    return m_duration == o.m_duration && m_repeatCount == o.m_repeatCount && m_timingFunction == o.m_timingFunction &&
715
    if (!o)
721
           m_property == o.m_property && m_durationSet == o.m_durationSet && m_repeatCountSet == o.m_repeatCountSet &&
716
        return false;
722
           m_timingFunctionSet == o.m_timingFunctionSet && m_propertySet == o.m_propertySet &&
717
    
723
           ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
718
    bool result = m_duration == o->m_duration &&
719
                  m_timingFunction == o->m_timingFunction &&
720
                  m_delay == o->m_delay &&
721
                  m_property == o->m_property && 
722
                  m_durationSet == o->m_durationSet && 
723
                  m_timingFunctionSet == o->m_timingFunctionSet && 
724
                  m_delaySet == o->m_delaySet &&
725
                  m_propertySet == o->m_propertySet;
726
    
727
    return result;
728
}
729
730
#define FILL_UNSET_PROPERTY(test, prop) \
731
for (curr = this; curr && curr->test(); curr = curr->next()) { } \
732
if (curr && curr != this) { \
733
/* We need to fill in the remaining values with the pattern specified. */ \
734
for (Transition* pattern = this; curr; curr = curr->next()) { \
735
curr->prop = pattern->prop; \
736
pattern = pattern->next(); \
737
if (pattern == curr || !pattern) \
738
pattern = this; \
739
} \
724
}
740
}
725
741
726
void Transition::fillUnsetProperties()
742
void Transition::fillUnsetProperties()
727
{
743
{
728
    Transition* curr;
744
    Transition* curr;
729
    for (curr = this; curr && curr->isDurationSet(); curr = curr->next()) { }
745
    FILL_UNSET_PROPERTY(isDurationSet, m_duration);
730
    if (curr && curr != this) {
746
    FILL_UNSET_PROPERTY(isTimingFunctionSet, m_timingFunction);
731
        // We need to fill in the remaining values with the pattern specified.
747
    FILL_UNSET_PROPERTY(isDelaySet, m_delay);
732
        for (Transition* pattern = this; curr; curr = curr->next()) {
748
    FILL_UNSET_PROPERTY(isPropertySet, m_property);
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
    }
772
}
749
}
773
750
774
StyleRareNonInheritedData::StyleRareNonInheritedData()
751
StyleRareNonInheritedData::StyleRareNonInheritedData()
Lines 825-831 StyleRareNonInheritedData::~StyleRareNonInheritedData() Link Here
825
    delete m_content;
802
    delete m_content;
826
    delete m_counterDirectives;
803
    delete m_counterDirectives;
827
    delete m_boxShadow;
804
    delete m_boxShadow;
828
    delete m_transition;
829
#if ENABLE(XBL)
805
#if ENABLE(XBL)
830
    delete bindingURI;
806
    delete bindingURI;
831
#endif
807
#endif
Lines 1871-1902 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions() Link Here
1871
void RenderStyle::adjustTransitions()
1847
void RenderStyle::adjustTransitions()
1872
{
1848
{
1873
    if (transitions()) {
1849
    if (transitions()) {
1874
        if (transitions()->isEmpty()) {
1850
        if (transitions()->isEmptyOrZeroDuration()) {
1875
            clearTransitions();
1851
            clearTransitions();
1876
            return;
1852
            return;
1877
        }
1853
        }
1878
1854
1879
        Transition* next;
1855
        Transition* next;
1880
        for (Transition* p = accessTransitions(); p; p = next) {
1856
        for (Transition* p = accessTransitions(); p; p = next) {
1881
            next = p->m_next;
1857
            next = p->next();
1882
            if (next && next->isEmpty()) {
1858
            if (next && next->isEmpty()) {
1883
                delete next;
1859
                p->setNext(0); // removes the ref, so next gets deleted
1884
                p->m_next = 0;
1860
                next = 0;
1885
                break;
1861
                break;
1886
            }
1862
            }
1887
        }
1863
        }
1888
    
1864
1865
        if (!transitions())
1866
            return;
1867
1889
        // Repeat patterns into layers that don't have some properties set.
1868
        // Repeat patterns into layers that don't have some properties set.
1890
        accessTransitions()->fillUnsetProperties();
1869
        accessTransitions()->fillUnsetProperties();
1870
        
1871
        // make sure there are no duplicate properties. This is an O(n^2) algorithm
1872
        // but the lists tend to be very short, so it is probably ok
1873
        Transition* previ = 0;
1874
        for (Transition* pi = accessTransitions(); pi; ) {
1875
            Transition* nexti = pi->next();
1876
            for (Transition* pj = nexti; pj; ) {
1877
                if (pi->property() == pj->property()) {
1878
                    // toss pi
1879
                    pi = pi->next();
1880
                    if (previ)
1881
                        previ->setNext(pi);
1882
                    else
1883
                        rareNonInheritedData.access()->m_transition = pi;
1884
                    nexti = pi->next();
1885
                    pj = nexti;
1886
                }
1887
                else
1888
                    pj = pj->next();
1889
            }
1890
            previ = pi;
1891
            pi = nexti;
1892
        }
1891
    }
1893
    }
1892
}
1894
}
1893
1895
1894
Transition* RenderStyle::accessTransitions()
1896
Transition* RenderStyle::accessTransitions()
1895
{
1897
{
1896
    Transition* layer = rareNonInheritedData.access()->m_transition;
1898
    Transition* layer = rareNonInheritedData.access()->m_transition.get();
1897
    if (!layer)
1899
    if (!layer)
1898
        rareNonInheritedData.access()->m_transition = new Transition();
1900
        rareNonInheritedData.access()->m_transition = new Transition();
1899
    return rareNonInheritedData->m_transition;
1901
    return rareNonInheritedData->m_transition.get();
1900
}
1902
}
1901
1903
1902
}
1904
}
(-)a/WebCore/rendering/style/RenderStyle.h (-37 / +48 lines)
Lines 1257-1314 private: Link Here
1257
    double m_y2;
1257
    double m_y2;
1258
};
1258
};
1259
1259
1260
struct Transition {
1260
class Transition : public RefCounted<Transition> {
1261
public:
1261
public:
1262
    Transition();
1262
    Transition();
1263
    ~Transition();
1264
1263
1265
    Transition* next() const { return m_next; }
1264
    const Transition* next() const { return m_next.get(); }
1266
    Transition* next() { return m_next; }
1265
    Transition* next() { return m_next.get(); }
1267
1266
1267
    bool isDelaySet() const { return m_delaySet; }
1268
    bool isDurationSet() const { return m_durationSet; }
1268
    bool isDurationSet() const { return m_durationSet; }
1269
    bool isRepeatCountSet() const { return m_repeatCountSet; }
1270
    bool isTimingFunctionSet() const { return m_timingFunctionSet; }
1269
    bool isTimingFunctionSet() const { return m_timingFunctionSet; }
1271
    bool isPropertySet() const { return m_propertySet; }
1270
    bool isPropertySet() const { return m_propertySet; }
1272
    
1271
1273
    bool isEmpty() const { return !m_durationSet && !m_repeatCountSet && !m_timingFunctionSet && !m_propertySet; }
1272
    bool isEmpty() const
1273
    {
1274
        return (!m_durationSet && !m_delaySet && !m_timingFunctionSet && !m_propertySet);
1275
    }
1276
1277
    bool isEmptyOrZeroDuration() const
1278
    {
1279
        return isEmpty() || (m_duration == 0 && m_delay <= 0);
1280
    }
1281
1282
    void clearDelay() { m_delaySet = false; }
1274
    void clearDuration() { m_durationSet = false; }
1283
    void clearDuration() { m_durationSet = false; }
1275
    void clearRepeatCount() { m_repeatCountSet = false; }
1276
    void clearTimingFunction() { m_timingFunctionSet = false; }
1284
    void clearTimingFunction() { m_timingFunctionSet = false; }
1285
1277
    void clearProperty() { m_propertySet = false; }
1286
    void clearProperty() { m_propertySet = false; }
1278
1287
1279
    int duration() const { return m_duration; }
1288
    double delay() const { return m_delay; }
1280
    int repeatCount() const { return m_repeatCount; }
1289
    double duration() const { return m_duration; }
1281
    const TimingFunction& timingFunction() const { return m_timingFunction; }
1290
    const TimingFunction& timingFunction() const { return m_timingFunction; }
1282
    int property() const { return m_property; }
1291
    int property() const { return m_property; }
1283
    
1292
1284
    void setDuration(int d) { m_duration = d; m_durationSet = true; }
1293
    void setDelay(double c) { m_delay = c; m_delaySet = true; }
1285
    void setRepeatCount(int c) { m_repeatCount = c; m_repeatCountSet = true; }
1294
    void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; }
1286
    void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; }
1295
    void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; }
1287
    void setProperty(int t) { m_property = t; m_propertySet = true; }
1296
    void setProperty(int t) { m_property = t; m_propertySet = true; }
1297
    void setNext(Transition* n) { if (m_next.get() != n) { m_next = n; } }
1288
1298
1289
    void setNext(Transition* n) { if (m_next != n) { delete m_next; m_next = n; } }
1299
    Transition& operator=(const Transition& o);
1290
1291
    Transition& operator=(const Transition& o);    
1292
    Transition(const Transition& o);
1300
    Transition(const Transition& o);
1293
1301
1294
    bool operator==(const Transition& o) const;
1302
    // return true if all members of this class match (excluding m_next)
1295
    bool operator!=(const Transition& o) const {
1303
    bool transitionsMatch(const Transition* t) const;
1296
        return !(*this == o);
1304
1297
    }
1305
    // return true every transition in the chain (defined by m_next) match 
1306
    bool operator==(const Transition& o) const { return transitionsMatch(&o) && ((m_next && o.m_next) ? (*m_next == *o.m_next) : (m_next == o.m_next)); }
1307
    bool operator!=(const Transition& o) const { return !(*this == o); }
1298
1308
1299
    void fillUnsetProperties();
1309
    void fillUnsetProperties();
1300
1310
1301
    int m_duration;
1311
private:
1302
    int m_repeatCount;
1312
    double m_duration;
1303
    TimingFunction m_timingFunction;
1313
    TimingFunction m_timingFunction;
1314
    double m_delay;
1304
    int m_property;
1315
    int m_property;
1305
1316
1306
    bool m_durationSet;
1317
    bool m_durationSet       : 1;
1307
    bool m_repeatCountSet;
1318
    bool m_timingFunctionSet : 1;
1308
    bool m_timingFunctionSet;
1319
    bool m_delaySet          : 1;
1309
    bool m_propertySet;
1320
    bool m_propertySet       : 1;
1310
1321
    
1311
    Transition* m_next;
1322
    RefPtr<Transition> m_next;
1312
};
1323
};
1313
1324
1314
class StyleReflection : public RefCounted<StyleReflection> {
1325
class StyleReflection : public RefCounted<StyleReflection> {
Lines 1389-1395 public: Link Here
1389
    
1400
    
1390
    RefPtr<StyleReflection> m_boxReflect;
1401
    RefPtr<StyleReflection> m_boxReflect;
1391
1402
1392
    Transition* m_transition;
1403
    RefPtr<Transition> m_transition;
1393
1404
1394
    FillLayer m_mask;
1405
    FillLayer m_mask;
1395
    NinePieceImage m_maskBoxImage;
1406
    NinePieceImage m_maskBoxImage;
Lines 2030-2038 public: Link Here
2030
        return background->m_outline._offset;
2041
        return background->m_outline._offset;
2031
    }
2042
    }
2032
    ShadowData* textShadow() const { return rareInheritedData->textShadow; }
2043
    ShadowData* textShadow() const { return rareInheritedData->textShadow; }
2033
    Color textStrokeColor() const { return rareInheritedData->textStrokeColor; }
2044
    const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; }
2034
    float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
2045
    float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
2035
    Color textFillColor() const { return rareInheritedData->textFillColor; }
2046
    const Color& textFillColor() const { return rareInheritedData->textFillColor; }
2036
    float opacity() const { return rareNonInheritedData->opacity; }
2047
    float opacity() const { return rareNonInheritedData->opacity; }
2037
    EAppearance appearance() const { return static_cast<EAppearance>(rareNonInheritedData->m_appearance); }
2048
    EAppearance appearance() const { return static_cast<EAppearance>(rareNonInheritedData->m_appearance); }
2038
    EBoxAlignment boxAlign() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->align); }
2049
    EBoxAlignment boxAlign() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->align); }
Lines 2088-2094 public: Link Here
2088
2099
2089
    // Apple-specific property getter methods
2100
    // Apple-specific property getter methods
2090
    Transition* accessTransitions();
2101
    Transition* accessTransitions();
2091
    const Transition* transitions() const { return rareNonInheritedData->m_transition; }
2102
    const Transition* transitions() const { return rareNonInheritedData->m_transition.get(); }
2092
    int lineClamp() const { return rareNonInheritedData->lineClamp; }
2103
    int lineClamp() const { return rareNonInheritedData->lineClamp; }
2093
    bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
2104
    bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
2094
    ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
2105
    ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
Lines 2352-2358 public: Link Here
2352
    // End CSS3 Setters
2363
    // End CSS3 Setters
2353
   
2364
   
2354
    // Apple-specific property setters
2365
    // Apple-specific property setters
2355
    void clearTransitions() { delete rareNonInheritedData.access()->m_transition; rareNonInheritedData.access()->m_transition = 0; }
2366
    void clearTransitions() { rareNonInheritedData.access()->m_transition = 0; }
2356
    void inheritTransitions(const Transition* parent) { clearTransitions(); if (parent) rareNonInheritedData.access()->m_transition = new Transition(*parent); }
2367
    void inheritTransitions(const Transition* parent) { clearTransitions(); if (parent) rareNonInheritedData.access()->m_transition = new Transition(*parent); }
2357
    void adjustTransitions();
2368
    void adjustTransitions();
2358
    void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
2369
    void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
Lines 2511-2520 public: Link Here
2511
    static Length initialTransformOriginY() { return Length(50.0, Percent); }
2522
    static Length initialTransformOriginY() { return Length(50.0, Percent); }
2512
    
2523
    
2513
    // Keep these at the end.
2524
    // Keep these at the end.
2514
    static int initialTransitionDuration() { return 0; }
2525
    static float initialDelay() { return 0; }
2515
    static int initialTransitionRepeatCount() { return 1; }
2526
    static double initialDuration() { return 0; }
2516
    static TimingFunction initialTransitionTimingFunction() { return TimingFunction(); }
2527
    static TimingFunction initialTimingFunction() { return TimingFunction(); }
2517
    static int initialTransitionProperty() { return cAnimateAll; }
2528
    static int initialProperty() { return cAnimateAll; }
2518
    static int initialLineClamp() { return -1; }
2529
    static int initialLineClamp() { return -1; }
2519
    static bool initialTextSizeAdjust() { return true; }
2530
    static bool initialTextSizeAdjust() { return true; }
2520
    static ETextSecurity initialTextSecurity() { return TSNONE; }
2531
    static ETextSecurity initialTextSecurity() { return TSNONE; }

Return to bug 19938