| Index: chrome/browser/renderer_host/render_widget_host.cc
|
| ===================================================================
|
| --- chrome/browser/renderer_host/render_widget_host.cc (revision 33056)
|
| +++ chrome/browser/renderer_host/render_widget_host.cc (working copy)
|
| @@ -51,6 +51,9 @@
|
| // How long to wait before we consider a renderer hung.
|
| static const int kHungRendererDelayMs = 20000;
|
|
|
| +// How long a PaintRect_ACK message can be postponed at most, in milliseconds.
|
| +static const int kPaintACKMsgMaxPostponedDurationMS = 1000;
|
| +
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // RenderWidgetHost
|
|
|
| @@ -73,8 +76,9 @@
|
| text_direction_updated_(false),
|
| text_direction_(WebKit::WebTextDirectionLeftToRight),
|
| text_direction_canceled_(false),
|
| - pending_key_events_(false),
|
| + pending_key_events_(0),
|
| suppress_next_char_events_(false),
|
| + paint_ack_postponed_(false),
|
| death_flag_(NULL) {
|
| if (routing_id_ == MSG_ROUTING_NONE)
|
| routing_id_ = process_->GetNextRoutingID();
|
| @@ -533,8 +537,16 @@
|
| mouse_move_pending_ = false;
|
| next_mouse_move_.reset();
|
|
|
| + // Must reset these to ensure that keyboard events work with a new renderer.
|
| + key_queue_.clear();
|
| + pending_key_events_ = 0;
|
| + suppress_next_char_events_ = false;
|
| +
|
| // Reset some fields in preparation for recovering from a crash.
|
| resize_ack_pending_ = false;
|
| + repaint_ack_pending_ = false;
|
| + paint_ack_postponed_ = false;
|
| +
|
| in_flight_size_.SetSize(0, 0);
|
| current_size_.SetSize(0, 0);
|
| is_hidden_ = false;
|
| @@ -669,6 +681,10 @@
|
|
|
| void RenderWidgetHost::OnMsgPaintRect(
|
| const ViewHostMsg_PaintRect_Params& params) {
|
| + // We shouldn't receive PaintRect message when the last PaintRect_ACK has not
|
| + // been sent to the renderer yet.
|
| + DCHECK(!paint_ack_postponed_);
|
| +
|
| TimeTicks paint_start = TimeTicks::Now();
|
|
|
| // Update our knowledge of the RenderWidget's size.
|
| @@ -715,7 +731,16 @@
|
| // This must be done AFTER we're done painting with the bitmap supplied by the
|
| // renderer. This ACK is a signal to the renderer that the backing store can
|
| // be re-used, so the bitmap may be invalid after this call.
|
| - Send(new ViewMsg_PaintRect_ACK(routing_id_));
|
| + //
|
| + // Postpone the ACK message until all pending key events have been sent to the
|
| + // renderer, so that the renderer can process the updates caused by the key
|
| + // events in batch.
|
| + if (pending_key_events_ > 0) {
|
| + paint_ack_postponed_ = true;
|
| + paint_ack_postponed_time_ = TimeTicks::Now();
|
| + } else {
|
| + Send(new ViewMsg_PaintRect_ACK(routing_id_));
|
| + }
|
|
|
| // We don't need to update the view if the view is hidden. We must do this
|
| // early return after the ACK is sent, however, or the renderer will not send
|
| @@ -801,10 +826,6 @@
|
| }
|
|
|
| void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) {
|
| - // Track if |this| is destroyed or not.
|
| - bool is_dead = false;
|
| - death_flag_ = &is_dead;
|
| -
|
| // Log the time delta for processing an input event.
|
| TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
|
| UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta);
|
| @@ -814,10 +835,9 @@
|
|
|
| void* iter = NULL;
|
| int type = 0;
|
| - if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined))
|
| + if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) {
|
| process()->ReceivedBadMessage(message.type());
|
| -
|
| - if (type == WebInputEvent::MouseMove) {
|
| + } else if (type == WebInputEvent::MouseMove) {
|
| mouse_move_pending_ = false;
|
|
|
| // now, we can send the next mouse move event
|
| @@ -825,96 +845,13 @@
|
| DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove);
|
| ForwardMouseEvent(*next_mouse_move_);
|
| }
|
| - }
|
| + } else if (WebInputEvent::isKeyboardEventType(type)) {
|
| + bool processed = false;
|
| + if (!message.ReadBool(&iter, &processed))
|
| + process()->ReceivedBadMessage(message.type());
|
|
|
| - if (WebInputEvent::isKeyboardEventType(type)) {
|
| - if (key_queue_.size() == 0) {
|
| - LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
|
| - << "don't seem to have sent it to the renderer!";
|
| - } else if (key_queue_.front().type != type) {
|
| - LOG(ERROR) << "We seem to have a different key type sent from "
|
| - << "the renderer. (" << key_queue_.front().type << " vs. "
|
| - << type << "). Ignoring event.";
|
| -
|
| - // Something must be wrong. |key_queue_| must be cleared here to make sure
|
| - // the feedback loop for sending upcoming keyboard events can be resumed
|
| - // correctly.
|
| - key_queue_.clear();
|
| - pending_key_events_ = 0;
|
| - suppress_next_char_events_ = false;
|
| - } else {
|
| - bool processed = false;
|
| - if (!message.ReadBool(&iter, &processed))
|
| - process()->ReceivedBadMessage(message.type());
|
| -
|
| - NativeWebKeyboardEvent front_item = key_queue_.front();
|
| - key_queue_.pop_front();
|
| -
|
| - bool processed_by_browser = false;
|
| - if (!processed) {
|
| - processed_by_browser = UnhandledKeyboardEvent(front_item);
|
| -
|
| - // WARNING: This RenderWidgetHost can be deallocated at this point
|
| - // (i.e. in the case of Ctrl+W, where the call to
|
| - // UnhandledKeyboardEvent destroys this RenderWidgetHost).
|
| - }
|
| -
|
| - // This RenderWidgetHost was already deallocated, we can't do anything
|
| - // from now on, including resetting |death_flag_|. So just return.
|
| - if (is_dead)
|
| - return;
|
| -
|
| - // Suppress the following Char events if the RawKeyDown event was handled
|
| - // by the browser rather than the renderer.
|
| - if (front_item.type == WebKeyboardEvent::RawKeyDown)
|
| - suppress_next_char_events_ = processed_by_browser;
|
| -
|
| - // If more than one key events in |key_queue_| were already sent to the
|
| - // renderer but haven't got ACK messages yet, we must wait for ACK
|
| - // messages of these key events before sending more key events to the
|
| - // renderer.
|
| - if (pending_key_events_ && key_queue_.size() == pending_key_events_) {
|
| - size_t i = 0;
|
| - if (suppress_next_char_events_) {
|
| - // Suppress the sequence of pending Char events if preceding
|
| - // RawKeyDown event was handled by the browser.
|
| - while (pending_key_events_ &&
|
| - key_queue_[0].type == WebKeyboardEvent::Char) {
|
| - --pending_key_events_;
|
| - key_queue_.pop_front();
|
| - }
|
| - } else {
|
| - // Otherwise, send these pending Char events to the renderer.
|
| - // Note: we can't remove them from |key_queue_|, as we still need to
|
| - // wait for their ACK messages from the renderer.
|
| - while (pending_key_events_ &&
|
| - key_queue_[i].type == WebKeyboardEvent::Char) {
|
| - --pending_key_events_;
|
| - ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
|
| - }
|
| - }
|
| -
|
| - // Reset |suppress_next_char_events_| if there is still one or more
|
| - // pending KeyUp or RawKeyDown events in the queue.
|
| - // We can't reset it if there is no pending event anymore, because we
|
| - // don't know if the following event is a Char event or not.
|
| - if (pending_key_events_)
|
| - suppress_next_char_events_ = false;
|
| -
|
| - // We can safely send following pending KeyUp and RawKeyDown events to
|
| - // the renderer, until we meet another Char event.
|
| - while (pending_key_events_ &&
|
| - key_queue_[i].type != WebKeyboardEvent::Char) {
|
| - --pending_key_events_;
|
| - ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
|
| - }
|
| - }
|
| - }
|
| + ProcessKeyboardEventAck(type, processed);
|
| }
|
| -
|
| - // Reset |death_flag_| to NULL, otherwise it'll point to an invalid memory
|
| - // address after returning from this method.
|
| - death_flag_ = NULL;
|
| }
|
|
|
| void RenderWidgetHost::OnMsgFocus() {
|
| @@ -1048,3 +985,102 @@
|
| void RenderWidgetHost::AdvanceToNextMisspelling() {
|
| Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_));
|
| }
|
| +
|
| +void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) {
|
| + if (key_queue_.size() == 0) {
|
| + LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
|
| + << "don't seem to have sent it to the renderer!";
|
| + } else if (key_queue_.front().type != type) {
|
| + LOG(ERROR) << "We seem to have a different key type sent from "
|
| + << "the renderer. (" << key_queue_.front().type << " vs. "
|
| + << type << "). Ignoring event.";
|
| +
|
| + // Something must be wrong. |key_queue_| must be cleared here to make sure
|
| + // the feedback loop for sending upcoming keyboard events can be resumed
|
| + // correctly.
|
| + key_queue_.clear();
|
| + pending_key_events_ = 0;
|
| + suppress_next_char_events_ = false;
|
| + } else {
|
| + // Track if |this| is destroyed or not.
|
| + bool is_dead = false;
|
| + death_flag_ = &is_dead;
|
| +
|
| + NativeWebKeyboardEvent front_item = key_queue_.front();
|
| + key_queue_.pop_front();
|
| +
|
| + bool processed_by_browser = false;
|
| + if (!processed) {
|
| + processed_by_browser = UnhandledKeyboardEvent(front_item);
|
| +
|
| + // WARNING: This RenderWidgetHost can be deallocated at this point
|
| + // (i.e. in the case of Ctrl+W, where the call to
|
| + // UnhandledKeyboardEvent destroys this RenderWidgetHost).
|
| + }
|
| +
|
| + // This RenderWidgetHost was already deallocated, we can't do anything
|
| + // from now on, including resetting |death_flag_|. So just return.
|
| + if (is_dead)
|
| + return;
|
| +
|
| + // Reset |death_flag_| to NULL, otherwise it'll point to an invalid memory
|
| + // address after returning from this method.
|
| + death_flag_ = NULL;
|
| +
|
| + // Suppress the following Char events if the RawKeyDown event was handled
|
| + // by the browser rather than the renderer.
|
| + if (front_item.type == WebKeyboardEvent::RawKeyDown)
|
| + suppress_next_char_events_ = processed_by_browser;
|
| +
|
| + // If more than one key events in |key_queue_| were already sent to the
|
| + // renderer but haven't got ACK messages yet, we must wait for ACK
|
| + // messages of these key events before sending more key events to the
|
| + // renderer.
|
| + if (pending_key_events_ && key_queue_.size() == pending_key_events_) {
|
| + size_t i = 0;
|
| + if (suppress_next_char_events_) {
|
| + // Suppress the sequence of pending Char events if preceding
|
| + // RawKeyDown event was handled by the browser.
|
| + while (pending_key_events_ &&
|
| + key_queue_[0].type == WebKeyboardEvent::Char) {
|
| + --pending_key_events_;
|
| + key_queue_.pop_front();
|
| + }
|
| + } else {
|
| + // Otherwise, send these pending Char events to the renderer.
|
| + // Note: we can't remove them from |key_queue_|, as we still need to
|
| + // wait for their ACK messages from the renderer.
|
| + while (pending_key_events_ &&
|
| + key_queue_[i].type == WebKeyboardEvent::Char) {
|
| + --pending_key_events_;
|
| + ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
|
| + }
|
| + }
|
| +
|
| + // Reset |suppress_next_char_events_| if there is still one or more
|
| + // pending KeyUp or RawKeyDown events in the queue.
|
| + // We can't reset it if there is no pending event anymore, because we
|
| + // don't know if the following event is a Char event or not.
|
| + if (pending_key_events_)
|
| + suppress_next_char_events_ = false;
|
| +
|
| + // We can safely send following pending KeyUp and RawKeyDown events to
|
| + // the renderer, until we meet another Char event.
|
| + while (pending_key_events_ &&
|
| + key_queue_[i].type != WebKeyboardEvent::Char) {
|
| + --pending_key_events_;
|
| + ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Send the pending PaintRect_ACK message after sending all pending key
|
| + // events or after a certain duration, so that the renderer can process
|
| + // the updates caused by the key events in batch.
|
| + if (paint_ack_postponed_ && (pending_key_events_ == 0 ||
|
| + (TimeTicks::Now() - paint_ack_postponed_time_).InMilliseconds() >
|
| + kPaintACKMsgMaxPostponedDurationMS)) {
|
| + paint_ack_postponed_ = false;
|
| + Send(new ViewMsg_PaintRect_ACK(routing_id_));
|
| + }
|
| +}
|
|
|