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

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

Issue 1948343002: [reland] Browser Side Text Input State Tracking for OOPIF (Aura Only) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 6 months 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <vector>
6
7 #include "base/command_line.h"
8 #include "chrome/browser/ui/browser.h"
9 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "chrome/test/base/in_process_browser_test.h"
11 #include "chrome/test/base/ui_test_utils.h"
12 #include "content/public/browser/render_frame_host.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/test/browser_test_utils.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/test_utils.h"
18 #include "content/public/test/text_input_test_utils.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "ui/base/ime/text_input_client.h"
22 #include "ui/base/ime/text_input_mode.h"
23 #include "ui/base/ime/text_input_type.h"
24
25 #include "url/gurl.h"
26
27 // TODO(ekaramad): After fixing crbug.com/578168 for all platforms, the
28 // following tests should be activated for other platforms, e.g., Mac and
29 // Android (crbug.com/602723).
30 #ifdef USE_AURA
31 ///////////////////////////////////////////////////////////////////////////////
32 // TextInputManager and IME Tests
33 //
34 // The following tests verify the correctness of TextInputState tracking on the
Charlie Reis 2016/06/02 22:03:29 Can you add something about how this test is outsi
EhsanK 2016/06/03 17:00:33 Acknowledged.
35 // browser side. They also make sure the IME logic works correctly. The baseline
36 // for comparison is the default functionality in the non-OOPIF case (i.e., the
37 // legacy implementation in RWHV's other than RWHVCF.).
Charlie Reis 2016/06/02 22:03:29 nit: No period before the close paren.
EhsanK 2016/06/03 17:00:33 Done.
38
39 namespace {
40
41 // TextInputManager Observers
42
43 // A base class for observing the TextInputManager owned by the given
44 // WebContents. Subclasses could observe the TextInputManager for different
45 // changes. The class wraps a public test observer which accepts callbacks that
Charlie Reis 2016/06/02 22:03:29 nit: public tester
EhsanK 2016/06/03 17:00:33 Done.
46 // are run after specific changes in TextInputManager. Different observers can
47 // be subclassed from this by providing their specific callback methods.
48 class TextInputManagerObserverBase {
49 public:
50 explicit TextInputManagerObserverBase(content::WebContents* web_contents)
51 : tester_(new content::TextInputManagerTester(web_contents)),
52 success_(false) {}
53
54 virtual ~TextInputManagerObserverBase() {}
55
56 // Wait for derived class's definition of success.
57 void Wait() {
58 if (success_)
59 return;
60 message_loop_runner_ = new content::MessageLoopRunner();
61 message_loop_runner_->Run();
62 }
63
64 bool success() const { return success_; }
65
66 protected:
67 content::TextInputManagerTester* tester() { return tester_.get(); }
68
69 void OnSuccess() {
70 success_ = true;
71 if (message_loop_runner_)
72 message_loop_runner_->Quit();
73 }
74
75 private:
76 std::unique_ptr<content::TextInputManagerTester> tester_;
77 bool success_;
78 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
79
80 DISALLOW_COPY_AND_ASSIGN(TextInputManagerObserverBase);
81 };
82
83 // This class observes TextInputManager for changes in |TextInputState.value|.
84 class TextInputManagerValueObserver : public TextInputManagerObserverBase {
85 public:
86 TextInputManagerValueObserver(content::WebContents* web_contents,
87 const std::string& expected_value)
88 : TextInputManagerObserverBase(web_contents),
89 expected_value_(expected_value) {
90 tester()->SetUpdateTextInputStateCalledCallback(base::Bind(
91 &TextInputManagerValueObserver::VerifyValue, base::Unretained(this)));
92 }
93
94 private:
95 void VerifyValue(content::TextInputManagerTester* text_input_manager_tester) {
96 ASSERT_EQ(tester(), text_input_manager_tester);
97 std::string value;
98 if (tester()->GetTextInputValue(&value) && expected_value_ == value)
99 OnSuccess();
100 }
101
102 std::string expected_value_;
103 };
104
105 // This class observes TextInputManager for changes in |TextInputState.type|.
106 class TextInputManagerTypeObserver : public TextInputManagerObserverBase {
107 public:
108 TextInputManagerTypeObserver(content::WebContents* web_contents,
109 ui::TextInputType expected_type)
110 : TextInputManagerObserverBase(web_contents),
111 expected_type_(expected_type) {
112 tester()->SetUpdateTextInputStateCalledCallback(base::Bind(
113 &TextInputManagerTypeObserver::VerifyType, base::Unretained(this)));
114 }
115
116 private:
117 void VerifyType(content::TextInputManagerTester* text_input_manager_tester) {
118 ASSERT_EQ(tester(), text_input_manager_tester);
119 ui::TextInputType type =
120 tester()->GetTextInputType(&type) ? type : ui::TEXT_INPUT_TYPE_NONE;
121 if (expected_type_ == type)
122 OnSuccess();
123 }
124
125 ui::TextInputType expected_type_;
126 };
127
128 // This class observes TextInputManager for the first change in TextInputState.
129 class TextInputManagerChangeObserver : public TextInputManagerObserverBase {
130 public:
131 explicit TextInputManagerChangeObserver(content::WebContents* web_contents)
132 : TextInputManagerObserverBase(web_contents) {
133 tester()->SetUpdateTextInputStateCalledCallback(base::Bind(
134 &TextInputManagerChangeObserver::VerifyChange, base::Unretained(this)));
135 }
136
137 private:
138 void VerifyChange(
139 content::TextInputManagerTester* text_input_manager_tester) {
140 ASSERT_EQ(tester(), text_input_manager_tester);
141 if (tester()->IsTextInputStateChanged())
142 OnSuccess();
143 }
144 };
145
146 // This class observes |TextInputState.type| for a specific RWHV.
147 class ViewTextInputTypeObserver : public TextInputManagerObserverBase {
148 public:
149 explicit ViewTextInputTypeObserver(content::WebContents* web_contents,
150 content::RenderWidgetHostView* rwhv,
151 ui::TextInputType expected_type)
152 : TextInputManagerObserverBase(web_contents),
153 web_contents_(web_contents),
154 view_(rwhv),
155 expected_type_(expected_type) {
156 tester()->SetUpdateTextInputStateCalledCallback(base::Bind(
157 &ViewTextInputTypeObserver::VerifyType, base::Unretained(this)));
158 }
159
160 private:
161 void VerifyType(content::TextInputManagerTester* tester) {
162 ui::TextInputType type;
163 if (!content::GetTextInputTypeForView(web_contents_, view_, &type))
164 return;
165 if (expected_type_ == type)
166 OnSuccess();
167 }
168
169 content::WebContents* web_contents_;
170 content::RenderWidgetHostView* view_;
171 ui::TextInputType expected_type_;
172 };
173
174 } // namespace
175
176 // Main class for all TextInputState and IME related tests.
177 class SitePerProcessTextInputManagerTest : public InProcessBrowserTest {
178 public:
179 SitePerProcessTextInputManagerTest() {}
180 ~SitePerProcessTextInputManagerTest() override {}
181
182 void SetUpCommandLine(base::CommandLine* command_line) override {
183 content::IsolateAllSitesForTesting(command_line);
184 }
185
186 void SetUpOnMainThread() override {
187 host_resolver()->AddRule("*", "127.0.0.1");
188
189 // Add content/test/data 'cross_site_iframe_factory.html'.
190 embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
191
192 ASSERT_TRUE(embedded_test_server()->Start());
193 }
194
195 protected:
196 content::WebContents* active_contents() {
197 return browser()->tab_strip_model()->GetActiveWebContents();
198 }
199
200 // static
201 // Adds an <input> field to a given frame by executing javascript code.
202 // The input can be added as the first element or the last element of
203 // |document.body|.
204 static void AddInputFieldToFrame(content::RenderFrameHost* rfh,
205 const std::string& type,
206 const std::string& value,
207 bool append_as_first_child) {
208 std::string script = base::StringPrintf(
209 "var input = document.createElement('input');"
210 "input.setAttribute('type', '%s');"
211 "input.setAttribute('value', '%s');"
212 "document.body.%s;",
213 type.c_str(), value.c_str(),
214 append_as_first_child ? "insertBefore(input, document.body.firstChild)"
215 : "appendChild(input)");
216 EXPECT_TRUE(ExecuteScript(rfh, script));
217 }
218
219 // Uses 'cross_site_iframe_factory.html'. The main frame's domain is
220 // 'a.com'.
221 void CreateIframePage(const std::string& structure) {
222 std::string path = base::StringPrintf("/cross_site_iframe_factory.html?%s",
223 structure.c_str());
224 GURL main_url(embedded_test_server()->GetURL("a.com", path));
225 ui_test_utils::NavigateToURL(browser(), main_url);
226 }
227
228 // Iteratively uses ChildFrameAt(frame, i) to get the i-th child frame
229 // inside frame. For example, for 'a(b(c, d(e)))', [0] returns b, and
230 // [0, 1, 0] returns e;
231 content::RenderFrameHost* GetFrame(const std::vector<size_t>& indices) {
232 content::RenderFrameHost* current = active_contents()->GetMainFrame();
233 for (size_t index : indices)
234 current = ChildFrameAt(current, index);
235 return current;
236 }
237
238 private:
239 DISALLOW_COPY_AND_ASSIGN(SitePerProcessTextInputManagerTest);
240 };
241
242 // The following test loads a page with multiple nested <iframe> elements which
243 // are in or out of process with the main frame. Then an <input> field with
244 // unique value is added to every single frame on the frame tree. The test then
245 // creates a sequence of tab presses and verifies that after each key press, the
246 // TextInputState.value reflects that of the focused input, i.e., the
247 // TextInputManager is correctly tracking TextInputState across frames.
248 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
249 TrackStateWhenSwitchingFocusedFrames) {
250 CreateIframePage("a(a,b,c(a,b,d(e, f)),g)");
251 std::vector<std::string> values{
252 "main", "node_a", "node_b", "node_c", "node_c_a",
253 "node_c_b", "node_c_d", "node_c_d_e", "node_c_d_f", "node_g"};
254
255 // TODO(ekaramad): This should not be needed and uniform initialization should
256 // work. However, in some bots, this is failing.
257 using vector = std::vector<size_t>;
258
259 std::vector<content::RenderFrameHost*> frames{
260 GetFrame(vector{}), GetFrame(vector{0}),
261 GetFrame(vector{1}), GetFrame(vector{2}),
262 GetFrame(vector{2, 0}), GetFrame(vector{2, 1}),
263 GetFrame(vector{2, 2}), GetFrame(vector{2, 2, 0}),
264 GetFrame(vector{2, 2, 1}), GetFrame(vector{3})};
265
266 for (size_t i = 0; i < frames.size(); ++i)
267 AddInputFieldToFrame(frames[i], "text", values[i], true);
268
269 for (size_t i = 0; i < frames.size(); ++i) {
270 TextInputManagerValueObserver observer(active_contents(), values[i]);
271 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false,
272 false);
273 observer.Wait();
274 }
275 }
276
277 // The following test loads a page with two OOPIFs. An <input> is added to both
278 // frames and tab key is pressed until the one in the second OOPIF is focused.
279 // Then, the renderer processes for both frames are crashed. The test verifies
280 // that the TextInputManager stops tracking the RWHVs as well as properly
281 // resets the TextInputState after the second (active) RWHV goes away.
282 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
283 StopTrackingCrashedChildFrame) {
284 CreateIframePage("a(b, c)");
285 std::vector<std::string> values{"node_b", "node_c"};
286 using vector = std::vector<size_t>;
287 std::vector<content::RenderFrameHost*> frames{GetFrame(vector{0}),
288 GetFrame(vector{1})};
289
290 for (size_t i = 0; i < frames.size(); ++i)
291 AddInputFieldToFrame(frames[i], "text", values[i], true);
292
293 // Tab into both inputs and make sure we correctly receive their
294 // TextInputState. For the second tab two IPCs arrive: one from the first
295 // frame to set the state to none, and another one from the second frame to
296 // set it to TEXT. To avoid the race between them, we shall also observe the
297 // first frame setting its state to NONE after the second tab.
298 ViewTextInputTypeObserver view_type_observer(
299 active_contents(), frames[0]->GetView(), ui::TEXT_INPUT_TYPE_NONE);
300
301 for (size_t i = 0; i < frames.size(); ++i) {
302 TextInputManagerValueObserver observer(active_contents(), values[i]);
303 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false,
304 false);
305 observer.Wait();
306 }
307
308 // Make sure that the first view has set its TextInputState.type to NONE.
309 view_type_observer.Wait();
310
311 // Verify that we are tracking the TextInputState from the first frame.
312 content::RenderWidgetHostView* first_view = frames[0]->GetView();
313 ui::TextInputType first_view_type;
314 EXPECT_TRUE(content::GetTextInputTypeForView(active_contents(), first_view,
315 &first_view_type));
316 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, first_view_type);
317
318 // Now that the second frame's <input> is focused, we crash the first frame
319 // and observe that text input state is updated for the view.
320 std::unique_ptr<content::TestRenderWidgetHostViewDestructionObserver>
321 destruction_observer(
322 new content::TestRenderWidgetHostViewDestructionObserver(first_view));
323 frames[0]->GetProcess()->Shutdown(0, false);
324 destruction_observer->Wait();
325
326 // Verifying that the TextInputManager is no longer tracking TextInputState
327 // for |first_view|. Note that |first_view| is now a dangling pointer.
328 EXPECT_FALSE(content::GetTextInputTypeForView(active_contents(), first_view,
329 &first_view_type));
330
331 // Now crash the second <iframe> which has an active view.
332 content::RenderWidgetHostView* second_view = frames[1]->GetView();
333 TextInputManagerChangeObserver change_observer(active_contents());
334 frames[1]->GetProcess()->Shutdown(0, false);
335 change_observer.Wait();
336 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
337 content::GetTextInputTypeFromWebContents(active_contents()));
338 EXPECT_FALSE(!!content::GetActiveViewFromWebContents(active_contents()));
339 ui::TextInputType second_view_type;
340 EXPECT_FALSE(content::GetTextInputTypeForView(active_contents(), second_view,
341 &second_view_type));
342 }
343
344 // The following test loads a page with two child frames: one in process and one
345 // out of process with main frame. The test inserts an <input> inside each frame
346 // and focuses the first frame and observes the TextInputManager setting the
347 // state to ui::TEXT_INPUT_TYPE_TEXT. Then, the frame is detached and the test
348 // observes that the state type is reset to ui::TEXT_INPUT_TYPE_NONE. The same
349 // sequence of actions is then performed on the out of process frame.
350 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
351 ResetStateAfterFrameDetached) {
352 CreateIframePage("a(a, b)");
353 using vector = std::vector<size_t>;
354 std::vector<content::RenderFrameHost*> frames{GetFrame(vector{0}),
355 GetFrame(vector{1})};
356
357 for (size_t i = 0; i < frames.size(); ++i)
358 AddInputFieldToFrame(frames[i], "text", "", true);
359
360 // Press tab key to focus the <input> in the first frame.
361 TextInputManagerTypeObserver type_observer_text_a(active_contents(),
362 ui::TEXT_INPUT_TYPE_TEXT);
363 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false, false);
364 type_observer_text_a.Wait();
365
366 std::string remove_first_iframe_script =
367 "var frame = document.querySelector('iframe');"
368 "frame.parentNode.removeChild(frame);";
369 // Detach first frame and observe |TextInputState.type| resetting to
370 // ui::TEXT_INPUT_TYPE_NONE.
371 TextInputManagerTypeObserver type_observer_none_a(active_contents(),
372 ui::TEXT_INPUT_TYPE_NONE);
373 EXPECT_TRUE(ExecuteScript(active_contents(), remove_first_iframe_script));
374 type_observer_none_a.Wait();
375
376 // Press tab to focus the <input> in the second frame.
377 TextInputManagerTypeObserver type_observer_text_b(active_contents(),
378 ui::TEXT_INPUT_TYPE_TEXT);
379 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false, false);
380 type_observer_text_b.Wait();
381
382 // Detach first frame and observe |TextInputState.type| resetting to
383 // ui::TEXT_INPUT_TYPE_NONE.
384 TextInputManagerTypeObserver type_observer_none_b(active_contents(),
385 ui::TEXT_INPUT_TYPE_NONE);
386 EXPECT_TRUE(ExecuteScript(active_contents(), remove_first_iframe_script));
387 type_observer_none_b.Wait();
388 }
389
390 // This test creates a page with one OOPIF and adds an <input> to it. Then, the
391 // <input> is focused and the test verfies that the |TextInputState.type| is set
392 // to ui::TEXT_INPUT_TYPE_TEXT. Next, the child frame is navigated away and the
393 // test verifies that |TextInputState.type| resets to ui::TEXT_INPUT_TYPE_NONE.
394 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
395 ResetStateAfterChildNavigation) {
396 CreateIframePage("a(b)");
397 using vector = std::vector<size_t>;
398 content::RenderFrameHost* main_frame = GetFrame(vector{});
399 content::RenderFrameHost* child_frame = GetFrame(vector{0});
400
401 AddInputFieldToFrame(child_frame, "text", "child", false);
402
403 // Focus <input> in child frame and verify the |TextInputState.value|.
404 TextInputManagerValueObserver child_set_state_observer(active_contents(),
405 "child");
406 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false, false);
407 child_set_state_observer.Wait();
408
409 // Navigate the child frame to about:blank and verify that TextInputManager
410 // correctly sets its |TextInputState.type| to ui::TEXT_INPUT_TYPE_NONE.
411 TextInputManagerTypeObserver child_reset_state_observer(
412 active_contents(), ui::TEXT_INPUT_TYPE_NONE);
413 EXPECT_TRUE(ExecuteScript(
414 main_frame, "document.querySelector('iframe').src = 'about:blank'"));
415 child_reset_state_observer.Wait();
416 }
417
418 // This test creates a blank page and adds an <input> to it. Then, the <input>
419 // is focused and the test verfies that the |TextInputState.type| is set to
420 // ui::TEXT_INPUT_TYPE_TEXT. Next, the browser is navigated away and the test
421 // verifies that |TextInputState.type| resets to ui::TEXT_INPUT_TYPE_NONE.
422 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
423 ResetStateAfterBrowserNavigation) {
424 CreateIframePage("a()");
425 content::RenderFrameHost* main_frame = GetFrame(std::vector<size_t>{});
426 AddInputFieldToFrame(main_frame, "text", "", false);
427
428 TextInputManagerTypeObserver set_state_observer(active_contents(),
429 ui::TEXT_INPUT_TYPE_TEXT);
430 SimulateKeyPress(active_contents(), ui::VKEY_TAB, false, false, false, false);
431 set_state_observer.Wait();
432
433 TextInputManagerTypeObserver reset_state_observer(active_contents(),
434 ui::TEXT_INPUT_TYPE_NONE);
435 ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
436 reset_state_observer.Wait();
437 }
438 #endif // USE_AURA
439
440 // TODO(ekaramad): The following tests are specifically written for Aura and are
441 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus
442 // (crbug.com/602723).
443 #ifdef USE_AURA
444 // Observes current input method for state changes.
445 class InputMethodObserverBase {
446 public:
447 explicit InputMethodObserverBase(content::WebContents* web_contents)
448 : success_(false),
449 test_observer_(content::TestInputMethodObserver::Create(web_contents)) {
450 }
451
452 void Wait() {
453 if (success_)
454 return;
455 message_loop_runner_ = new content::MessageLoopRunner();
456 message_loop_runner_->Run();
457 }
458
459 bool success() const { return success_; }
460
461 protected:
462 content::TestInputMethodObserver* test_observer() {
463 return test_observer_.get();
464 }
465
466 const base::Closure success_closure() {
467 return base::Bind(&InputMethodObserverBase::OnSuccess,
468 base::Unretained(this));
469 }
470
471 private:
472 void OnSuccess() {
473 success_ = true;
474 if (message_loop_runner_)
475 message_loop_runner_->Quit();
476 }
477
478 bool success_;
479 std::unique_ptr<content::TestInputMethodObserver> test_observer_;
480 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
481
482 DISALLOW_COPY_AND_ASSIGN(InputMethodObserverBase);
483 };
484
485 class InputMethodObserverForShowIme : public InputMethodObserverBase {
486 public:
487 explicit InputMethodObserverForShowIme(content::WebContents* web_contents)
488 : InputMethodObserverBase(web_contents) {
489 test_observer()->SetOnShowImeIfNeededCallback(success_closure());
490 }
491 };
492
493 // This test verifies that the IME for Aura is shown if and only if the current
494 // client's |TextInputState.type| is not ui::TEXT_INPUT_TYPE_NONE and the flag
495 // |TextInputState.show_ime_if_needed| is true. This should happen even when
496 // the TextInputState has not changed (according to the platform), e.g., in
497 // aura when receiving two consecutive updates with same |TextInputState.type|.
498 // TODO(ekaramad): This test is actually a unit test not necessarily an OOPIF
499 // test. We should move it to somewhere more relevant.
500 IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
501 CorrectlyShowImeIfNeeded) {
502 // We only need the <iframe> page to create RWHV.
503 CreateIframePage("a()");
504 content::RenderFrameHost* main_frame = GetFrame(std::vector<size_t>{});
505 content::RenderWidgetHostView* view = main_frame->GetView();
506 content::WebContents* web_contents = active_contents();
507
508 content::TextInputStateSender sender(view);
509
510 auto send_and_check_show_ime = [&sender, &web_contents]() {
511 InputMethodObserverForShowIme observer(web_contents);
512 sender.Send();
513 return observer.success();
514 };
515
516 // Sending an empty state should not trigger ime.
517 EXPECT_FALSE(send_and_check_show_ime());
518
519 // Set |TextInputState.type| to text. Expect no IME.
520 sender.SetType(ui::TEXT_INPUT_TYPE_TEXT);
521 EXPECT_FALSE(send_and_check_show_ime());
522
523 // Set |TextInputState.show_ime_if_needed| to true. Expect IME.
524 sender.SetShowImeIfNeeded(true);
525 EXPECT_TRUE(send_and_check_show_ime());
526
527 // Send the same message. Expect IME (no change).
528 EXPECT_TRUE(send_and_check_show_ime());
529
530 // Reset |TextInputState.show_ime_if_needed|. Expect no IME.
531 sender.SetShowImeIfNeeded(false);
532 EXPECT_FALSE(send_and_check_show_ime());
533
534 // Setting an irrelevant field. Expect no IME.
535 sender.SetMode(ui::TEXT_INPUT_MODE_LATIN);
536 EXPECT_FALSE(send_and_check_show_ime());
537
538 // Set |TextInputState.show_ime_if_needed|. Expect IME.
539 sender.SetShowImeIfNeeded(true);
540 EXPECT_TRUE(send_and_check_show_ime());
541
542 // Set |TextInputState.type| to ui::TEXT_INPUT_TYPE_NONE. Expect no IME.
543 sender.SetType(ui::TEXT_INPUT_TYPE_NONE);
544 EXPECT_FALSE(send_and_check_show_ime());
545 }
546 #endif // USE_AURA
OLDNEW
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | content/browser/renderer_host/render_widget_host_view_base.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698