OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/renderer_host/render_widget_host.h" | 5 #include "chrome/browser/renderer_host/render_widget_host.h" |
6 | 6 |
7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/keyboard_codes.h" | 9 #include "base/keyboard_codes.h" |
10 #include "chrome/browser/renderer_host/backing_store.h" | 10 #include "chrome/browser/renderer_host/backing_store.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 is_hidden_(false), | 64 is_hidden_(false), |
65 repaint_ack_pending_(false), | 65 repaint_ack_pending_(false), |
66 resize_ack_pending_(false), | 66 resize_ack_pending_(false), |
67 mouse_move_pending_(false), | 67 mouse_move_pending_(false), |
68 needs_repainting_on_restore_(false), | 68 needs_repainting_on_restore_(false), |
69 is_unresponsive_(false), | 69 is_unresponsive_(false), |
70 in_get_backing_store_(false), | 70 in_get_backing_store_(false), |
71 view_being_painted_(false), | 71 view_being_painted_(false), |
72 text_direction_updated_(false), | 72 text_direction_updated_(false), |
73 text_direction_(WebKit::WebTextDirectionLeftToRight), | 73 text_direction_(WebKit::WebTextDirectionLeftToRight), |
74 text_direction_canceled_(false) { | 74 text_direction_canceled_(false), |
75 pending_key_events_(false), | |
76 suppress_next_char_events_(false), | |
77 death_flag_(NULL) { | |
75 if (routing_id_ == MSG_ROUTING_NONE) | 78 if (routing_id_ == MSG_ROUTING_NONE) |
76 routing_id_ = process_->GetNextRoutingID(); | 79 routing_id_ = process_->GetNextRoutingID(); |
77 | 80 |
78 process_->Attach(this, routing_id_); | 81 process_->Attach(this, routing_id_); |
79 // Because the widget initializes as is_hidden_ == false, | 82 // Because the widget initializes as is_hidden_ == false, |
80 // tell the process host that we're alive. | 83 // tell the process host that we're alive. |
81 process_->WidgetRestored(); | 84 process_->WidgetRestored(); |
82 } | 85 } |
83 | 86 |
84 RenderWidgetHost::~RenderWidgetHost() { | 87 RenderWidgetHost::~RenderWidgetHost() { |
88 // Force the method that destroys this object to exit immediately. | |
89 if (death_flag_) | |
darin (slow to review)
2009/11/24 07:47:36
this seems like a very ugly hack for the fact that
James Su
2009/11/24 09:10:56
I don't like it either, but I don't know how to fi
| |
90 *death_flag_ = true; | |
91 | |
85 // Clear our current or cached backing store if either remains. | 92 // Clear our current or cached backing store if either remains. |
86 BackingStoreManager::RemoveBackingStore(this); | 93 BackingStoreManager::RemoveBackingStore(this); |
87 | 94 |
88 process_->Release(routing_id_); | 95 process_->Release(routing_id_); |
89 } | 96 } |
90 | 97 |
91 gfx::NativeViewId RenderWidgetHost::GetNativeViewId() { | 98 gfx::NativeViewId RenderWidgetHost::GetNativeViewId() { |
92 if (view_) | 99 if (view_) |
93 return gfx::IdFromNativeView(view_->GetNativeView()); | 100 return gfx::IdFromNativeView(view_->GetNativeView()); |
94 return NULL; | 101 return NULL; |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 OnUserGesture(); | 395 OnUserGesture(); |
389 } | 396 } |
390 | 397 |
391 // Double check the type to make sure caller hasn't sent us nonsense that | 398 // Double check the type to make sure caller hasn't sent us nonsense that |
392 // will mess up our key queue. | 399 // will mess up our key queue. |
393 if (WebInputEvent::isKeyboardEventType(key_event.type)) { | 400 if (WebInputEvent::isKeyboardEventType(key_event.type)) { |
394 // Don't add this key to the queue if we have no way to send the message... | 401 // Don't add this key to the queue if we have no way to send the message... |
395 if (!process_->HasConnection()) | 402 if (!process_->HasConnection()) |
396 return; | 403 return; |
397 | 404 |
405 // To help understand following logic, please refer to the comments | |
406 // explaining |pending_key_events_| and |suppress_next_char_events_| | |
407 // members. And the comments in OnMsgInputEventAck() method, which contains | |
408 // the bottom half of the logic. | |
409 // | |
410 // There are to different situations for us to handle key events: | |
darin (slow to review)
2009/11/24 07:47:36
nit: "There are two..."
James Su
2009/11/24 09:10:56
This is fixed in CL 400012.
| |
411 // 1. After sending a key event to the renderer, we receive its ACK message | |
412 // from the renderer before sending the next key event. | |
413 // In this case, there is always no more than 1 key event in |key_queue_|, | |
414 // and we send the key event one by one in this method, except that a | |
415 // sequence of Char events may be suppressed directly if the preceding | |
416 // RawKeyDown event was handled as an accelerator key in the browser. | |
417 // | |
418 // 2. We get the next key event before receving the previous one's ACK | |
419 // message from the renderer. | |
420 // In this case, when we get a key event, the previous key event is still in | |
421 // |keq_queue_| waiting for being handled in OnMsgInputEventAck() method. | |
422 // Then we need handle following cases differently: | |
423 // 1) If we get a Char event, then the previous key event in |key_queue_| | |
424 // waiting for ACK must be a RawKeyDown event. Then we need keep this Char | |
425 // event in |key_queue_| rather than sending it immediately, because we | |
426 // can't determine if we should send it to the renderer or just suppress | |
427 // it, until we receive the preceding RawKeyDown event's ACK message. | |
428 // We increase the count of |pending_key_events_| to help remember this | |
429 // Char event is not sent to the renderer yet. | |
430 // 2) If there is already one or more key event pending in |key_queue_| | |
431 // (|pending_key_events_| > 0), we can not send a new key event | |
432 // immediately no matter what type it is. Otherwise the key events will be | |
433 // in wrong order. In this case we just keep them in |key_queue_| and | |
434 // increase |pending_key_events_| to remember them. | |
435 // | |
436 // Then all pending key events in |key_queue_| will be handled properly in | |
437 // OnMsgInputEventAck() method. Please refer to that method for details. | |
438 | |
398 // Tab switching/closing accelerators aren't sent to the renderer to avoid a | 439 // Tab switching/closing accelerators aren't sent to the renderer to avoid a |
399 // hung/malicious renderer from interfering. | 440 // hung/malicious renderer from interfering. |
400 if (!ShouldSendToRenderer(key_event)) { | 441 if (!ShouldSendToRenderer(key_event)) { |
401 UnhandledKeyboardEvent(key_event); | 442 UnhandledKeyboardEvent(key_event); |
443 if (key_event.type == WebKeyboardEvent::RawKeyDown) | |
444 suppress_next_char_events_ = true; | |
402 return; | 445 return; |
403 } | 446 } |
404 | 447 |
448 bool is_char = (key_event.type == WebKeyboardEvent::Char); | |
449 | |
450 // Handle the first situation mentioned above. | |
451 if (suppress_next_char_events_) { | |
darin (slow to review)
2009/11/24 07:51:45
couldn't we implement this discarding of events in
James Su
2009/11/24 09:10:56
Good suggestion. I'll look into this approach to s
| |
452 // If preceding RawKeyDown event was handled by the browser, then we need | |
453 // suppress all Char events generated by it. Please note that, one | |
454 // RawKeyDown event may generate multiple Char events, so we can't reset | |
455 // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. | |
456 if (is_char) | |
457 return; | |
458 // We get a KeyUp or a RawKeyDown event. | |
459 suppress_next_char_events_ = false; | |
460 } | |
461 | |
405 // Put all WebKeyboardEvent objects in a queue since we can't trust the | 462 // Put all WebKeyboardEvent objects in a queue since we can't trust the |
406 // renderer and we need to give something to the UnhandledInputEvent | 463 // renderer and we need to give something to the UnhandledInputEvent |
407 // handler. | 464 // handler. |
408 key_queue_.push(key_event); | 465 key_queue_.push_back(key_event); |
409 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | 466 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
467 | |
468 // Handle the second situation mentioned above. | |
469 size_t key_queue_size = key_queue_.size(); | |
470 if ((is_char && key_queue_size > 1) || pending_key_events_) { | |
471 // The event is not send to the renderer, increase |pending_key_events_| | |
472 // to remember it. | |
473 ++pending_key_events_; | |
474 | |
475 // Some sanity checks. | |
476 // At least one key event in the front of |key_queue_| has been sent to | |
477 // the renderer, otherwise we won't be able to get any ACK back from the | |
478 // renderer. | |
479 DCHECK(key_queue_size > pending_key_events_); | |
480 // Char events must be preceded by RawKeyDown events. | |
481 // TODO(suzhe): verify it on all platforms. | |
482 DCHECK(key_queue_[key_queue_size - pending_key_events_ - 1].type == | |
483 WebKeyboardEvent::RawKeyDown); | |
484 // The first pending key event must be a Char event. Other key events must | |
485 // already be sent to the renderer at this point. | |
486 DCHECK(key_queue_[key_queue_size - pending_key_events_].type == | |
487 WebKeyboardEvent::Char); | |
488 } else { | |
489 // Fall into the first situation, so we can send the event immediately. | |
490 // Only forward the non-native portions of our event. | |
491 ForwardInputEvent(key_event, sizeof(WebKeyboardEvent)); | |
492 } | |
410 } | 493 } |
411 | |
412 // Only forward the non-native portions of our event. | |
413 ForwardInputEvent(key_event, sizeof(WebKeyboardEvent)); | |
414 } | 494 } |
415 | 495 |
416 void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, | 496 void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, |
417 int event_size) { | 497 int event_size) { |
418 if (!process_->HasConnection()) | 498 if (!process_->HasConnection()) |
419 return; | 499 return; |
420 | 500 |
421 DCHECK(!process_->ignore_input_events()); | 501 DCHECK(!process_->ignore_input_events()); |
422 | 502 |
423 IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); | 503 IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
714 | 794 |
715 if (painting_observer_) | 795 if (painting_observer_) |
716 painting_observer_->WidgetDidUpdateBackingStore(this); | 796 painting_observer_->WidgetDidUpdateBackingStore(this); |
717 | 797 |
718 // Log the time delta for processing a scroll message. | 798 // Log the time delta for processing a scroll message. |
719 TimeDelta delta = TimeTicks::Now() - scroll_start; | 799 TimeDelta delta = TimeTicks::Now() - scroll_start; |
720 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta); | 800 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta); |
721 } | 801 } |
722 | 802 |
723 void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { | 803 void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { |
804 // Track if |this| is destroyed or not. | |
805 bool is_dead = false; | |
806 death_flag_ = &is_dead; | |
807 | |
724 // Log the time delta for processing an input event. | 808 // Log the time delta for processing an input event. |
725 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; | 809 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; |
726 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); | 810 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); |
727 | 811 |
728 // Cancel pending hung renderer checks since the renderer is responsive. | 812 // Cancel pending hung renderer checks since the renderer is responsive. |
729 StopHangMonitorTimeout(); | 813 StopHangMonitorTimeout(); |
730 | 814 |
731 void* iter = NULL; | 815 void* iter = NULL; |
732 int type = 0; | 816 int type = 0; |
733 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) | 817 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) |
(...skipping 10 matching lines...) Expand all Loading... | |
744 } | 828 } |
745 | 829 |
746 if (WebInputEvent::isKeyboardEventType(type)) { | 830 if (WebInputEvent::isKeyboardEventType(type)) { |
747 if (key_queue_.size() == 0) { | 831 if (key_queue_.size() == 0) { |
748 LOG(ERROR) << "Got a KeyEvent back from the renderer but we " | 832 LOG(ERROR) << "Got a KeyEvent back from the renderer but we " |
749 << "don't seem to have sent it to the renderer!"; | 833 << "don't seem to have sent it to the renderer!"; |
750 } else if (key_queue_.front().type != type) { | 834 } else if (key_queue_.front().type != type) { |
751 LOG(ERROR) << "We seem to have a different key type sent from " | 835 LOG(ERROR) << "We seem to have a different key type sent from " |
752 << "the renderer. (" << key_queue_.front().type << " vs. " | 836 << "the renderer. (" << key_queue_.front().type << " vs. " |
753 << type << "). Ignoring event."; | 837 << type << "). Ignoring event."; |
838 | |
839 // Something must be wrong. |key_queue_| must be cleared here to make sure | |
840 // the feedback loop for sending upcoming keyboard events can be resumed | |
841 // correctly. | |
842 key_queue_.clear(); | |
843 pending_key_events_ = 0; | |
844 suppress_next_char_events_ = false; | |
754 } else { | 845 } else { |
755 bool processed = false; | 846 bool processed = false; |
756 if (!message.ReadBool(&iter, &processed)) | 847 if (!message.ReadBool(&iter, &processed)) |
757 process()->ReceivedBadMessage(message.type()); | 848 process()->ReceivedBadMessage(message.type()); |
758 | 849 |
759 NativeWebKeyboardEvent front_item = key_queue_.front(); | 850 NativeWebKeyboardEvent front_item = key_queue_.front(); |
760 key_queue_.pop(); | 851 key_queue_.pop_front(); |
761 | 852 |
853 bool processed_by_browser = false; | |
762 if (!processed) { | 854 if (!processed) { |
763 UnhandledKeyboardEvent(front_item); | 855 processed_by_browser = UnhandledKeyboardEvent(front_item); |
764 | 856 |
765 // WARNING: This RenderWidgetHost can be deallocated at this point | 857 // WARNING: This RenderWidgetHost can be deallocated at this point |
766 // (i.e. in the case of Ctrl+W, where the call to | 858 // (i.e. in the case of Ctrl+W, where the call to |
767 // UnhandledKeyboardEvent destroys this RenderWidgetHost). | 859 // UnhandledKeyboardEvent destroys this RenderWidgetHost). |
768 } | 860 } |
861 | |
862 // This RenderWidgetHost was already deallocated, we can't do anything | |
863 // from now on, including resetting |death_flag_|. So just return. | |
864 if (is_dead) | |
865 return; | |
866 | |
867 // Suppress the following Char events if the RawKeyDown event was handled | |
868 // by the browser rather than the renderer. | |
869 if (front_item.type == WebKeyboardEvent::RawKeyDown) | |
870 suppress_next_char_events_ = processed_by_browser; | |
871 | |
872 // If more than one key events in |key_queue_| were already sent to the | |
873 // renderer but haven't got ACK messages yet, we must wait for ACK | |
874 // messages of these key events before sending more key events to the | |
875 // renderer. | |
876 if (pending_key_events_ && key_queue_.size() == pending_key_events_) { | |
877 size_t i = 0; | |
878 if (suppress_next_char_events_) { | |
879 // Suppress the sequence of pending Char events if preceding | |
880 // RawKeyDown event was handled by the browser. | |
881 while (pending_key_events_ && | |
882 key_queue_[0].type == WebKeyboardEvent::Char) { | |
883 --pending_key_events_; | |
884 key_queue_.pop_front(); | |
885 } | |
886 } else { | |
887 // Otherwise, send these pending Char events to the renderer. | |
888 // Note: we can't remove them from |key_queue_|, as we still need to | |
889 // wait for their ACK messages from the renderer. | |
890 while (pending_key_events_ && | |
891 key_queue_[i].type == WebKeyboardEvent::Char) { | |
892 --pending_key_events_; | |
893 ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent)); | |
894 } | |
895 } | |
896 | |
897 // Reset |suppress_next_char_events_| if there is still one or more | |
898 // pending KeyUp or RawKeyDown events in the queue. | |
899 // We can't reset it if there is no pending event anymore, because we | |
900 // don't know if the following event is a Char event or not. | |
901 if (pending_key_events_) | |
902 suppress_next_char_events_ = false; | |
903 | |
904 // We can safely send following pending KeyUp and RawKeyDown events to | |
905 // the renderer, until we meet another Char event. | |
906 while (pending_key_events_ && | |
907 key_queue_[i].type != WebKeyboardEvent::Char) { | |
908 --pending_key_events_; | |
909 ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent)); | |
910 } | |
911 } | |
769 } | 912 } |
770 } | 913 } |
914 | |
915 // Reset |death_flag_| to NULL, otherwise it'll point to an invalid memory | |
916 // address after returning from this method. | |
917 death_flag_ = NULL; | |
771 } | 918 } |
772 | 919 |
773 void RenderWidgetHost::OnMsgFocus() { | 920 void RenderWidgetHost::OnMsgFocus() { |
774 // Only the user can focus a RenderWidgetHost. | 921 // Only the user can focus a RenderWidgetHost. |
775 process()->ReceivedBadMessage(ViewHostMsg_Focus__ID); | 922 process()->ReceivedBadMessage(ViewHostMsg_Focus__ID); |
776 } | 923 } |
777 | 924 |
778 void RenderWidgetHost::OnMsgBlur() { | 925 void RenderWidgetHost::OnMsgBlur() { |
779 if (view_) { | 926 if (view_) { |
780 view_->Blur(); | 927 view_->Blur(); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
894 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); | 1041 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); |
895 } | 1042 } |
896 | 1043 |
897 void RenderWidgetHost::Replace(const string16& word) { | 1044 void RenderWidgetHost::Replace(const string16& word) { |
898 Send(new ViewMsg_Replace(routing_id_, word)); | 1045 Send(new ViewMsg_Replace(routing_id_, word)); |
899 } | 1046 } |
900 | 1047 |
901 void RenderWidgetHost::AdvanceToNextMisspelling() { | 1048 void RenderWidgetHost::AdvanceToNextMisspelling() { |
902 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); | 1049 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); |
903 } | 1050 } |
OLD | NEW |