1 // Copyright (c) 2013 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 "ash/shell.h" 6 #include "base/strings/string_number_conversions.h" 7 #include "base/strings/string_util.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/chromeos/input_method/textinput_test_helper.h" 10 #include "chrome/browser/ui/browser.h" 11 #include "chrome/test/base/interactive_test_utils.h" 12 #include "content/public/browser/render_view_host.h" 13 #include "content/public/browser/web_contents.h" 14 #include "content/public/test/browser_test_utils.h" 15 #include "ui/aura/client/aura_constants.h" 16 #include "ui/aura/root_window.h" 17 #include "ui/base/ime/input_method_factory.h" 18 19 namespace chromeos { 20 namespace { 21 ui::MockInputMethod* GetInputMethod() { 22 ui::MockInputMethod* input_method = static_cast<ui::MockInputMethod*>( 23 ash::Shell::GetPrimaryRootWindow()->GetProperty( 24 aura::client::kRootWindowInputMethodKey)); 25 CHECK(input_method); 26 return input_method; 27 } 28 } // namespace 29 30 void TextInputTestBase::SetUpInProcessBrowserTestFixture() { 31 ui::SetUpInputMethodFactoryForTesting(); 32 } 33 34 TextInputTestHelper::TextInputTestHelper() 35 : waiting_type_(NO_WAIT), 36 selection_range_(gfx::Range::InvalidRange()), 37 focus_state_(false), 38 latest_text_input_type_(ui::TEXT_INPUT_TYPE_NONE) { 39 GetInputMethod()->AddObserver(this); 40 } 41 42 TextInputTestHelper::~TextInputTestHelper() { 43 GetInputMethod()->RemoveObserver(this); 44 } 45 46 base::string16 TextInputTestHelper::GetSurroundingText() const { 47 return surrounding_text_; 48 } 49 50 gfx::Rect TextInputTestHelper::GetCaretRect() const { 51 return caret_rect_; 52 } 53 54 gfx::Rect TextInputTestHelper::GetCompositionHead() const { 55 return composition_head_; 56 } 57 58 gfx::Range TextInputTestHelper::GetSelectionRange() const { 59 return selection_range_; 60 } 61 62 bool TextInputTestHelper::GetFocusState() const { 63 return focus_state_; 64 } 65 66 ui::TextInputType TextInputTestHelper::GetTextInputType() const { 67 return latest_text_input_type_; 68 } 69 70 ui::TextInputClient* TextInputTestHelper::GetTextInputClient() const { 71 return GetInputMethod()->GetTextInputClient(); 72 } 73 74 void TextInputTestHelper::OnTextInputTypeChanged( 75 const ui::TextInputClient* client) { 76 latest_text_input_type_ = client->GetTextInputType(); 77 if (waiting_type_ == WAIT_ON_TEXT_INPUT_TYPE_CHANGED) 78 base::MessageLoop::current()->Quit(); 79 } 80 81 void TextInputTestHelper::OnInputMethodDestroyed( 82 const ui::InputMethod* input_method) { 83 } 84 85 void TextInputTestHelper::OnFocus() { 86 focus_state_ = true; 87 if (waiting_type_ == WAIT_ON_FOCUS) 88 base::MessageLoop::current()->Quit(); 89 } 90 91 void TextInputTestHelper::OnBlur() { 92 focus_state_ = false; 93 if (waiting_type_ == WAIT_ON_BLUR) 94 base::MessageLoop::current()->Quit(); 95 } 96 97 void TextInputTestHelper::OnCaretBoundsChanged( 98 const ui::TextInputClient* client) { 99 gfx::Range text_range; 100 if (!GetTextInputClient()->GetTextRange(&text_range) || 101 !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text_) || 102 !GetTextInputClient()->GetSelectionRange(&selection_range_)) 103 return; 104 if (waiting_type_ == WAIT_ON_CARET_BOUNDS_CHANGED) 105 base::MessageLoop::current()->Quit(); 106 } 107 108 void TextInputTestHelper::OnTextInputStateChanged( 109 const ui::TextInputClient* client) { 110 } 111 112 void TextInputTestHelper::WaitForTextInputStateChanged( 113 ui::TextInputType expected_type) { 114 CHECK_EQ(NO_WAIT, waiting_type_); 115 waiting_type_ = WAIT_ON_TEXT_INPUT_TYPE_CHANGED; 116 while (latest_text_input_type_ != expected_type) 117 content::RunMessageLoop(); 118 waiting_type_ = NO_WAIT; 119 } 120 121 void TextInputTestHelper::WaitForFocus() { 122 CHECK_EQ(NO_WAIT, waiting_type_); 123 waiting_type_ = WAIT_ON_FOCUS; 124 while (focus_state_) 125 content::RunMessageLoop(); 126 waiting_type_ = NO_WAIT; 127 } 128 129 void TextInputTestHelper::WaitForBlur() { 130 CHECK_EQ(NO_WAIT, waiting_type_); 131 waiting_type_ = WAIT_ON_BLUR; 132 while (!focus_state_) 133 content::RunMessageLoop(); 134 waiting_type_ = NO_WAIT; 135 } 136 137 void TextInputTestHelper::WaitForCaretBoundsChanged( 138 const gfx::Rect& expected_caret_rect, 139 const gfx::Rect& expected_composition_head) { 140 waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; 141 while (expected_caret_rect != caret_rect_ || 142 expected_composition_head != composition_head_) 143 content::RunMessageLoop(); 144 waiting_type_ = NO_WAIT; 145 } 146 147 void TextInputTestHelper::WaitForSurroundingTextChanged( 148 const base::string16& expected_text, 149 const gfx::Range& expected_selection) { 150 waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; 151 while (expected_text != surrounding_text_ || 152 expected_selection != selection_range_) 153 content::RunMessageLoop(); 154 waiting_type_ = NO_WAIT; 155 } 156 157 // static 158 bool TextInputTestHelper::ConvertRectFromString(const std::string& str, 159 gfx::Rect* rect) { 160 DCHECK(rect); 161 std::vector<std::string> rect_piece; 162 if (Tokenize(str, ",", &rect_piece) != 4UL) 163 return false; 164 int x, y, width, height; 165 if (!base::StringToInt(rect_piece[0], &x)) 166 return false; 167 if (!base::StringToInt(rect_piece[1], &y)) 168 return false; 169 if (!base::StringToInt(rect_piece[2], &width)) 170 return false; 171 if (!base::StringToInt(rect_piece[3], &height)) 172 return false; 173 *rect = gfx::Rect(x, y, width, height); 174 return true; 175 } 176 177 // static 178 bool TextInputTestHelper::ClickElement(const std::string& id, 179 content::WebContents* tab) { 180 std::string coordinate; 181 if (!content::ExecuteScriptAndExtractString( 182 tab, 183 "textinput_helper.retrieveElementCoordinate('" + id + "')", 184 &coordinate)) 185 return false; 186 gfx::Rect rect; 187 if (!ConvertRectFromString(coordinate, &rect)) 188 return false; 189 190 blink::WebMouseEvent mouse_event; 191 mouse_event.type = blink::WebInputEvent::MouseDown; 192 mouse_event.button = blink::WebMouseEvent::ButtonLeft; 193 mouse_event.x = rect.CenterPoint().x(); 194 mouse_event.y = rect.CenterPoint().y(); 195 mouse_event.clickCount = 1; 196 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 197 198 mouse_event.type = blink::WebInputEvent::MouseUp; 199 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 200 return true; 201 } 202 203 } // namespace chromeos 204