Introduce RenderWidgetHostViewWinTest for Tsf handling
BUG=None TBR=avi TEST=try bots Review URL: https://chromiumcodereview.appspot.com/10912171 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158189 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/win/metro.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/test/test_utils.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/shell/shell.h"
|
||||
#include "content/test/content_browser_test_utils.h"
|
||||
#include "content/test/content_browser_test.h"
|
||||
#include "ui/base/ime/text_input_type.h"
|
||||
#include "ui/base/win/mock_tsf_bridge.h"
|
||||
#include "ui/base/win/tsf_bridge.h"
|
||||
|
||||
namespace {
|
||||
class RenderWidgetHostViewWinTest : public content::ContentBrowserTest {
|
||||
public:
|
||||
RenderWidgetHostViewWinTest() {}
|
||||
|
||||
virtual void SetUpCommandLine(CommandLine* command_line) {
|
||||
command_line->AppendSwitch(switches::kEnableTextServicesFramework);
|
||||
}
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTest, SwichToPasswordField) {
|
||||
ui::MockTsfBridge mock_bridge;
|
||||
ui::TsfBridge* old_bridge = ui::TsfBridge::ReplaceForTesting(&mock_bridge);
|
||||
GURL test_url = content::GetTestUrl("textinput",
|
||||
"ime_enable_disable_test.html");
|
||||
|
||||
content::NavigateToURL(shell(), test_url);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to the text field, the IME should be enabled.
|
||||
bool success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(text01_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to the password field, the IME should be disabled.
|
||||
success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(password02_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
|
||||
|
||||
ui::TsfBridge::ReplaceForTesting(old_bridge);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTest, SwitchToSameField) {
|
||||
ui::MockTsfBridge mock_bridge;
|
||||
ui::TsfBridge* old_bridge = ui::TsfBridge::ReplaceForTesting(&mock_bridge);
|
||||
GURL test_url = content::GetTestUrl("textinput",
|
||||
"ime_enable_disable_test.html");
|
||||
|
||||
content::NavigateToURL(shell(), test_url);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to the text field, the IME should be enabled.
|
||||
bool success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(text01_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to another text field, the IME should be enabled.
|
||||
success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(text02_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, mock_bridge.latest_text_iput_type());
|
||||
|
||||
ui::TsfBridge::ReplaceForTesting(old_bridge);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewWinTest, SwitchToSamePasswordField) {
|
||||
ui::MockTsfBridge mock_bridge;
|
||||
ui::TsfBridge* old_bridge = ui::TsfBridge::ReplaceForTesting(&mock_bridge);
|
||||
GURL test_url = content::GetTestUrl("textinput",
|
||||
"ime_enable_disable_test.html");
|
||||
|
||||
content::NavigateToURL(shell(), test_url);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to the password field, the IME should be disabled.
|
||||
bool success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(password01_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
|
||||
|
||||
// Focus to the another password field, the IME should be disabled.
|
||||
success = false;
|
||||
EXPECT_TRUE(ExecuteJavaScriptAndExtractBool(
|
||||
shell()->web_contents()->GetRenderViewHost(), L"",
|
||||
L"window.domAutomationController.send(password02_focus());",
|
||||
&success));
|
||||
EXPECT_TRUE(success);
|
||||
content::WaitForLoadStop(shell()->web_contents());
|
||||
content::RunAllPendingInMessageLoop();
|
||||
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, mock_bridge.latest_text_iput_type());
|
||||
|
||||
ui::TsfBridge::ReplaceForTesting(old_bridge);
|
||||
}
|
||||
} // namespace
|
@ -658,6 +658,7 @@
|
||||
'browser/plugin_service_impl_browsertest.cc',
|
||||
'browser/renderer_host/render_view_host_browsertest.cc',
|
||||
'browser/renderer_host/render_view_host_manager_browsertest.cc',
|
||||
'browser/renderer_host/render_widget_host_view_win_browsertest.cc',
|
||||
'browser/renderer_host/resource_dispatcher_host_browsertest.cc',
|
||||
'browser/session_history_browsertest.cc',
|
||||
'browser/speech/speech_recognition_browsertest.cc',
|
||||
@ -723,6 +724,10 @@
|
||||
},
|
||||
},
|
||||
},
|
||||
}, { # OS!="win"
|
||||
'sources!': [
|
||||
'browser/renderer_host/render_widget_host_view_win_browsertest.cc',
|
||||
],
|
||||
}],
|
||||
['OS=="win" and win_use_allocator_shim==1', {
|
||||
'dependencies': [
|
||||
|
31
content/test/data/textinput/ime_enable_disable_test.html
Normal file
31
content/test/data/textinput/ime_enable_disable_test.html
Normal file
@ -0,0 +1,31 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function text01_focus() {
|
||||
document.getElementById('text01_id').focus();
|
||||
return true;
|
||||
}
|
||||
function text02_focus() {
|
||||
document.getElementById('text02_id').focus();
|
||||
return true;
|
||||
}
|
||||
function password01_focus() {
|
||||
document.getElementById('password01_id').focus();
|
||||
return true;
|
||||
}
|
||||
function password02_focus() {
|
||||
document.getElementById('password02_id').focus();
|
||||
return true;
|
||||
}
|
||||
function onLoad() {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="onLoad()">
|
||||
<input type="text" id="text01_id">
|
||||
<input type="text" id="text02_id">
|
||||
<input type="password" id="password01_id">
|
||||
<input type="password" id="password02_id">
|
||||
</body>
|
||||
</html>
|
68
ui/base/win/mock_tsf_bridge.cc
Normal file
68
ui/base/win/mock_tsf_bridge.cc
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ui/base/win/mock_tsf_bridge.h"
|
||||
|
||||
#include "ui/base/ime/text_input_client.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
MockTsfBridge::MockTsfBridge()
|
||||
: shutdown_call_count_(0),
|
||||
enable_ime_call_count_(0),
|
||||
disalbe_ime_call_count_(0),
|
||||
cancel_composition_call_count_(0),
|
||||
associate_focus_call_count_(0),
|
||||
set_focused_client_call_count_(0),
|
||||
remove_focused_client_call_count_(0),
|
||||
text_input_client_(NULL),
|
||||
focused_window_(NULL),
|
||||
latest_text_input_type_(TEXT_INPUT_TYPE_NONE) {
|
||||
}
|
||||
|
||||
MockTsfBridge::~MockTsfBridge() {
|
||||
}
|
||||
|
||||
void MockTsfBridge::Shutdown() {
|
||||
shutdown_call_count_++;
|
||||
}
|
||||
|
||||
bool MockTsfBridge::CancelComposition() {
|
||||
++cancel_composition_call_count_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MockTsfBridge::OnTextInputTypeChanged(TextInputClient* client) {
|
||||
latest_text_input_type_ = client->GetTextInputType();
|
||||
}
|
||||
|
||||
void MockTsfBridge::SetFocusedClient(HWND focused_window,
|
||||
TextInputClient* client) {
|
||||
++set_focused_client_call_count_;
|
||||
focused_window_ = focused_window;
|
||||
text_input_client_ = client;
|
||||
}
|
||||
|
||||
void MockTsfBridge::RemoveFocusedClient(TextInputClient* client) {
|
||||
++remove_focused_client_call_count_;
|
||||
DCHECK_EQ(client, text_input_client_);
|
||||
text_input_client_ = NULL;
|
||||
focused_window_ = NULL;
|
||||
}
|
||||
|
||||
void MockTsfBridge::Reset() {
|
||||
shutdown_call_count_ = 0;
|
||||
enable_ime_call_count_ = 0;
|
||||
disalbe_ime_call_count_ = 0;
|
||||
cancel_composition_call_count_ = 0;
|
||||
associate_focus_call_count_ = 0;
|
||||
set_focused_client_call_count_ = 0;
|
||||
remove_focused_client_call_count_ = 0;
|
||||
text_input_client_ = NULL;
|
||||
focused_window_ = NULL;
|
||||
latest_text_input_type_ = TEXT_INPUT_TYPE_NONE;
|
||||
}
|
||||
|
||||
} // namespace ui
|
93
ui/base/win/mock_tsf_bridge.h
Normal file
93
ui/base/win/mock_tsf_bridge.h
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef UI_BASE_WIN_MOCK_TSF_BRIDGE_H_
|
||||
#define UI_BASE_WIN_MOCK_TSF_BRIDGE_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "ui/base/ime/text_input_type.h"
|
||||
#include "ui/base/win/tsf_bridge.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class MockTsfBridge : public TsfBridge {
|
||||
public:
|
||||
MockTsfBridge();
|
||||
virtual ~MockTsfBridge();
|
||||
|
||||
// TsfBridge override.
|
||||
virtual void Shutdown() OVERRIDE;
|
||||
|
||||
// TsfBridge override.
|
||||
virtual bool CancelComposition() OVERRIDE;
|
||||
|
||||
// TsfBridge override.
|
||||
virtual void OnTextInputTypeChanged(TextInputClient* client) OVERRIDE;
|
||||
|
||||
// TsfBridge override.
|
||||
virtual void SetFocusedClient(HWND focused_window,
|
||||
TextInputClient* client) OVERRIDE;
|
||||
|
||||
// TsfBridge override.
|
||||
virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE;
|
||||
|
||||
// Resets MockTsfBridge state including function call counter.
|
||||
void Reset();
|
||||
|
||||
// Call count of Shutdown().
|
||||
int shutdown_call_count() const { return shutdown_call_count_; }
|
||||
|
||||
// Call count of EnableIME().
|
||||
int enable_ime_call_count() const { return enable_ime_call_count_; }
|
||||
|
||||
// Call count of DisableIME().
|
||||
int disalbe_ime_call_count() const { return disalbe_ime_call_count_; }
|
||||
|
||||
// Call count of CancelComposition().
|
||||
int cancel_composition_call_count() const {
|
||||
return cancel_composition_call_count_;
|
||||
}
|
||||
|
||||
// Call count of AssociateFocus().
|
||||
int associate_focus_call_count() const { return associate_focus_call_count_; }
|
||||
|
||||
// Call count of SetFocusClient().
|
||||
int set_focused_client_call_count() const {
|
||||
return set_focused_client_call_count_;
|
||||
}
|
||||
|
||||
// Call count of Shutdown().
|
||||
int remove_focused_client_call_count() const {
|
||||
return remove_focused_client_call_count_;
|
||||
}
|
||||
|
||||
// Returns current TextInputClient.
|
||||
TextInputClient* text_input_clinet() const { return text_input_client_; }
|
||||
|
||||
// Returns currently focused window handle.
|
||||
HWND focused_window() const { return focused_window_; }
|
||||
|
||||
// Returns latest text input type.
|
||||
TextInputType latest_text_iput_type() const {
|
||||
return latest_text_input_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
int shutdown_call_count_;
|
||||
int enable_ime_call_count_;
|
||||
int disalbe_ime_call_count_;
|
||||
int cancel_composition_call_count_;
|
||||
int associate_focus_call_count_;
|
||||
int set_focused_client_call_count_;
|
||||
int remove_focused_client_call_count_;
|
||||
TextInputClient* text_input_client_;
|
||||
HWND focused_window_;
|
||||
TextInputType latest_text_input_type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MockTsfBridge);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // UI_BASE_WIN_MOCK_TSF_BRIDGE_H_
|
@ -462,6 +462,17 @@ bool TsfBridge::Initialize() {
|
||||
return delegate->Initialize();
|
||||
}
|
||||
|
||||
// static
|
||||
TsfBridge* TsfBridge::ReplaceForTesting(TsfBridge* bridge) {
|
||||
if (MessageLoop::current()->type() != MessageLoop::TYPE_UI) {
|
||||
VLOG(1) << "Do not use TsfBridge without UI thread.";
|
||||
return NULL;
|
||||
}
|
||||
TsfBridge* old_bridge = TsfBridge::GetInstance();
|
||||
tls_tsf_bridge.Set(bridge);
|
||||
return old_bridge;
|
||||
}
|
||||
|
||||
// static
|
||||
TsfBridge* TsfBridge::GetInstance() {
|
||||
if (MessageLoop::current()->type() != MessageLoop::TYPE_UI) {
|
||||
|
@ -23,17 +23,22 @@ class TextInputClient;
|
||||
// of text inputting and current focused TextInputClient.
|
||||
//
|
||||
// All methods in this class must be used in UI thread.
|
||||
class TsfBridge {
|
||||
class UI_EXPORT TsfBridge {
|
||||
public:
|
||||
virtual ~TsfBridge();
|
||||
|
||||
// Returns the thread local TsfBridge instance. Initialize() must be called
|
||||
// first. Do not cache this pointer and use it after TsfBridge Shutdown().
|
||||
static UI_EXPORT TsfBridge* GetInstance();
|
||||
static TsfBridge* GetInstance();
|
||||
|
||||
// Sets the thread local instance. Must be called before any calls to
|
||||
// GetInstance().
|
||||
static UI_EXPORT bool Initialize();
|
||||
static bool Initialize();
|
||||
|
||||
// Injects an alternative TsfBridge such as MockTsfBridge for testing. The
|
||||
// injected object should be released by the caller. This function returns
|
||||
// previous TsfBridge pointer with ownership.
|
||||
static TsfBridge* ReplaceForTesting(TsfBridge* bridge);
|
||||
|
||||
// Destroys the thread local instance.
|
||||
virtual void Shutdown() = 0;
|
||||
|
@ -9,6 +9,7 @@
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'../base/base.gyp:base',
|
||||
'../skia/skia.gyp:skia',
|
||||
'../testing/gtest.gyp:gtest',
|
||||
],
|
||||
'sources': [
|
||||
@ -18,6 +19,8 @@
|
||||
'base/test/ui_cocoa_test_helper.mm',
|
||||
'base/test/dummy_input_method.cc',
|
||||
'base/test/dummy_input_method.h',
|
||||
'base/win/mock_tsf_bridge.cc',
|
||||
'base/win/mock_tsf_bridge.h',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../',
|
||||
|
Reference in New Issue
Block a user