Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Side by Side Diff: chrome/browser/renderer_host/render_widget_host.cc

Issue 235039: Fix conflicts between accelerator keys and HTML DOM accesskeys.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698