|  | // Copyright (c) 2013 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 "chrome/browser/chromeos/input_method/textinput_test_helper.h" | 
|  | #include "ash/shell.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_split.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "base/threading/platform_thread.h" | 
|  | #include "chrome/browser/ui/browser.h" | 
|  | #include "chrome/test/base/interactive_test_utils.h" | 
|  | #include "content/public/browser/render_view_host.h" | 
|  | #include "content/public/browser/render_widget_host.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  | #include "ui/aura/window_event_dispatcher.h" | 
|  | #include "ui/aura/window_tree_host.h" | 
|  | #include "ui/base/ime/input_method_factory.h" | 
|  |  | 
|  | namespace chromeos { | 
|  | namespace { | 
|  | ui::MockInputMethod* GetInputMethod() { | 
|  | ui::MockInputMethod* input_method = static_cast<ui::MockInputMethod*>( | 
|  | ash::Shell::GetPrimaryRootWindow()->GetHost()->GetInputMethod()); | 
|  | CHECK(input_method); | 
|  | return input_method; | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | void TextInputTestBase::SetUpInProcessBrowserTestFixture() { | 
|  | ui::SetUpInputMethodFactoryForTesting(); | 
|  | } | 
|  |  | 
|  | TextInputTestHelper::TextInputTestHelper() | 
|  | : waiting_type_(NO_WAIT), | 
|  | selection_range_(gfx::Range::InvalidRange()), | 
|  | focus_state_(false), | 
|  | latest_text_input_type_(ui::TEXT_INPUT_TYPE_NONE) { | 
|  | GetInputMethod()->AddObserver(this); | 
|  | } | 
|  |  | 
|  | TextInputTestHelper::~TextInputTestHelper() { | 
|  | GetInputMethod()->RemoveObserver(this); | 
|  | } | 
|  |  | 
|  | base::string16 TextInputTestHelper::GetSurroundingText() const { | 
|  | return surrounding_text_; | 
|  | } | 
|  |  | 
|  | gfx::Rect TextInputTestHelper::GetCaretRect() const { | 
|  | return caret_rect_; | 
|  | } | 
|  |  | 
|  | gfx::Rect TextInputTestHelper::GetCompositionHead() const { | 
|  | return composition_head_; | 
|  | } | 
|  |  | 
|  | gfx::Range TextInputTestHelper::GetSelectionRange() const { | 
|  | return selection_range_; | 
|  | } | 
|  |  | 
|  | bool TextInputTestHelper::GetFocusState() const { | 
|  | return focus_state_; | 
|  | } | 
|  |  | 
|  | ui::TextInputType TextInputTestHelper::GetTextInputType() const { | 
|  | return latest_text_input_type_; | 
|  | } | 
|  |  | 
|  | ui::TextInputClient* TextInputTestHelper::GetTextInputClient() const { | 
|  | return GetInputMethod()->GetTextInputClient(); | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnShowImeIfNeeded() { | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnInputMethodDestroyed( | 
|  | const ui::InputMethod* input_method) { | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnFocus() { | 
|  | focus_state_ = true; | 
|  | if (waiting_type_ == WAIT_ON_FOCUS) | 
|  | base::RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnBlur() { | 
|  | focus_state_ = false; | 
|  | if (waiting_type_ == WAIT_ON_BLUR) | 
|  | base::RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnCaretBoundsChanged( | 
|  | const ui::TextInputClient* client) { | 
|  | gfx::Range text_range; | 
|  | if (GetTextInputClient()) { | 
|  | if (!GetTextInputClient()->GetTextRange(&text_range) || | 
|  | !GetTextInputClient()->GetTextFromRange(text_range, | 
|  | &surrounding_text_) || | 
|  | !GetTextInputClient()->GetSelectionRange(&selection_range_)) | 
|  | return; | 
|  | } | 
|  | if (waiting_type_ == WAIT_ON_CARET_BOUNDS_CHANGED) | 
|  | base::RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::OnTextInputStateChanged( | 
|  | const ui::TextInputClient* client) { | 
|  | latest_text_input_type_ = | 
|  | client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE; | 
|  | if (waiting_type_ == WAIT_ON_TEXT_INPUT_TYPE_CHANGED) | 
|  | base::RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForTextInputStateChanged( | 
|  | ui::TextInputType expected_type) { | 
|  | CHECK_EQ(NO_WAIT, waiting_type_); | 
|  | waiting_type_ = WAIT_ON_TEXT_INPUT_TYPE_CHANGED; | 
|  | while (latest_text_input_type_ != expected_type) | 
|  | content::RunMessageLoop(); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForFocus() { | 
|  | CHECK_EQ(NO_WAIT, waiting_type_); | 
|  | waiting_type_ = WAIT_ON_FOCUS; | 
|  | while (focus_state_) | 
|  | content::RunMessageLoop(); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForBlur() { | 
|  | CHECK_EQ(NO_WAIT, waiting_type_); | 
|  | waiting_type_ = WAIT_ON_BLUR; | 
|  | while (!focus_state_) | 
|  | content::RunMessageLoop(); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForCaretBoundsChanged( | 
|  | const gfx::Rect& expected_caret_rect, | 
|  | const gfx::Rect& expected_composition_head) { | 
|  | waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; | 
|  | while (expected_caret_rect != caret_rect_ || | 
|  | expected_composition_head != composition_head_) | 
|  | content::RunMessageLoop(); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForSurroundingTextChanged( | 
|  | const base::string16& expected_text, | 
|  | const gfx::Range& expected_selection) { | 
|  | waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; | 
|  | while (expected_text != surrounding_text_ || | 
|  | expected_selection != selection_range_) | 
|  | content::RunMessageLoop(); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | void TextInputTestHelper::WaitForPassageOfTimeMillis(const int milliseconds) { | 
|  | CHECK_EQ(NO_WAIT, waiting_type_); | 
|  | waiting_type_ = WAIT_ON_PASSAGE_OF_TIME; | 
|  | base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(milliseconds)); | 
|  | waiting_type_ = NO_WAIT; | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool TextInputTestHelper::ConvertRectFromString(const std::string& str, | 
|  | gfx::Rect* rect) { | 
|  | DCHECK(rect); | 
|  | std::vector<base::StringPiece> rect_piece = base::SplitStringPiece( | 
|  | str, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | 
|  | if (rect_piece.size() != 4UL) | 
|  | return false; | 
|  | int x, y, width, height; | 
|  | if (!base::StringToInt(rect_piece[0], &x)) | 
|  | return false; | 
|  | if (!base::StringToInt(rect_piece[1], &y)) | 
|  | return false; | 
|  | if (!base::StringToInt(rect_piece[2], &width)) | 
|  | return false; | 
|  | if (!base::StringToInt(rect_piece[3], &height)) | 
|  | return false; | 
|  | *rect = gfx::Rect(x, y, width, height); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool TextInputTestHelper::ClickElement(const std::string& id, | 
|  | content::WebContents* tab) { | 
|  | std::string coordinate; | 
|  | if (!content::ExecuteScriptAndExtractString( | 
|  | tab, | 
|  | "textinput_helper.retrieveElementCoordinate('" + id + "')", | 
|  | &coordinate)) | 
|  | return false; | 
|  | gfx::Rect rect; | 
|  | if (!ConvertRectFromString(coordinate, &rect)) | 
|  | return false; | 
|  |  | 
|  | blink::WebMouseEvent mouse_event( | 
|  | blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers, | 
|  | blink::WebInputEvent::GetStaticTimeStampForTests()); | 
|  | mouse_event.button = blink::WebMouseEvent::Button::kLeft; | 
|  | mouse_event.SetPositionInWidget(rect.CenterPoint().x(), | 
|  | rect.CenterPoint().y()); | 
|  | mouse_event.click_count = 1; | 
|  | tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event); | 
|  |  | 
|  | mouse_event.SetType(blink::WebInputEvent::kMouseUp); | 
|  | tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | } // namespace chromeos |