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

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

Issue 435002: Optimize the rendering when there are pending key events.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years 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
« no previous file with comments | « chrome/browser/renderer_host/render_widget_host.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/histogram.h" 8 #include "base/histogram.h"
9 #include "base/keyboard_codes.h" 9 #include "base/keyboard_codes.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 44
45 // How long to (synchronously) wait for the renderer to respond with a 45 // How long to (synchronously) wait for the renderer to respond with a
46 // PaintRect message, when our backing-store is invalid, before giving up and 46 // PaintRect message, when our backing-store is invalid, before giving up and
47 // returning a null or incorrectly sized backing-store from GetBackingStore. 47 // returning a null or incorrectly sized backing-store from GetBackingStore.
48 // This timeout impacts the "choppiness" of our window resize perf. 48 // This timeout impacts the "choppiness" of our window resize perf.
49 static const int kPaintMsgTimeoutMS = 40; 49 static const int kPaintMsgTimeoutMS = 40;
50 50
51 // How long to wait before we consider a renderer hung. 51 // How long to wait before we consider a renderer hung.
52 static const int kHungRendererDelayMs = 20000; 52 static const int kHungRendererDelayMs = 20000;
53 53
54 // How long a PaintRect_ACK message can be postponed at most, in milliseconds.
55 static const int kPaintACKMsgMaxPostponedDurationMS = 1000;
56
54 /////////////////////////////////////////////////////////////////////////////// 57 ///////////////////////////////////////////////////////////////////////////////
55 // RenderWidgetHost 58 // RenderWidgetHost
56 59
57 RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, 60 RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
58 int routing_id) 61 int routing_id)
59 : renderer_initialized_(false), 62 : renderer_initialized_(false),
60 view_(NULL), 63 view_(NULL),
61 process_(process), 64 process_(process),
62 painting_observer_(NULL), 65 painting_observer_(NULL),
63 routing_id_(routing_id), 66 routing_id_(routing_id),
64 is_loading_(false), 67 is_loading_(false),
65 is_hidden_(false), 68 is_hidden_(false),
66 repaint_ack_pending_(false), 69 repaint_ack_pending_(false),
67 resize_ack_pending_(false), 70 resize_ack_pending_(false),
68 mouse_move_pending_(false), 71 mouse_move_pending_(false),
69 needs_repainting_on_restore_(false), 72 needs_repainting_on_restore_(false),
70 is_unresponsive_(false), 73 is_unresponsive_(false),
71 in_get_backing_store_(false), 74 in_get_backing_store_(false),
72 view_being_painted_(false), 75 view_being_painted_(false),
73 text_direction_updated_(false), 76 text_direction_updated_(false),
74 text_direction_(WebKit::WebTextDirectionLeftToRight), 77 text_direction_(WebKit::WebTextDirectionLeftToRight),
75 text_direction_canceled_(false), 78 text_direction_canceled_(false),
76 pending_key_events_(false), 79 pending_key_events_(0),
77 suppress_next_char_events_(false), 80 suppress_next_char_events_(false),
81 paint_ack_postponed_(false),
78 death_flag_(NULL) { 82 death_flag_(NULL) {
79 if (routing_id_ == MSG_ROUTING_NONE) 83 if (routing_id_ == MSG_ROUTING_NONE)
80 routing_id_ = process_->GetNextRoutingID(); 84 routing_id_ = process_->GetNextRoutingID();
81 85
82 process_->Attach(this, routing_id_); 86 process_->Attach(this, routing_id_);
83 // Because the widget initializes as is_hidden_ == false, 87 // Because the widget initializes as is_hidden_ == false,
84 // tell the process host that we're alive. 88 // tell the process host that we're alive.
85 process_->WidgetRestored(); 89 process_->WidgetRestored();
86 } 90 }
87 91
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
526 530
527 void RenderWidgetHost::RendererExited() { 531 void RenderWidgetHost::RendererExited() {
528 // Clearing this flag causes us to re-create the renderer when recovering 532 // Clearing this flag causes us to re-create the renderer when recovering
529 // from a crashed renderer. 533 // from a crashed renderer.
530 renderer_initialized_ = false; 534 renderer_initialized_ = false;
531 535
532 // Must reset these to ensure that mouse move events work with a new renderer. 536 // Must reset these to ensure that mouse move events work with a new renderer.
533 mouse_move_pending_ = false; 537 mouse_move_pending_ = false;
534 next_mouse_move_.reset(); 538 next_mouse_move_.reset();
535 539
540 // Must reset these to ensure that keyboard events work with a new renderer.
541 key_queue_.clear();
542 pending_key_events_ = 0;
543 suppress_next_char_events_ = false;
544
536 // Reset some fields in preparation for recovering from a crash. 545 // Reset some fields in preparation for recovering from a crash.
537 resize_ack_pending_ = false; 546 resize_ack_pending_ = false;
547 repaint_ack_pending_ = false;
548 paint_ack_postponed_ = false;
549
538 in_flight_size_.SetSize(0, 0); 550 in_flight_size_.SetSize(0, 0);
539 current_size_.SetSize(0, 0); 551 current_size_.SetSize(0, 0);
540 is_hidden_ = false; 552 is_hidden_ = false;
541 553
542 if (view_) { 554 if (view_) {
543 view_->RenderViewGone(); 555 view_->RenderViewGone();
544 view_ = NULL; // The View should be deleted by RenderViewGone. 556 view_ = NULL; // The View should be deleted by RenderViewGone.
545 } 557 }
546 558
547 BackingStoreManager::RemoveBackingStore(this); 559 BackingStoreManager::RemoveBackingStore(this);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) { 674 void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) {
663 // Note that we ignore the position. 675 // Note that we ignore the position.
664 if (view_) { 676 if (view_) {
665 view_->SetSize(pos.size()); 677 view_->SetSize(pos.size());
666 Send(new ViewMsg_Move_ACK(routing_id_)); 678 Send(new ViewMsg_Move_ACK(routing_id_));
667 } 679 }
668 } 680 }
669 681
670 void RenderWidgetHost::OnMsgPaintRect( 682 void RenderWidgetHost::OnMsgPaintRect(
671 const ViewHostMsg_PaintRect_Params& params) { 683 const ViewHostMsg_PaintRect_Params& params) {
684 // We shouldn't receive PaintRect message when the last PaintRect_ACK has not
685 // been sent to the renderer yet.
686 DCHECK(!paint_ack_postponed_);
687
672 TimeTicks paint_start = TimeTicks::Now(); 688 TimeTicks paint_start = TimeTicks::Now();
673 689
674 // Update our knowledge of the RenderWidget's size. 690 // Update our knowledge of the RenderWidget's size.
675 current_size_ = params.view_size; 691 current_size_ = params.view_size;
676 692
677 bool is_resize_ack = 693 bool is_resize_ack =
678 ViewHostMsg_PaintRect_Flags::is_resize_ack(params.flags); 694 ViewHostMsg_PaintRect_Flags::is_resize_ack(params.flags);
679 695
680 // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since 696 // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since
681 // that will end up reaching GetBackingStore. 697 // that will end up reaching GetBackingStore.
(...skipping 26 matching lines...) Expand all
708 // bits. The view will read out of the backing store later to actually 724 // bits. The view will read out of the backing store later to actually
709 // draw to the screen. 725 // draw to the screen.
710 PaintBackingStoreRect(dib, params.bitmap_rect, params.view_size); 726 PaintBackingStoreRect(dib, params.bitmap_rect, params.view_size);
711 } 727 }
712 } 728 }
713 729
714 // ACK early so we can prefetch the next PaintRect if there is a next one. 730 // ACK early so we can prefetch the next PaintRect if there is a next one.
715 // This must be done AFTER we're done painting with the bitmap supplied by the 731 // This must be done AFTER we're done painting with the bitmap supplied by the
716 // renderer. This ACK is a signal to the renderer that the backing store can 732 // renderer. This ACK is a signal to the renderer that the backing store can
717 // be re-used, so the bitmap may be invalid after this call. 733 // be re-used, so the bitmap may be invalid after this call.
718 Send(new ViewMsg_PaintRect_ACK(routing_id_)); 734 //
735 // Postpone the ACK message until all pending key events have been sent to the
736 // renderer, so that the renderer can process the updates caused by the key
737 // events in batch.
738 if (pending_key_events_ > 0) {
739 paint_ack_postponed_ = true;
740 paint_ack_postponed_time_ = TimeTicks::Now();
741 } else {
742 Send(new ViewMsg_PaintRect_ACK(routing_id_));
743 }
719 744
720 // We don't need to update the view if the view is hidden. We must do this 745 // We don't need to update the view if the view is hidden. We must do this
721 // early return after the ACK is sent, however, or the renderer will not send 746 // early return after the ACK is sent, however, or the renderer will not send
722 // us more data. 747 // us more data.
723 if (is_hidden_) 748 if (is_hidden_)
724 return; 749 return;
725 750
726 // Now paint the view. Watch out: it might be destroyed already. 751 // Now paint the view. Watch out: it might be destroyed already.
727 if (view_) { 752 if (view_) {
728 view_->MovePluginWindows(params.plugin_window_moves); 753 view_->MovePluginWindows(params.plugin_window_moves);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
794 819
795 if (painting_observer_) 820 if (painting_observer_)
796 painting_observer_->WidgetDidUpdateBackingStore(this); 821 painting_observer_->WidgetDidUpdateBackingStore(this);
797 822
798 // Log the time delta for processing a scroll message. 823 // Log the time delta for processing a scroll message.
799 TimeDelta delta = TimeTicks::Now() - scroll_start; 824 TimeDelta delta = TimeTicks::Now() - scroll_start;
800 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta); 825 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgScrollRect", delta);
801 } 826 }
802 827
803 void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { 828 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
808 // Log the time delta for processing an input event. 829 // Log the time delta for processing an input event.
809 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; 830 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
810 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); 831 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta);
811 832
812 // Cancel pending hung renderer checks since the renderer is responsive. 833 // Cancel pending hung renderer checks since the renderer is responsive.
813 StopHangMonitorTimeout(); 834 StopHangMonitorTimeout();
814 835
815 void* iter = NULL; 836 void* iter = NULL;
816 int type = 0; 837 int type = 0;
817 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) 838 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) {
818 process()->ReceivedBadMessage(message.type()); 839 process()->ReceivedBadMessage(message.type());
819 840 } else if (type == WebInputEvent::MouseMove) {
820 if (type == WebInputEvent::MouseMove) {
821 mouse_move_pending_ = false; 841 mouse_move_pending_ = false;
822 842
823 // now, we can send the next mouse move event 843 // now, we can send the next mouse move event
824 if (next_mouse_move_.get()) { 844 if (next_mouse_move_.get()) {
825 DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove); 845 DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove);
826 ForwardMouseEvent(*next_mouse_move_); 846 ForwardMouseEvent(*next_mouse_move_);
827 } 847 }
848 } else if (WebInputEvent::isKeyboardEventType(type)) {
849 bool processed = false;
850 if (!message.ReadBool(&iter, &processed))
851 process()->ReceivedBadMessage(message.type());
852
853 ProcessKeyboardEventAck(type, processed);
828 } 854 }
829
830 if (WebInputEvent::isKeyboardEventType(type)) {
831 if (key_queue_.size() == 0) {
832 LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
833 << "don't seem to have sent it to the renderer!";
834 } else if (key_queue_.front().type != type) {
835 LOG(ERROR) << "We seem to have a different key type sent from "
836 << "the renderer. (" << key_queue_.front().type << " vs. "
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;
845 } else {
846 bool processed = false;
847 if (!message.ReadBool(&iter, &processed))
848 process()->ReceivedBadMessage(message.type());
849
850 NativeWebKeyboardEvent front_item = key_queue_.front();
851 key_queue_.pop_front();
852
853 bool processed_by_browser = false;
854 if (!processed) {
855 processed_by_browser = UnhandledKeyboardEvent(front_item);
856
857 // WARNING: This RenderWidgetHost can be deallocated at this point
858 // (i.e. in the case of Ctrl+W, where the call to
859 // UnhandledKeyboardEvent destroys this RenderWidgetHost).
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 }
912 }
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;
918 } 855 }
919 856
920 void RenderWidgetHost::OnMsgFocus() { 857 void RenderWidgetHost::OnMsgFocus() {
921 // Only the user can focus a RenderWidgetHost. 858 // Only the user can focus a RenderWidgetHost.
922 process()->ReceivedBadMessage(ViewHostMsg_Focus__ID); 859 process()->ReceivedBadMessage(ViewHostMsg_Focus__ID);
923 } 860 }
924 861
925 void RenderWidgetHost::OnMsgBlur() { 862 void RenderWidgetHost::OnMsgBlur() {
926 if (view_) { 863 if (view_) {
927 view_->Blur(); 864 view_->Blur();
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); 978 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible));
1042 } 979 }
1043 980
1044 void RenderWidgetHost::Replace(const string16& word) { 981 void RenderWidgetHost::Replace(const string16& word) {
1045 Send(new ViewMsg_Replace(routing_id_, word)); 982 Send(new ViewMsg_Replace(routing_id_, word));
1046 } 983 }
1047 984
1048 void RenderWidgetHost::AdvanceToNextMisspelling() { 985 void RenderWidgetHost::AdvanceToNextMisspelling() {
1049 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); 986 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_));
1050 } 987 }
988
989 void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) {
990 if (key_queue_.size() == 0) {
991 LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
992 << "don't seem to have sent it to the renderer!";
993 } else if (key_queue_.front().type != type) {
994 LOG(ERROR) << "We seem to have a different key type sent from "
995 << "the renderer. (" << key_queue_.front().type << " vs. "
996 << type << "). Ignoring event.";
997
998 // Something must be wrong. |key_queue_| must be cleared here to make sure
999 // the feedback loop for sending upcoming keyboard events can be resumed
1000 // correctly.
1001 key_queue_.clear();
1002 pending_key_events_ = 0;
1003 suppress_next_char_events_ = false;
1004 } else {
1005 // Track if |this| is destroyed or not.
1006 bool is_dead = false;
1007 death_flag_ = &is_dead;
1008
1009 NativeWebKeyboardEvent front_item = key_queue_.front();
1010 key_queue_.pop_front();
1011
1012 bool processed_by_browser = false;
1013 if (!processed) {
1014 processed_by_browser = UnhandledKeyboardEvent(front_item);
1015
1016 // WARNING: This RenderWidgetHost can be deallocated at this point
1017 // (i.e. in the case of Ctrl+W, where the call to
1018 // UnhandledKeyboardEvent destroys this RenderWidgetHost).
1019 }
1020
1021 // This RenderWidgetHost was already deallocated, we can't do anything
1022 // from now on, including resetting |death_flag_|. So just return.
1023 if (is_dead)
1024 return;
1025
1026 // Reset |death_flag_| to NULL, otherwise it'll point to an invalid memory
1027 // address after returning from this method.
1028 death_flag_ = NULL;
1029
1030 // Suppress the following Char events if the RawKeyDown event was handled
1031 // by the browser rather than the renderer.
1032 if (front_item.type == WebKeyboardEvent::RawKeyDown)
1033 suppress_next_char_events_ = processed_by_browser;
1034
1035 // If more than one key events in |key_queue_| were already sent to the
1036 // renderer but haven't got ACK messages yet, we must wait for ACK
1037 // messages of these key events before sending more key events to the
1038 // renderer.
1039 if (pending_key_events_ && key_queue_.size() == pending_key_events_) {
1040 size_t i = 0;
1041 if (suppress_next_char_events_) {
1042 // Suppress the sequence of pending Char events if preceding
1043 // RawKeyDown event was handled by the browser.
1044 while (pending_key_events_ &&
1045 key_queue_[0].type == WebKeyboardEvent::Char) {
1046 --pending_key_events_;
1047 key_queue_.pop_front();
1048 }
1049 } else {
1050 // Otherwise, send these pending Char events to the renderer.
1051 // Note: we can't remove them from |key_queue_|, as we still need to
1052 // wait for their ACK messages from the renderer.
1053 while (pending_key_events_ &&
1054 key_queue_[i].type == WebKeyboardEvent::Char) {
1055 --pending_key_events_;
1056 ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
1057 }
1058 }
1059
1060 // Reset |suppress_next_char_events_| if there is still one or more
1061 // pending KeyUp or RawKeyDown events in the queue.
1062 // We can't reset it if there is no pending event anymore, because we
1063 // don't know if the following event is a Char event or not.
1064 if (pending_key_events_)
1065 suppress_next_char_events_ = false;
1066
1067 // We can safely send following pending KeyUp and RawKeyDown events to
1068 // the renderer, until we meet another Char event.
1069 while (pending_key_events_ &&
1070 key_queue_[i].type != WebKeyboardEvent::Char) {
1071 --pending_key_events_;
1072 ForwardInputEvent(key_queue_[i++], sizeof(WebKeyboardEvent));
1073 }
1074 }
1075 }
1076
1077 // Send the pending PaintRect_ACK message after sending all pending key
1078 // events or after a certain duration, so that the renderer can process
1079 // the updates caused by the key events in batch.
1080 if (paint_ack_postponed_ && (pending_key_events_ == 0 ||
1081 (TimeTicks::Now() - paint_ack_postponed_time_).InMilliseconds() >
1082 kPaintACKMsgMaxPostponedDurationMS)) {
1083 paint_ack_postponed_ = false;
1084 Send(new ViewMsg_PaintRect_ACK(routing_id_));
1085 }
1086 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/render_widget_host.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698