Index: chrome/browser/renderer_host/render_widget_host.cc |
=================================================================== |
--- chrome/browser/renderer_host/render_widget_host.cc (revision 34219) |
+++ chrome/browser/renderer_host/render_widget_host.cc (working copy) |
@@ -51,9 +51,6 @@ |
// 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 |
@@ -76,10 +73,7 @@ |
text_direction_updated_(false), |
text_direction_(WebKit::WebTextDirectionLeftToRight), |
text_direction_canceled_(false), |
- pending_key_events_(0), |
- suppress_next_char_events_(false), |
- paint_ack_postponed_(false), |
- death_flag_(NULL) { |
+ suppress_next_char_events_(false) { |
if (routing_id_ == MSG_ROUTING_NONE) |
routing_id_ = process_->GetNextRoutingID(); |
@@ -90,10 +84,6 @@ |
} |
RenderWidgetHost::~RenderWidgetHost() { |
- // Force the method that destroys this object to exit immediately. |
- if (death_flag_) |
- *death_flag_ = true; |
- |
// Clear our current or cached backing store if either remains. |
BackingStoreManager::RemoveBackingStore(this); |
@@ -375,7 +365,7 @@ |
OnUserGesture(); |
} |
- ForwardInputEvent(mouse_event, sizeof(WebMouseEvent)); |
+ ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false); |
} |
void RenderWidgetHost::ForwardWheelEvent( |
@@ -383,7 +373,7 @@ |
if (process_->ignore_input_events()) |
return; |
- ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent)); |
+ ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); |
} |
void RenderWidgetHost::ForwardKeyboardEvent( |
@@ -400,104 +390,52 @@ |
// Double check the type to make sure caller hasn't sent us nonsense that |
// will mess up our key queue. |
if (WebInputEvent::isKeyboardEventType(key_event.type)) { |
- // Don't add this key to the queue if we have no way to send the message... |
- if (!process_->HasConnection()) |
- return; |
- |
- // To help understand following logic, please refer to the comments |
- // explaining |pending_key_events_| and |suppress_next_char_events_| |
- // members. And the comments in OnMsgInputEventAck() method, which contains |
- // the bottom half of the logic. |
- // |
- // There are to different situations for us to handle key events: |
- // 1. After sending a key event to the renderer, we receive its ACK message |
- // from the renderer before sending the next key event. |
- // In this case, there is always no more than 1 key event in |key_queue_|, |
- // and we send the key event one by one in this method, except that a |
- // sequence of Char events may be suppressed directly if the preceding |
- // RawKeyDown event was handled as an accelerator key in the browser. |
- // |
- // 2. We get the next key event before receving the previous one's ACK |
- // message from the renderer. |
- // In this case, when we get a key event, the previous key event is still in |
- // |keq_queue_| waiting for being handled in OnMsgInputEventAck() method. |
- // Then we need handle following cases differently: |
- // 1) If we get a Char event, then the previous key event in |key_queue_| |
- // waiting for ACK must be a RawKeyDown event. Then we need keep this Char |
- // event in |key_queue_| rather than sending it immediately, because we |
- // can't determine if we should send it to the renderer or just suppress |
- // it, until we receive the preceding RawKeyDown event's ACK message. |
- // We increase the count of |pending_key_events_| to help remember this |
- // Char event is not sent to the renderer yet. |
- // 2) If there is already one or more key event pending in |key_queue_| |
- // (|pending_key_events_| > 0), we can not send a new key event |
- // immediately no matter what type it is. Otherwise the key events will be |
- // in wrong order. In this case we just keep them in |key_queue_| and |
- // increase |pending_key_events_| to remember them. |
- // |
- // Then all pending key events in |key_queue_| will be handled properly in |
- // OnMsgInputEventAck() method. Please refer to that method for details. |
- |
- // Tab switching/closing accelerators aren't sent to the renderer to avoid a |
- // hung/malicious renderer from interfering. |
- if (!ShouldSendToRenderer(key_event)) { |
- if (key_event.type == WebKeyboardEvent::RawKeyDown) |
- suppress_next_char_events_ = true; |
- UnhandledKeyboardEvent(key_event); |
- // We might be deleted now. |
- return; |
- } |
- |
- bool is_char = (key_event.type == WebKeyboardEvent::Char); |
- |
- // Handle the first situation mentioned above. |
if (suppress_next_char_events_) { |
// If preceding RawKeyDown event was handled by the browser, then we need |
// suppress all Char events generated by it. Please note that, one |
// RawKeyDown event may generate multiple Char events, so we can't reset |
// |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. |
- if (is_char) |
+ if (key_event.type == WebKeyboardEvent::Char) |
return; |
// We get a KeyUp or a RawKeyDown event. |
suppress_next_char_events_ = false; |
} |
+ // We need to set |suppress_next_char_events_| to true if |
+ // PreHandleKeyboardEvent() returns true, but |this| may already be |
+ // destroyed at that time. So set |suppress_next_char_events_| true here, |
+ // then revert it afterwards when necessary. |
+ if (key_event.type == WebKeyboardEvent::RawKeyDown) |
+ suppress_next_char_events_ = true; |
+ |
+ bool is_keyboard_shortcut = false; |
+ // Tab switching/closing accelerators aren't sent to the renderer to avoid a |
+ // hung/malicious renderer from interfering. |
+ if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) |
+ return; |
+ |
+ if (key_event.type == WebKeyboardEvent::RawKeyDown) |
+ suppress_next_char_events_ = false; |
+ |
+ // Don't add this key to the queue if we have no way to send the message... |
+ if (!process_->HasConnection()) |
+ return; |
+ |
// Put all WebKeyboardEvent objects in a queue since we can't trust the |
// renderer and we need to give something to the UnhandledInputEvent |
// handler. |
key_queue_.push_back(key_event); |
HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
- // Handle the second situation mentioned above. |
- size_t key_queue_size = key_queue_.size(); |
- if ((is_char && key_queue_size > 1) || pending_key_events_) { |
- // The event is not send to the renderer, increase |pending_key_events_| |
- // to remember it. |
- ++pending_key_events_; |
- |
- // Some sanity checks. |
- // At least one key event in the front of |key_queue_| has been sent to |
- // the renderer, otherwise we won't be able to get any ACK back from the |
- // renderer. |
- DCHECK(key_queue_size > pending_key_events_); |
- // Char events must be preceded by RawKeyDown events. |
- // TODO(suzhe): verify it on all platforms. |
- DCHECK(key_queue_[key_queue_size - pending_key_events_ - 1].type == |
- WebKeyboardEvent::RawKeyDown); |
- // The first pending key event must be a Char event. Other key events must |
- // already be sent to the renderer at this point. |
- DCHECK(key_queue_[key_queue_size - pending_key_events_].type == |
- WebKeyboardEvent::Char); |
- } else { |
- // Fall into the first situation, so we can send the event immediately. |
- // Only forward the non-native portions of our event. |
- ForwardInputEvent(key_event, sizeof(WebKeyboardEvent)); |
- } |
+ // Only forward the non-native portions of our event. |
+ ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), |
+ is_keyboard_shortcut); |
} |
} |
void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, |
- int event_size) { |
+ int event_size, |
+ bool is_keyboard_shortcut) { |
if (!process_->HasConnection()) |
return; |
@@ -506,6 +444,9 @@ |
IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); |
message->WriteData( |
reinterpret_cast<const char*>(&input_event), event_size); |
+ // |is_keyboard_shortcut| only makes sense for RawKeyDown events. |
+ if (input_event.type == WebInputEvent::RawKeyDown) |
+ message->WriteBool(is_keyboard_shortcut); |
input_event_start_time_ = TimeTicks::Now(); |
Send(message); |
@@ -539,13 +480,11 @@ |
// 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); |
@@ -681,10 +620,6 @@ |
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. |
@@ -732,16 +667,7 @@ |
// 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. |
- // |
- // 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_)); |
- } |
+ 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 |
@@ -1009,92 +935,20 @@ |
<< "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. |
+ // Something must be wrong. Clear the |key_queue_| and |
+ // |suppress_next_char_events_| so that we can resume from the error. |
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); |
+ 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_)); |
- } |
} |