Chromium Code Reviews| 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 |