summaryrefslogtreecommitdiff
path: root/chromium/ui/base/ime/win
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/base/ime/win')
-rw-r--r--chromium/ui/base/ime/win/input_method_win_tsf.cc8
-rw-r--r--chromium/ui/base/ime/win/input_method_win_tsf.h1
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc25
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.h3
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc100
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.h8
6 files changed, 89 insertions, 56 deletions
diff --git a/chromium/ui/base/ime/win/input_method_win_tsf.cc b/chromium/ui/base/ime/win/input_method_win_tsf.cc
index 5eff60756ee..972945e6b00 100644
--- a/chromium/ui/base/ime/win/input_method_win_tsf.cc
+++ b/chromium/ui/base/ime/win/input_method_win_tsf.cc
@@ -129,6 +129,14 @@ void InputMethodWinTSF::DetachTextInputClient(TextInputClient* client) {
ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
}
+bool InputMethodWinTSF::IsInputLocaleCJK() const {
+ if (!ui::TSFBridge::GetInstance()) {
+ return false;
+ }
+
+ return ui::TSFBridge::GetInstance()->IsInputLanguageCJK();
+}
+
bool InputMethodWinTSF::IsCandidatePopupOpen() const {
return tsf_event_observer_->IsCandidatePopupOpen();
}
diff --git a/chromium/ui/base/ime/win/input_method_win_tsf.h b/chromium/ui/base/ime/win/input_method_win_tsf.h
index b04867d627b..9fcf170142b 100644
--- a/chromium/ui/base/ime/win/input_method_win_tsf.h
+++ b/chromium/ui/base/ime/win/input_method_win_tsf.h
@@ -33,6 +33,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) InputMethodWinTSF
void OnCaretBoundsChanged(const TextInputClient* client) override;
void CancelComposition(const TextInputClient* client) override;
void DetachTextInputClient(TextInputClient* client) override;
+ bool IsInputLocaleCJK() const override;
bool IsCandidatePopupOpen() const override;
// Overridden from InputMethodBase:
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
index fa78d5c973a..e70f1b91517 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -42,6 +42,7 @@ class TSFBridgeImpl : public TSFBridge {
void RemoveFocusedClient(TextInputClient* client) override;
void SetInputMethodDelegate(internal::InputMethodDelegate* delegate) override;
void RemoveInputMethodDelegate() override;
+ bool IsInputLanguageCJK() override;
Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override;
TextInputClient* GetFocusedTextInputClient() const override;
@@ -109,6 +110,10 @@ class TSFBridgeImpl : public TSFBridge {
// An ITfThreadMgr object to be used in focus and document management.
Microsoft::WRL::ComPtr<ITfThreadMgr> thread_manager_;
+ // An ITfInputProcessorProfiles object to be used to get current language
+ // locale profile.
+ Microsoft::WRL::ComPtr<ITfInputProcessorProfiles> input_processor_profiles_;
+
// A map from TextInputType to an editable document for TSF. We use multiple
// TSF documents that have different InputScopes and TSF attributes based on
// the TextInputType associated with the target document. For a TextInputType
@@ -172,6 +177,13 @@ bool TSFBridgeImpl::Initialize() {
return false;
}
+ if (FAILED(::CoCreateInstance(CLSID_TF_InputProcessorProfiles, nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(&input_processor_profiles_)))) {
+ DVLOG(1) << "Failed to create InputProcessorProfiles instance.";
+ return false;
+ }
+
if (FAILED(::CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_ALL,
IID_PPV_ARGS(&thread_manager_)))) {
DVLOG(1) << "Failed to create ThreadManager instance.";
@@ -332,6 +344,17 @@ void TSFBridgeImpl::RemoveInputMethodDelegate() {
}
}
+bool TSFBridgeImpl::IsInputLanguageCJK() {
+ LANGID lang_locale;
+ if (SUCCEEDED(input_processor_profiles_->GetCurrentLanguage(&lang_locale))) {
+ lang_locale = PRIMARYLANGID(lang_locale);
+ return lang_locale == LANG_CHINESE || lang_locale == LANG_JAPANESE ||
+ lang_locale == LANG_KOREAN;
+ } else {
+ return false;
+ }
+}
+
TextInputClient* TSFBridgeImpl::GetFocusedTextInputClient() const {
return client_;
}
@@ -429,6 +452,8 @@ bool TSFBridgeImpl::InitializeDocumentMapInternal() {
tsf_document_map_[input_type].text_store = text_store;
tsf_document_map_[input_type].document_manager = document_manager;
tsf_document_map_[input_type].cookie = cookie;
+ if (text_store)
+ text_store->OnContextInitialized(context.Get());
}
return true;
}
diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h
index 2fbc7bf5fcc..0082f521f1b 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.h
+++ b/chromium/ui/base/ime/win/tsf_bridge.h
@@ -82,6 +82,9 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFBridge {
// Remove InputMethodDelegate instance from TSFTextStore when not in focus.
virtual void RemoveInputMethodDelegate() = 0;
+ // Returns whether the system's input language is CJK.
+ virtual bool IsInputLanguageCJK() = 0;
+
// Obtains current thread manager.
virtual Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() = 0;
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
index 5e846168ab2..b82b3e2e93c 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store.cc
@@ -849,6 +849,7 @@ STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context,
if (SUCCEEDED(
context_composition->EnumCompositions(&enum_composition_view))) {
Microsoft::WRL::ComPtr<ITfCompositionView> composition_view;
+ bool has_composition = false;
if (enum_composition_view->Next(1, &composition_view, nullptr) == S_OK) {
Microsoft::WRL::ComPtr<ITfRange> range;
if (SUCCEEDED(composition_view->GetRange(&range))) {
@@ -857,14 +858,21 @@ STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context,
LONG start = 0;
LONG length = 0;
if (SUCCEEDED(range_acp->GetExtent(&start, &length))) {
- composition_start_ = start;
- has_composition_range_ = true;
- composition_range_.set_start(start);
- composition_range_.set_end(start + length);
+ // We should only consider it as a valid composition if the
+ // composition range is not collapsed (length > 0).
+ if (length > 0) {
+ has_composition = true;
+ composition_start_ = start;
+ has_composition_range_ = true;
+ composition_range_.set_start(start);
+ composition_range_.set_end(start + length);
+ }
}
}
}
- } else {
+ }
+
+ if (!has_composition) {
composition_start_ = selection_.start();
if (has_composition_range_) {
has_composition_range_ = false;
@@ -986,6 +994,19 @@ bool TSFTextStore::GetCompositionStatus(
return true;
}
+bool TSFTextStore::TerminateComposition() {
+ if (context_ && has_composition_range_) {
+ Microsoft::WRL::ComPtr<ITfContextOwnerCompositionServices> service;
+
+ if (SUCCEEDED(context_->QueryInterface(IID_PPV_ARGS(&service)))) {
+ service->TerminateComposition(nullptr);
+ return true;
+ }
+ }
+
+ return false;
+}
+
void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() {
if (!text_input_client_)
return;
@@ -1094,6 +1115,10 @@ void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() {
}
}
+void TSFTextStore::OnContextInitialized(ITfContext* context) {
+ context_ = context;
+}
+
void TSFTextStore::SetFocusedTextInputClient(
HWND focused_window,
TextInputClient* text_input_client) {
@@ -1119,39 +1144,17 @@ void TSFTextStore::RemoveInputMethodDelegate() {
}
bool TSFTextStore::CancelComposition() {
- // If there is an on-going document lock, we must not edit the text.
- if (edit_flag_)
- return false;
-
- if (string_pending_insertion_.empty())
- return true;
-
- // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does
- // not have a dedicated method to cancel composition. However, CUAS actually
- // has a protocol conversion from CPS_CANCEL into TSF operations. According
- // to the observations on Windows 7, TIPs are expected to cancel composition
- // when an on-going composition text is replaced with an empty string. So
- // we use the same operation to cancel composition here to minimize the risk
- // of potential compatibility issues.
-
- previous_composition_string_.clear();
- previous_composition_start_ = 0;
- previous_composition_selection_range_ = gfx::Range::InvalidRange();
- const size_t previous_buffer_size = string_buffer_document_.size();
- string_pending_insertion_.clear();
- composition_start_ = selection_.start();
- if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
- text_store_acp_sink_->OnSelectionChange();
- if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
- text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
- if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
- TS_TEXTCHANGE textChange = {};
- textChange.acpStart = 0;
- textChange.acpOldEnd = previous_buffer_size;
- textChange.acpNewEnd = 0;
- text_store_acp_sink_->OnTextChange(0, &textChange);
- }
- return true;
+ // This method should correspond to
+ // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0)
+ // in IMM32 hence calling falling back to |ConfirmComposition()| is not
+ // technically correct, because |ConfirmComposition()| corresponds to
+ // |CPS_COMPLETE| rather than |CPS_CANCEL|.
+ // However in Chromium it seems that |InputMethod::CancelComposition()|
+ // might have already committed composing text despite its name.
+ // TODO(IME): Check other platforms to see if |CancelComposition()| is
+ // actually working or not.
+
+ return ConfirmComposition();
}
bool TSFTextStore::ConfirmComposition() {
@@ -1165,28 +1168,13 @@ bool TSFTextStore::ConfirmComposition() {
if (!text_input_client_)
return false;
- // See the comment in TSFTextStore::CancelComposition.
- // This logic is based on the observation about how to emulate
- // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS.
-
previous_composition_string_.clear();
previous_composition_start_ = 0;
previous_composition_selection_range_ = gfx::Range::InvalidRange();
- const size_t previous_buffer_size = string_buffer_document_.size();
string_pending_insertion_.clear();
- composition_start_ = selection_.start();
- if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
- text_store_acp_sink_->OnSelectionChange();
- if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
- text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
- if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
- TS_TEXTCHANGE textChange = {};
- textChange.acpStart = 0;
- textChange.acpOldEnd = previous_buffer_size;
- textChange.acpNewEnd = 0;
- text_store_acp_sink_->OnTextChange(0, &textChange);
- }
- return true;
+ composition_start_ = selection_.end();
+
+ return TerminateComposition();
}
void TSFTextStore::SendOnLayoutChange() {
diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h
index 2605a96a462..4eed8c08e81 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.h
+++ b/chromium/ui/base/ime/win/tsf_text_store.h
@@ -234,6 +234,10 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
STDMETHOD(OnKeyTraceUp)
(WPARAM wParam, LPARAM lParam) override;
+ // Called after |TSFBridgeImpl::CreateDocumentManager| to tell that the
+ // text-store is successfully associated with a Context.
+ void OnContextInitialized(ITfContext* context);
+
// Sets currently focused TextInputClient.
void SetFocusedTextInputClient(HWND focused_window,
TextInputClient* text_input_client);
@@ -259,6 +263,9 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
friend class TSFTextStoreTest;
friend class TSFTextStoreTestCallback;
+ // Terminate an active composition for this text store.
+ bool TerminateComposition();
+
// Compare our cached text buffer and selection with the up-to-date
// text buffer and selection from TextInputClient. We also update
// cached text buffer and selection with the new version. Then notify
@@ -413,6 +420,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
// attributes of the composition string.
Microsoft::WRL::ComPtr<ITfCategoryMgr> category_manager_;
Microsoft::WRL::ComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;
+ Microsoft::WRL::ComPtr<ITfContext> context_;
DISALLOW_COPY_AND_ASSIGN(TSFTextStore);
};