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/window_event_dispatcher.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_ = 77 client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE; 78 if (waiting_type_ == WAIT_ON_TEXT_INPUT_TYPE_CHANGED) 79 base::MessageLoop::current()->Quit(); 80 } 81 82 void TextInputTestHelper::OnShowImeIfNeeded() { 83 } 84 85 void TextInputTestHelper::OnInputMethodDestroyed( 86 const ui::InputMethod* input_method) { 87 } 88 89 void TextInputTestHelper::OnFocus() { 90 focus_state_ = true; 91 if (waiting_type_ == WAIT_ON_FOCUS) 92 base::MessageLoop::current()->Quit(); 93 } 94 95 void TextInputTestHelper::OnBlur() { 96 focus_state_ = false; 97 if (waiting_type_ == WAIT_ON_BLUR) 98 base::MessageLoop::current()->Quit(); 99 } 100 101 void TextInputTestHelper::OnCaretBoundsChanged( 102 const ui::TextInputClient* client) { 103 gfx::Range text_range; 104 if (GetTextInputClient()) { 105 if (!GetTextInputClient()->GetTextRange(&text_range) || 106 !GetTextInputClient()->GetTextFromRange(text_range, 107 &surrounding_text_) || 108 !GetTextInputClient()->GetSelectionRange(&selection_range_)) 109 return; 110 } 111 if (waiting_type_ == WAIT_ON_CARET_BOUNDS_CHANGED) 112 base::MessageLoop::current()->Quit(); 113 } 114 115 void TextInputTestHelper::OnTextInputStateChanged( 116 const ui::TextInputClient* client) { 117 } 118 119 void TextInputTestHelper::WaitForTextInputStateChanged( 120 ui::TextInputType expected_type) { 121 CHECK_EQ(NO_WAIT, waiting_type_); 122 waiting_type_ = WAIT_ON_TEXT_INPUT_TYPE_CHANGED; 123 while (latest_text_input_type_ != expected_type) 124 content::RunMessageLoop(); 125 waiting_type_ = NO_WAIT; 126 } 127 128 void TextInputTestHelper::WaitForFocus() { 129 CHECK_EQ(NO_WAIT, waiting_type_); 130 waiting_type_ = WAIT_ON_FOCUS; 131 while (focus_state_) 132 content::RunMessageLoop(); 133 waiting_type_ = NO_WAIT; 134 } 135 136 void TextInputTestHelper::WaitForBlur() { 137 CHECK_EQ(NO_WAIT, waiting_type_); 138 waiting_type_ = WAIT_ON_BLUR; 139 while (!focus_state_) 140 content::RunMessageLoop(); 141 waiting_type_ = NO_WAIT; 142 } 143 144 void TextInputTestHelper::WaitForCaretBoundsChanged( 145 const gfx::Rect& expected_caret_rect, 146 const gfx::Rect& expected_composition_head) { 147 waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; 148 while (expected_caret_rect != caret_rect_ || 149 expected_composition_head != composition_head_) 150 content::RunMessageLoop(); 151 waiting_type_ = NO_WAIT; 152 } 153 154 void TextInputTestHelper::WaitForSurroundingTextChanged( 155 const base::string16& expected_text, 156 const gfx::Range& expected_selection) { 157 waiting_type_ = WAIT_ON_CARET_BOUNDS_CHANGED; 158 while (expected_text != surrounding_text_ || 159 expected_selection != selection_range_) 160 content::RunMessageLoop(); 161 waiting_type_ = NO_WAIT; 162 } 163 164 // static 165 bool TextInputTestHelper::ConvertRectFromString(const std::string& str, 166 gfx::Rect* rect) { 167 DCHECK(rect); 168 std::vector<std::string> rect_piece; 169 if (Tokenize(str, ",", &rect_piece) != 4UL) 170 return false; 171 int x, y, width, height; 172 if (!base::StringToInt(rect_piece[0], &x)) 173 return false; 174 if (!base::StringToInt(rect_piece[1], &y)) 175 return false; 176 if (!base::StringToInt(rect_piece[2], &width)) 177 return false; 178 if (!base::StringToInt(rect_piece[3], &height)) 179 return false; 180 *rect = gfx::Rect(x, y, width, height); 181 return true; 182 } 183 184 // static 185 bool TextInputTestHelper::ClickElement(const std::string& id, 186 content::WebContents* tab) { 187 std::string coordinate; 188 if (!content::ExecuteScriptAndExtractString( 189 tab, 190 "textinput_helper.retrieveElementCoordinate('" + id + "')", 191 &coordinate)) 192 return false; 193 gfx::Rect rect; 194 if (!ConvertRectFromString(coordinate, &rect)) 195 return false; 196 197 blink::WebMouseEvent mouse_event; 198 mouse_event.type = blink::WebInputEvent::MouseDown; 199 mouse_event.button = blink::WebMouseEvent::ButtonLeft; 200 mouse_event.x = rect.CenterPoint().x(); 201 mouse_event.y = rect.CenterPoint().y(); 202 mouse_event.clickCount = 1; 203 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 204 205 mouse_event.type = blink::WebInputEvent::MouseUp; 206 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 207 return true; 208 } 209 210 } // namespace chromeos 211