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 |
} |