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/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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |