OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 <stddef.h> | 5 #include <stddef.h> |
6 | 6 |
7 #include <new> | 7 #include <new> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 28 matching lines...) Expand all Loading... |
39 | 39 |
40 namespace content { | 40 namespace content { |
41 namespace { | 41 namespace { |
42 | 42 |
43 const unsigned kRafAlignedEnabledTouch = 1; | 43 const unsigned kRafAlignedEnabledTouch = 1; |
44 const unsigned kRafAlignedEnabledMouse = 1 << 1; | 44 const unsigned kRafAlignedEnabledMouse = 1 << 1; |
45 | 45 |
46 // Simulate a 16ms frame signal. | 46 // Simulate a 16ms frame signal. |
47 const base::TimeDelta kFrameInterval = base::TimeDelta::FromMilliseconds(16); | 47 const base::TimeDelta kFrameInterval = base::TimeDelta::FromMilliseconds(16); |
48 | 48 |
49 const int kTestRoutingID = 13; | |
50 const char* kCoalescedCountHistogram = | 49 const char* kCoalescedCountHistogram = |
51 "Event.MainThreadEventQueue.CoalescedCount"; | 50 "Event.MainThreadEventQueue.CoalescedCount"; |
52 | 51 |
53 } // namespace | 52 } // namespace |
54 | 53 |
55 class HandledTask { | 54 class HandledTask { |
56 public: | 55 public: |
57 virtual ~HandledTask() {} | 56 virtual ~HandledTask() {} |
58 | 57 |
59 virtual blink::WebCoalescedInputEvent* taskAsEvent() = 0; | 58 virtual blink::WebCoalescedInputEvent* taskAsEvent() = 0; |
60 virtual unsigned taskAsClosure() const = 0; | 59 virtual unsigned taskAsClosure() const = 0; |
61 }; | 60 }; |
62 | 61 |
63 class HandledEvent : public HandledTask { | 62 class HandledEvent : public HandledTask { |
64 public: | 63 public: |
65 explicit HandledEvent(const blink::WebCoalescedInputEvent* event) | 64 explicit HandledEvent(const blink::WebCoalescedInputEvent& event) |
66 : event_(event->Event(), event->GetCoalescedEventsPointers()) {} | 65 : event_(event.Event(), event.GetCoalescedEventsPointers()) {} |
67 ~HandledEvent() override {} | 66 ~HandledEvent() override {} |
68 | 67 |
69 blink::WebCoalescedInputEvent* taskAsEvent() override { return &event_; } | 68 blink::WebCoalescedInputEvent* taskAsEvent() override { return &event_; } |
70 unsigned taskAsClosure() const override { | 69 unsigned taskAsClosure() const override { |
71 NOTREACHED(); | 70 NOTREACHED(); |
72 return 0; | 71 return 0; |
73 } | 72 } |
74 | 73 |
75 private: | 74 private: |
76 blink::WebCoalescedInputEvent event_; | 75 blink::WebCoalescedInputEvent event_; |
77 }; | 76 }; |
78 | 77 |
79 class HandledClosure : public HandledTask { | 78 class HandledClosure : public HandledTask { |
80 public: | 79 public: |
81 explicit HandledClosure(unsigned closure_id) : closure_id_(closure_id) {} | 80 explicit HandledClosure(unsigned closure_id) : closure_id_(closure_id) {} |
82 ~HandledClosure() override {} | 81 ~HandledClosure() override {} |
83 | 82 |
84 blink::WebCoalescedInputEvent* taskAsEvent() override { | 83 blink::WebCoalescedInputEvent* taskAsEvent() override { |
85 NOTREACHED(); | 84 NOTREACHED(); |
86 return nullptr; | 85 return nullptr; |
87 } | 86 } |
88 unsigned taskAsClosure() const override { return closure_id_; } | 87 unsigned taskAsClosure() const override { return closure_id_; } |
89 | 88 |
90 private: | 89 private: |
91 unsigned closure_id_; | 90 unsigned closure_id_; |
92 }; | 91 }; |
93 | 92 |
94 class MainThreadEventQueueTest : public testing::TestWithParam<unsigned>, | 93 class MainThreadEventQueueTest; |
95 public MainThreadEventQueueClient { | 94 |
| 95 class MainThreadEventQueueForTest : public MainThreadEventQueue { |
| 96 public: |
| 97 MainThreadEventQueueForTest( |
| 98 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
| 99 blink::scheduler::RendererScheduler* scheduler, |
| 100 MainThreadEventQueueTest* test) |
| 101 : MainThreadEventQueue(main_task_runner, scheduler), test_(test) {} |
| 102 |
| 103 InputEventAckState HandleEventOnMainThread( |
| 104 const blink::WebCoalescedInputEvent& event, |
| 105 const ui::LatencyInfo& latency, |
| 106 InputEventDispatchType dispatch_type) override; |
| 107 |
| 108 void SendInputEventAck(blink::WebInputEvent::Type type, |
| 109 InputEventAckState ack_result, |
| 110 uint32_t touch_event_id) override; |
| 111 |
| 112 void NeedsMainFrame() override; |
| 113 |
| 114 private: |
| 115 ~MainThreadEventQueueForTest() override {} |
| 116 |
| 117 MainThreadEventQueueTest* test_; |
| 118 }; |
| 119 |
| 120 class MainThreadEventQueueTest : public testing::TestWithParam<unsigned> { |
96 public: | 121 public: |
97 MainThreadEventQueueTest() | 122 MainThreadEventQueueTest() |
98 : main_task_runner_(new base::TestSimpleTaskRunner()), | 123 : main_task_runner_(new base::TestSimpleTaskRunner()), |
99 raf_aligned_input_setting_(GetParam()), | 124 raf_aligned_input_setting_(GetParam()), |
100 needs_main_frame_(false), | 125 needs_main_frame_(false), |
101 closure_count_(0) { | 126 closure_count_(0) { |
102 std::vector<base::StringPiece> features; | 127 std::vector<base::StringPiece> features; |
103 std::vector<base::StringPiece> disabled_features; | 128 std::vector<base::StringPiece> disabled_features; |
104 if (raf_aligned_input_setting_ & kRafAlignedEnabledTouch) { | 129 if (raf_aligned_input_setting_ & kRafAlignedEnabledTouch) { |
105 features.push_back(features::kRafAlignedTouchInputEvents.name); | 130 features.push_back(features::kRafAlignedTouchInputEvents.name); |
106 } else { | 131 } else { |
107 disabled_features.push_back(features::kRafAlignedTouchInputEvents.name); | 132 disabled_features.push_back(features::kRafAlignedTouchInputEvents.name); |
108 } | 133 } |
109 if (raf_aligned_input_setting_ & kRafAlignedEnabledMouse) { | 134 if (raf_aligned_input_setting_ & kRafAlignedEnabledMouse) { |
110 features.push_back(features::kRafAlignedMouseInputEvents.name); | 135 features.push_back(features::kRafAlignedMouseInputEvents.name); |
111 } else { | 136 } else { |
112 disabled_features.push_back(features::kRafAlignedMouseInputEvents.name); | 137 disabled_features.push_back(features::kRafAlignedMouseInputEvents.name); |
113 } | 138 } |
114 | 139 |
115 feature_list_.InitFromCommandLine(base::JoinString(features, ","), | 140 feature_list_.InitFromCommandLine(base::JoinString(features, ","), |
116 base::JoinString(disabled_features, ",")); | 141 base::JoinString(disabled_features, ",")); |
117 } | 142 } |
118 | 143 |
119 void SetUp() override { | 144 void SetUp() override { |
120 queue_ = new MainThreadEventQueue(kTestRoutingID, this, main_task_runner_, | 145 queue_ = new MainThreadEventQueueForTest(main_task_runner_, |
121 &renderer_scheduler_); | 146 &renderer_scheduler_, this); |
122 } | |
123 | |
124 void HandleEventOnMainThread(int routing_id, | |
125 const blink::WebCoalescedInputEvent* event, | |
126 const ui::LatencyInfo& latency, | |
127 InputEventDispatchType type) override { | |
128 EXPECT_EQ(kTestRoutingID, routing_id); | |
129 | |
130 std::unique_ptr<HandledTask> handled_event(new HandledEvent(event)); | |
131 handled_tasks_.push_back(std::move(handled_event)); | |
132 | |
133 queue_->EventHandled(event->Event().GetType(), | |
134 blink::WebInputEventResult::kHandledApplication, | |
135 INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
136 } | |
137 | |
138 void SendInputEventAck(int routing_id, | |
139 blink::WebInputEvent::Type type, | |
140 InputEventAckState ack_result, | |
141 uint32_t touch_event_id) override { | |
142 additional_acked_events_.push_back(touch_event_id); | |
143 } | 147 } |
144 | 148 |
145 bool HandleEvent(WebInputEvent& event, InputEventAckState ack_result) { | 149 bool HandleEvent(WebInputEvent& event, InputEventAckState ack_result) { |
146 return queue_->HandleEvent(ui::WebInputEventTraits::Clone(event), | 150 return queue_->HandleEvent(ui::WebInputEventTraits::Clone(event), |
147 ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 151 ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, |
148 ack_result); | 152 ack_result); |
149 } | 153 } |
150 | 154 |
151 void RunClosure(unsigned closure_id) { | 155 void RunClosure(unsigned closure_id) { |
152 std::unique_ptr<HandledTask> closure(new HandledClosure(closure_id)); | 156 std::unique_ptr<HandledTask> closure(new HandledClosure(closure_id)); |
153 handled_tasks_.push_back(std::move(closure)); | 157 handled_tasks_.push_back(std::move(closure)); |
154 } | 158 } |
155 | 159 |
156 void QueueClosure() { | 160 void QueueClosure() { |
157 unsigned closure_id = ++closure_count_; | 161 unsigned closure_id = ++closure_count_; |
158 queue_->QueueClosure(base::Bind(&MainThreadEventQueueTest::RunClosure, | 162 queue_->QueueClosure(base::Bind(&MainThreadEventQueueTest::RunClosure, |
159 base::Unretained(this), closure_id)); | 163 base::Unretained(this), closure_id)); |
160 } | 164 } |
161 | 165 |
162 void NeedsMainFrame(int routing_id) override { needs_main_frame_ = true; } | |
163 | |
164 MainThreadEventQueueTaskList& event_queue() { | 166 MainThreadEventQueueTaskList& event_queue() { |
165 return queue_->shared_state_.events_; | 167 return queue_->shared_state_.events_; |
166 } | 168 } |
167 | 169 |
168 bool last_touch_start_forced_nonblocking_due_to_fling() { | 170 bool last_touch_start_forced_nonblocking_due_to_fling() { |
169 return queue_->last_touch_start_forced_nonblocking_due_to_fling_; | 171 return queue_->last_touch_start_forced_nonblocking_due_to_fling_; |
170 } | 172 } |
171 | 173 |
172 void set_enable_fling_passive_listener_flag(bool enable_flag) { | 174 void set_enable_fling_passive_listener_flag(bool enable_flag) { |
173 queue_->enable_fling_passive_listener_flag_ = enable_flag; | 175 queue_->enable_fling_passive_listener_flag_ = enable_flag; |
(...skipping 10 matching lines...) Expand all Loading... |
184 | 186 |
185 void RunSimulatedRafOnce() { | 187 void RunSimulatedRafOnce() { |
186 if (needs_main_frame_) { | 188 if (needs_main_frame_) { |
187 needs_main_frame_ = false; | 189 needs_main_frame_ = false; |
188 frame_time_ += kFrameInterval; | 190 frame_time_ += kFrameInterval; |
189 queue_->DispatchRafAlignedInput(frame_time_); | 191 queue_->DispatchRafAlignedInput(frame_time_); |
190 } | 192 } |
191 } | 193 } |
192 | 194 |
193 protected: | 195 protected: |
| 196 friend class MainThreadEventQueueForTest; |
194 base::test::ScopedFeatureList feature_list_; | 197 base::test::ScopedFeatureList feature_list_; |
195 scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; | 198 scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; |
196 blink::scheduler::MockRendererScheduler renderer_scheduler_; | 199 blink::scheduler::MockRendererScheduler renderer_scheduler_; |
197 scoped_refptr<MainThreadEventQueue> queue_; | 200 scoped_refptr<MainThreadEventQueueForTest> queue_; |
198 std::vector<std::unique_ptr<HandledTask>> handled_tasks_; | 201 std::vector<std::unique_ptr<HandledTask>> handled_tasks_; |
199 | 202 |
200 std::vector<uint32_t> additional_acked_events_; | 203 std::vector<uint32_t> additional_acked_events_; |
201 int raf_aligned_input_setting_; | 204 int raf_aligned_input_setting_; |
202 bool needs_main_frame_; | 205 bool needs_main_frame_; |
203 base::TimeTicks frame_time_; | 206 base::TimeTicks frame_time_; |
204 unsigned closure_count_; | 207 unsigned closure_count_; |
205 }; | 208 }; |
206 | 209 |
| 210 InputEventAckState MainThreadEventQueueForTest::HandleEventOnMainThread( |
| 211 const blink::WebCoalescedInputEvent& event, |
| 212 const ui::LatencyInfo& latency, |
| 213 InputEventDispatchType dispatch_type) { |
| 214 std::unique_ptr<HandledTask> handled_event(new HandledEvent(event)); |
| 215 test_->handled_tasks_.push_back(std::move(handled_event)); |
| 216 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; |
| 217 } |
| 218 |
| 219 void MainThreadEventQueueForTest::SendInputEventAck( |
| 220 blink::WebInputEvent::Type type, |
| 221 InputEventAckState ack_result, |
| 222 uint32_t touch_event_id) { |
| 223 test_->additional_acked_events_.push_back(touch_event_id); |
| 224 } |
| 225 |
| 226 void MainThreadEventQueueForTest::NeedsMainFrame() { |
| 227 test_->needs_main_frame_ = true; |
| 228 } |
| 229 |
207 TEST_P(MainThreadEventQueueTest, NonBlockingWheel) { | 230 TEST_P(MainThreadEventQueueTest, NonBlockingWheel) { |
208 base::HistogramTester histogram_tester; | 231 base::HistogramTester histogram_tester; |
209 | 232 |
210 WebMouseWheelEvent kEvents[4] = { | 233 WebMouseWheelEvent kEvents[4] = { |
211 SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false), | 234 SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false), |
212 SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false), | 235 SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false), |
213 SyntheticWebMouseWheelEventBuilder::Build(30, 30, 0, 53, 1, false), | 236 SyntheticWebMouseWheelEventBuilder::Build(30, 30, 0, 53, 1, false), |
214 SyntheticWebMouseWheelEventBuilder::Build(30, 30, 0, 53, 1, false), | 237 SyntheticWebMouseWheelEventBuilder::Build(30, 30, 0, 53, 1, false), |
215 }; | 238 }; |
216 | 239 |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 } | 896 } |
874 | 897 |
875 // The boolean parameterized test varies whether rAF aligned input | 898 // The boolean parameterized test varies whether rAF aligned input |
876 // is enabled or not. | 899 // is enabled or not. |
877 INSTANTIATE_TEST_CASE_P( | 900 INSTANTIATE_TEST_CASE_P( |
878 MainThreadEventQueueTests, | 901 MainThreadEventQueueTests, |
879 MainThreadEventQueueTest, | 902 MainThreadEventQueueTest, |
880 testing::Range(0u, | 903 testing::Range(0u, |
881 (kRafAlignedEnabledTouch | kRafAlignedEnabledMouse) + 1)); | 904 (kRafAlignedEnabledTouch | kRafAlignedEnabledMouse) + 1)); |
882 | 905 |
883 class DummyMainThreadEventQueueClient : public MainThreadEventQueueClient { | |
884 void HandleEventOnMainThread(int routing_id, | |
885 const blink::WebCoalescedInputEvent* event, | |
886 const ui::LatencyInfo& latency, | |
887 InputEventDispatchType dispatch_type) override {} | |
888 | |
889 void SendInputEventAck(int routing_id, | |
890 blink::WebInputEvent::Type type, | |
891 InputEventAckState ack_result, | |
892 uint32_t touch_event_id) override {} | |
893 | |
894 void NeedsMainFrame(int routing_id) override {} | |
895 }; | |
896 | |
897 class MainThreadEventQueueInitializationTest | 906 class MainThreadEventQueueInitializationTest |
898 : public testing::Test { | 907 : public testing::Test { |
899 public: | 908 public: |
900 MainThreadEventQueueInitializationTest() | 909 MainThreadEventQueueInitializationTest() |
901 : field_trial_list_(new base::FieldTrialList(nullptr)) {} | 910 : field_trial_list_(new base::FieldTrialList(nullptr)) {} |
902 | 911 |
903 base::TimeDelta main_thread_responsiveness_threshold() { | 912 base::TimeDelta main_thread_responsiveness_threshold() { |
904 return queue_->main_thread_responsiveness_threshold_; | 913 return queue_->main_thread_responsiveness_threshold_; |
905 } | 914 } |
906 | 915 |
907 bool enable_non_blocking_due_to_main_thread_responsiveness_flag() { | 916 bool enable_non_blocking_due_to_main_thread_responsiveness_flag() { |
908 return queue_->enable_non_blocking_due_to_main_thread_responsiveness_flag_; | 917 return queue_->enable_non_blocking_due_to_main_thread_responsiveness_flag_; |
909 } | 918 } |
910 | 919 |
911 protected: | 920 protected: |
912 scoped_refptr<MainThreadEventQueue> queue_; | 921 scoped_refptr<MainThreadEventQueue> queue_; |
913 base::test::ScopedFeatureList feature_list_; | 922 base::test::ScopedFeatureList feature_list_; |
914 blink::scheduler::MockRendererScheduler renderer_scheduler_; | 923 blink::scheduler::MockRendererScheduler renderer_scheduler_; |
915 scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; | 924 scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; |
916 std::unique_ptr<base::FieldTrialList> field_trial_list_; | 925 std::unique_ptr<base::FieldTrialList> field_trial_list_; |
917 DummyMainThreadEventQueueClient dummy_main_thread_event_queue_client_; | 926 }; |
| 927 |
| 928 class MockMainThreadEventQueue : public MainThreadEventQueue { |
| 929 public: |
| 930 MockMainThreadEventQueue( |
| 931 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
| 932 blink::scheduler::RendererScheduler* scheduler) |
| 933 : MainThreadEventQueue(main_task_runner, scheduler) {} |
| 934 |
| 935 MOCK_METHOD3(HandleEventOnMainThread, |
| 936 InputEventAckState(const blink::WebCoalescedInputEvent& event, |
| 937 const ui::LatencyInfo& latency, |
| 938 InputEventDispatchType dispatch_type)); |
| 939 |
| 940 MOCK_METHOD3(SendInputEventAck, |
| 941 void(blink::WebInputEvent::Type type, |
| 942 InputEventAckState ack_result, |
| 943 uint32_t touch_event_id)); |
| 944 MOCK_METHOD0(NeedsMainFrame, void()); |
| 945 |
| 946 private: |
| 947 ~MockMainThreadEventQueue() override {} |
918 }; | 948 }; |
919 | 949 |
920 TEST_F(MainThreadEventQueueInitializationTest, | 950 TEST_F(MainThreadEventQueueInitializationTest, |
921 MainThreadResponsivenessThresholdEnabled) { | 951 MainThreadResponsivenessThresholdEnabled) { |
922 feature_list_.InitFromCommandLine( | 952 feature_list_.InitFromCommandLine( |
923 features::kMainThreadBusyScrollIntervention.name, ""); | 953 features::kMainThreadBusyScrollIntervention.name, ""); |
924 | 954 |
925 base::FieldTrialList::CreateFieldTrial( | 955 base::FieldTrialList::CreateFieldTrial( |
926 "MainThreadResponsivenessScrollIntervention", "Enabled123"); | 956 "MainThreadResponsivenessScrollIntervention", "Enabled123"); |
927 queue_ = new MainThreadEventQueue(kTestRoutingID, | 957 queue_ = |
928 &dummy_main_thread_event_queue_client_, | 958 new MockMainThreadEventQueue(main_task_runner_, &renderer_scheduler_); |
929 main_task_runner_, &renderer_scheduler_); | |
930 EXPECT_TRUE(enable_non_blocking_due_to_main_thread_responsiveness_flag()); | 959 EXPECT_TRUE(enable_non_blocking_due_to_main_thread_responsiveness_flag()); |
931 EXPECT_EQ(base::TimeDelta::FromMilliseconds(123), | 960 EXPECT_EQ(base::TimeDelta::FromMilliseconds(123), |
932 main_thread_responsiveness_threshold()); | 961 main_thread_responsiveness_threshold()); |
933 } | 962 } |
934 | 963 |
935 TEST_F(MainThreadEventQueueInitializationTest, | 964 TEST_F(MainThreadEventQueueInitializationTest, |
936 MainThreadResponsivenessThresholdDisabled) { | 965 MainThreadResponsivenessThresholdDisabled) { |
937 base::FieldTrialList::CreateFieldTrial( | 966 base::FieldTrialList::CreateFieldTrial( |
938 "MainThreadResponsivenessScrollIntervention", "Control"); | 967 "MainThreadResponsivenessScrollIntervention", "Control"); |
939 queue_ = new MainThreadEventQueue(kTestRoutingID, | 968 queue_ = |
940 &dummy_main_thread_event_queue_client_, | 969 new MockMainThreadEventQueue(main_task_runner_, &renderer_scheduler_); |
941 main_task_runner_, &renderer_scheduler_); | |
942 EXPECT_FALSE(enable_non_blocking_due_to_main_thread_responsiveness_flag()); | 970 EXPECT_FALSE(enable_non_blocking_due_to_main_thread_responsiveness_flag()); |
943 EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), | 971 EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), |
944 main_thread_responsiveness_threshold()); | 972 main_thread_responsiveness_threshold()); |
945 } | 973 } |
946 | 974 |
947 TEST_P(MainThreadEventQueueTest, QueuingTwoClosures) { | 975 TEST_P(MainThreadEventQueueTest, QueuingTwoClosures) { |
948 EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 976 EXPECT_FALSE(main_task_runner_->HasPendingTask()); |
949 EXPECT_EQ(0u, event_queue().size()); | 977 EXPECT_EQ(0u, event_queue().size()); |
950 | 978 |
951 QueueClosure(); | 979 QueueClosure(); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 static_cast<const WebTouchEvent&>( | 1125 static_cast<const WebTouchEvent&>( |
1098 handled_tasks_.at(0)->taskAsEvent()->Event()) | 1126 handled_tasks_.at(0)->taskAsEvent()->Event()) |
1099 .dispatch_type); | 1127 .dispatch_type); |
1100 EXPECT_EQ(WebInputEvent::kBlocking, | 1128 EXPECT_EQ(WebInputEvent::kBlocking, |
1101 static_cast<const WebTouchEvent&>( | 1129 static_cast<const WebTouchEvent&>( |
1102 handled_tasks_.at(1)->taskAsEvent()->Event()) | 1130 handled_tasks_.at(1)->taskAsEvent()->Event()) |
1103 .dispatch_type); | 1131 .dispatch_type); |
1104 } | 1132 } |
1105 | 1133 |
1106 } // namespace content | 1134 } // namespace content |
OLD | NEW |