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_base.cc61
-rw-r--r--chromium/ui/base/ime/win/input_method_win_base.h13
-rw-r--r--chromium/ui/base/ime/win/input_method_win_imm32.cc19
-rw-r--r--chromium/ui/base/ime/win/input_method_win_tsf.cc5
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc12
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h10
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h1
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc37
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc27
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.h9
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc87
11 files changed, 169 insertions, 112 deletions
diff --git a/chromium/ui/base/ime/win/input_method_win_base.cc b/chromium/ui/base/ime/win/input_method_win_base.cc
index 83850840d83..fc9c8d3a0f2 100644
--- a/chromium/ui/base/ime/win/input_method_win_base.cc
+++ b/chromium/ui/base/ime/win/input_method_win_base.cc
@@ -13,8 +13,6 @@
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/win/windows_version.h"
-#include "ui/base/ime/ime_bridge.h"
-#include "ui/base/ime/ime_engine_handler_interface.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h"
#include "ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h"
@@ -237,21 +235,6 @@ ui::EventDispatchDetails InputMethodWinBase::DispatchKeyEvent(
!std::iswcntrl(static_cast<wint_t>(char_msgs[0].wParam)))
event->set_character(static_cast<base::char16>(char_msgs[0].wParam));
- // Dispatches the key events to the Chrome IME extension which is listening to
- // key events on the following two situations:
- // 1) |char_msgs| is empty when the event is non-character key.
- // 2) |char_msgs|.size() == 1 when the event is character key and the WM_CHAR
- // messages have been combined in the event processing flow.
- if (char_msgs.size() <= 1 && GetEngine()) {
- ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
- base::BindOnce(&InputMethodWinBase::ProcessKeyEventDone,
- weak_ptr_factory_.GetWeakPtr(),
- base::Owned(new ui::KeyEvent(*event)),
- base::Owned(new std::vector<MSG>(char_msgs)));
- GetEngine()->ProcessKeyEvent(*event, std::move(callback));
- return ui::EventDispatchDetails();
- }
-
return ProcessUnhandledKeyEvent(event, &char_msgs);
}
@@ -506,48 +489,4 @@ ui::EventDispatchDetails InputMethodWinBase::ProcessUnhandledKeyEvent(
return details;
}
-void InputMethodWinBase::UpdateCompositionBoundsForEngine(
- const TextInputClient* client) {
- TextInputType text_input_type = GetTextInputType();
- if (client == GetTextInputClient() &&
- text_input_type != TEXT_INPUT_TYPE_NONE &&
- text_input_type != TEXT_INPUT_TYPE_PASSWORD && GetEngine()) {
- GetEngine()->SetCompositionBounds(GetCompositionBounds(client));
- }
-}
-
-void InputMethodWinBase::ResetEngine() {
- if (GetEngine())
- GetEngine()->Reset();
-}
-
-void InputMethodWinBase::CancelCompositionForEngine() {
- TextInputType text_input_type = GetTextInputType();
- if (text_input_type != TEXT_INPUT_TYPE_NONE &&
- text_input_type != TEXT_INPUT_TYPE_PASSWORD) {
- InputMethodWinBase::ResetEngine();
- }
-}
-
-void InputMethodWinBase::UpdateEngineFocusAndInputContext() {
- if (!ui::IMEBridge::Get()) // IMEBridge could be null for tests.
- return;
-
- const TextInputType old_text_input_type =
- ui::IMEBridge::Get()->GetCurrentInputContext().type;
- ui::IMEEngineHandlerInterface::InputContext context(
- GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
- ui::TextInputClient::FOCUS_REASON_OTHER, GetClientShouldDoLearning());
- ui::IMEBridge::Get()->SetCurrentInputContext(context);
-
- // Update IME Engine state.
- ui::IMEEngineHandlerInterface* engine = GetEngine();
- if (engine) {
- if (old_text_input_type != ui::TEXT_INPUT_TYPE_NONE)
- engine->FocusOut();
- if (GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
- engine->FocusIn(context);
- }
-}
-
} // namespace ui
diff --git a/chromium/ui/base/ime/win/input_method_win_base.h b/chromium/ui/base/ime/win/input_method_win_base.h
index 139d966dc0e..c788c6b5f35 100644
--- a/chromium/ui/base/ime/win/input_method_win_base.h
+++ b/chromium/ui/base/ime/win/input_method_win_base.h
@@ -62,19 +62,6 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) InputMethodWinBase
ui::KeyEvent* event,
const std::vector<MSG>* char_msgs);
- // Update composition bounds for Chromium IME extension.
- void UpdateCompositionBoundsForEngine(const TextInputClient* client);
-
- // Reset composition status for Chromium IME extension.
- void ResetEngine();
-
- // Cancel composition for Chromium IME extension.
- void CancelCompositionForEngine();
-
- // Update focus state for Chromium IME extension and update input context in
- // ui::IMEBridge.
- void UpdateEngineFocusAndInputContext();
-
// The toplevel window handle.
const HWND toplevel_window_handle_;
diff --git a/chromium/ui/base/ime/win/input_method_win_imm32.cc b/chromium/ui/base/ime/win/input_method_win_imm32.cc
index 7c0ee3ee966..324a6bc91fb 100644
--- a/chromium/ui/base/ime/win/input_method_win_imm32.cc
+++ b/chromium/ui/base/ime/win/input_method_win_imm32.cc
@@ -12,8 +12,6 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
-#include "ui/base/ime/ime_bridge.h"
-#include "ui/base/ime/ime_engine_handler_interface.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/win/tsf_input_scope.h"
#include "ui/display/win/screen_win.h"
@@ -101,7 +99,6 @@ void InputMethodWinImm32::OnCaretBoundsChanged(const TextInputClient* client) {
if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
return;
NotifyTextInputCaretBoundsChanged(client);
- InputMethodWinBase::UpdateCompositionBoundsForEngine(client);
if (!enabled_)
return;
@@ -126,13 +123,8 @@ void InputMethodWinImm32::OnCaretBoundsChanged(const TextInputClient* client) {
}
void InputMethodWinImm32::CancelComposition(const TextInputClient* client) {
- if (IsTextInputClientFocused(client)) {
- // |enabled_| == false could be faked, and the engine should rely on the
- // real type get from GetTextInputType().
- InputMethodWinBase::CancelCompositionForEngine();
-
- if (enabled_)
- imm32_manager_.CancelIME(toplevel_window_handle_);
+ if (IsTextInputClientFocused(client) && enabled_) {
+ imm32_manager_.CancelIME(toplevel_window_handle_);
}
}
@@ -326,8 +318,6 @@ void InputMethodWinImm32::RefreshInputLanguage() {
void InputMethodWinImm32::ConfirmCompositionText(bool reset_engine,
bool keep_selection) {
InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection);
- if (reset_engine)
- InputMethodWinBase::ResetEngine();
// Makes sure the native IME app can be informed about the composition is
// cleared, so that it can clean up its internal states.
@@ -339,8 +329,7 @@ void InputMethodWinImm32::UpdateIMEState() {
// Use switch here in case we are going to add more text input types.
// We disable input method in password field.
const HWND window_handle = toplevel_window_handle_;
- const TextInputType text_input_type =
- GetEngine() ? TEXT_INPUT_TYPE_NONE : GetTextInputType();
+ const TextInputType text_input_type = GetTextInputType();
const TextInputMode text_input_mode = GetTextInputMode();
switch (text_input_type) {
case ui::TEXT_INPUT_TYPE_NONE:
@@ -357,8 +346,6 @@ void InputMethodWinImm32::UpdateIMEState() {
imm32_manager_.SetTextInputMode(window_handle, text_input_mode);
tsf_inputscope::SetInputScopeForTsfUnawareWindow(
window_handle, text_input_type, text_input_mode);
-
- InputMethodWinBase::UpdateEngineFocusAndInputContext();
}
} // namespace ui
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 58926e51a7f..b4e4fcc2e67 100644
--- a/chromium/ui/base/ime/win/input_method_win_tsf.cc
+++ b/chromium/ui/base/ime/win/input_method_win_tsf.cc
@@ -100,7 +100,6 @@ void InputMethodWinTSF::OnTextInputTypeChanged(const TextInputClient* client) {
}
ui::TSFBridge::GetInstance()->CancelComposition();
ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client);
- InputMethodWinBase::UpdateEngineFocusAndInputContext();
}
void InputMethodWinTSF::OnCaretBoundsChanged(const TextInputClient* client) {
@@ -110,14 +109,12 @@ void InputMethodWinTSF::OnCaretBoundsChanged(const TextInputClient* client) {
}
NotifyTextInputCaretBoundsChanged(client);
ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
- InputMethodWinBase::UpdateCompositionBoundsForEngine(client);
}
void InputMethodWinTSF::CancelComposition(const TextInputClient* client) {
if (ui::TSFBridge::GetInstance() && IsTextInputClientFocused(client) &&
IsWindowFocused(client)) {
ui::TSFBridge::GetInstance()->CancelComposition();
- InputMethodWinBase::CancelCompositionForEngine();
}
}
@@ -181,8 +178,6 @@ void InputMethodWinTSF::ConfirmCompositionText(bool reset_engine,
if (IsTextInputTypeNone())
return;
- if (reset_engine && GetTextInputClient()->HasCompositionText())
- InputMethodWinBase::ResetEngine();
if (ui::TSFBridge::GetInstance())
ui::TSFBridge::GetInstance()->ConfirmComposition();
}
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
index cf2caabef7d..5c19abd64d6 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
@@ -222,7 +222,7 @@ void OnScreenKeyboardDisplayManagerInputPane::Run() {
// Execute show() or hide() on the background thread after the debounce
// expires.
switch (last_vk_visibility_request_) {
- case VirtualKeyboardVisibilityRequest::SHOW: {
+ case mojom::VirtualKeyboardVisibilityRequest::SHOW: {
background_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
@@ -231,7 +231,7 @@ void OnScreenKeyboardDisplayManagerInputPane::Run() {
base::RetainedRef(virtual_keyboard_input_pane_), hwnd_));
break;
}
- case VirtualKeyboardVisibilityRequest::HIDE: {
+ case mojom::VirtualKeyboardVisibilityRequest::HIDE: {
background_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
@@ -240,18 +240,18 @@ void OnScreenKeyboardDisplayManagerInputPane::Run() {
base::RetainedRef(virtual_keyboard_input_pane_), hwnd_));
break;
}
- case VirtualKeyboardVisibilityRequest::NONE: {
+ case mojom::VirtualKeyboardVisibilityRequest::NONE: {
break;
}
}
// Reset the VK visibility state to none so we can keep track of subsequent
// API calls.
- last_vk_visibility_request_ = VirtualKeyboardVisibilityRequest::NONE;
+ last_vk_visibility_request_ = mojom::VirtualKeyboardVisibilityRequest::NONE;
}
bool OnScreenKeyboardDisplayManagerInputPane::DisplayVirtualKeyboard() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- last_vk_visibility_request_ = VirtualKeyboardVisibilityRequest::SHOW;
+ last_vk_visibility_request_ = mojom::VirtualKeyboardVisibilityRequest::SHOW;
debouncer_->RequestRun(base::BindOnce(
&OnScreenKeyboardDisplayManagerInputPane::Run, base::Unretained(this)));
return true;
@@ -259,7 +259,7 @@ bool OnScreenKeyboardDisplayManagerInputPane::DisplayVirtualKeyboard() {
void OnScreenKeyboardDisplayManagerInputPane::DismissVirtualKeyboard() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- last_vk_visibility_request_ = VirtualKeyboardVisibilityRequest::HIDE;
+ last_vk_visibility_request_ = mojom::VirtualKeyboardVisibilityRequest::HIDE;
debouncer_->RequestRun(base::BindOnce(
&OnScreenKeyboardDisplayManagerInputPane::Run, base::Unretained(this)));
}
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
index 40c8578cb79..68b15c27f21 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
@@ -18,7 +18,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_types.h"
#include "ui/base/ime/input_method_keyboard_controller.h"
-#include "ui/base/ime/virtual_keyboard_visibility_request.h"
+#include "ui/base/ime/mojom/virtual_keyboard_types.mojom-shared.h"
#include "ui/base/ime/win/virtual_keyboard_debounce_timer.h"
#include "ui/gfx/geometry/rect.h"
@@ -47,8 +47,8 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN)
pane);
// Returns whether show/hide VK API is called from
// InputMethodKeyboardController or not.
- VirtualKeyboardVisibilityRequest GetLastVirtualKeyboardVisibilityRequest()
- const {
+ mojom::VirtualKeyboardVisibilityRequest
+ GetLastVirtualKeyboardVisibilityRequest() const {
return last_vk_visibility_request_;
}
@@ -69,8 +69,8 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN)
const scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_;
scoped_refptr<VirtualKeyboardInputPane> virtual_keyboard_input_pane_;
bool is_keyboard_visible_;
- VirtualKeyboardVisibilityRequest last_vk_visibility_request_ =
- VirtualKeyboardVisibilityRequest::NONE;
+ mojom::VirtualKeyboardVisibilityRequest last_vk_visibility_request_ =
+ mojom::VirtualKeyboardVisibilityRequest::NONE;
std::unique_ptr<VirtualKeyboardDebounceTimer> debouncer_;
base::WeakPtrFactory<OnScreenKeyboardDisplayManagerInputPane> weak_factory_{
this};
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
index c32989e65b7..f718926d662 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
@@ -11,7 +11,6 @@
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "ui/base/ime/input_method_keyboard_controller.h"
-#include "ui/base/ui_base_export.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
index 778f19bb853..f5c8c7155d4 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -111,6 +111,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
@@ -134,6 +138,9 @@ class TSFBridgeImpl : public TSFBridge {
// Handle to ITfKeyTraceEventSink.
DWORD key_trace_sink_cookie_ = 0;
+ // Handle to ITfLanguageProfileNotifySink
+ DWORD language_profile_cookie_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(TSFBridgeImpl);
};
@@ -149,6 +156,11 @@ TSFBridgeImpl::~TSFBridgeImpl() {
if (SUCCEEDED(thread_manager_->QueryInterface(IID_PPV_ARGS(&source)))) {
source->UnadviseSink(key_trace_sink_cookie_);
}
+ Microsoft::WRL::ComPtr<ITfSource> language_source;
+ if (SUCCEEDED(input_processor_profiles_->QueryInterface(
+ IID_PPV_ARGS(&language_source)))) {
+ language_source->UnadviseSink(language_profile_cookie_);
+ }
}
for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
@@ -174,6 +186,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.";
@@ -309,7 +328,8 @@ void TSFBridgeImpl::SetFocusedClient(HWND focused_window,
void TSFBridgeImpl::RemoveFocusedClient(TextInputClient* client) {
DCHECK(base::MessageLoopCurrentForUI::IsSet());
- DCHECK(IsInitialized());
+ if (!IsInitialized())
+ return;
if (client_ != client)
return;
ClearAssociateFocus();
@@ -422,6 +442,21 @@ bool TSFBridgeImpl::CreateDocumentManager(TSFTextStore* text_store,
return false;
}
+ Microsoft::WRL::ComPtr<ITfSource> language_source;
+ if (FAILED(input_processor_profiles_->QueryInterface(
+ IID_PPV_ARGS(&language_source)))) {
+ DVLOG(1) << "Failed to get source_ITfInputProcessorProfiles.";
+ return false;
+ }
+
+ if (FAILED(
+ language_source->AdviseSink(IID_ITfLanguageProfileNotifySink,
+ static_cast<ITfTextEditSink*>(text_store),
+ &language_profile_cookie_))) {
+ DVLOG(1) << "AdviseSink for language profile notify sink failed.";
+ return false;
+ }
+
if (*source_cookie == TF_INVALID_COOKIE) {
DVLOG(1) << "The result of cookie is invalid.";
return false;
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
index 22f43ff72b0..98ca302320d 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store.cc
@@ -11,6 +11,7 @@
#include <algorithm>
+#include "base/logging.h"
#include "base/numerics/ranges.h"
#include "base/win/scoped_variant.h"
#include "ui/base/ime/text_input_client.h"
@@ -80,6 +81,8 @@ HRESULT TSFTextStore::QueryInterface(REFIID iid, void** result) {
*result = static_cast<ITextStoreACP*>(this);
} else if (iid == IID_ITfContextOwnerCompositionSink) {
*result = static_cast<ITfContextOwnerCompositionSink*>(this);
+ } else if (iid == IID_ITfLanguageProfileNotifySink) {
+ *result = static_cast<ITfLanguageProfileNotifySink*>(this);
} else if (iid == IID_ITfTextEditSink) {
*result = static_cast<ITfTextEditSink*>(this);
} else if (iid == IID_ITfKeyTraceEventSink) {
@@ -647,9 +650,7 @@ HRESULT TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
// 3. User commits current composition text.
if (((new_composition_start > last_composition_start &&
text_input_client_->HasCompositionText()) ||
- (wparam_keydown_fired_ == 0 && !has_composition_range_ &&
- !text_input_client_->HasCompositionText()) ||
- (wparam_keydown_fired_ != 0 && !has_composition_range_)) &&
+ !has_composition_range_) &&
text_input_client_) {
CommitTextAndEndCompositionIfAny(last_composition_start,
new_composition_start);
@@ -694,6 +695,7 @@ HRESULT TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
// reset the flag since we've already inserted/replaced the text.
new_text_inserted_ = false;
+ is_selection_interim_char_ = false;
// reset string_buffer_ if composition is no longer active.
if (!text_input_client_->HasCompositionText()) {
@@ -760,6 +762,7 @@ HRESULT TSFTextStore::SetSelection(ULONG selection_buffer_size,
}
selection_.set_start(start_pos);
selection_.set_end(end_pos);
+ is_selection_interim_char_ = selection_buffer[0].style.fInterimChar;
}
return S_OK;
}
@@ -829,6 +832,15 @@ HRESULT TSFTextStore::OnEndComposition(ITfCompositionView* composition_view) {
return S_OK;
}
+HRESULT TSFTextStore::OnLanguageChange(LANGID langid, BOOL* pfAccept) {
+ return S_OK;
+}
+HRESULT TSFTextStore::OnLanguageChanged() {
+ if (text_input_client_)
+ text_input_client_->OnInputMethodChanged();
+ return S_OK;
+}
+
HRESULT TSFTextStore::OnKeyTraceDown(WPARAM wParam, LPARAM lParam) {
// fire the event right away if we're in composition
if (has_composition_range_) {
@@ -1052,6 +1064,10 @@ bool TSFTextStore::GetCompositionStatus(
span.end_offset = start_pos + length;
span.underline_color = SK_ColorBLACK;
span.background_color = SK_ColorTRANSPARENT;
+ if (selection_.EqualsIgnoringDirection(
+ gfx::Range(span.start_offset, span.end_offset))) {
+ span.interim_char_selection = is_selection_interim_char_;
+ }
if (has_display_attribute)
GetStyle(display_attribute, &span);
spans->push_back(span);
@@ -1355,8 +1371,11 @@ void TSFTextStore::CommitTextAndEndCompositionIfAny(size_t old_size,
: new_committed_string_size);
// TODO(crbug.com/978678): Unify the behavior of
// |TextInputClient::InsertText(text)| for the empty text.
- if (!new_committed_string.empty())
+ if (!new_committed_string.empty()) {
text_input_client_->InsertText(new_committed_string);
+ } else {
+ text_input_client_->ClearCompositionText();
+ }
// Notify accessibility about this committed composition
text_input_client_->SetActiveCompositionForAccessibility(
replace_text_range_, new_committed_string,
diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h
index 10bbae5a50e..bf02704ffff 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.h
+++ b/chromium/ui/base/ime/win/tsf_text_store.h
@@ -102,6 +102,7 @@ class TextInputClient;
class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
: public ITextStoreACP,
public ITfContextOwnerCompositionSink,
+ public ITfLanguageProfileNotifySink,
public ITfKeyTraceEventSink,
public ITfTextEditSink {
public:
@@ -216,6 +217,10 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
IFACEMETHODIMP OnEndComposition(
ITfCompositionView* composition_view) override;
+ // ITfLanguageProfileNotifySink:
+ IFACEMETHODIMP OnLanguageChange(LANGID langid, BOOL* pfAccept) override;
+ IFACEMETHODIMP OnLanguageChanged() override;
+
// ITfTextEditSink:
IFACEMETHODIMP OnEndEdit(ITfContext* context,
TfEditCookie read_only_edit_cookie,
@@ -391,6 +396,10 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
// |selection_.end()|: 4
gfx::Range selection_;
+ // Indicates if the selection is an interim character. Please refer to
+ // https://docs.microsoft.com/en-us/windows/win32/api/textstor/ns-textstor-ts_selectionstyle
+ bool is_selection_interim_char_ = false;
+
// |start_offset| and |end_offset| of |text_spans_| indicates
// the offsets in |string_buffer_document_|.
// Example: "aoi" is committed. There are two underlines in "umi" and "no".
diff --git a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
index 081809d75a1..4e81d7c1012 100644
--- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -3394,5 +3394,92 @@ TEST_F(TSFTextStoreTest, RegressionTest7) {
EXPECT_EQ(S_OK, result);
}
+// regression tests for crbug.com/1091069.
+// We should allow inserting empty compositon string to cancel composition.
+class RegressionTest8Callback : public TSFTextStoreTestCallback {
+ public:
+ explicit RegressionTest8Callback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ SetTextTest(0, 0, L"bbbb", S_OK);
+ SetSelectionTest(0, 4, S_OK);
+
+ text_spans()->clear();
+ ImeTextSpan text_span_1;
+ text_span_1.start_offset = 0;
+ text_span_1.end_offset = 4;
+ text_span_1.underline_color = SK_ColorBLACK;
+ text_span_1.thickness = ImeTextSpan::Thickness::kThin;
+ text_span_1.background_color = SK_ColorTRANSPARENT;
+ text_spans()->push_back(text_span_1);
+
+ *edit_flag() = true;
+ *composition_start() = 0;
+ composition_range()->set_start(0);
+ composition_range()->set_end(4);
+ *has_composition_range() = true;
+
+ text_store_->OnKeyTraceDown(65u, 1966081u);
+ return S_OK;
+ }
+
+ void SetCompositionText1(const ui::CompositionText& composition) {
+ EXPECT_EQ(L"bbbb", composition.text);
+ EXPECT_EQ(0u, composition.selection.start());
+ EXPECT_EQ(4u, composition.selection.end());
+ ASSERT_EQ(1u, composition.ime_text_spans.size());
+ EXPECT_EQ(0u, composition.ime_text_spans[0].start_offset);
+ EXPECT_EQ(4u, composition.ime_text_spans[0].end_offset);
+ SetHasCompositionText(true);
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ GetTextTest(0, -1, L"bbbb", 4);
+ SetTextTest(0, 4, L"", S_OK);
+
+ text_spans()->clear();
+ *edit_flag() = true;
+ *composition_start() = 0;
+ composition_range()->set_start(0);
+ composition_range()->set_end(0);
+
+ *has_composition_range() = false;
+ text_store_->OnKeyTraceUp(65u, 1966081u);
+ return S_OK;
+ }
+
+ void ClearCompositionText2() { EXPECT_EQ(false, *has_composition_range()); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegressionTest8Callback);
+};
+
+TEST_F(TSFTextStoreTest, RegressionTest8) {
+ RegressionTest8Callback callback(text_store_.get());
+ EXPECT_CALL(text_input_client_, SetCompositionText(_))
+ .WillOnce(
+ Invoke(&callback, &RegressionTest8Callback::SetCompositionText1));
+
+ EXPECT_CALL(text_input_client_, ClearCompositionText())
+ .WillOnce(
+ Invoke(&callback, &RegressionTest8Callback::ClearCompositionText2));
+
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &RegressionTest8Callback::LockGranted1))
+ .WillOnce(Invoke(&callback, &RegressionTest8Callback::LockGranted2));
+
+ ON_CALL(text_input_client_, HasCompositionText())
+ .WillByDefault(
+ Invoke(&callback, &TSFTextStoreTestCallback::HasCompositionText));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
} // namespace
} // namespace ui