Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_mac.h" | 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" |
| 6 | 6 |
| 7 #include <Cocoa/Cocoa.h> | 7 #include <Cocoa/Cocoa.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 #include <tuple> | 10 #include <tuple> |
| 11 | 11 |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/mac/scoped_nsautorelease_pool.h" | 13 #include "base/mac/scoped_nsautorelease_pool.h" |
| 14 #include "base/mac/sdk_forward_declarations.h" | 14 #include "base/mac/sdk_forward_declarations.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/test/histogram_tester.h" | 18 #include "base/test/histogram_tester.h" |
| 19 #include "base/test/simple_test_tick_clock.h" | 19 #include "base/test/simple_test_tick_clock.h" |
| 20 #include "content/browser/browser_thread_impl.h" | 20 #include "content/browser/browser_thread_impl.h" |
| 21 #include "content/browser/compositor/test/no_transport_image_transport_factory.h " | 21 #include "content/browser/compositor/test/no_transport_image_transport_factory.h " |
| 22 #include "content/browser/frame_host/render_widget_host_view_guest.h" | 22 #include "content/browser/frame_host/render_widget_host_view_guest.h" |
| 23 #include "content/browser/gpu/compositor_util.h" | 23 #include "content/browser/gpu/compositor_util.h" |
| 24 #include "content/browser/renderer_host/render_widget_host_delegate.h" | 24 #include "content/browser/renderer_host/render_widget_host_delegate.h" |
| 25 #include "content/browser/renderer_host/text_input_manager.h" | |
| 25 #include "content/common/input/web_input_event_traits.h" | 26 #include "content/common/input/web_input_event_traits.h" |
| 26 #include "content/common/input_messages.h" | 27 #include "content/common/input_messages.h" |
| 28 #include "content/common/text_input_state.h" | |
| 27 #include "content/common/view_messages.h" | 29 #include "content/common/view_messages.h" |
| 28 #include "content/public/browser/notification_types.h" | 30 #include "content/public/browser/notification_types.h" |
| 29 #include "content/public/browser/render_widget_host_view_mac_delegate.h" | 31 #include "content/public/browser/render_widget_host_view_mac_delegate.h" |
| 30 #include "content/public/common/content_switches.h" | 32 #include "content/public/common/content_switches.h" |
| 31 #include "content/public/test/mock_render_process_host.h" | 33 #include "content/public/test/mock_render_process_host.h" |
| 32 #include "content/public/test/test_browser_context.h" | 34 #include "content/public/test/test_browser_context.h" |
| 33 #include "content/public/test/test_utils.h" | 35 #include "content/public/test/test_utils.h" |
| 34 #include "content/test/test_render_view_host.h" | 36 #include "content/test/test_render_view_host.h" |
| 35 #include "gpu/ipc/common/gpu_messages.h" | 37 #include "gpu/ipc/common/gpu_messages.h" |
| 36 #include "testing/gmock/include/gmock/gmock.h" | 38 #include "testing/gmock/include/gmock/gmock.h" |
| (...skipping 1209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1246 // Send an initial wheel event for scrolling by 3 lines. | 1248 // Send an initial wheel event for scrolling by 3 lines. |
| 1247 // Verify that Event.Latency.OS.MOUSE_WHEEL histogram is computed properly. | 1249 // Verify that Event.Latency.OS.MOUSE_WHEEL histogram is computed properly. |
| 1248 NSEvent* wheelEvent = MockScrollWheelEventWithPhase(@selector(phaseBegan),3); | 1250 NSEvent* wheelEvent = MockScrollWheelEventWithPhase(@selector(phaseBegan),3); |
| 1249 [view->cocoa_view() scrollWheel:wheelEvent]; | 1251 [view->cocoa_view() scrollWheel:wheelEvent]; |
| 1250 histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); | 1252 histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); |
| 1251 | 1253 |
| 1252 // Clean up. | 1254 // Clean up. |
| 1253 host->ShutdownAndDestroyWidget(true); | 1255 host->ShutdownAndDestroyWidget(true); |
| 1254 } | 1256 } |
| 1255 | 1257 |
| 1258 // This class is used for IME-related unit tests which verify correctness of IME | |
| 1259 // for pages with multiple RWHVs. | |
| 1260 class InputMethodMacTest : public RenderWidgetHostViewMacTest { | |
| 1261 public: | |
| 1262 InputMethodMacTest() {} | |
| 1263 ~InputMethodMacTest() override {} | |
| 1264 void SetUp() override { | |
| 1265 RenderWidgetHostViewMacTest::SetUp(); | |
| 1266 | |
| 1267 // Initializing a child frame's view. | |
| 1268 child_process_host_ = new MockRenderProcessHost(&browser_context_); | |
|
erikchen
2016/08/11 16:25:30
Do we need unique_ptrs to prevent leaks?
EhsanK
2016/08/11 20:42:58
The |child_widget_| is being destroyed in TearDown
erikchen
2016/08/11 20:52:38
Point taken.
That's a really opaque cleanup path
| |
| 1269 RenderWidgetHostDelegate* rwh_delegate = | |
| 1270 RenderWidgetHostImpl::From(rvh()->GetWidget())->delegate(); | |
| 1271 child_widget_ = new RenderWidgetHostImpl( | |
| 1272 rwh_delegate, child_process_host_, | |
| 1273 child_process_host_->GetNextRoutingID(), false); | |
| 1274 child_view_ = new TestRenderWidgetHostView(child_widget_); | |
| 1275 text_input_manager_ = rwh_delegate->GetTextInputManager(); | |
| 1276 tab_widget_ = RenderWidgetHostImpl::From(rvh()->GetWidget()); | |
| 1277 } | |
| 1278 | |
| 1279 void TearDown() override { | |
| 1280 child_widget_->ShutdownAndDestroyWidget(true); | |
| 1281 | |
| 1282 RenderWidgetHostViewMacTest::TearDown(); | |
| 1283 } | |
| 1284 | |
| 1285 void SetTextInputType(RenderWidgetHostViewBase* view, | |
| 1286 ui::TextInputType type) { | |
| 1287 TextInputState state; | |
| 1288 state.type = type; | |
| 1289 view->TextInputStateChanged(state); | |
| 1290 } | |
| 1291 | |
| 1292 IPC::TestSink& tab_sink() { return process()->sink(); } | |
| 1293 IPC::TestSink& child_sink() { return child_process_host_->sink(); } | |
| 1294 TextInputManager* text_input_manager() { return text_input_manager_; } | |
| 1295 RenderWidgetHostViewBase* tab_view() { return rwhv_mac_; } | |
| 1296 RenderWidgetHostImpl* tab_widget() { return tab_widget_; } | |
| 1297 | |
| 1298 protected: | |
| 1299 MockRenderProcessHost* child_process_host_; | |
| 1300 RenderWidgetHostImpl* child_widget_; | |
| 1301 TestRenderWidgetHostView* child_view_; | |
| 1302 | |
| 1303 private: | |
| 1304 TestBrowserContext browser_context_; | |
| 1305 TextInputManager* text_input_manager_; | |
| 1306 RenderWidgetHostImpl* tab_widget_; | |
| 1307 | |
| 1308 DISALLOW_COPY_AND_ASSIGN(InputMethodMacTest); | |
| 1309 }; | |
| 1310 | |
| 1311 // This test will verify that calling unmarkText on the cocoa view will lead to | |
| 1312 // a confirm composition IPC for the corresponding active widget. | |
| 1313 TEST_F(InputMethodMacTest, UnmarkText) { | |
| 1314 // Make the child view active and then call unmarkText on the view (Note that | |
| 1315 // |RenderWidgetHostViewCocoa::handlingKeyDown_| is false so calling | |
| 1316 // unmarkText would lead to an IPC. This assumption is made in other similar | |
| 1317 // tests as well). We should observe an IPC being sent to the |child_widget_|. | |
| 1318 SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT); | |
| 1319 EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget()); | |
| 1320 child_sink().ClearMessages(); | |
| 1321 [rwhv_cocoa_ unmarkText]; | |
| 1322 EXPECT_TRUE(!!child_sink().GetFirstMessageMatching( | |
| 1323 InputMsg_ImeConfirmComposition::ID)); | |
| 1324 | |
| 1325 // Repeat the same steps for the tab's view . | |
| 1326 SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); | |
| 1327 EXPECT_EQ(tab_widget(), text_input_manager()->GetActiveWidget()); | |
| 1328 tab_sink().ClearMessages(); | |
| 1329 [rwhv_cocoa_ unmarkText]; | |
| 1330 EXPECT_TRUE( | |
| 1331 !!tab_sink().GetFirstMessageMatching(InputMsg_ImeConfirmComposition::ID)); | |
| 1332 } | |
| 1333 | |
| 1334 // This test makes sure that calling setMarkedText on the cocoa view will lead | |
| 1335 // to a set composition IPC for the corresponding active widget. | |
| 1336 TEST_F(InputMethodMacTest, SetMarkedText) { | |
| 1337 // Some values for the call to setMarkedText. | |
| 1338 NSString* text = [[NSString alloc] initWithString:@"sample text"]; | |
| 1339 NSRange selectedRange = NSMakeRange(0, 4); | |
|
erikchen
2016/08/11 16:25:30
wrap in scoped_nsobject. Ditto for other ObjC allo
Avi (use Gerrit)
2016/08/11 17:25:31
This is re line 1338, the NSString, not the NSRang
EhsanK
2016/08/11 20:42:58
Acknowledged.
EhsanK
2016/08/11 20:42:58
Acknowledged.
| |
| 1340 NSRange replacementRange = NSMakeRange(0, 1); | |
| 1341 | |
| 1342 // Make the child view active and then call setMarkedText with some values. We | |
| 1343 // should observe an IPC being sent to the |child_widget_|. | |
| 1344 SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT); | |
| 1345 EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget()); | |
| 1346 child_sink().ClearMessages(); | |
| 1347 [rwhv_cocoa_ setMarkedText:text | |
| 1348 selectedRange:selectedRange | |
| 1349 replacementRange:replacementRange]; | |
| 1350 EXPECT_TRUE( | |
| 1351 !!child_sink().GetFirstMessageMatching(InputMsg_ImeSetComposition::ID)); | |
| 1352 | |
| 1353 // Repeat the same steps for the tab's view. | |
| 1354 SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); | |
| 1355 EXPECT_EQ(tab_widget(), text_input_manager()->GetActiveWidget()); | |
| 1356 tab_sink().ClearMessages(); | |
| 1357 [rwhv_cocoa_ setMarkedText:text | |
| 1358 selectedRange:selectedRange | |
| 1359 replacementRange:replacementRange]; | |
| 1360 EXPECT_TRUE( | |
| 1361 !!tab_sink().GetFirstMessageMatching(InputMsg_ImeSetComposition::ID)); | |
| 1362 } | |
| 1363 | |
| 1364 // This test verifies that calling insertText on the cocoa view will lead to a | |
| 1365 // confirm composition IPC sent to the active widget. | |
| 1366 TEST_F(InputMethodMacTest, InsetText) { | |
| 1367 // Some values for the call to insertText. | |
| 1368 NSString* text = [[NSString alloc] initWithString:@"sample text"]; | |
| 1369 NSRange replacementRange = NSMakeRange(0, 1); | |
| 1370 | |
| 1371 // Make the child view active and then call insertText with some values. We | |
| 1372 // should observe an IPC being sent to the |child_widget_|. | |
| 1373 SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT); | |
| 1374 EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget()); | |
| 1375 child_sink().ClearMessages(); | |
| 1376 [rwhv_cocoa_ insertText:text replacementRange:replacementRange]; | |
| 1377 EXPECT_TRUE(!!child_sink().GetFirstMessageMatching( | |
| 1378 InputMsg_ImeConfirmComposition::ID)); | |
| 1379 | |
| 1380 // Repeat the same steps for the tab's view. | |
| 1381 SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); | |
| 1382 EXPECT_EQ(tab_widget(), text_input_manager()->GetActiveWidget()); | |
| 1383 [rwhv_cocoa_ insertText:text replacementRange:replacementRange]; | |
| 1384 EXPECT_TRUE( | |
| 1385 !!tab_sink().GetFirstMessageMatching(InputMsg_ImeConfirmComposition::ID)); | |
| 1386 } | |
| 1387 | |
| 1388 // This test makes sure that calling confirmComposition on the cocoa view will | |
| 1389 // lead to a confirm composition IPC for a the corresponding active widget. | |
| 1390 TEST_F(InputMethodMacTest, ConfirmComposition) { | |
| 1391 // Some values for the call to setMarkedText. | |
| 1392 NSString* text = [[NSString alloc] initWithString:@"sample text"]; | |
| 1393 NSRange selectedRange = NSMakeRange(0, 4); | |
| 1394 NSRange replacementRange = NSMakeRange(0, 1); | |
| 1395 | |
| 1396 // Make child view active and then call confirmComposition. We should observe | |
| 1397 // an IPC being sent to the |child_widget_|. | |
| 1398 SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT); | |
| 1399 EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget()); | |
| 1400 child_sink().ClearMessages(); | |
| 1401 // In order to confirm composition, we must first have some marked text. So, | |
| 1402 // we will first call setMarkedText on cocoa view. This would lead to a set | |
| 1403 // composition IPC in the sink, but it doesn't matter since we will be looking | |
| 1404 // for a confirm composition IPC for this test. | |
| 1405 [rwhv_cocoa_ setMarkedText:text | |
| 1406 selectedRange:selectedRange | |
| 1407 replacementRange:replacementRange]; | |
| 1408 [rwhv_cocoa_ confirmComposition]; | |
| 1409 EXPECT_TRUE(!!child_sink().GetFirstMessageMatching( | |
| 1410 InputMsg_ImeConfirmComposition::ID)); | |
| 1411 | |
| 1412 // Repeat the same steps for the tab's view. | |
| 1413 SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); | |
| 1414 EXPECT_EQ(tab_widget(), text_input_manager()->GetActiveWidget()); | |
| 1415 tab_sink().ClearMessages(); | |
| 1416 [rwhv_cocoa_ setMarkedText:text | |
| 1417 selectedRange:selectedRange | |
| 1418 replacementRange:replacementRange]; | |
| 1419 [rwhv_cocoa_ confirmComposition]; | |
| 1420 EXPECT_TRUE( | |
| 1421 !!tab_sink().GetFirstMessageMatching(InputMsg_ImeConfirmComposition::ID)); | |
| 1422 } | |
| 1423 | |
| 1256 } // namespace content | 1424 } // namespace content |
| OLD | NEW |