Chromium Code Reviews| 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 84% |
| copy from ui/base/ime/win/tsf_text_store.cc |
| copy to win8/metro_driver/ime/text_store.cc |
| index 0ef34b5be89a56b649abc9e3a68e1d0ab4392da4..48f394bd49d03c9785739d9f2df2228a8a281997 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,12 +22,16 @@ const TsViewCookie kViewCookie = 1; |
| } // namespace |
| -TSFTextStore::TSFTextStore() |
| +TSFTextStore::TSFTextStore(HWND window_handle, |
| + const std::vector<InputScope>& input_scopes, |
| + 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))) { |
|
ananta
2013/11/27 20:02:47
Failing in the ctor is not a great idea. Can we mo
yukawa
2013/11/28 06:06:20
Good point. Done.
|
| @@ -40,6 +43,7 @@ TSFTextStore::TSFTextStore() |
| LOG(FATAL) << "Failed to initialize DisplayAttributeMgr."; |
| return; |
| } |
| + input_scope_ = CreteInputScope(input_scopes); |
| } |
| TSFTextStore::~TSFTextStore() { |
| @@ -166,13 +170,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 +200,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; |
| @@ -276,7 +273,7 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, |
| BOOL* clipped) { |
| if (!rect || !clipped) |
| return E_INVALIDARG; |
| - if (!text_input_client_) |
| + if (!delegate_) |
| return E_UNEXPECTED; |
| if (view_cookie != kViewCookie) |
| return E_INVALIDARG; |
| @@ -294,7 +291,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 +302,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 +332,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 +380,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 +413,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; |
| } |
| @@ -516,12 +506,12 @@ 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(). |
| + // TextStoreDelegate::ConfirmComposition() or |
| + // TextStoreDelegate::SetComposition(). |
| const size_t new_committed_size = committed_size_; |
| const string16& new_committed_string = |
| string_buffer_.substr(last_committed_size, |
| @@ -529,41 +519,36 @@ STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { |
| 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); |
| - } |
| - |
| - // Calls TextInputClient::SetCompositionText(). |
| - CompositionText composition_text; |
| - composition_text.text = composition_string; |
| - composition_text.underlines = composition_undelines_; |
| - // 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 (delegate_) { |
| + // If there is new committed string, calls |
| + // TextStoreDelegate::ConfirmComposition(). |
| + if ((!new_committed_string.empty())) |
| + delegate_->OnTextCommitted(new_committed_string); |
| + |
| + // Calls TextInputClient::SetCompositionText(). |
| + std::vector<metro_viewer::UnderlineInfo> underlines = underlines_; |
| + // Adjusts the offset. |
| + 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 (text_input_client_) |
| - text_input_client_->SetCompositionText(composition_text); |
| // 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 +571,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 +587,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 +600,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 +619,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 +690,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; |
| } |
| @@ -741,7 +720,7 @@ bool TSFTextStore::GetCompositionStatus( |
| ITfContext* context, |
| const TfEditCookie read_only_edit_cookie, |
| size_t* committed_size, |
| - CompositionUnderlines* undelines) { |
| + std::vector<metro_viewer::UnderlineInfo>* undelines) { |
| DCHECK(context); |
| DCHECK(committed_size); |
| DCHECK(undelines); |
| @@ -810,33 +789,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_) |
| @@ -856,8 +818,8 @@ bool TSFTextStore::CancelComposition() { |
| const size_t previous_buffer_size = 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 +848,13 @@ 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(); |
| 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 +882,4 @@ bool TSFTextStore::HasReadWriteLock() const { |
| return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE; |
| } |
| -} // namespace ui |
| +} // namespace metro_driver |