OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "blimp/engine/feature/engine_render_widget_feature.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "base/numerics/safe_conversions.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "blimp/common/create_blimp_message.h" | |
14 #include "blimp/common/proto/blimp_message.pb.h" | |
15 #include "blimp/common/proto/compositor.pb.h" | |
16 #include "blimp/common/proto/render_widget.pb.h" | |
17 #include "blimp/net/input_message_generator.h" | |
18 #include "blimp/net/test_common.h" | |
19 #include "content/public/browser/render_widget_host.h" | |
20 #include "content/public/common/form_field_data.h" | |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/test_completion_callback.h" | |
23 #include "testing/gmock/include/gmock/gmock.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 #include "third_party/WebKit/public/platform/WebInputEvent.h" | |
26 #include "ui/base/ime/dummy_text_input_client.h" | |
27 | |
28 using testing::_; | |
29 using testing::InSequence; | |
30 using testing::Sequence; | |
31 | |
32 namespace blimp { | |
33 namespace engine { | |
34 | |
35 namespace { | |
36 | |
37 class MockHostRenderWidgetMessageDelegate | |
38 : public EngineRenderWidgetFeature::RenderWidgetMessageDelegate { | |
39 public: | |
40 // EngineRenderWidgetFeature implementation. | |
41 void OnWebGestureEvent( | |
42 content::RenderWidgetHost* render_widget_host, | |
43 std::unique_ptr<blink::WebGestureEvent> event) override { | |
44 MockableOnWebGestureEvent(render_widget_host); | |
45 } | |
46 | |
47 void OnCompositorMessageReceived( | |
48 content::RenderWidgetHost* render_widget_host, | |
49 const std::vector<uint8_t>& message) override { | |
50 MockableOnCompositorMessageReceived(render_widget_host, message); | |
51 } | |
52 | |
53 MOCK_METHOD1(MockableOnWebGestureEvent, | |
54 void(content::RenderWidgetHost* render_widget_host)); | |
55 MOCK_METHOD2(MockableOnCompositorMessageReceived, | |
56 void(content::RenderWidgetHost* render_widget_host, | |
57 const std::vector<uint8_t>& message)); | |
58 }; | |
59 | |
60 class MockRenderWidgetHost | |
61 : public content::RenderWidgetHost { | |
62 public: | |
63 MockRenderWidgetHost() {} | |
64 ~MockRenderWidgetHost() override {} | |
65 void UpdateTextDirection(blink::WebTextDirection direction) override {} | |
66 void NotifyTextDirection() override {} | |
67 void Focus() override {} | |
68 void Blur() override {} | |
69 void SetActive(bool active) override {} | |
70 void CopyFromBackingStore(const gfx::Rect& src_rect, | |
71 const gfx::Size& accelerated_dst_size, | |
72 const content::ReadbackRequestCallback& callback, | |
73 const SkColorType color_type) override {} | |
74 bool CanCopyFromBackingStore() override { return false; } | |
75 void LockBackingStore() override {} | |
76 void UnlockBackingStore() override {} | |
77 void ForwardMouseEvent( | |
78 const blink::WebMouseEvent& mouse_event) override {} | |
79 void ForwardWheelEvent( | |
80 const blink::WebMouseWheelEvent& wheel_event) override {} | |
81 void ForwardKeyboardEvent( | |
82 const content::NativeWebKeyboardEvent& key_event) override {} | |
83 void ForwardGestureEvent( | |
84 const blink::WebGestureEvent& gesture_event) override {} | |
85 content::RenderProcessHost* GetProcess() const override { return nullptr; } | |
86 int GetRoutingID() const override { return 0; } | |
87 content::RenderWidgetHostView* GetView() const override { return nullptr; } | |
88 bool IsLoading() const override { return false; } | |
89 void RestartHangMonitorTimeoutIfNecessary() override {} | |
90 void DisableHangMonitorForTesting() override {} | |
91 void SetIgnoreInputEvents(bool ignore_input_events) override {} | |
92 void WasResized() override {} | |
93 void AddKeyPressEventCallback( | |
94 const KeyPressEventCallback& callback) override {} | |
95 void RemoveKeyPressEventCallback( | |
96 const KeyPressEventCallback& callback) override {} | |
97 void AddMouseEventCallback(const MouseEventCallback& callback) override {} | |
98 void RemoveMouseEventCallback(const MouseEventCallback& callback) override {} | |
99 void AddInputEventObserver(InputEventObserver* observer) override {} | |
100 void RemoveInputEventObserver(InputEventObserver* observer) override {} | |
101 void GetScreenInfo(content::ScreenInfo* result) override {} | |
102 void HandleCompositorProto(const std::vector<uint8_t>& proto) override {} | |
103 | |
104 bool Send(IPC::Message* msg) override { return false; } | |
105 }; | |
106 | |
107 class MockTextInputClient : public ui::DummyTextInputClient { | |
108 public: | |
109 MockTextInputClient() : DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT) {} | |
110 | |
111 bool GetTextFromRange(const gfx::Range& range, | |
112 base::string16* text) const override { | |
113 *text = base::string16(base::ASCIIToUTF16("green apple")); | |
114 return false; | |
115 } | |
116 }; | |
117 | |
118 MATCHER_P(CompMsgEquals, contents, "") { | |
119 if (contents.size() != arg.size()) | |
120 return false; | |
121 | |
122 return memcmp(contents.data(), arg.data(), contents.size()) == 0; | |
123 } | |
124 | |
125 MATCHER_P3(BlimpCompMsgEquals, tab_id, rw_id, contents, "") { | |
126 if (contents.size() != arg.compositor().payload().size()) | |
127 return false; | |
128 | |
129 if (memcmp(contents.data(), | |
130 arg.compositor().payload().data(), | |
131 contents.size()) != 0) { | |
132 return false; | |
133 } | |
134 | |
135 return arg.compositor().render_widget_id() == rw_id && | |
136 arg.target_tab_id() == tab_id; | |
137 } | |
138 | |
139 MATCHER_P3(BlimpRWMsgEquals, tab_id, rw_id, message_type, "") { | |
140 return arg.render_widget().render_widget_id() == rw_id && | |
141 arg.target_tab_id() == tab_id && | |
142 arg.render_widget().type() == message_type; | |
143 } | |
144 | |
145 MATCHER_P2(BlimpImeMsgEquals, tab_id, message_type, "") { | |
146 return arg.target_tab_id() == tab_id && arg.ime().type() == message_type; | |
147 } | |
148 | |
149 MATCHER_P5(BlimpImeMsgEquals, | |
150 tab_id, | |
151 rwid, | |
152 message_type, | |
153 text, | |
154 text_input_type, | |
155 "") { | |
156 return arg.target_tab_id() == tab_id && | |
157 arg.ime().render_widget_id() == rwid && | |
158 arg.ime().type() == message_type && | |
159 arg.ime().ime_text().compare(text) == 0 && | |
160 arg.ime().text_input_type() == text_input_type; | |
161 } | |
162 | |
163 void SendInputMessage(BlimpMessageProcessor* processor, | |
164 int tab_id, | |
165 int rw_id) { | |
166 blink::WebGestureEvent input_event(blink::WebGestureEvent::Type::GestureTap, | |
167 blink::WebInputEvent::NoModifiers, | |
168 blink::WebInputEvent::TimeStampForTesting); | |
169 | |
170 InputMessageGenerator generator; | |
171 std::unique_ptr<BlimpMessage> message = | |
172 generator.GenerateMessage(input_event); | |
173 message->set_target_tab_id(tab_id); | |
174 message->mutable_input()->set_render_widget_id(rw_id); | |
175 | |
176 net::TestCompletionCallback cb; | |
177 processor->ProcessMessage(std::move(message), cb.callback()); | |
178 EXPECT_EQ(net::OK, cb.WaitForResult()); | |
179 } | |
180 | |
181 void SendCompositorMessage(BlimpMessageProcessor* processor, | |
182 int tab_id, | |
183 int rw_id, | |
184 const std::vector<uint8_t>& payload) { | |
185 CompositorMessage* details; | |
186 std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id); | |
187 details->set_render_widget_id(rw_id); | |
188 details->set_payload(payload.data(), base::checked_cast<int>(payload.size())); | |
189 net::TestCompletionCallback cb; | |
190 processor->ProcessMessage(std::move(message), cb.callback()); | |
191 EXPECT_EQ(net::OK, cb.WaitForResult()); | |
192 } | |
193 | |
194 } // namespace | |
195 | |
196 class EngineRenderWidgetFeatureTest : public testing::Test { | |
197 public: | |
198 EngineRenderWidgetFeatureTest() : feature_(&settings_) {} | |
199 | |
200 void SetUp() override { | |
201 render_widget_message_sender_ = new MockBlimpMessageProcessor; | |
202 feature_.set_render_widget_message_sender( | |
203 base::WrapUnique(render_widget_message_sender_)); | |
204 compositor_message_sender_ = new MockBlimpMessageProcessor; | |
205 feature_.set_compositor_message_sender( | |
206 base::WrapUnique(compositor_message_sender_)); | |
207 ime_message_sender_ = new MockBlimpMessageProcessor; | |
208 feature_.set_ime_message_sender(base::WrapUnique(ime_message_sender_)); | |
209 feature_.SetDelegate(1, &delegate1_); | |
210 feature_.SetDelegate(2, &delegate2_); | |
211 } | |
212 | |
213 protected: | |
214 MockBlimpMessageProcessor* render_widget_message_sender_; | |
215 MockBlimpMessageProcessor* compositor_message_sender_; | |
216 MockBlimpMessageProcessor* ime_message_sender_; | |
217 MockRenderWidgetHost render_widget_host1_; | |
218 MockRenderWidgetHost render_widget_host2_; | |
219 MockHostRenderWidgetMessageDelegate delegate1_; | |
220 MockHostRenderWidgetMessageDelegate delegate2_; | |
221 MockTextInputClient text_input_client_; | |
222 SettingsManager settings_; | |
223 EngineRenderWidgetFeature feature_; | |
224 }; | |
225 | |
226 TEST_F(EngineRenderWidgetFeatureTest, DelegateCallsOK) { | |
227 std::vector<uint8_t> payload = { 'd', 'a', 'v', 'i', 'd' }; | |
228 | |
229 EXPECT_CALL(*render_widget_message_sender_, MockableProcessMessage( | |
230 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::CREATED), _)) | |
231 .Times(1); | |
232 EXPECT_CALL(*render_widget_message_sender_, MockableProcessMessage( | |
233 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::INITIALIZE), _)) | |
234 .Times(1); | |
235 EXPECT_CALL(*render_widget_message_sender_, MockableProcessMessage( | |
236 BlimpRWMsgEquals(2, 2, RenderWidgetMessage::CREATED), _)) | |
237 .Times(1); | |
238 | |
239 EXPECT_CALL(delegate1_, | |
240 MockableOnCompositorMessageReceived(&render_widget_host1_, | |
241 CompMsgEquals(payload))) | |
242 .Times(1); | |
243 EXPECT_CALL(delegate1_, MockableOnWebGestureEvent(&render_widget_host1_)) | |
244 .Times(1); | |
245 EXPECT_CALL(delegate2_, | |
246 MockableOnCompositorMessageReceived(&render_widget_host2_, | |
247 CompMsgEquals(payload))) | |
248 .Times(1); | |
249 | |
250 feature_.OnRenderWidgetCreated(1, &render_widget_host1_); | |
251 feature_.OnRenderWidgetInitialized(1, &render_widget_host1_); | |
252 feature_.OnRenderWidgetCreated(2, &render_widget_host2_); | |
253 SendCompositorMessage(&feature_, 1, 1, payload); | |
254 SendInputMessage(&feature_, 1, 1); | |
255 SendCompositorMessage(&feature_, 2, 2, payload); | |
256 } | |
257 | |
258 TEST_F(EngineRenderWidgetFeatureTest, ImeRequestSentCorrectly) { | |
259 EXPECT_CALL( | |
260 *ime_message_sender_, | |
261 MockableProcessMessage(BlimpImeMsgEquals(2, 1, ImeMessage::SHOW_IME, | |
262 std::string("green apple"), 1), | |
263 _)); | |
264 | |
265 EXPECT_CALL( | |
266 *ime_message_sender_, | |
267 MockableProcessMessage(BlimpImeMsgEquals(2, ImeMessage::HIDE_IME), _)); | |
268 | |
269 content::FormFieldData field; | |
270 field.text = "green apple"; | |
271 field.placeholder = "fruit name"; | |
272 field.text_input_type = ui::TEXT_INPUT_TYPE_TEXT; | |
273 | |
274 feature_.OnRenderWidgetCreated(2, &render_widget_host1_); | |
275 feature_.SendShowImeRequest(2, &render_widget_host1_, field); | |
276 feature_.SendHideImeRequest(2, &render_widget_host1_); | |
277 } | |
278 | |
279 TEST_F(EngineRenderWidgetFeatureTest, DropsStaleMessages) { | |
280 InSequence sequence; | |
281 std::vector<uint8_t> payload = { 'f', 'u', 'n' }; | |
282 std::vector<uint8_t> new_payload = {'n', 'o', ' ', 'f', 'u', 'n'}; | |
283 | |
284 EXPECT_CALL(*render_widget_message_sender_, | |
285 MockableProcessMessage( | |
286 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::CREATED), _)); | |
287 EXPECT_CALL(delegate1_, | |
288 MockableOnCompositorMessageReceived(&render_widget_host1_, | |
289 CompMsgEquals(payload))); | |
290 EXPECT_CALL(*render_widget_message_sender_, | |
291 MockableProcessMessage( | |
292 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::DELETED), _)); | |
293 EXPECT_CALL(*render_widget_message_sender_, | |
294 MockableProcessMessage( | |
295 BlimpRWMsgEquals(1, 2, RenderWidgetMessage::CREATED), _)); | |
296 | |
297 EXPECT_CALL(delegate1_, | |
298 MockableOnCompositorMessageReceived(&render_widget_host2_, | |
299 CompMsgEquals(new_payload))); | |
300 EXPECT_CALL(delegate1_, MockableOnWebGestureEvent(&render_widget_host2_)); | |
301 | |
302 feature_.OnRenderWidgetCreated(1, &render_widget_host1_); | |
303 SendCompositorMessage(&feature_, 1, 1, payload); | |
304 feature_.OnRenderWidgetDeleted(1, &render_widget_host1_); | |
305 feature_.OnRenderWidgetCreated(1, &render_widget_host2_); | |
306 | |
307 // These next three calls should be dropped. | |
308 SendCompositorMessage(&feature_, 1, 1, payload); | |
309 SendCompositorMessage(&feature_, 1, 1, payload); | |
310 SendInputMessage(&feature_, 1, 1); | |
311 | |
312 SendCompositorMessage(&feature_, 1, 2, new_payload); | |
313 SendInputMessage(&feature_, 1, 2); | |
314 } | |
315 | |
316 TEST_F(EngineRenderWidgetFeatureTest, RepliesHaveCorrectRenderWidgetId) { | |
317 Sequence delegate1_sequence; | |
318 Sequence delegate2_sequence; | |
319 std::vector<uint8_t> payload = { 'a', 'b', 'c', 'd' }; | |
320 | |
321 EXPECT_CALL(*render_widget_message_sender_, | |
322 MockableProcessMessage( | |
323 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::CREATED), _)) | |
324 .InSequence(delegate1_sequence); | |
325 EXPECT_CALL(*render_widget_message_sender_, | |
326 MockableProcessMessage( | |
327 BlimpRWMsgEquals(1, 1, RenderWidgetMessage::INITIALIZE), _)) | |
328 .InSequence(delegate1_sequence); | |
329 EXPECT_CALL(*compositor_message_sender_, | |
330 MockableProcessMessage(BlimpCompMsgEquals(1, 1, payload), _)) | |
331 .InSequence(delegate1_sequence); | |
332 | |
333 EXPECT_CALL(*render_widget_message_sender_, | |
334 MockableProcessMessage( | |
335 BlimpRWMsgEquals(2, 2, RenderWidgetMessage::CREATED), _)) | |
336 .InSequence(delegate2_sequence); | |
337 EXPECT_CALL(*render_widget_message_sender_, | |
338 MockableProcessMessage( | |
339 BlimpRWMsgEquals(2, 2, RenderWidgetMessage::DELETED), _)) | |
340 .InSequence(delegate2_sequence); | |
341 | |
342 feature_.OnRenderWidgetCreated(1, &render_widget_host1_); | |
343 feature_.OnRenderWidgetCreated(2, &render_widget_host2_); | |
344 feature_.OnRenderWidgetInitialized(1, &render_widget_host1_); | |
345 feature_.OnRenderWidgetDeleted(2, &render_widget_host2_); | |
346 feature_.SendCompositorMessage(1, &render_widget_host1_, payload); | |
347 } | |
348 | |
349 } // namespace engine | |
350 } // namespace blimp | |
OLD | NEW |