Commit e95876d6 authored by Siye Liu's avatar Siye Liu Committed by Commit Bot

Use ITfContextOwnerCompositionServices to terminate composition

This change aims to demonstrate how we can re-implement the following
methods in a sane way.

 * TSFTextStore::CancelComposition()
 * TSFTextStore::ConfirmComposition()

In our initial implementation [1], those two methods were implemented
in a really hacky way. It was implemented by simulating a text change
event during a composition with an assumption that the current IME will
terminate the composition when it receives |OnTextChange|.
|ITfContextOwnerCompositionServices::TerminateComposition| should have
been used instead in this scenario.

[1]: e7888801

Bug: 948783
Change-Id: Ibfb270d9f8dc2459ca73824c7405f10111e12ad1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1572240
Commit-Queue: Siye Liu <siliu@microsoft.com>
Reviewed-by: default avatarYohei Yukawa <yukawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652873}
parent e2fa7198
......@@ -429,6 +429,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;
}
......
......@@ -986,6 +986,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 +1107,10 @@ void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() {
}
}
void TSFTextStore::OnContextInitialized(ITfContext* context) {
context_ = context;
}
void TSFTextStore::SetFocusedTextInputClient(
HWND focused_window,
TextInputClient* text_input_client) {
......@@ -1119,39 +1136,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 +1160,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() {
......
......@@ -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);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment