| Index: content/public/test/text_input_test_utils.cc | 
| diff --git a/content/public/test/text_input_test_utils.cc b/content/public/test/text_input_test_utils.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..895f7b743d0bee0f76c7df4b0aa4641cdf921927 | 
| --- /dev/null | 
| +++ b/content/public/test/text_input_test_utils.cc | 
| @@ -0,0 +1,325 @@ | 
| +// Copyright 2016 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 "content/public/test/text_input_test_utils.h" | 
| + | 
| +#include "content/browser/renderer_host/render_widget_host_view_aura.h" | 
| +#include "content/browser/renderer_host/render_widget_host_view_base.h" | 
| +#include "content/browser/renderer_host/render_widget_host_view_base_observer.h" | 
| +#include "content/browser/renderer_host/text_input_manager.h" | 
| +#include "content/browser/web_contents/web_contents_impl.h" | 
| +#include "content/common/text_input_state.h" | 
| +#include "content/public/browser/render_widget_host_view.h" | 
| +#include "content/public/browser/web_contents.h" | 
| +#include "content/public/browser/web_contents_observer.h" | 
| +#include "content/public/test/test_utils.h" | 
| +#include "ui/base/ime/input_method.h" | 
| +#include "ui/base/ime/input_method_observer.h" | 
| + | 
| +namespace ui { | 
| +class TextInputClient; | 
| +} | 
| + | 
| +namespace content { | 
| + | 
| +// This class is an observer of TextInputManager associated with the provided | 
| +// WebContents. An instance of this class is used in TextInputManagerTester to | 
| +// expose the required API for testing outside of content/. | 
| +class TextInputManagerTester::InternalObserver | 
| +    : public TextInputManager::Observer, | 
| +      public WebContentsObserver { | 
| + public: | 
| +  InternalObserver(WebContents* web_contents, TextInputManagerTester* tester) | 
| +      : WebContentsObserver(web_contents), | 
| +        tester_(tester), | 
| +        updated_view_(nullptr), | 
| +        text_input_state_changed_(false) { | 
| +    text_input_manager_ = | 
| +        static_cast<WebContentsImpl*>(web_contents)->GetTextInputManager(); | 
| +    DCHECK(!!text_input_manager_); | 
| +    text_input_manager_->AddObserver(this); | 
| +  } | 
| + | 
| +  ~InternalObserver() override { | 
| +    if (text_input_manager_) | 
| +      text_input_manager_->RemoveObserver(this); | 
| +  } | 
| + | 
| +  void set_update_text_input_state_called_callback( | 
| +      const TextInputManagerTester::Callback& callback) { | 
| +    update_text_input_state_callback_ = callback; | 
| +  } | 
| + | 
| +  const RenderWidgetHostView* GetUpdatedView() const { return updated_view_; } | 
| + | 
| +  bool text_input_state_changed() const { return text_input_state_changed_; } | 
| + | 
| +  TextInputManager* text_input_manager() const { return text_input_manager_; } | 
| + | 
| +  // TextInputManager::Observer implementations. | 
| +  void OnUpdateTextInputStateCalled(TextInputManager* text_input_manager, | 
| +                                    RenderWidgetHostViewBase* updated_view, | 
| +                                    bool did_change_state) override { | 
| +    if (text_input_manager_ != text_input_manager) | 
| +      return; | 
| +    text_input_state_changed_ = did_change_state; | 
| +    updated_view_ = updated_view; | 
| +    update_text_input_state_callback_.Run(tester_); | 
| +  } | 
| + | 
| +  // WebContentsObserver implementation. | 
| +  void WebContentsDestroyed() override { text_input_manager_ = nullptr; } | 
| + | 
| + private: | 
| +  TextInputManagerTester* tester_; | 
| +  TextInputManager* text_input_manager_; | 
| +  RenderWidgetHostViewBase* updated_view_; | 
| +  bool text_input_state_changed_; | 
| +  TextInputManagerTester::Callback update_text_input_state_callback_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(InternalObserver); | 
| +}; | 
| + | 
| +// This class observes the lifetime of a RenderWidgetHostView. An instance of | 
| +// this class is used in TestRenderWidgetHostViewDestructionObserver to expose | 
| +// the required observer API for testing outside of content/. | 
| +class TestRenderWidgetHostViewDestructionObserver::InternalObserver | 
| +    : public RenderWidgetHostViewBaseObserver { | 
| + public: | 
| +  InternalObserver(RenderWidgetHostViewBase* view) | 
| +      : view_(view), destroyed_(false) { | 
| +    view->AddObserver(this); | 
| +  } | 
| + | 
| +  ~InternalObserver() override { | 
| +    if (view_) | 
| +      view_->RemoveObserver(this); | 
| +  } | 
| + | 
| +  void Wait() { | 
| +    if (destroyed_) | 
| +      return; | 
| +    message_loop_runner_ = new content::MessageLoopRunner(); | 
| +    message_loop_runner_->Run(); | 
| +  } | 
| + | 
| + private: | 
| +  void OnRenderWidgetHostViewBaseDestroyed( | 
| +      RenderWidgetHostViewBase* view) override { | 
| +    DCHECK_EQ(view_, view); | 
| +    destroyed_ = true; | 
| +    view->RemoveObserver(this); | 
| +    view_ = nullptr; | 
| +    if (message_loop_runner_) | 
| +      message_loop_runner_->Quit(); | 
| +  } | 
| + | 
| +  RenderWidgetHostViewBase* view_; | 
| +  bool destroyed_; | 
| +  scoped_refptr<MessageLoopRunner> message_loop_runner_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(InternalObserver); | 
| +}; | 
| + | 
| +#ifdef USE_AURA | 
| +class InputMethodObserverAura : public TestInputMethodObserver, | 
| +                                public ui::InputMethodObserver { | 
| + public: | 
| +  explicit InputMethodObserverAura(ui::InputMethod* input_method) | 
| +      : input_method_(input_method), text_input_client_(nullptr) { | 
| +    input_method_->AddObserver(this); | 
| +  } | 
| + | 
| +  ~InputMethodObserverAura() override { | 
| +    if (input_method_) | 
| +      input_method_->RemoveObserver(this); | 
| +  } | 
| + | 
| +  // TestInputMethodObserver implementations. | 
| +  ui::TextInputType GetTextInputTypeFromClient() override { | 
| +    if (text_input_client_) | 
| +      return text_input_client_->GetTextInputType(); | 
| + | 
| +    return ui::TEXT_INPUT_TYPE_NONE; | 
| +  } | 
| + | 
| +  void SetOnTextInputTypeChangedCallback( | 
| +      const base::Closure& callback) override { | 
| +    on_text_input_type_changed_callback_ = callback; | 
| +  } | 
| + | 
| +  void SetOnShowImeIfNeededCallback(const base::Closure& callback) override { | 
| +    on_show_ime_if_needed_callback_ = callback; | 
| +  } | 
| + | 
| + private: | 
| +  // ui::InputMethodObserver implementations. | 
| +  void OnTextInputTypeChanged(const ui::TextInputClient* client) override { | 
| +    text_input_client_ = client; | 
| +    on_text_input_type_changed_callback_.Run(); | 
| +  } | 
| + | 
| +  void OnFocus() override {} | 
| +  void OnBlur() override {} | 
| +  void OnCaretBoundsChanged(const ui::TextInputClient* client) override {} | 
| +  void OnTextInputStateChanged(const ui::TextInputClient* client) override {} | 
| +  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {} | 
| + | 
| +  void OnShowImeIfNeeded() override { on_show_ime_if_needed_callback_.Run(); } | 
| + | 
| +  ui::InputMethod* input_method_; | 
| +  const ui::TextInputClient* text_input_client_; | 
| +  base::Closure on_text_input_type_changed_callback_; | 
| +  base::Closure on_show_ime_if_needed_callback_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(InputMethodObserverAura); | 
| +}; | 
| +#endif | 
| + | 
| +ui::TextInputType GetTextInputTypeFromWebContents(WebContents* web_contents) { | 
| +  const TextInputState* state = static_cast<WebContentsImpl*>(web_contents) | 
| +                                    ->GetTextInputManager() | 
| +                                    ->GetTextInputState(); | 
| +  return !!state ? state->type : ui::TEXT_INPUT_TYPE_NONE; | 
| +} | 
| + | 
| +bool GetTextInputTypeForView(WebContents* web_contents, | 
| +                             RenderWidgetHostView* view, | 
| +                             ui::TextInputType* type) { | 
| +  TextInputManager* manager = | 
| +      static_cast<WebContentsImpl*>(web_contents)->GetTextInputManager(); | 
| + | 
| +  RenderWidgetHostViewBase* view_base = | 
| +      static_cast<RenderWidgetHostViewBase*>(view); | 
| +  if (!manager || !manager->IsRegistered(view_base)) | 
| +    return false; | 
| + | 
| +  *type = manager->text_input_state_map_[view_base].type; | 
| +  return true; | 
| +} | 
| + | 
| +RenderWidgetHostView* GetActiveViewFromWebContents(WebContents* web_contents) { | 
| +  return static_cast<WebContentsImpl*>(web_contents) | 
| +      ->GetTextInputManager() | 
| +      ->GetActiveView(); | 
| +} | 
| + | 
| +TextInputManagerTester::TextInputManagerTester(WebContents* web_contents) | 
| +    : observer_(new InternalObserver(web_contents, this)) {} | 
| + | 
| +TextInputManagerTester::~TextInputManagerTester() {} | 
| + | 
| +void TextInputManagerTester::SetUpdateTextInputStateCalledCallback( | 
| +    const Callback& callback) { | 
| +  observer_->set_update_text_input_state_called_callback(callback); | 
| +} | 
| + | 
| +bool TextInputManagerTester::GetTextInputType(ui::TextInputType* type) { | 
| +  DCHECK(observer_->text_input_manager()); | 
| +  const TextInputState* state = | 
| +      observer_->text_input_manager()->GetTextInputState(); | 
| +  if (!state) | 
| +    return false; | 
| +  *type = state->type; | 
| +  return true; | 
| +} | 
| + | 
| +bool TextInputManagerTester::GetTextInputValue(std::string* value) { | 
| +  DCHECK(observer_->text_input_manager()); | 
| +  const TextInputState* state = | 
| +      observer_->text_input_manager()->GetTextInputState(); | 
| +  if (!state) | 
| +    return false; | 
| +  *value = state->value; | 
| +  return true; | 
| +} | 
| + | 
| +const RenderWidgetHostView* TextInputManagerTester::GetActiveView() { | 
| +  DCHECK(observer_->text_input_manager()); | 
| +  return observer_->text_input_manager()->GetActiveView(); | 
| +} | 
| + | 
| +const RenderWidgetHostView* TextInputManagerTester::GetUpdatedView() { | 
| +  return observer_->GetUpdatedView(); | 
| +} | 
| + | 
| +bool TextInputManagerTester::IsTextInputStateChanged() { | 
| +  return observer_->text_input_state_changed(); | 
| +} | 
| + | 
| +TestRenderWidgetHostViewDestructionObserver:: | 
| +    TestRenderWidgetHostViewDestructionObserver(RenderWidgetHostView* view) | 
| +    : observer_( | 
| +          new InternalObserver(static_cast<RenderWidgetHostViewBase*>(view))) {} | 
| + | 
| +TestRenderWidgetHostViewDestructionObserver:: | 
| +    ~TestRenderWidgetHostViewDestructionObserver() {} | 
| + | 
| +void TestRenderWidgetHostViewDestructionObserver::Wait() { | 
| +  observer_->Wait(); | 
| +} | 
| + | 
| +TextInputStateSender::TextInputStateSender(RenderWidgetHostView* view) | 
| +    : text_input_state_(new TextInputState()), | 
| +      view_(static_cast<RenderWidgetHostViewBase*>(view)) {} | 
| + | 
| +TextInputStateSender::~TextInputStateSender() {} | 
| + | 
| +void TextInputStateSender::Send() { | 
| +  if (view_) | 
| +    view_->TextInputStateChanged(*text_input_state_); | 
| +} | 
| + | 
| +void TextInputStateSender::SetFromCurrentState() { | 
| +  if (view_) { | 
| +    *text_input_state_ = | 
| +        *RenderWidgetHostImpl::From(view_->GetRenderWidgetHost()) | 
| +             ->delegate() | 
| +             ->GetTextInputManager() | 
| +             ->GetTextInputState(); | 
| +  } | 
| +} | 
| + | 
| +void TextInputStateSender::SetType(ui::TextInputType type) { | 
| +  text_input_state_->type = type; | 
| +} | 
| + | 
| +void TextInputStateSender::SetMode(ui::TextInputMode mode) { | 
| +  text_input_state_->mode = mode; | 
| +} | 
| + | 
| +void TextInputStateSender::SetFlags(int flags) { | 
| +  text_input_state_->flags = flags; | 
| +} | 
| + | 
| +void TextInputStateSender::SetCanComposeInline(bool can_compose_inline) { | 
| +  text_input_state_->can_compose_inline = can_compose_inline; | 
| +} | 
| + | 
| +void TextInputStateSender::SetShowImeIfNeeded(bool show_ime_if_needed) { | 
| +  text_input_state_->show_ime_if_needed = show_ime_if_needed; | 
| +} | 
| + | 
| +void TextInputStateSender::SetIsNonImeChange(bool is_non_ime_change) { | 
| +  text_input_state_->is_non_ime_change = is_non_ime_change; | 
| +} | 
| + | 
| +TestInputMethodObserver::TestInputMethodObserver() {} | 
| + | 
| +TestInputMethodObserver::~TestInputMethodObserver() {} | 
| + | 
| +// static | 
| +std::unique_ptr<TestInputMethodObserver> TestInputMethodObserver::Create( | 
| +    WebContents* web_contents) { | 
| +  std::unique_ptr<TestInputMethodObserver> observer; | 
| + | 
| +#ifdef USE_AURA | 
| +  RenderWidgetHostViewAura* view = static_cast<RenderWidgetHostViewAura*>( | 
| +      web_contents->GetRenderWidgetHostView()); | 
| +  observer.reset(new InputMethodObserverAura(view->GetInputMethod())); | 
| +#endif | 
| +  return observer; | 
| +} | 
| + | 
| +}  // namespace content | 
|  |