Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(706)

Unified Diff: ui/base/win/tsf_text_store.cc

Issue 10831403: TsfTextStore implementation. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« ui/base/win/tsf_text_store.h ('K') | « ui/base/win/tsf_text_store.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/base/win/tsf_text_store.cc
diff --git a/ui/base/win/tsf_text_store.cc b/ui/base/win/tsf_text_store.cc
index 2c49d6b0949154ffaec3bf3ba47e5e1efff59d1c..7b74aefce7b2639ce942df33c16937f80296eba8 100644
--- a/ui/base/win/tsf_text_store.cc
+++ b/ui/base/win/tsf_text_store.cc
@@ -5,13 +5,28 @@
#include "ui/base/win/tsf_text_store.h"
#include <OleCtl.h>
-#include "base/logging.h"
+#include "base/win/scoped_variant.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/gfx/rect.h"
namespace ui {
TsfTextStore::TsfTextStore()
: ref_count_(0),
- text_store_acp_sink_mask_(0) {
+ text_store_acp_sink_mask_(0),
+ hwnd_(0),
+ text_input_client_(NULL),
+ current_lock_type_(0) {
+ if (FAILED(category_manager_.CreateInstance(
+ CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER))) {
+ LOG(FATAL) << "Failed to initialize CategoryMgr.";
+ return;
+ }
+ if (FAILED(display_attribute_manager_.CreateInstance(
+ CLSID_TF_DisplayAttributeMgr, NULL, CLSCTX_INPROC_SERVER))) {
+ LOG(FATAL) << "Failed to initialize DisplayAttributeMgr.";
+ return;
+ }
}
TsfTextStore::~TsfTextStore() {
@@ -73,8 +88,13 @@ STDMETHODIMP TsfTextStore::FindNextAttrTransition(
LONG* acp_next,
BOOL* found,
LONG* found_offset) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!acp_next || !found || !found_offset)
+ return E_INVALIDARG;
+ // We does not support FindNextAttrTransition.
+ *acp_next = 0;
+ *found = FALSE;
+ *found_offset = 0;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetACPFromPoint(
@@ -82,14 +102,16 @@ STDMETHODIMP TsfTextStore::GetACPFromPoint(
const POINT* point,
DWORD flags,
LONG* acp) {
+ // We does not support GetACPFromPoint.
NOTIMPLEMENTED();
return E_NOTIMPL;
}
STDMETHODIMP TsfTextStore::GetActiveView(TsViewCookie* view_cookie) {
- NOTIMPLEMENTED();
if (!view_cookie)
return E_INVALIDARG;
+ // We support only one view.
+ *view_cookie = 0;
return S_OK;
}
@@ -97,6 +119,7 @@ STDMETHODIMP TsfTextStore::GetEmbedded(LONG acp_pos,
REFGUID service,
REFIID iid,
IUnknown** unknown) {
+ // We does not support any embedded objects.
NOTIMPLEMENTED();
if (!unknown)
return E_INVALIDARG;
@@ -105,14 +128,17 @@ STDMETHODIMP TsfTextStore::GetEmbedded(LONG acp_pos,
}
STDMETHODIMP TsfTextStore::GetEndACP(LONG* acp) {
- NOTIMPLEMENTED();
if (!acp)
return E_INVALIDARG;
- return E_NOTIMPL;
+ if (!ReaderLocked())
+ return TS_E_NOLOCK;
+ *acp = status_.string_buffer_.length();
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetFormattedText(LONG acp_start, LONG acp_end,
IDataObject** data_object) {
+ // We does not support GetFormattedText.
NOTIMPLEMENTED();
return E_NOTIMPL;
}
@@ -129,19 +155,32 @@ STDMETHODIMP TsfTextStore::GetSelection(ULONG selection_index,
ULONG selection_buffer_size,
TS_SELECTION_ACP* selection_buffer,
ULONG* fetched_count) {
- NOTIMPLEMENTED();
if (!selection_buffer)
return E_INVALIDARG;
if (!fetched_count)
return E_INVALIDARG;
- return E_NOTIMPL;
+ if (!ReaderLocked())
+ return TS_E_NOLOCK;
+ *fetched_count = 0;
+ if ((selection_buffer_size > 0) &&
+ ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) {
+ selection_buffer[0].acpStart = status_.selection_.start();
+ selection_buffer[0].acpEnd = status_.selection_.end();
+ selection_buffer[0].style.ase = TS_AE_END;
+ selection_buffer[0].style.fInterimChar = FALSE;
+ *fetched_count = 1;
+ }
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetStatus(TS_STATUS* status) {
- NOTIMPLEMENTED();
if (!status)
return E_INVALIDARG;
- return E_NOTIMPL;
+
+ status->dwDynamicFlags = 0;
+ status->dwStaticFlags = TS_SS_NOHIDDENTEXT;
+
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetText(LONG acp_start,
@@ -153,14 +192,36 @@ STDMETHODIMP TsfTextStore::GetText(LONG acp_start,
ULONG run_info_buffer_size,
ULONG* run_info_buffer_copied,
LONG* next_acp) {
- NOTIMPLEMENTED();
if (!text_buffer_copied || !run_info_buffer_copied)
return E_INVALIDARG;
if (!text_buffer && text_buffer_size != 0)
return E_INVALIDARG;
if (!run_info_buffer && run_info_buffer_size != 0)
return E_INVALIDARG;
- return E_NOTIMPL;
+ if (!ReaderLocked())
+ return TF_E_NOLOCK;
+
+ if (acp_end == -1) {
+ acp_end = status_.string_buffer_.length();
+ }
+
+ acp_end = std::min(acp_end, acp_start + (int)text_buffer_size);
+ *text_buffer_copied = acp_end - acp_start;
+
+ const string16 result =
+ status_.string_buffer_.substr(acp_start, *text_buffer_copied);
+ for (size_t i = 0; i < result.size(); ++i) {
+ text_buffer[i] = result[i];
+ }
+
+ if (run_info_buffer_size) {
+ run_info_buffer[0].uCount = *text_buffer_copied;
+ run_info_buffer[0].type = TS_RT_PLAIN;
+ *run_info_buffer_copied = 1;
+ }
+
+ *next_acp = acp_end;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetTextExt(TsViewCookie view_cookie,
@@ -168,14 +229,62 @@ STDMETHODIMP TsfTextStore::GetTextExt(TsViewCookie view_cookie,
LONG acp_end,
Seigo Nonaka 2012/08/21 16:14:06 I'm confusing the |acp_end| spec. Please let me kn
horo 2012/08/22 02:22:33 Sorry my code was wrong. I think |acp_end| should
RECT* rect,
BOOL* clipped) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!rect || !clipped)
+ return E_INVALIDARG;
+ if (!text_input_client_)
+ return E_UNEXPECTED;
+ if (!ReaderLocked())
+ return TS_E_NOLOCK;
+ if (acp_start < static_cast<LONG>(status_.commited_size_))
+ return TS_E_INVALIDPOS;
+ if (acp_end < acp_start)
+ return E_INVALIDARG;
+
+ gfx::Rect result;
+ gfx::Rect tmp_rect;
+ uint32 start_pos = acp_start - status_.commited_size_;
Seigo Nonaka 2012/08/21 16:14:06 nit: const?
horo 2012/08/22 02:22:33 Done.
+ uint32 end_pos = acp_end - status_.commited_size_;
Seigo Nonaka 2012/08/21 16:14:06 nit: const?
horo 2012/08/22 02:22:33 Done.
+
+ if (start_pos == end_pos) {
+ if (text_input_client_->GetCompositionCharacterBounds(start_pos + 1,
Seigo Nonaka 2012/08/21 16:14:06 /start_pos + 1/start_pos/ ? GetCompositionCharacte
horo 2012/08/22 02:22:33 ah yes, it is my mistake. Done.
+ &tmp_rect)) {
+ result = tmp_rect;
+ result.set_width(0);
+ } else if (text_input_client_->GetCompositionCharacterBounds(start_pos,
Seigo Nonaka 2012/08/21 16:14:06 /start_pos/start_pos -1/ ?
horo 2012/08/22 02:22:33 Done.
+ &tmp_rect)) {
+ result.set_x(tmp_rect.right());
+ result.set_y(tmp_rect.y());
+ result.set_width(0);
+ result.set_height(tmp_rect.height());
+ } else if (start_pos == 0) {
+ result = text_input_client_->GetCaretBounds();
Seigo Nonaka 2012/08/21 16:14:06 Sorry this is my mistake. Caret does not always ex
horo 2012/08/22 02:22:33 Done. And added } else { return TS_E_NOL
+ } else {
+ return TS_E_NOLAYOUT;
+ }
+ } else {
+ if (!text_input_client_->GetCompositionCharacterBounds(start_pos,
+ &result)) {
+ return TS_E_NOLAYOUT;
+ }
+ for (uint32 i = start_pos + 1; i < end_pos - 1; ++i) {
Seigo Nonaka 2012/08/21 16:14:06 I think |i| should go |end_pos| -1.
horo 2012/08/22 02:22:33 Done.
+ if (!text_input_client_->GetCompositionCharacterBounds(start_pos,
Seigo Nonaka 2012/08/21 16:14:06 /start_pos/i/ ?
horo 2012/08/22 02:22:33 Done.
+ &tmp_rect)) {
+ break;
+ }
+ result.Union(tmp_rect);
Seigo Nonaka 2012/08/21 16:14:06 Union function returns new rectangle. result = res
Seigo Nonaka 2012/08/21 16:14:06 BTW, do we concern multiple line composition strin
horo 2012/08/22 02:22:33 Done.
horo 2012/08/22 02:22:33 There is no problem in the implementation of GetTe
+ }
+ }
+ *rect = result.ToRECT();
+ *clipped = FALSE;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::GetWnd(TsViewCookie view_cookie,
HWND* window_handle) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!window_handle)
+ return E_INVALIDARG;
+ *window_handle = hwnd_;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::InsertEmbedded(DWORD flags,
@@ -183,6 +292,7 @@ STDMETHODIMP TsfTextStore::InsertEmbedded(DWORD flags,
LONG acp_end,
IDataObject* data_object,
TS_TEXTCHANGE* change) {
+ // We does not support any embedded objects.
NOTIMPLEMENTED();
return E_NOTIMPL;
}
@@ -192,6 +302,7 @@ STDMETHODIMP TsfTextStore::InsertEmbeddedAtSelection(DWORD flags,
LONG* acp_start,
LONG* acp_end,
TS_TEXTCHANGE* change) {
+ // We does not support any embedded objects.
NOTIMPLEMENTED();
return E_NOTIMPL;
}
@@ -202,8 +313,38 @@ STDMETHODIMP TsfTextStore::InsertTextAtSelection(DWORD flags,
LONG* acp_start,
LONG* acp_end,
TS_TEXTCHANGE* text_change) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!WriterLocked())
+ return TS_E_NOLOCK;
+
+ LONG start_pos = status_.selection_.start();
Seigo Nonaka 2012/08/21 16:14:06 nit: const?
horo 2012/08/22 02:22:33 Done.
+ LONG end_pos = status_.selection_.end();
Seigo Nonaka 2012/08/21 16:14:06 nit: const?
horo 2012/08/22 02:22:33 Done.
+
+ if (flags & TS_IAS_QUERYONLY) {
+ *acp_start = start_pos;
+ *acp_end = end_pos + text_buffer_size;
+ return S_OK;
+ }
+
+ if (!text_buffer)
+ return E_INVALIDARG;
+ status_.RemoveText(start_pos, end_pos - start_pos);
+ status_.InsertText(start_pos,
+ string16(text_buffer,
+ text_buffer + text_buffer_size));
+ if (acp_start) {
Seigo Nonaka 2012/08/21 16:14:06 nit: remove braces
horo 2012/08/22 02:22:33 Done.
+ *acp_start = start_pos;
+ }
+ if (acp_end) {
Seigo Nonaka 2012/08/21 16:14:06 nit: remove braces
horo 2012/08/22 02:22:33 Done.
+ *acp_end = start_pos + text_buffer_size;
+ }
+ if (text_change) {
+ text_change->acpStart = start_pos;
+ text_change->acpOldEnd = end_pos;
+ text_change->acpNewEnd = start_pos + text_buffer_size;
+ }
+ status_.MoveSelection(start_pos, start_pos + text_buffer_size);
+ text_store_acp_sink_->OnSelectionChange();
+ return S_OK;
}
STDMETHODIMP TsfTextStore::QueryInsert(
@@ -212,13 +353,17 @@ STDMETHODIMP TsfTextStore::QueryInsert(
ULONG text_size,
LONG* acp_result_start,
LONG* acp_result_end) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (acp_result_start)
+ *acp_result_start = acp_test_start;
+ if (acp_result_end)
+ *acp_result_end = acp_test_start + text_size;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::QueryInsertEmbedded(const GUID* service,
const FORMATETC* format,
BOOL* insertable) {
+ // We does not support any embedded objects.
NOTIMPLEMENTED();
return E_NOTIMPL;
}
@@ -228,8 +373,10 @@ STDMETHODIMP TsfTextStore::RequestAttrsAtPosition(
ULONG attribute_buffer_size,
const TS_ATTRID* attribute_buffer,
DWORD flags) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ // We does not support any document attributes.
+ // This method just returns S_OK, and the subsequently called
+ // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
+ return S_OK;
}
STDMETHODIMP TsfTextStore::RequestAttrsTransitioningAtPosition(
@@ -237,36 +384,147 @@ STDMETHODIMP TsfTextStore::RequestAttrsTransitioningAtPosition(
ULONG attribute_buffer_size,
const TS_ATTRID* attribute_buffer,
DWORD flags) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ // We does not support any document attributes.
+ // This method just returns S_OK, and the subsequently called
+ // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
+ return S_OK;
}
STDMETHODIMP TsfTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!text_store_acp_sink_.get())
+ return E_FAIL;
+ if (result == NULL)
+ return E_INVALIDARG;
+
+ if (current_lock_type_ != 0) {
+ if (lock_flags & TS_LF_SYNC) {
+ // Can't lock synchronously.
+ *result = TS_E_SYNCHRONOUS;
+ return S_OK;
+ }
+ // Queue the lock request.
+ lock_queue_.push_back(lock_flags & TS_LF_READWRITE);
+ *result = TS_S_ASYNC;
+ return S_OK;
+ }
+
+ // Lock
+ current_lock_type_ = (lock_flags & TS_LF_READWRITE);
+
+ status_.edit_flag_ = false;
+ size_t last_commited_size = status_.commited_size_;
Seigo Nonaka 2012/08/21 16:14:06 nit: const and /commited/committed/
horo 2012/08/22 02:22:33 Done.
+
+ // Grant the lock.
+ *result = text_store_acp_sink_->OnLockGranted(current_lock_type_);
+
+ // Unlock
+ current_lock_type_ = 0;
+
+ // Handles the pending lock requests.
+ if(lock_queue_.size() > 0) {
Seigo Nonaka 2012/08/21 16:14:06 nit: /if(/if (/
horo 2012/08/22 02:22:33 Done.
+ current_lock_type_ = lock_queue_.front();
+ lock_queue_.pop_front();
+ text_store_acp_sink_->OnLockGranted(current_lock_type_);
+ current_lock_type_ = 0;
+ }
+
+ // If the text store status is edited in OnLockGranted(), we may need to call
+ // TextInputClient::InsertText() or TextInputClient::SetCompositionText().
+ if (status_.edit_flag_) {
+ size_t new_commited_size = status_.commited_size_;
+ const string16 new_commited_string =
+ status_.string_buffer_.substr(last_commited_size,
+ new_commited_size - last_commited_size);
+ const string16 composition_string =
+ status_.string_buffer_.substr(new_commited_size);
+
+ // If there is new commited string, calls TextInputClient::InsertText().
+ if (new_commited_string.length() != 0) {
+ if (text_input_client_) {
Seigo Nonaka 2012/08/21 16:14:06 nit: remove braces
horo 2012/08/22 02:22:33 Done.
+ text_input_client_->InsertText(new_commited_string);
+ }
+ }
+
+ // Calls TextInputClient::SetCompositionText().
+ CompositionText composition_text;
+ composition_text.text = composition_string;
+ composition_text.underlines = status_.composition_undelines_;
+ for (size_t i = 0; i < composition_text.underlines.size(); ++i) {
+ composition_text.underlines[i].start_offset -= new_commited_size;
+ composition_text.underlines[i].end_offset -= new_commited_size;
+ }
+ if (status_.selection_.start() < new_commited_size) {
+ composition_text.selection.set_start(0);
+ } else {
+ composition_text.selection.set_start(
+ status_.selection_.start() - new_commited_size);
+ }
+ if (status_.selection_.end() < new_commited_size) {
+ composition_text.selection.set_end(0);
+ } else {
+ composition_text.selection.set_end(
+ status_.selection_.end() - new_commited_size);
+ }
+ if (text_input_client_) {
Seigo Nonaka 2012/08/21 16:14:06 nit: remove braces
horo 2012/08/22 02:22:33 Done.
+ 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.length() == 0) && (new_commited_size != 0)) {
+ status_.RemoveText(0, new_commited_size);
+ status_.commited_size_ = 0;
+ status_.MoveSelection(0, 0);
+ text_store_acp_sink_->OnSelectionChange();
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+ TS_TEXTCHANGE textChange;
+ textChange.acpStart = 0;
+ textChange.acpOldEnd = new_commited_size;
+ textChange.acpNewEnd = 0;
+ text_store_acp_sink_->OnTextChange(0, &textChange);
+ }
+ }
+
+ return S_OK;
}
STDMETHODIMP TsfTextStore::RequestSupportedAttrs(
DWORD flags,
ULONG attribute_buffer_size,
const TS_ATTRID* attribute_buffer) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ // We does not support any document attributes.
+ // This method just returns S_OK, and the subsequently called
+ // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
+ return S_OK;
}
STDMETHODIMP TsfTextStore::RetrieveRequestedAttrs(
ULONG attribute_buffer_size,
TS_ATTRVAL* attribute_buffer,
ULONG* attribute_buffer_copied) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (attribute_buffer_copied == NULL)
+ return E_INVALIDARG;
+ // We does not support any document attributes.
+ attribute_buffer_copied = 0;
+ return S_OK;
}
STDMETHODIMP TsfTextStore::SetSelection(
ULONG selection_buffer_size,
const TS_SELECTION_ACP* selection_buffer) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!WriterLocked())
+ return TF_E_NOLOCK;
+ if (selection_buffer_size > 0) {
+ const LONG start_pos = selection_buffer[0].acpStart;
+ const LONG end_pos = selection_buffer[0].acpEnd;
+ if ((start_pos < 0) ||
+ (static_cast<LONG>(status_.string_buffer_.length()) < start_pos) ||
+ (end_pos < start_pos) ||
+ (static_cast<LONG>(status_.string_buffer_.length()) < end_pos))
Seigo Nonaka 2012/08/21 16:14:06 nit: please do not remove braces if the condition
horo 2012/08/22 02:22:33 Done.
+ return TF_E_INVALIDPOS;
+ status_.MoveSelection(start_pos, end_pos);
+ }
+ return S_OK;
}
STDMETHODIMP TsfTextStore::SetText(DWORD flags,
@@ -275,8 +533,34 @@ STDMETHODIMP TsfTextStore::SetText(DWORD flags,
const wchar_t* text_buffer,
ULONG text_buffer_size,
TS_TEXTCHANGE* text_change) {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
+ if (!WriterLocked())
+ return TS_E_NOLOCK;
+ if (acp_start < static_cast<LONG>(status_.commited_size_))
+ return TS_E_INVALIDPOS;
+ if (static_cast<LONG>(status_.string_buffer_.length()) < acp_start)
+ return TS_E_INVALIDPOS;
+ if (acp_end < acp_start)
+ return E_INVALIDARG;
+ if (static_cast<LONG>(status_.string_buffer_.length()) < acp_end)
+ return TS_E_INVALIDPOS;
+
+ TS_SELECTION_ACP selection;
+ selection.acpStart = acp_start;
+ selection.acpEnd = acp_end;
+ selection.style.ase = TS_AE_NONE;
+ selection.style.fInterimChar = 0;
+ if (SetSelection(1, &selection) != S_OK)
+ return E_UNEXPECTED;
+
+ TS_TEXTCHANGE change;
+ if (InsertTextAtSelection(0, text_buffer, text_buffer_size,
+ &acp_start, &acp_end, &change) != S_OK) {
+ return E_UNEXPECTED;
+ }
+ if (text_change)
+ *text_change = change;
+
+ return S_OK;
}
STDMETHODIMP TsfTextStore::UnadviseSink(IUnknown* unknown) {
@@ -290,7 +574,7 @@ STDMETHODIMP TsfTextStore::UnadviseSink(IUnknown* unknown) {
STDMETHODIMP TsfTextStore::OnStartComposition(
ITfCompositionView* composition_view,
BOOL* ok) {
- if (!ok)
+ if (ok)
*ok = TRUE;
return S_OK;
}
@@ -309,7 +593,144 @@ STDMETHODIMP TsfTextStore::OnEndComposition(
STDMETHODIMP TsfTextStore::OnEndEdit(ITfContext* context,
TfEditCookie read_only_edit_cookie,
ITfEditRecord* edit_record) {
+ if (!context || !edit_record)
+ return E_INVALIDARG;
+
+ size_t commited_size;
+ CompositionUnderlines undelines;
+ if (!GetCompositionStatus(context, read_only_edit_cookie, &commited_size,
+ &undelines)) {
+ return S_OK;
+ }
+ status_.composition_undelines_ = undelines;
+ status_.commited_size_ = commited_size;
+ status_.edit_flag_ = true;
return S_OK;
}
-} // namespace ui
+bool TsfTextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
+ TF_DISPLAYATTRIBUTE* attribute) {
+ GUID guid;
+ if (FAILED(category_manager_->GetGUID(guid_atom, &guid)))
+ return false;
+
+ base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info;
+ if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo(
+ guid, display_attribute_info.Receive(), NULL))) {
+ return false;
+ }
+ return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
+}
+
+bool TsfTextStore::GetCompositionStatus(
+ ITfContext* context,
+ const TfEditCookie read_only_edit_cookie,
+ size_t* committed_size,
+ CompositionUnderlines* undelines) {
+ DCHECK(context);
+ DCHECK(committed_size);
+ DCHECK(undelines);
+ const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
+ base::win::ScopedComPtr<ITfReadOnlyProperty> track_property;
+ if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0,
+ track_property.Receive()))) {
+ return false;
+ }
+
+ *committed_size = 0;
+ undelines->clear();
+ base::win::ScopedComPtr<ITfRange> start_to_end_range;
+ base::win::ScopedComPtr<ITfRange> end_range;
+ if (FAILED(context->GetStart(read_only_edit_cookie,
+ start_to_end_range.Receive()))) {
+ return false;
+ }
+ if (FAILED(context->GetEnd(read_only_edit_cookie, end_range.Receive())))
+ return false;
+ if (FAILED(start_to_end_range->ShiftEndToRange(read_only_edit_cookie,
+ end_range, TF_ANCHOR_END))) {
+ return false;
+ }
+
+ base::win::ScopedComPtr<IEnumTfRanges> ranges;
+ if (FAILED(track_property->EnumRanges(read_only_edit_cookie, ranges.Receive(),
+ start_to_end_range))) {
+ return false;
+ }
+
+ base::win::ScopedComPtr<ITfRange> range;
+ while (ranges->Next(1, range.Receive(), NULL) == S_OK) {
+ base::win::ScopedVariant value;
+ base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value;
+ if (FAILED(track_property->GetValue(read_only_edit_cookie, range,
+ value.Receive()))) {
+ return false;
+ }
+ if (FAILED(enum_prop_value.QueryFrom(value.AsInput()->punkVal)))
+ return false;
+
+ TF_PROPERTYVAL property_value;
+ bool is_composition = false;
+ bool has_display_attribute = false;
+ TF_DISPLAYATTRIBUTE display_attribute;
+ while (enum_prop_value->Next(1, &property_value, NULL) == S_OK) {
+ if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) {
+ is_composition = (property_value.varValue.lVal == TRUE);
+ } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) {
+ TfGuidAtom guid_atom =
+ static_cast<TfGuidAtom>(property_value.varValue.lVal);
+ if (GetDisplayAttribute(guid_atom, &display_attribute))
+ has_display_attribute = true;
+ }
+ VariantClear(&property_value.varValue);
+ }
+
+ base::win::ScopedComPtr<ITfRangeACP> range_acp;
+ range_acp.QueryFrom(range);
+ LONG start_pos, length;
+ range_acp->GetExtent(&start_pos, &length);
+ if (!is_composition) {
+ if (*committed_size < static_cast<size_t>(start_pos + length))
+ *committed_size = start_pos + length;
+ } else {
+ CompositionUnderline 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;
+ undelines->push_back(underline);
+ }
+ range.Release();
+ }
+ return true;
+}
+
+void TsfTextStore::SetFocusedTextInputClient(
+ HWND focused_window,
+ TextInputClient* text_input_client) {
+ hwnd_ = focused_window;
+ text_input_client_ = text_input_client;
+}
+
+void TsfTextStore::RemoveFocusedTextInputClient(
+ TextInputClient* text_input_client) {
+ if (text_input_client_ == text_input_client) {
+ hwnd_ = 0;
+ text_input_client_ = NULL;
+ }
+}
+
+void TsfTextStore::SendOnLayoutChange() {
+ if (text_store_acp_sink_)
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+}
+
+bool TsfTextStore::ReaderLocked() const {
+ return (current_lock_type_ & TS_LF_READ) == TS_LF_READ;
+}
+
+bool TsfTextStore::WriterLocked() const {
+ return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE;
+}
+} // namespace ui
« ui/base/win/tsf_text_store.h ('K') | « ui/base/win/tsf_text_store.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698