Index: chrome/renderer/render_widget.cc |
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc |
index 5f66e49987ccf8a3709caac736a76c0726d45cad..7187e3cd4872eeb8131980a530d314d336a5350f 100644 |
--- a/chrome/renderer/render_widget.cc |
+++ b/chrome/renderer/render_widget.cc |
@@ -77,7 +77,8 @@ RenderWidget::RenderWidget(RenderThreadBase* render_thread, |
pending_window_rect_count_(0), |
suppress_next_char_events_(false), |
is_accelerated_compositing_active_(false), |
- animation_update_pending_(false) { |
+ animation_update_pending_(false), |
+ animation_waiting_for_paint_(false) { |
RenderProcess::current()->AddRefProcess(); |
DCHECK(render_thread_); |
} |
@@ -488,11 +489,17 @@ void RenderWidget::CallDoDeferredUpdate() { |
} |
void RenderWidget::UpdateAnimationsIfNeeded() { |
- if (!is_hidden() && animation_update_pending_) { |
+ if (webwidget_ && !is_hidden() && animation_update_pending_ && |
+ !animation_waiting_for_paint_) { |
base::Time now = base::Time::Now(); |
if (now >= animation_floor_time_) { |
- animation_update_pending_ = false; |
- webwidget_->animate(); |
+ UpdateAnimationsAndFloorTime(); |
+ // If updating the animation caused invalidations, make sure that we paint |
+ // at least once before we call animate() again. |
+ // Update layout first as that might cause further invalidations. |
+ webwidget_->layout(); |
+ if (paint_aggregator_.HasPendingUpdate()) |
+ animation_waiting_for_paint_ = true; |
} else { |
// This code uses base::Time::Now() to calculate the floor and next fire |
// time because javascript's Date object uses base::Time::Now(). The |
@@ -501,7 +508,7 @@ void RenderWidget::UpdateAnimationsIfNeeded() { |
// The upshot of all this is that this function might be called before |
// base::Time::Now() has advanced past the animation_floor_time_. To |
// avoid exposing this delay to javascript, we keep posting delayed |
- // tasks until we observe base::Time::Now() advancing far enough. |
+ // tasks until base::Time::Now() has advanced far enough. |
int64 delay = (animation_floor_time_ - now).InMillisecondsRoundedUp(); |
MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( |
this, &RenderWidget::UpdateAnimationsIfNeeded), delay); |
@@ -509,6 +516,13 @@ void RenderWidget::UpdateAnimationsIfNeeded() { |
} |
} |
+void RenderWidget::UpdateAnimationsAndFloorTime() { |
+ animation_update_pending_ = false; |
+ animation_floor_time_ = |
+ base::Time::Now() + base::TimeDelta::FromMilliseconds(16); |
+ webwidget_->animate(); |
+} |
+ |
void RenderWidget::DoDeferredUpdate() { |
if (!webwidget_ || update_reply_pending()) |
return; |
@@ -520,8 +534,21 @@ void RenderWidget::DoDeferredUpdate() { |
return; |
} |
- if (base::Time::Now() > animation_floor_time_) |
- UpdateAnimationsIfNeeded(); |
+ if (animation_update_pending_) { |
+ if (animation_waiting_for_paint_) { |
+ // If we have pending animation updates but need to paint before updating |
+ // them, post a task to UpdateAnimationsIfNeeded that will either update |
+ // animations directly (if the animation floor time has passed by the time |
+ // the function runs) or post a delayed task if the floor time is not yet |
+ // reached. |
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &RenderWidget::UpdateAnimationsIfNeeded)); |
+ } else if (base::Time::Now() > animation_floor_time_) { |
+ // Otherwise, if it's time to update the animations go ahead. |
+ UpdateAnimationsAndFloorTime(); |
+ } |
+ } |
+ animation_waiting_for_paint_ = false; |
// Layout may generate more invalidation. It may also enable the |
// GPU acceleration, so make sure to run layout before we send the |
@@ -715,13 +742,11 @@ void RenderWidget::scheduleComposite() { |
} |
void RenderWidget::scheduleAnimation() { |
- if (!animation_update_pending_) { |
- animation_update_pending_ = true; |
- animation_floor_time_ = |
- base::Time::Now() + base::TimeDelta::FromMilliseconds(10); |
- MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( |
- this, &RenderWidget::UpdateAnimationsIfNeeded), 10); |
- } |
+ if (!animation_update_pending_) { |
+ animation_update_pending_ = true; |
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &RenderWidget::UpdateAnimationsIfNeeded)); |
+ } |
} |
void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { |