Index: win8/metro_driver/ime/text_store.cc |
diff --git a/ui/base/ime/win/tsf_text_store.cc b/win8/metro_driver/ime/text_store.cc |
similarity index 82% |
copy from ui/base/ime/win/tsf_text_store.cc |
copy to win8/metro_driver/ime/text_store.cc |
index 0ef34b5be89a56b649abc9e3a68e1d0ab4392da4..2465fa6040e6dd29ffca277db4b53d29c90d692c 100644 |
--- a/ui/base/ime/win/tsf_text_store.cc |
+++ b/win8/metro_driver/ime/text_store.cc |
@@ -1,9 +1,9 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Copyright (c) 2013 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. |
#define INITGUID // required for GUID_PROP_INPUTSCOPE |
-#include "ui/base/ime/win/tsf_text_store.h" |
+#include "win8/metro_driver/ime/text_store.h" |
#include <InputScope.h> |
#include <OleCtl.h> |
@@ -11,11 +11,10 @@ |
#include <algorithm> |
#include "base/win/scoped_variant.h" |
-#include "ui/base/ime/text_input_client.h" |
-#include "ui/base/ime/win/tsf_input_scope.h" |
-#include "ui/gfx/rect.h" |
+#include "win8/metro_driver/ime/input_scope.h" |
+#include "win8/metro_driver/ime/text_store_delegate.h" |
-namespace ui { |
+namespace metro_driver { |
namespace { |
// We support only one view. |
@@ -23,23 +22,58 @@ const TsViewCookie kViewCookie = 1; |
} // namespace |
-TSFTextStore::TSFTextStore() |
+TSFTextStore::TSFTextStore(HWND window_handle, |
+ ITfCategoryMgr* category_manager, |
+ ITfDisplayAttributeMgr* display_attribute_manager, |
+ ITfInputScope* input_scope, |
+ TextStoreDelegate* delegate) |
: ref_count_(0), |
text_store_acp_sink_mask_(0), |
- window_handle_(NULL), |
- text_input_client_(NULL), |
+ window_handle_(window_handle), |
+ delegate_(delegate), |
committed_size_(0), |
+ selection_start_(0), |
+ selection_end_(0), |
edit_flag_(false), |
- current_lock_type_(0) { |
- if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) { |
- LOG(FATAL) << "Failed to initialize CategoryMgr."; |
- return; |
- } |
- if (FAILED(display_attribute_manager_.CreateInstance( |
- CLSID_TF_DisplayAttributeMgr))) { |
- LOG(FATAL) << "Failed to initialize DisplayAttributeMgr."; |
- return; |
- } |
+ current_lock_type_(0), |
+ category_manager_(category_manager), |
+ display_attribute_manager_(display_attribute_manager), |
+ input_scope_(input_scope) { |
+} |
+ |
+// static |
+scoped_refptr<TSFTextStore> TSFTextStore::Create( |
+ HWND window_handle, |
+ const std::vector<InputScope>& input_scopes, |
+ TextStoreDelegate* delegate) { |
+ if (!delegate) { |
+ LOG(ERROR) << "|delegate| must be non-NULL."; |
+ return scoped_refptr<TSFTextStore>(); |
+ } |
+ base::win::ScopedComPtr<ITfCategoryMgr> category_manager; |
+ HRESULT hr = category_manager.CreateInstance(CLSID_TF_CategoryMgr); |
+ if (FAILED(hr)) { |
+ LOG(ERROR) << "Failed to initialize CategoryMgr. hr = " << hr; |
+ return scoped_refptr<TSFTextStore>(); |
+ } |
+ base::win::ScopedComPtr<ITfDisplayAttributeMgr> display_attribute_manager; |
+ hr = display_attribute_manager.CreateInstance(CLSID_TF_DisplayAttributeMgr); |
+ if (FAILED(hr)) { |
+ LOG(ERROR) << "Failed to initialize DisplayAttributeMgr. hr = " << hr; |
+ return scoped_refptr<TSFTextStore>(); |
+ } |
+ base::win::ScopedComPtr<ITfInputScope> input_scope = |
+ CreteInputScope(input_scopes); |
+ if (!input_scope) { |
+ LOG(ERROR) << "Failed to initialize InputScope."; |
+ return scoped_refptr<TSFTextStore>(); |
+ } |
+ return scoped_refptr<TSFTextStore>( |
+ new TSFTextStore(window_handle, |
+ category_manager, |
+ display_attribute_manager, |
+ input_scope, |
+ delegate)); |
} |
TSFTextStore::~TSFTextStore() { |
@@ -147,7 +181,7 @@ STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) { |
return E_INVALIDARG; |
if (!HasReadLock()) |
return TS_E_NOLOCK; |
- *acp = string_buffer_.size(); |
+ *acp = static_cast<LONG>(string_buffer_.size()); |
return S_OK; |
} |
@@ -166,13 +200,6 @@ STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) { |
// {0, 0, 0, 0} means that the document rect is not currently displayed. |
SetRect(rect, 0, 0, 0, 0); |
- if (!IsWindow(window_handle_)) |
- return E_FAIL; |
- |
- // Currently ui::TextInputClient does not expose the document rect. So use |
- // the Win32 client rectangle instead. |
- // TODO(yukawa): Upgrade TextInputClient so that the client can retrieve the |
- // document rectangle. |
RECT client_rect = {}; |
if (!GetClientRect(window_handle_, &client_rect)) |
return E_FAIL; |
@@ -203,8 +230,8 @@ STDMETHODIMP TSFTextStore::GetSelection(ULONG selection_index, |
*fetched_count = 0; |
if ((selection_buffer_size > 0) && |
((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) { |
- selection_buffer[0].acpStart = selection_.start(); |
- selection_buffer[0].acpEnd = selection_.end(); |
+ selection_buffer[0].acpStart = selection_start_; |
+ selection_buffer[0].acpEnd = selection_end_; |
selection_buffer[0].style.ase = TS_AE_END; |
selection_buffer[0].style.fInterimChar = FALSE; |
*fetched_count = 1; |
@@ -242,7 +269,7 @@ STDMETHODIMP TSFTextStore::GetText(LONG acp_start, |
return E_INVALIDARG; |
if (!HasReadLock()) |
return TF_E_NOLOCK; |
- const LONG string_buffer_size = string_buffer_.size(); |
+ const LONG string_buffer_size = static_cast<LONG>(string_buffer_.size()); |
if (acp_end == -1) |
acp_end = string_buffer_size; |
if (!((0 <= acp_start) && |
@@ -276,8 +303,6 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, |
BOOL* clipped) { |
if (!rect || !clipped) |
return E_INVALIDARG; |
- if (!text_input_client_) |
- return E_UNEXPECTED; |
if (view_cookie != kViewCookie) |
return E_INVALIDARG; |
if (!HasReadLock()) |
@@ -294,7 +319,7 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, |
// We use RECT instead of gfx::Rect since left position may be bigger than |
// right position when composition has multiple lines. |
RECT result; |
- gfx::Rect tmp_rect; |
+ RECT tmp_rect; |
const uint32 start_pos = acp_start - committed_size_; |
const uint32 end_pos = acp_end - committed_size_; |
@@ -305,34 +330,27 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, |
// But when using Pinin IME of Windows 8, this method is called with the |
// equal values of |acp_start| and |acp_end|. So we handle this condition. |
if (start_pos == 0) { |
- if (text_input_client_->GetCompositionCharacterBounds(0, &tmp_rect)) { |
- tmp_rect.set_width(0); |
- result = tmp_rect.ToRECT(); |
+ if (delegate_->GetCompositionCharacterBounds(0, &tmp_rect)) { |
+ tmp_rect.right = tmp_rect.right; |
+ result = tmp_rect; |
} else if (string_buffer_.size() == committed_size_) { |
- result = text_input_client_->GetCaretBounds().ToRECT(); |
+ result = delegate_->GetCaretBounds(); |
} else { |
return TS_E_NOLAYOUT; |
} |
- } else if (text_input_client_->GetCompositionCharacterBounds(start_pos - 1, |
- &tmp_rect)) { |
- result.left = tmp_rect.right(); |
- result.right = tmp_rect.right(); |
- result.top = tmp_rect.y(); |
- result.bottom = tmp_rect.bottom(); |
+ } else if (delegate_->GetCompositionCharacterBounds(start_pos - 1, |
+ &tmp_rect)) { |
+ tmp_rect.left = tmp_rect.right; |
+ result = tmp_rect; |
} else { |
return TS_E_NOLAYOUT; |
} |
} else { |
- if (text_input_client_->GetCompositionCharacterBounds(start_pos, |
- &tmp_rect)) { |
- result.left = tmp_rect.x(); |
- result.top = tmp_rect.y(); |
- result.right = tmp_rect.right(); |
- result.bottom = tmp_rect.bottom(); |
- if (text_input_client_->GetCompositionCharacterBounds(end_pos - 1, |
- &tmp_rect)) { |
- result.right = tmp_rect.right(); |
- result.bottom = tmp_rect.bottom(); |
+ if (delegate_->GetCompositionCharacterBounds(start_pos, &tmp_rect)) { |
+ result = tmp_rect; |
+ if (delegate_->GetCompositionCharacterBounds(end_pos - 1, &tmp_rect)) { |
+ result.right = tmp_rect.right; |
+ result.bottom = tmp_rect.bottom; |
} else { |
// We may not be able to get the last character bounds, so we use the |
// first character bounds instead of returning TS_E_NOLAYOUT. |
@@ -342,7 +360,7 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, |
// it's better to return previous caret rectangle instead. |
// TODO(nona, kinaba): Remove this hack. |
if (start_pos == 0) { |
- result = text_input_client_->GetCaretBounds().ToRECT(); |
+ result = delegate_->GetCaretBounds(); |
} else { |
return TS_E_NOLAYOUT; |
} |
@@ -390,8 +408,8 @@ STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags, |
LONG* acp_start, |
LONG* acp_end, |
TS_TEXTCHANGE* text_change) { |
- const LONG start_pos = selection_.start(); |
- const LONG end_pos = selection_.end(); |
+ const LONG start_pos = selection_start_; |
+ const LONG end_pos = selection_end_; |
const LONG new_end_pos = start_pos + text_buffer_size; |
if (flags & TS_IAS_QUERYONLY) { |
@@ -423,8 +441,8 @@ STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags, |
text_change->acpOldEnd = end_pos; |
text_change->acpNewEnd = new_end_pos; |
} |
- selection_.set_start(start_pos); |
- selection_.set_end(new_end_pos); |
+ selection_start_ = start_pos; |
+ selection_end_ = new_end_pos; |
return S_OK; |
} |
@@ -500,7 +518,7 @@ STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { |
current_lock_type_ = (lock_flags & TS_LF_READWRITE); |
edit_flag_ = false; |
- const size_t last_committed_size = committed_size_; |
+ const uint32 last_committed_size = committed_size_; |
// Grant the lock. |
*result = text_store_acp_sink_->OnLockGranted(current_lock_type_); |
@@ -516,54 +534,47 @@ STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { |
current_lock_type_ = 0; |
} |
- if (!edit_flag_) { |
+ if (!edit_flag_) |
return S_OK; |
- } |
// If the text store is edited in OnLockGranted(), we may need to call |
- // TextInputClient::InsertText() or TextInputClient::SetCompositionText(). |
- const size_t new_committed_size = committed_size_; |
+ // TextStoreDelegate::ConfirmComposition() or |
+ // TextStoreDelegate::SetComposition(). |
+ const uint32 new_committed_size = committed_size_; |
const string16& new_committed_string = |
string_buffer_.substr(last_committed_size, |
new_committed_size - last_committed_size); |
const string16& composition_string = |
string_buffer_.substr(new_committed_size); |
- // If there is new committed string, calls TextInputClient::InsertText(). |
- if ((!new_committed_string.empty()) && text_input_client_) { |
- text_input_client_->InsertText(new_committed_string); |
- } |
+ // If there is new committed string, calls |
+ // TextStoreDelegate::ConfirmComposition(). |
+ if ((!new_committed_string.empty())) |
+ delegate_->OnTextCommitted(new_committed_string); |
// Calls TextInputClient::SetCompositionText(). |
- CompositionText composition_text; |
- composition_text.text = composition_string; |
- composition_text.underlines = composition_undelines_; |
+ std::vector<metro_viewer::UnderlineInfo> underlines = underlines_; |
// Adjusts the offset. |
- for (size_t i = 0; i < composition_text.underlines.size(); ++i) { |
- composition_text.underlines[i].start_offset -= new_committed_size; |
- composition_text.underlines[i].end_offset -= new_committed_size; |
- } |
- if (selection_.start() < new_committed_size) { |
- composition_text.selection.set_start(0); |
- } else { |
- composition_text.selection.set_start( |
- selection_.start() - new_committed_size); |
- } |
- if (selection_.end() < new_committed_size) { |
- composition_text.selection.set_end(0); |
- } else { |
- composition_text.selection.set_end(selection_.end() - new_committed_size); |
- } |
- if (text_input_client_) |
- text_input_client_->SetCompositionText(composition_text); |
+ for (size_t i = 0; i < underlines_.size(); ++i) { |
+ underlines[i].start_offset -= new_committed_size; |
+ underlines[i].end_offset -= new_committed_size; |
+ } |
+ int32 selection_start = 0; |
+ int32 selection_end = 0; |
+ if (selection_start_ >= new_committed_size) |
+ selection_start = selection_start_ - new_committed_size; |
+ if (selection_end_ >= new_committed_size) |
+ selection_end = selection_end_ - new_committed_size; |
+ delegate_->OnCompositionChanged( |
+ composition_string, selection_start, selection_end, underlines); |
// If there is no composition string, clear the text store status. |
// And call OnSelectionChange(), OnLayoutChange(), and OnTextChange(). |
if ((composition_string.empty()) && (new_committed_size != 0)) { |
string_buffer_.clear(); |
committed_size_ = 0; |
- selection_.set_start(0); |
- selection_.set_end(0); |
+ selection_start_ = 0; |
+ selection_end_ = 0; |
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) |
@@ -586,7 +597,7 @@ STDMETHODIMP TSFTextStore::RequestSupportedAttrs( |
const TS_ATTRID* attribute_buffer) { |
if (!attribute_buffer) |
return E_INVALIDARG; |
- if (!text_input_client_) |
+ if (!input_scope_) |
return E_FAIL; |
// We support only input scope attribute. |
for (size_t i = 0; i < attribute_buffer_size; ++i) { |
@@ -602,9 +613,10 @@ STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs( |
ULONG* attribute_buffer_copied) { |
if (!attribute_buffer_copied) |
return E_INVALIDARG; |
+ *attribute_buffer_copied = 0; |
if (!attribute_buffer) |
return E_INVALIDARG; |
- if (!text_input_client_) |
+ if (!input_scope_) |
return E_UNEXPECTED; |
// We support only input scope attribute. |
*attribute_buffer_copied = 0; |
@@ -614,9 +626,7 @@ STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs( |
attribute_buffer[0].dwOverlapId = 0; |
attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE; |
attribute_buffer[0].varValue.vt = VT_UNKNOWN; |
- attribute_buffer[0].varValue.punkVal = tsf_inputscope::CreateInputScope( |
- text_input_client_->GetTextInputType(), |
- text_input_client_->GetTextInputMode()); |
+ attribute_buffer[0].varValue.punkVal = input_scope_.get(); |
attribute_buffer[0].varValue.punkVal->AddRef(); |
*attribute_buffer_copied = 1; |
return S_OK; |
@@ -635,8 +645,8 @@ STDMETHODIMP TSFTextStore::SetSelection( |
(end_pos <= static_cast<LONG>(string_buffer_.size())))) { |
return TF_E_INVALIDPOS; |
} |
- selection_.set_start(start_pos); |
- selection_.set_end(end_pos); |
+ selection_start_ = start_pos; |
+ selection_end_ = end_pos; |
} |
return S_OK; |
} |
@@ -706,19 +716,14 @@ STDMETHODIMP TSFTextStore::OnEndComposition( |
} |
STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, |
- TfEditCookie read_only_edit_cookie, |
- ITfEditRecord* edit_record) { |
+ TfEditCookie read_only_edit_cookie, |
+ ITfEditRecord* edit_record) { |
if (!context || !edit_record) |
return E_INVALIDARG; |
- |
- size_t committed_size; |
- CompositionUnderlines undelines; |
- if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size, |
- &undelines)) { |
+ if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size_, |
+ &underlines_)) { |
return S_OK; |
} |
- composition_undelines_ = undelines; |
- committed_size_ = committed_size; |
edit_flag_ = true; |
return S_OK; |
} |
@@ -740,8 +745,8 @@ bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom, |
bool TSFTextStore::GetCompositionStatus( |
ITfContext* context, |
const TfEditCookie read_only_edit_cookie, |
- size_t* committed_size, |
- CompositionUnderlines* undelines) { |
+ uint32* committed_size, |
+ std::vector<metro_viewer::UnderlineInfo>* undelines) { |
DCHECK(context); |
DCHECK(committed_size); |
DCHECK(undelines); |
@@ -810,33 +815,16 @@ bool TSFTextStore::GetCompositionStatus( |
if (*committed_size < static_cast<size_t>(start_pos + length)) |
*committed_size = start_pos + length; |
} else { |
- CompositionUnderline underline; |
+ metro_viewer::UnderlineInfo underline; |
underline.start_offset = start_pos; |
underline.end_offset = start_pos + length; |
- underline.color = SK_ColorBLACK; |
- if (has_display_attribute) |
- underline.thick = !!display_attribute.fBoldLine; |
+ underline.thick = !!display_attribute.fBoldLine; |
undelines->push_back(underline); |
} |
} |
return true; |
} |
-void TSFTextStore::SetFocusedTextInputClient( |
- HWND focused_window, |
- TextInputClient* text_input_client) { |
- window_handle_ = focused_window; |
- text_input_client_ = text_input_client; |
-} |
- |
-void TSFTextStore::RemoveFocusedTextInputClient( |
- TextInputClient* text_input_client) { |
- if (text_input_client_ == text_input_client) { |
- window_handle_ = NULL; |
- text_input_client_ = NULL; |
- } |
-} |
- |
bool TSFTextStore::CancelComposition() { |
// If there is an on-going document lock, we must not edit the text. |
if (edit_flag_) |
@@ -853,11 +841,12 @@ bool TSFTextStore::CancelComposition() { |
// we use the same operation to cancel composition here to minimize the risk |
// of potential compatibility issues. |
- const size_t previous_buffer_size = string_buffer_.size(); |
+ const uint32 previous_buffer_size = |
+ static_cast<uint32>(string_buffer_.size()); |
string_buffer_.clear(); |
committed_size_ = 0; |
- selection_.set_start(0); |
- selection_.set_end(0); |
+ selection_start_ = 0; |
+ selection_end_ = 0; |
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) |
@@ -886,13 +875,14 @@ bool TSFTextStore::ConfirmComposition() { |
const string16& composition_text = string_buffer_.substr(committed_size_); |
if (!composition_text.empty()) |
- text_input_client_->InsertText(composition_text); |
+ delegate_->OnTextCommitted(composition_text); |
- const size_t previous_buffer_size = string_buffer_.size(); |
+ const uint32 previous_buffer_size = |
+ static_cast<uint32>(string_buffer_.size()); |
string_buffer_.clear(); |
committed_size_ = 0; |
- selection_.set_start(0); |
- selection_.set_end(0); |
+ selection_start_ = 0; |
+ selection_end_ = 0; |
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) |
@@ -920,4 +910,4 @@ bool TSFTextStore::HasReadWriteLock() const { |
return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE; |
} |
-} // namespace ui |
+} // namespace metro_driver |