0

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:
nona@chromium.org
2012-09-22 20:10:50 +00:00
parent c1a12d2311
commit 0c3f07feb6
8 changed files with 357 additions and 3 deletions

@ -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': [

@ -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>

@ -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

@ -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': [
'../',