diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/arc.gypi | 6 | ||||
-rw-r--r-- | components/arc/BUILD.gn | 6 | ||||
-rw-r--r-- | components/arc/arc_bridge_service.cc | 25 | ||||
-rw-r--r-- | components/arc/arc_bridge_service.h | 11 | ||||
-rw-r--r-- | components/arc/arc_service_manager.cc | 2 | ||||
-rw-r--r-- | components/arc/arc_service_manager.h | 2 | ||||
-rw-r--r-- | components/arc/common/arc_bridge.mojom | 4 | ||||
-rw-r--r-- | components/arc/common/ime.mojom | 59 | ||||
-rw-r--r-- | components/arc/ime/DEPS | 6 | ||||
-rw-r--r-- | components/arc/ime/arc_ime_bridge.cc | 218 | ||||
-rw-r--r-- | components/arc/ime/arc_ime_bridge.h | 105 | ||||
-rw-r--r-- | components/arc/ime/arc_ime_ipc_host.cc | 132 | ||||
-rw-r--r-- | components/arc/ime/arc_ime_ipc_host.h | 63 |
13 files changed, 639 insertions, 0 deletions
diff --git a/components/arc.gypi b/components/arc.gypi index cb38d29..a5e0835 100644 --- a/components/arc.gypi +++ b/components/arc.gypi @@ -19,6 +19,7 @@ '../ipc/ipc.gyp:ipc', '../ui/arc/arc.gyp:arc', '../ui/aura/aura.gyp:aura', + '../ui/base/ime/ui_base_ime.gyp:ui_base_ime', '../ui/base/ui_base.gyp:ui_base', '../ui/events/events.gyp:events_base', ], @@ -34,6 +35,10 @@ 'arc/arc_service_manager.h', 'arc/clipboard/arc_clipboard_bridge.cc', 'arc/clipboard/arc_clipboard_bridge.h', + 'arc/ime/arc_ime_bridge.cc', + 'arc/ime/arc_ime_bridge.h', + 'arc/ime/arc_ime_ipc_host.cc', + 'arc/ime/arc_ime_ipc_host.h', 'arc/input/arc_input_bridge.h', 'arc/input/arc_input_bridge_impl.cc', 'arc/input/arc_input_bridge_impl.h', @@ -79,6 +84,7 @@ 'arc/common/arc_bridge.mojom', 'arc/common/auth.mojom', 'arc/common/clipboard.mojom', + 'arc/common/ime.mojom', 'arc/common/input.mojom', 'arc/common/notifications.mojom', 'arc/common/power.mojom', diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index 6ea143d..e753041 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn @@ -17,6 +17,10 @@ static_library("arc") { "auth/arc_auth_service.h", "clipboard/arc_clipboard_bridge.cc", "clipboard/arc_clipboard_bridge.h", + "ime/arc_ime_bridge.cc", + "ime/arc_ime_bridge.h", + "ime/arc_ime_ipc_host.cc", + "ime/arc_ime_ipc_host.h", "input/arc_input_bridge.h", "input/arc_input_bridge_impl.cc", "input/arc_input_bridge_impl.h", @@ -41,6 +45,7 @@ static_library("arc") { "//ui/arc", "//ui/aura", "//ui/base:base", + "//ui/base/ime", "//ui/events", "//ui/events:dom_keycode_converter", ] @@ -56,6 +61,7 @@ mojom("arc_bindings") { "common/arc_bridge.mojom", "common/auth.mojom", "common/clipboard.mojom", + "common/ime.mojom", "common/input.mojom", "common/notifications.mojom", "common/power.mojom", diff --git a/components/arc/arc_bridge_service.cc b/components/arc/arc_bridge_service.cc index 9183477..cbb8bde 100644 --- a/components/arc/arc_bridge_service.cc +++ b/components/arc/arc_bridge_service.cc @@ -129,6 +129,30 @@ void ArcBridgeService::CloseClipboardChannel() { FOR_EACH_OBSERVER(Observer, observer_list(), OnClipboardInstanceClosed()); } +void ArcBridgeService::OnImeInstanceReady(ImeInstancePtr ime_ptr) { + DCHECK(CalledOnValidThread()); + temporary_ime_ptr_ = std::move(ime_ptr); + temporary_ime_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnImeVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnImeVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + ime_ptr_ = std::move(temporary_ime_ptr_); + ime_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::CloseImeChannel, weak_factory_.GetWeakPtr())); + FOR_EACH_OBSERVER(Observer, observer_list(), OnImeInstanceReady()); +} + +void ArcBridgeService::CloseImeChannel() { + DCHECK(CalledOnValidThread()); + if (!ime_ptr_) + return; + + ime_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnImeInstanceClosed()); +} + void ArcBridgeService::OnInputInstanceReady(InputInstancePtr input_ptr) { DCHECK(CalledOnValidThread()); temporary_input_ptr_ = std::move(input_ptr); @@ -302,6 +326,7 @@ void ArcBridgeService::CloseAllChannels() { CloseAppChannel(); CloseAuthChannel(); CloseClipboardChannel(); + CloseImeChannel(); CloseInputChannel(); CloseNotificationsChannel(); ClosePowerChannel(); diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h index 509c79c..94871c7 100644 --- a/components/arc/arc_bridge_service.h +++ b/components/arc/arc_bridge_service.h @@ -85,6 +85,10 @@ class ArcBridgeService : public ArcBridgeHost { virtual void OnClipboardInstanceReady() {} virtual void OnClipboardInstanceClosed() {} + // Called whenever the ARC IME interface state changes. + virtual void OnImeInstanceReady() {} + virtual void OnImeInstanceClosed() {} + // Called whenever the ARC input interface state changes. virtual void OnInputInstanceReady() {} virtual void OnInputInstanceClosed() {} @@ -149,6 +153,7 @@ class ArcBridgeService : public ArcBridgeHost { AppInstance* app_instance() { return app_ptr_.get(); } AuthInstance* auth_instance() { return auth_ptr_.get(); } ClipboardInstance* clipboard_instance() { return clipboard_ptr_.get(); } + ImeInstance* ime_instance() { return ime_ptr_.get(); } InputInstance* input_instance() { return input_ptr_.get(); } NotificationsInstance* notifications_instance() { return notifications_ptr_.get(); @@ -161,6 +166,7 @@ class ArcBridgeService : public ArcBridgeHost { int32_t app_version() const { return app_ptr_.version(); } int32_t auth_version() const { return auth_ptr_.version(); } int32_t clipboard_version() const { return clipboard_ptr_.version(); } + int32_t ime_version() const { return ime_ptr_.version(); } int32_t input_version() const { return input_ptr_.version(); } int32_t notifications_version() const { return notifications_ptr_.version(); } int32_t power_version() const { return power_ptr_.version(); } @@ -172,6 +178,7 @@ class ArcBridgeService : public ArcBridgeHost { void OnAppInstanceReady(AppInstancePtr app_ptr) override; void OnAuthInstanceReady(AuthInstancePtr auth_ptr) override; void OnClipboardInstanceReady(ClipboardInstancePtr clipboard_ptr) override; + void OnImeInstanceReady(ImeInstancePtr ime_ptr) override; void OnInputInstanceReady(InputInstancePtr input_ptr) override; void OnNotificationsInstanceReady( NotificationsInstancePtr notifications_ptr) override; @@ -213,6 +220,7 @@ class ArcBridgeService : public ArcBridgeHost { void CloseAppChannel(); void CloseAuthChannel(); void CloseClipboardChannel(); + void CloseImeChannel(); void CloseInputChannel(); void CloseNotificationsChannel(); void ClosePowerChannel(); @@ -224,6 +232,7 @@ class ArcBridgeService : public ArcBridgeHost { void OnAppVersionReady(int32_t version); void OnAuthVersionReady(int32_t version); void OnClipboardVersionReady(int32_t version); + void OnImeVersionReady(int32_t version); void OnInputVersionReady(int32_t version); void OnNotificationsVersionReady(int32_t version); void OnPowerVersionReady(int32_t version); @@ -235,6 +244,7 @@ class ArcBridgeService : public ArcBridgeHost { AppInstancePtr app_ptr_; AuthInstancePtr auth_ptr_; ClipboardInstancePtr clipboard_ptr_; + ImeInstancePtr ime_ptr_; InputInstancePtr input_ptr_; NotificationsInstancePtr notifications_ptr_; PowerInstancePtr power_ptr_; @@ -251,6 +261,7 @@ class ArcBridgeService : public ArcBridgeHost { AppInstancePtr temporary_app_ptr_; AuthInstancePtr temporary_auth_ptr_; ClipboardInstancePtr temporary_clipboard_ptr_; + ImeInstancePtr temporary_ime_ptr_; InputInstancePtr temporary_input_ptr_; NotificationsInstancePtr temporary_notifications_ptr_; PowerInstancePtr temporary_power_ptr_; diff --git a/components/arc/arc_service_manager.cc b/components/arc/arc_service_manager.cc index 4146738..3769c03 100644 --- a/components/arc/arc_service_manager.cc +++ b/components/arc/arc_service_manager.cc @@ -12,6 +12,7 @@ #include "components/arc/arc_bridge_service_impl.h" #include "components/arc/auth/arc_auth_service.h" #include "components/arc/clipboard/arc_clipboard_bridge.h" +#include "components/arc/ime/arc_ime_bridge.h" #include "components/arc/input/arc_input_bridge.h" #include "components/arc/power/arc_power_bridge.h" #include "components/arc/settings/arc_settings_bridge.h" @@ -35,6 +36,7 @@ ArcServiceManager::ArcServiceManager( new ArcBridgeServiceImpl(ArcBridgeBootstrap::Create())), arc_auth_service_(std::move(auth_service)), arc_clipboard_bridge_(new ArcClipboardBridge(arc_bridge_service_.get())), + arc_ime_bridge_(new ArcImeBridge(arc_bridge_service_.get())), arc_input_bridge_(ArcInputBridge::Create(arc_bridge_service_.get())), arc_settings_bridge_(std::move(settings_bridge)), arc_power_bridge_(new ArcPowerBridge(arc_bridge_service_.get())), diff --git a/components/arc/arc_service_manager.h b/components/arc/arc_service_manager.h index 0eaa746..8b0bc8c 100644 --- a/components/arc/arc_service_manager.h +++ b/components/arc/arc_service_manager.h @@ -15,6 +15,7 @@ namespace arc { class ArcAuthService; class ArcBridgeService; class ArcClipboardBridge; +class ArcImeBridge; class ArcInputBridge; class ArcNotificationManager; class ArcPowerBridge; @@ -48,6 +49,7 @@ class ArcServiceManager { // Individual services scoped_ptr<ArcAuthService> arc_auth_service_; scoped_ptr<ArcClipboardBridge> arc_clipboard_bridge_; + scoped_ptr<ArcImeBridge> arc_ime_bridge_; scoped_ptr<ArcInputBridge> arc_input_bridge_; scoped_ptr<ArcNotificationManager> arc_notification_manager_; scoped_ptr<ArcSettingsBridge> arc_settings_bridge_; diff --git a/components/arc/common/arc_bridge.mojom b/components/arc/common/arc_bridge.mojom index 3844592..4e38413 100644 --- a/components/arc/common/arc_bridge.mojom +++ b/components/arc/common/arc_bridge.mojom @@ -7,6 +7,7 @@ module arc; import "app.mojom"; import "auth.mojom"; import "clipboard.mojom"; +import "ime.mojom"; import "input.mojom"; import "notifications.mojom"; import "power.mojom"; @@ -28,6 +29,9 @@ interface ArcBridgeHost { // Notifies Chrome that the ClipboardInstance interface is ready. [MinVersion=2] OnClipboardInstanceReady@109(ClipboardInstance instance_ptr); + // Notifies Chrome that the ImeInstance interface is ready. + [MinVersion=3] OnImeInstanceReady@110(ImeInstance instance_ptr); + // Notifies Chrome that the InputInstnace interface is ready. OnInputInstanceReady@101(InputInstance instance_ptr); diff --git a/components/arc/common/ime.mojom b/components/arc/common/ime.mojom new file mode 100644 index 0000000..9722ddf --- /dev/null +++ b/components/arc/common/ime.mojom @@ -0,0 +1,59 @@ +// 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. + +module arc; + +// Represents the type of text input field currently focused. +enum TextInputType { + NONE, + TEXT, + PASSWORD, + SEARCH, + EMAIL, + NUMBER, + TELEPHONE, + URL, + DATE, + TIME, + DATETIME, +}; + +// Represents the text insertion points in the container screen coordinates. +struct CursorRect { + int32 left; + int32 top; + int32 right; + int32 bottom; +}; + +// Represents a single segment of text currently composed by IME. +struct CompositionSegment { + // Start offset of the segment in UTF-16 index. + uint32 start_offset; + // End offset of the segment in UTF-16 index. + uint32 end_offset; + // Indicates that this segment should be emphasized. + bool emphasized; +}; + +interface ImeHost { + // Notifies Chrome that the text input focus is changed. + OnTextInputTypeChanged(TextInputType type); + + // Notifies Chrome that the cursor poisition has changed. + OnCursorRectChanged(CursorRect rect); +}; + +interface ImeInstance { + Init(ImeHost host_ptr); + + // Sets composition text and attributes requested by the host IME. + SetCompositionText(string text, array<CompositionSegment> segments); + + // Commits the last set composition text and clears the composition. + ConfirmCompositionText(); + + // Commits the specified text and clears the composition. + InsertText(string text); +}; diff --git a/components/arc/ime/DEPS b/components/arc/ime/DEPS new file mode 100644 index 0000000..6d03f02 --- /dev/null +++ b/components/arc/ime/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+ui/aura", + "+ui/base/ime", + "+ui/events", + "+ui/gfx/geometry", +] diff --git a/components/arc/ime/arc_ime_bridge.cc b/components/arc/ime/arc_ime_bridge.cc new file mode 100644 index 0000000..1606f3f --- /dev/null +++ b/components/arc/ime/arc_ime_bridge.cc @@ -0,0 +1,218 @@ +// 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 "components/arc/ime/arc_ime_bridge.h" + +#include "base/logging.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/env.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/ime/input_method.h" +#include "ui/events/base_event_utils.h" +#include "ui/events/event.h" + +namespace arc { + +namespace { + +// TODO(kinaba): handling ARC windows by window names is the same temporary +// workaroud also used in arc/input/arc_input_bridge_impl.cc. We need to move +// it to more solid implementation after focus handling in components/exo is +// stabilized. +bool IsArcWindow(const aura::Window* window) { + return window->name() == "ExoSurface"; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ArcImeBridge main implementation: + +ArcImeBridge::ArcImeBridge(ArcBridgeService* arc_bridge_service) + : ipc_host_(this, arc_bridge_service), + ime_type_(ui::TEXT_INPUT_TYPE_NONE) { + aura::Env* env = aura::Env::GetInstanceDontCreate(); + if (env) + env->AddObserver(this); +} + +ArcImeBridge::~ArcImeBridge() { + ui::InputMethod* const input_method = GetInputMethod(); + if (input_method) + input_method->DetachTextInputClient(this); + + for (aura::Window* window : arc_windows_.windows()) + window->RemoveObserver(this); + for (aura::Window* root : observing_root_windows_.windows()) + aura::client::GetFocusClient(root)->RemoveObserver(this); + aura::Env* env = aura::Env::GetInstanceDontCreate(); + if (env) + env->RemoveObserver(this); +} + +ui::InputMethod* ArcImeBridge::GetInputMethod() { + if (!focused_arc_window_.has_windows()) + return nullptr; + return focused_arc_window_.windows().front()->GetHost()->GetInputMethod(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Overridden from aura::EnvObserver: + +void ArcImeBridge::OnWindowInitialized(aura::Window* new_window) { + if (IsArcWindow(new_window)) { + arc_windows_.Add(new_window); + new_window->AddObserver(this); + } +} + +void ArcImeBridge::OnWindowAddedToRootWindow(aura::Window* window) { + aura::Window* root = window->GetRootWindow(); + aura::client::FocusClient* focus_client = aura::client::GetFocusClient(root); + if (focus_client && !observing_root_windows_.Contains(root)) { + focus_client->AddObserver(this); + observing_root_windows_.Add(root); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Overridden from aura::client::FocusChangeObserver: + +void ArcImeBridge::OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) { + if (focused_arc_window_.Contains(lost_focus)) { + ui::InputMethod* const input_method = GetInputMethod(); + if (input_method) + input_method->DetachTextInputClient(this); + focused_arc_window_.Remove(lost_focus); + } + + if (IsArcWindow(gained_focus)) { + focused_arc_window_.Add(gained_focus); + ui::InputMethod* const input_method = GetInputMethod(); + if (input_method) + input_method->SetFocusedTextInputClient(this); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Overridden from arc::ArcImeIpcHost::Delegate + +void ArcImeBridge::OnTextInputTypeChanged(ui::TextInputType type) { + if (ime_type_ == type) + return; + ime_type_ = type; + + ui::InputMethod* const input_method = GetInputMethod(); + if (input_method) + input_method->OnTextInputTypeChanged(this); +} + +void ArcImeBridge::OnCursorRectChanged(const gfx::Rect& rect) { + if (cursor_rect_ == rect) + return; + cursor_rect_ = rect; + + ui::InputMethod* const input_method = GetInputMethod(); + if (input_method) + input_method->OnCaretBoundsChanged(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// Oberridden from ui::TextInputClient: + +void ArcImeBridge::SetCompositionText( + const ui::CompositionText& composition) { + ipc_host_.SendSetCompositionText(composition); +} + +void ArcImeBridge::ConfirmCompositionText() { + ipc_host_.SendConfirmCompositionText(); +} + +void ArcImeBridge::ClearCompositionText() { + ipc_host_.SendInsertText(base::string16()); +} + +void ArcImeBridge::InsertText(const base::string16& text) { + ipc_host_.SendInsertText(text); +} + +void ArcImeBridge::InsertChar(const ui::KeyEvent& event) { + // Drop 0x00-0x1f (C0 controls), 0x7f (DEL), and 0x80-0x9f (C1 controls). + // See: https://en.wikipedia.org/wiki/Unicode_control_characters + // They are control characters and not treated as a text insertion. + const base::char16 ch = event.GetCharacter(); + const bool is_control_char = (0x00 <= ch && ch <= 0x1f) || + (0x7f <= ch && ch <= 0x9f); + + if (!is_control_char && !ui::IsSystemKeyModifier(event.flags())) + ipc_host_.SendInsertText(base::string16(1, event.GetText())); +} + +ui::TextInputType ArcImeBridge::GetTextInputType() const { + return ime_type_; +} + +gfx::Rect ArcImeBridge::GetCaretBounds() const { + return cursor_rect_; +} + +ui::TextInputMode ArcImeBridge::GetTextInputMode() const { + return ui::TEXT_INPUT_MODE_DEFAULT; +} + +int ArcImeBridge::GetTextInputFlags() const { + return ui::TEXT_INPUT_FLAG_NONE; +} + +bool ArcImeBridge::CanComposeInline() const { + return true; +} + +bool ArcImeBridge::GetCompositionCharacterBounds( + uint32_t index, gfx::Rect* rect) const { + return false; +} + +bool ArcImeBridge::HasCompositionText() const { + return true; +} + +bool ArcImeBridge::GetTextRange(gfx::Range* range) const { + return false; +} + +bool ArcImeBridge::GetCompositionTextRange(gfx::Range* range) const { + return false; +} + +bool ArcImeBridge::GetSelectionRange(gfx::Range* range) const { + return false; +} + +bool ArcImeBridge::SetSelectionRange(const gfx::Range& range) { + return false; +} + +bool ArcImeBridge::DeleteRange(const gfx::Range& range) { + return false; +} + +bool ArcImeBridge::GetTextFromRange( + const gfx::Range& range, base::string16* text) const { + return false; +} + +bool ArcImeBridge::ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection direction) { + return false; +} + +bool ArcImeBridge::IsEditCommandEnabled(int command_id) { + return false; +} + +} // namespace arc diff --git a/components/arc/ime/arc_ime_bridge.h b/components/arc/ime/arc_ime_bridge.h new file mode 100644 index 0000000..65b67f8 --- /dev/null +++ b/components/arc/ime/arc_ime_bridge.h @@ -0,0 +1,105 @@ +// 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. + +#ifndef COMPONENTS_ARC_IME_ARC_IME_BRIDGE_H_ +#define COMPONENTS_ARC_IME_ARC_IME_BRIDGE_H_ + +#include "base/macros.h" +#include "components/arc/ime/arc_ime_ipc_host.h" +#include "ui/aura/client/focus_change_observer.h" +#include "ui/aura/env_observer.h" +#include "ui/aura/window_observer.h" +#include "ui/aura/window_tracker.h" +#include "ui/base/ime/text_input_client.h" +#include "ui/base/ime/text_input_flags.h" +#include "ui/base/ime/text_input_type.h" +#include "ui/gfx/geometry/rect.h" + +namespace aura { +class Window; +} + +namespace ui { +class InputMethod; +} + +namespace arc { + +class ArcBridgeService; + +// This class implements ui::TextInputClient and makes ARC windows behave +// as a text input target in Chrome OS environment. +class ArcImeBridge : public ArcImeIpcHost::Delegate, + public aura::EnvObserver, + public aura::WindowObserver, + public aura::client::FocusChangeObserver, + public ui::TextInputClient { + public: + explicit ArcImeBridge(ArcBridgeService* arc_bridge_service); + ~ArcImeBridge() override; + + // Overridden from aura::EnvObserver: + void OnWindowInitialized(aura::Window* new_window) override; + + // Overridden from aura::WindowObserver: + void OnWindowAddedToRootWindow(aura::Window* window) override; + + // Overridden from aura::client::FocusChangeObserver: + void OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) override; + + // Overridden from ArcImeIpcHost::Delegate: + void OnTextInputTypeChanged(ui::TextInputType type) override; + void OnCursorRectChanged(const gfx::Rect& rect) override; + + // Overridden from ui::TextInputClient: + void SetCompositionText(const ui::CompositionText& composition) override; + void ConfirmCompositionText() override; + void ClearCompositionText() override; + void InsertText(const base::string16& text) override; + void InsertChar(const ui::KeyEvent& event) override; + ui::TextInputType GetTextInputType() const override; + gfx::Rect GetCaretBounds() const override; + + // Overridden from ui::TextInputClient (with default implementation): + // TODO(kinaba): Support each of these methods to the extent possible in + // Android input method API. + ui::TextInputMode GetTextInputMode() const override; + int GetTextInputFlags() const override; + bool CanComposeInline() const override; + bool GetCompositionCharacterBounds(uint32_t index, + gfx::Rect* rect) const override; + bool HasCompositionText() const override; + bool GetTextRange(gfx::Range* range) const override; + bool GetCompositionTextRange(gfx::Range* range) const override; + bool GetSelectionRange(gfx::Range* range) const override; + bool SetSelectionRange(const gfx::Range& range) override; + bool DeleteRange(const gfx::Range& range) override; + bool GetTextFromRange(const gfx::Range& range, + base::string16* text) const override; + void OnInputMethodChanged() override {} + bool ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection direction) override; + void ExtendSelectionAndDelete(size_t before, size_t after) override {} + void EnsureCaretInRect(const gfx::Rect& rect) override {} + bool IsEditCommandEnabled(int command_id) override; + void SetEditCommandForNextKeyEvent(int command_id) override {} + + private: + ui::InputMethod* GetInputMethod(); + + ArcImeIpcHost ipc_host_; + ui::TextInputType ime_type_; + gfx::Rect cursor_rect_; + + aura::WindowTracker observing_root_windows_; + aura::WindowTracker arc_windows_; + aura::WindowTracker focused_arc_window_; + + DISALLOW_COPY_AND_ASSIGN(ArcImeBridge); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_IME_ARC_IME_BRIDGE_H_ diff --git a/components/arc/ime/arc_ime_ipc_host.cc b/components/arc/ime/arc_ime_ipc_host.cc new file mode 100644 index 0000000..93fcef4 --- /dev/null +++ b/components/arc/ime/arc_ime_ipc_host.cc @@ -0,0 +1,132 @@ +// 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 "components/arc/ime/arc_ime_ipc_host.h" + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "components/arc/arc_bridge_service.h" +#include "ui/base/ime/composition_text.h" +#include "ui/base/ime/text_input_type.h" +#include "ui/gfx/geometry/rect.h" + +namespace arc { +namespace { + +ui::TextInputType ConvertTextInputType(arc::TextInputType ipc_type) { + // The two enum types are similar, but intentionally made not identical. + // We cannot force them to be in sync. If we do, updates in ui::TextInputType + // must always be propagated to the arc::TextInputType mojo definition in + // ARC container side, which is in a different repository than Chromium. + // We don't want such dependency. + // + // That's why we need a lengthy switch statement instead of static_cast + // guarded by a static assert on the two enums to be in sync. + switch (ipc_type) { + case arc::TEXT_INPUT_TYPE_NONE: + return ui::TEXT_INPUT_TYPE_NONE; + case arc::TEXT_INPUT_TYPE_TEXT: + return ui::TEXT_INPUT_TYPE_TEXT; + case arc::TEXT_INPUT_TYPE_PASSWORD: + return ui::TEXT_INPUT_TYPE_PASSWORD; + case arc::TEXT_INPUT_TYPE_SEARCH: + return ui::TEXT_INPUT_TYPE_SEARCH; + case arc::TEXT_INPUT_TYPE_EMAIL: + return ui::TEXT_INPUT_TYPE_EMAIL; + case arc::TEXT_INPUT_TYPE_NUMBER: + return ui::TEXT_INPUT_TYPE_NUMBER; + case arc::TEXT_INPUT_TYPE_TELEPHONE: + return ui::TEXT_INPUT_TYPE_TELEPHONE; + case arc::TEXT_INPUT_TYPE_URL: + return ui::TEXT_INPUT_TYPE_URL; + case arc::TEXT_INPUT_TYPE_DATE: + return ui::TEXT_INPUT_TYPE_DATE; + case arc::TEXT_INPUT_TYPE_TIME: + return ui::TEXT_INPUT_TYPE_TIME; + case arc::TEXT_INPUT_TYPE_DATETIME: + return ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL; + default: + return ui::TEXT_INPUT_TYPE_TEXT; + } +} + +mojo::Array<arc::CompositionSegmentPtr> ConvertSegments( + const ui::CompositionText& composition) { + mojo::Array<arc::CompositionSegmentPtr> segments = + mojo::Array<arc::CompositionSegmentPtr>::New(0); + for (const ui::CompositionUnderline& underline : composition.underlines) { + arc::CompositionSegmentPtr segment = arc::CompositionSegment::New(); + segment->start_offset = underline.start_offset; + segment->end_offset = underline.end_offset; + segment->emphasized = (underline.thick || + (composition.selection.start() == underline.start_offset && + composition.selection.end() == underline.end_offset)); + segments.push_back(std::move(segment)); + } + return segments; +} + +} // namespace + +ArcImeIpcHost::ArcImeIpcHost(Delegate* delegate, + ArcBridgeService* bridge_service) + : binding_(this), delegate_(delegate), bridge_service_(bridge_service) { + bridge_service_->AddObserver(this); +} + +ArcImeIpcHost::~ArcImeIpcHost() { + bridge_service_->RemoveObserver(this); +} + +void ArcImeIpcHost::OnImeInstanceReady() { + arc::ImeHostPtr host; + binding_.Bind(mojo::GetProxy(&host)); + bridge_service_->ime_instance()->Init(std::move(host)); +} + +void ArcImeIpcHost::SendSetCompositionText( + const ui::CompositionText& composition) { + ImeInstance* ime_instance = bridge_service_->ime_instance(); + if (!ime_instance) { + LOG(ERROR) << "ArcImeInstance method called before being ready."; + return; + } + + ime_instance->SetCompositionText(base::UTF16ToUTF8(composition.text), + ConvertSegments(composition)); +} + +void ArcImeIpcHost::SendConfirmCompositionText() { + ImeInstance* ime_instance = bridge_service_->ime_instance(); + if (!ime_instance) { + LOG(ERROR) << "ArcImeInstance method called before being ready."; + return; + } + + ime_instance->ConfirmCompositionText(); +} + +void ArcImeIpcHost::SendInsertText(const base::string16& text) { + ImeInstance* ime_instance = bridge_service_->ime_instance(); + if (!ime_instance) { + LOG(ERROR) << "ArcImeInstance method called before being ready."; + return; + } + + ime_instance->InsertText(base::UTF16ToUTF8(text)); +} + +void ArcImeIpcHost::OnTextInputTypeChanged(arc::TextInputType type) { + delegate_->OnTextInputTypeChanged(ConvertTextInputType(type)); +} + +void ArcImeIpcHost::OnCursorRectChanged(arc::CursorRectPtr rect) { + delegate_->OnCursorRectChanged(gfx::Rect( + rect->left, + rect->top, + rect->right - rect->left, + rect->bottom - rect->top)); +} + +} // namespace arc diff --git a/components/arc/ime/arc_ime_ipc_host.h b/components/arc/ime/arc_ime_ipc_host.h new file mode 100644 index 0000000..e050e84 --- /dev/null +++ b/components/arc/ime/arc_ime_ipc_host.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef COMPONENTS_ARC_IME_ARC_IME_IPC_HOST_H_ +#define COMPONENTS_ARC_IME_ARC_IME_IPC_HOST_H_ + +#include "base/macros.h" +#include "base/strings/string16.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/common/ime.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "ui/base/ime/text_input_type.h" +#include "ui/gfx/geometry/rect.h" + +namespace gfx { +class Rect; +} // namespace gfx + +namespace ui { +struct CompositionText; +} // namespace ui + +namespace arc { + +// This class encapsulates the detail of IME related IPC between +// Chromium and the ARC container. +class ArcImeIpcHost : public ImeHost, + public ArcBridgeService::Observer { + public: + // Received IPCs are deserialized and passed to this delegate. + class Delegate { + public: + virtual void OnTextInputTypeChanged(ui::TextInputType type) = 0; + virtual void OnCursorRectChanged(const gfx::Rect& rect) = 0; + }; + + ArcImeIpcHost(Delegate* delegate, ArcBridgeService* bridge_service); + ~ArcImeIpcHost() override; + + // arc::ArcBridgeService::Observer: + void OnImeInstanceReady() override; + + // Serializes and sends IME related requests through IPCs. + void SendSetCompositionText(const ui::CompositionText& composition); + void SendConfirmCompositionText(); + void SendInsertText(const base::string16& text); + + // arc::ImeHost: + void OnTextInputTypeChanged(arc::TextInputType type) override; + void OnCursorRectChanged(arc::CursorRectPtr rect) override; + + private: + mojo::Binding<ImeHost> binding_; + Delegate* const delegate_; + ArcBridgeService* const bridge_service_; + + DISALLOW_COPY_AND_ASSIGN(ArcImeIpcHost); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_IME_ARC_IME_IPC_HOST_H_ |