| 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
|
|
|