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

Side by Side 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: fix misstype 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/base/win/tsf_text_store.h" 5 #include "ui/base/win/tsf_text_store.h"
6 6
7 #include <OleCtl.h> 7 #include <OleCtl.h>
8 #include "base/logging.h" 8 #include "base/win/scoped_variant.h"
9 #include "ui/gfx/rect.h"
9 10
10 namespace ui { 11 namespace ui {
11 12
12 TsfTextStore::TsfTextStore() 13 TsfTextStore::TsfTextStore()
13 : ref_count_(0), 14 : ref_count_(0),
14 text_store_acp_sink_mask_(0) { 15 text_store_acp_sink_mask_(0),
16 hwnd_(0),
17 text_input_client_(NULL),
18 current_lock_type_(0) {
19
Seigo Nonaka 2012/08/21 12:22:41 nit: remove line.
horo 2012/08/21 13:59:57 Done.
20 if (FAILED(category_mgr_.CreateInstance(CLSID_TF_CategoryMgr, NULL,
21 CLSCTX_INPROC_SERVER))) {
Seigo Nonaka 2012/08/21 12:22:41 nit: align
horo 2012/08/21 13:59:57 Done.
22 LOG(FATAL) << "Failed to initialize CategoryMgr.";
23 return;
24 }
25 if (FAILED(display_attribute_mgr_.CreateInstance(CLSID_TF_DisplayAttributeMgr,
26 NULL,
Seigo Nonaka 2012/08/21 12:22:41 nit:align
horo 2012/08/21 13:59:57 Done.
27 CLSCTX_INPROC_SERVER))) {
28 LOG(FATAL) << "Failed to initialize DisplayAttributeMgr.";
29 return;
30 }
15 } 31 }
16 32
17 TsfTextStore::~TsfTextStore() { 33 TsfTextStore::~TsfTextStore() {
18 } 34 }
19 35
20 ULONG STDMETHODCALLTYPE TsfTextStore::AddRef() { 36 ULONG STDMETHODCALLTYPE TsfTextStore::AddRef() {
21 return InterlockedIncrement(&ref_count_); 37 return InterlockedIncrement(&ref_count_);
22 } 38 }
23 39
24 ULONG STDMETHODCALLTYPE TsfTextStore::Release() { 40 ULONG STDMETHODCALLTYPE TsfTextStore::Release() {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 82
67 STDMETHODIMP TsfTextStore::FindNextAttrTransition( 83 STDMETHODIMP TsfTextStore::FindNextAttrTransition(
68 LONG acp_start, 84 LONG acp_start,
69 LONG acp_halt, 85 LONG acp_halt,
70 ULONG num_filter_attributes, 86 ULONG num_filter_attributes,
71 const TS_ATTRID* filter_attributes, 87 const TS_ATTRID* filter_attributes,
72 DWORD flags, 88 DWORD flags,
73 LONG* acp_next, 89 LONG* acp_next,
74 BOOL* found, 90 BOOL* found,
75 LONG* found_offset) { 91 LONG* found_offset) {
76 NOTIMPLEMENTED(); 92 if (!acp_next || !found || !found_offset)
77 return E_NOTIMPL; 93 return E_INVALIDARG;
94 // We does not support FindNextAttrTransition.
95 *acp_next = 0;
96 *found = FALSE;
97 *found_offset = 0;
98 return S_OK;
78 } 99 }
79 100
80 STDMETHODIMP TsfTextStore::GetACPFromPoint( 101 STDMETHODIMP TsfTextStore::GetACPFromPoint(
81 TsViewCookie view_cookie, 102 TsViewCookie view_cookie,
82 const POINT* point, 103 const POINT* point,
83 DWORD flags, 104 DWORD flags,
84 LONG* acp) { 105 LONG* acp) {
106 // We does not support GetACPFromPoint.
85 NOTIMPLEMENTED(); 107 NOTIMPLEMENTED();
86 return E_NOTIMPL; 108 return E_NOTIMPL;
87 } 109 }
88 110
89 STDMETHODIMP TsfTextStore::GetActiveView(TsViewCookie* view_cookie) { 111 STDMETHODIMP TsfTextStore::GetActiveView(TsViewCookie* view_cookie) {
90 NOTIMPLEMENTED();
91 if (!view_cookie) 112 if (!view_cookie)
92 return E_INVALIDARG; 113 return E_INVALIDARG;
114 // We support only one view.
115 *view_cookie = 0;
93 return S_OK; 116 return S_OK;
94 } 117 }
95 118
96 STDMETHODIMP TsfTextStore::GetEmbedded(LONG acp_pos, 119 STDMETHODIMP TsfTextStore::GetEmbedded(LONG acp_pos,
97 REFGUID service, 120 REFGUID service,
98 REFIID iid, 121 REFIID iid,
99 IUnknown** unknown) { 122 IUnknown** unknown) {
123 // We does not support any embedded objects.
100 NOTIMPLEMENTED(); 124 NOTIMPLEMENTED();
101 if (!unknown) 125 if (!unknown)
102 return E_INVALIDARG; 126 return E_INVALIDARG;
103 *unknown = NULL; 127 *unknown = NULL;
104 return E_NOTIMPL; 128 return E_NOTIMPL;
105 } 129 }
106 130
107 STDMETHODIMP TsfTextStore::GetEndACP(LONG* acp) { 131 STDMETHODIMP TsfTextStore::GetEndACP(LONG* acp) {
108 NOTIMPLEMENTED();
109 if (!acp) 132 if (!acp)
110 return E_INVALIDARG; 133 return E_INVALIDARG;
111 return E_NOTIMPL; 134 if (!ReaderLocked())
135 return TS_E_NOLOCK;
136 *acp = status_.string_buffer_.length();
137 return S_OK;
112 } 138 }
113 139
114 STDMETHODIMP TsfTextStore::GetFormattedText(LONG acp_start, LONG acp_end, 140 STDMETHODIMP TsfTextStore::GetFormattedText(LONG acp_start, LONG acp_end,
115 IDataObject** data_object) { 141 IDataObject** data_object) {
142 // We does not support GetFormattedText.
116 NOTIMPLEMENTED(); 143 NOTIMPLEMENTED();
117 return E_NOTIMPL; 144 return E_NOTIMPL;
118 } 145 }
119 146
120 STDMETHODIMP TsfTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) { 147 STDMETHODIMP TsfTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) {
121 NOTIMPLEMENTED(); 148 NOTIMPLEMENTED();
122 if (!rect) 149 if (!rect)
123 return E_INVALIDARG; 150 return E_INVALIDARG;
124 SetRect(rect, 0, 0, 0, 0); 151 SetRect(rect, 0, 0, 0, 0);
125 return S_OK; 152 return S_OK;
126 } 153 }
127 154
128 STDMETHODIMP TsfTextStore::GetSelection(ULONG selection_index, 155 STDMETHODIMP TsfTextStore::GetSelection(ULONG selection_index,
129 ULONG selection_buffer_size, 156 ULONG selection_buffer_size,
130 TS_SELECTION_ACP* selection_buffer, 157 TS_SELECTION_ACP* selection_buffer,
131 ULONG* fetched_count) { 158 ULONG* fetched_count) {
132 NOTIMPLEMENTED();
133 if (!selection_buffer) 159 if (!selection_buffer)
134 return E_INVALIDARG; 160 return E_INVALIDARG;
135 if (!fetched_count) 161 if (!fetched_count)
136 return E_INVALIDARG; 162 return E_INVALIDARG;
137 return E_NOTIMPL; 163 if (!ReaderLocked())
164 return TS_E_NOLOCK;
165 *fetched_count = 0;
166 if ((selection_buffer_size > 0) &&
167 ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) {
168 selection_buffer[0].acpStart = status_.selection_start_;
169 selection_buffer[0].acpEnd = status_.selection_end_;
170 selection_buffer[0].style.ase = TS_AE_END;
171 selection_buffer[0].style.fInterimChar = FALSE;
172 *fetched_count = 1;
173 }
174 return S_OK;
138 } 175 }
139 176
140 STDMETHODIMP TsfTextStore::GetStatus(TS_STATUS* status) { 177 STDMETHODIMP TsfTextStore::GetStatus(TS_STATUS* status) {
141 NOTIMPLEMENTED();
142 if (!status) 178 if (!status)
143 return E_INVALIDARG; 179 return E_INVALIDARG;
144 return E_NOTIMPL; 180
181 if (text_input_client_ == NULL) {
182 status->dwDynamicFlags = 0;
183 status->dwStaticFlags = 0;
184 } else {
185 const TextInputType type = text_input_client_->GetTextInputType();
186 if (type == TEXT_INPUT_TYPE_NONE ||
187 type == TEXT_INPUT_TYPE_PASSWORD) {
Seigo Nonaka 2012/08/21 12:22:41 I think DCHECK(type != TEXT_INPUT_TYPE_NONE && typ
horo 2012/08/21 13:59:57 Oh I see. Then, status->dwDynamicFlags = 0; st
188 status->dwDynamicFlags = TS_SD_READONLY;
189 } else {
190 status->dwDynamicFlags = 0;
191 }
192 status->dwStaticFlags = TS_SS_NOHIDDENTEXT;
193 }
194 return S_OK;
145 } 195 }
146 196
147 STDMETHODIMP TsfTextStore::GetText(LONG acp_start, 197 STDMETHODIMP TsfTextStore::GetText(LONG acp_start,
148 LONG acp_end, 198 LONG acp_end,
149 wchar_t* text_buffer, 199 wchar_t* text_buffer,
150 ULONG text_buffer_size, 200 ULONG text_buffer_size,
151 ULONG* text_buffer_copied, 201 ULONG* text_buffer_copied,
152 TS_RUNINFO* run_info_buffer, 202 TS_RUNINFO* run_info_buffer,
153 ULONG run_info_buffer_size, 203 ULONG run_info_buffer_size,
154 ULONG* run_info_buffer_copied, 204 ULONG* run_info_buffer_copied,
155 LONG* next_acp) { 205 LONG* next_acp) {
156 NOTIMPLEMENTED();
157 if (!text_buffer_copied || !run_info_buffer_copied) 206 if (!text_buffer_copied || !run_info_buffer_copied)
158 return E_INVALIDARG; 207 return E_INVALIDARG;
159 if (!text_buffer && text_buffer_size != 0) 208 if (!text_buffer && text_buffer_size != 0)
160 return E_INVALIDARG; 209 return E_INVALIDARG;
161 if (!run_info_buffer && run_info_buffer_size != 0) 210 if (!run_info_buffer && run_info_buffer_size != 0)
162 return E_INVALIDARG; 211 return E_INVALIDARG;
163 return E_NOTIMPL; 212 if (!ReaderLocked())
213 return TF_E_NOLOCK;
214
215 if (acp_end == -1) {
216 acp_end = status_.string_buffer_.length();
217 }
218
219 acp_end = std::min(acp_end, acp_start + (int)text_buffer_size);
220 *text_buffer_copied = acp_end - acp_start;
221
222 const string16 result =
223 status_.string_buffer_.substr(acp_start, *text_buffer_copied);
224 for (size_t i = 0; i < result.size(); ++i) {
225 text_buffer[i] = result[i];
226 }
227
228 if (run_info_buffer_size) {
229 run_info_buffer[0].uCount = *text_buffer_copied;
230 run_info_buffer[0].type = TS_RT_PLAIN;
231 *run_info_buffer_copied = 1;
232 }
233
234 *next_acp = acp_end;
235 return S_OK;
164 } 236 }
165 237
166 STDMETHODIMP TsfTextStore::GetTextExt(TsViewCookie view_cookie, 238 STDMETHODIMP TsfTextStore::GetTextExt(TsViewCookie view_cookie,
167 LONG acp_start, 239 LONG acp_start,
168 LONG acp_end, 240 LONG acp_end,
169 RECT* rect, 241 RECT* rect,
170 BOOL* clipped) { 242 BOOL* clipped) {
171 NOTIMPLEMENTED(); 243 if (!rect || !clipped)
172 return E_NOTIMPL; 244 return E_INVALIDARG;
245 if (!text_input_client_)
246 return E_UNEXPECTED;
247 if (!ReaderLocked())
248 return TS_E_NOLOCK;
249 if (acp_start < static_cast<LONG>(status_.commited_size_))
250 return TS_E_INVALIDPOS;
251 if (acp_end < acp_start)
252 return E_INVALIDARG;
253
254 gfx::Rect result;
255 gfx::Rect tmp_rect;
256 uint32 start_pos = acp_start - status_.commited_size_;
257 uint32 end_pos = acp_end - status_.commited_size_;
258
259 if (start_pos == end_pos) {
260 if (text_input_client_->GetCompositionCharacterBounds(start_pos + 1,
261 &tmp_rect)) {
262 result = tmp_rect;
263 result.set_width(0);
264 } else if (text_input_client_->GetCompositionCharacterBounds(start_pos,
265 &tmp_rect)) {
266 result.set_x(tmp_rect.right());
267 result.set_y(tmp_rect.y());
268 result.set_width(0);
269 result.set_height(tmp_rect.height());
270 } else {
271 return E_FAIL;
Seigo Nonaka 2012/08/21 12:22:41 How about using GetCaretBounds if the start_pos ==
horo 2012/08/21 13:59:57 Done.
272 }
273 } else {
274 if (!text_input_client_->GetCompositionCharacterBounds(start_pos,
275 &result)) {
276 return E_FAIL;
277 }
278 for (uint32 i = start_pos + 1; i < end_pos - 1; ++i) {
279 if (!text_input_client_->GetCompositionCharacterBounds(start_pos,
280 &tmp_rect)) {
281 break;
282 }
283 result.Union(tmp_rect);
284 }
285 }
286 *rect = result.ToRECT();
287 *clipped = FALSE;
288 return S_OK;
173 } 289 }
174 290
Seigo Nonaka 2012/08/21 12:22:41 nit: remove line
horo 2012/08/21 13:59:57 Done.
291
175 STDMETHODIMP TsfTextStore::GetWnd(TsViewCookie view_cookie, 292 STDMETHODIMP TsfTextStore::GetWnd(TsViewCookie view_cookie,
176 HWND* window_handle) { 293 HWND* window_handle) {
177 NOTIMPLEMENTED(); 294 if (!window_handle)
178 return E_NOTIMPL; 295 return E_INVALIDARG;
296 *window_handle = hwnd_;
297 return S_OK;
179 } 298 }
180 299
181 STDMETHODIMP TsfTextStore::InsertEmbedded(DWORD flags, 300 STDMETHODIMP TsfTextStore::InsertEmbedded(DWORD flags,
182 LONG acp_start, 301 LONG acp_start,
183 LONG acp_end, 302 LONG acp_end,
184 IDataObject* data_object, 303 IDataObject* data_object,
185 TS_TEXTCHANGE* change) { 304 TS_TEXTCHANGE* change) {
305 // We does not support any embedded objects.
186 NOTIMPLEMENTED(); 306 NOTIMPLEMENTED();
187 return E_NOTIMPL; 307 return E_NOTIMPL;
188 } 308 }
189 309
190 STDMETHODIMP TsfTextStore::InsertEmbeddedAtSelection(DWORD flags, 310 STDMETHODIMP TsfTextStore::InsertEmbeddedAtSelection(DWORD flags,
191 IDataObject* data_object, 311 IDataObject* data_object,
192 LONG* acp_start, 312 LONG* acp_start,
193 LONG* acp_end, 313 LONG* acp_end,
194 TS_TEXTCHANGE* change) { 314 TS_TEXTCHANGE* change) {
315 // We does not support any embedded objects.
195 NOTIMPLEMENTED(); 316 NOTIMPLEMENTED();
196 return E_NOTIMPL; 317 return E_NOTIMPL;
197 } 318 }
198 319
199 STDMETHODIMP TsfTextStore::InsertTextAtSelection(DWORD flags, 320 STDMETHODIMP TsfTextStore::InsertTextAtSelection(DWORD flags,
200 const wchar_t* text_buffer, 321 const wchar_t* text_buffer,
201 ULONG text_buffer_size, 322 ULONG text_buffer_size,
202 LONG* acp_start, 323 LONG* acp_start,
203 LONG* acp_end, 324 LONG* acp_end,
204 TS_TEXTCHANGE* text_change) { 325 TS_TEXTCHANGE* text_change) {
205 NOTIMPLEMENTED(); 326 if (!WriterLocked()) {
Seigo Nonaka 2012/08/21 12:22:41 nit: remove braces
horo 2012/08/21 13:59:57 Done.
206 return E_NOTIMPL; 327 return TS_E_NOLOCK;
328 }
329 LONG start_pos = status_.selection_start_;
330 LONG end_pos = status_.selection_end_;
331
332 if (flags & TS_IAS_QUERYONLY) {
333 *acp_start = start_pos;
334 *acp_end = end_pos + text_buffer_size;
335 return S_OK;
336 }
337
338 status_.RemoveText(start_pos, end_pos - start_pos);
339 status_.InsertText(start_pos,
Seigo Nonaka 2012/08/21 12:22:41 DCHECK(text_buffer)?
horo 2012/08/21 13:59:57 Added if (!text_buffer) return E_INVALIDARG;
340 string16(text_buffer,
341 text_buffer + text_buffer_size));
342 if (acp_start) {
343 *acp_start = start_pos;
344 }
345 if (acp_end) {
346 *acp_end = start_pos + text_buffer_size;
347 }
348 if (text_change) {
349 text_change->acpStart = start_pos;
350 text_change->acpOldEnd = end_pos;
351 text_change->acpNewEnd = start_pos + text_buffer_size;
352 }
353 status_.MoveSelection(start_pos, start_pos + text_buffer_size);
354 text_store_acp_sink_->OnSelectionChange();
Seigo Nonaka 2012/08/21 12:22:41 I'm not sure but is it okay to call OnSelectionCha
horo 2012/08/21 13:59:57 I think it is ok. The sample application "TsfPad"
Seigo Nonaka 2012/08/21 16:14:06 Got it, thanks. On 2012/08/21 13:59:57, horo wrote
355 return S_OK;
207 } 356 }
208 357
209 STDMETHODIMP TsfTextStore::QueryInsert( 358 STDMETHODIMP TsfTextStore::QueryInsert(
210 LONG acp_test_start, 359 LONG acp_test_start,
211 LONG acp_test_end, 360 LONG acp_test_end,
212 ULONG text_size, 361 ULONG text_size,
213 LONG* acp_result_start, 362 LONG* acp_result_start,
214 LONG* acp_result_end) { 363 LONG* acp_result_end) {
215 NOTIMPLEMENTED(); 364 if (acp_result_start)
216 return E_NOTIMPL; 365 *acp_result_start = acp_test_start;
366 if (acp_result_end)
367 *acp_result_end = acp_test_start + text_size;
368 return S_OK;
217 } 369 }
218 370
219 STDMETHODIMP TsfTextStore::QueryInsertEmbedded(const GUID* service, 371 STDMETHODIMP TsfTextStore::QueryInsertEmbedded(const GUID* service,
220 const FORMATETC* format, 372 const FORMATETC* format,
221 BOOL* insertable) { 373 BOOL* insertable) {
374 // We does not support any embedded objects.
222 NOTIMPLEMENTED(); 375 NOTIMPLEMENTED();
223 return E_NOTIMPL; 376 return E_NOTIMPL;
224 } 377 }
225 378
226 STDMETHODIMP TsfTextStore::RequestAttrsAtPosition( 379 STDMETHODIMP TsfTextStore::RequestAttrsAtPosition(
227 LONG acp_pos, 380 LONG acp_pos,
228 ULONG attribute_buffer_size, 381 ULONG attribute_buffer_size,
229 const TS_ATTRID* attribute_buffer, 382 const TS_ATTRID* attribute_buffer,
230 DWORD flags) { 383 DWORD flags) {
231 NOTIMPLEMENTED(); 384 // We does not support any document attributes.
232 return E_NOTIMPL; 385 // This method just returns S_OK, and the subsequently called
386 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
387 return S_OK;
233 } 388 }
234 389
235 STDMETHODIMP TsfTextStore::RequestAttrsTransitioningAtPosition( 390 STDMETHODIMP TsfTextStore::RequestAttrsTransitioningAtPosition(
236 LONG acp_pos, 391 LONG acp_pos,
237 ULONG attribute_buffer_size, 392 ULONG attribute_buffer_size,
238 const TS_ATTRID* attribute_buffer, 393 const TS_ATTRID* attribute_buffer,
239 DWORD flags) { 394 DWORD flags) {
240 NOTIMPLEMENTED(); 395 // We does not support any document attributes.
241 return E_NOTIMPL; 396 // This method just returns S_OK, and the subsequently called
397 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
398 return S_OK;
242 } 399 }
243 400
244 STDMETHODIMP TsfTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { 401 STDMETHODIMP TsfTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
Seigo Nonaka 2012/08/21 12:22:41 I think it is clear that just returning E_FAIL if
horo 2012/08/21 13:59:57 Done.
245 NOTIMPLEMENTED(); 402 if (!text_store_acp_sink_.get())
246 return E_NOTIMPL; 403 return E_UNEXPECTED;
404 if (result == NULL)
405 return E_INVALIDARG;
406
407 if (current_lock_type_ != 0) {
408 if (lock_flags & TS_LF_SYNC) {
409 // Can't lock synchronously.
410 *result = TS_E_SYNCHRONOUS;
411 return S_OK;
412 }
413 // Queue the lock request.
414 lock_queue_.push_back(lock_flags & TS_LF_READWRITE);
415 *result = TS_S_ASYNC;
416 return S_OK;
417 }
418
419 // Lock
420 current_lock_type_ = (lock_flags & TS_LF_READWRITE);
421
422 status_.edit_flag_ = false;
423 size_t last_commited_size = status_.commited_size_;
424
425 // Grant the lock.
426 *result = text_store_acp_sink_->OnLockGranted(current_lock_type_);
427
428 // Unlock
429 current_lock_type_ = 0;
430
431 // Handles the pending lock requests.
432 if(lock_queue_.size() > 0) {
433 current_lock_type_ = lock_queue_.front();
434 lock_queue_.pop_front();
435 text_store_acp_sink_->OnLockGranted(current_lock_type_);
436 current_lock_type_ = 0;
437 }
438
439 // If the text store status is edited in OnLockGranted(), we may need to call
440 // TextInputClient::InsertText() or TextInputClient::SetCompositionText().
441 if (status_.edit_flag_) {
442 size_t new_commited_size = status_.commited_size_;
443 const string16 new_commited_string =
444 status_.string_buffer_.substr(last_commited_size,
445 new_commited_size - last_commited_size);
Seigo Nonaka 2012/08/21 12:22:41 nit: align
horo 2012/08/21 13:59:57 Done.
446 const string16 composition_string =
447 status_.string_buffer_.substr(new_commited_size);
448
449 // If there is new commited string, calls TextInputClient::InsertText().
450 if (new_commited_string.length() != 0) {
451 if (text_input_client_) {
452 text_input_client_->InsertText(new_commited_string);
453 }
454 }
455
456 // Calls TextInputClient::SetCompositionText().
457 CompositionText composition_text;
458 composition_text.text = composition_string;
459 composition_text.underlines = status_.composition_undelines_;
460 for (size_t i = 0; i < composition_text.underlines.size(); ++i) {
461 composition_text.underlines[i].start_offset -= new_commited_size;
462 composition_text.underlines[i].end_offset -= new_commited_size;
463 }
464 if (status_.selection_start_ < new_commited_size) {
465 composition_text.selection.set_start(0);
466 } else {
467 composition_text.selection.set_start(
468 status_.selection_start_ - new_commited_size);
469 }
470 if (status_.selection_end_ < new_commited_size) {
471 composition_text.selection.set_end(0);
472 } else {
473 composition_text.selection.set_end(
474 status_.selection_end_ - new_commited_size);
475 }
476 if (text_input_client_) {
477 text_input_client_->SetCompositionText(composition_text);
478 }
479
480 // If there is no composition string, clear the text store status.
481 // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange().
482 if ((composition_string.length() == 0) && (new_commited_size != 0)) {
483 status_.RemoveText(0, new_commited_size);
484 status_.commited_size_ = 0;
485 status_.MoveSelection(0, 0);
486 text_store_acp_sink_->OnSelectionChange();
487 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
488 TS_TEXTCHANGE textChange;
489 textChange.acpStart = 0;
490 textChange.acpOldEnd = new_commited_size;
491 textChange.acpNewEnd = 0;
492 text_store_acp_sink_->OnTextChange(0, &textChange);
493 }
494 }
495
496 return S_OK;
247 } 497 }
248 498
249 STDMETHODIMP TsfTextStore::RequestSupportedAttrs( 499 STDMETHODIMP TsfTextStore::RequestSupportedAttrs(
250 DWORD flags, 500 DWORD flags,
251 ULONG attribute_buffer_size, 501 ULONG attribute_buffer_size,
252 const TS_ATTRID* attribute_buffer) { 502 const TS_ATTRID* attribute_buffer) {
253 NOTIMPLEMENTED(); 503 // We does not support any document attributes.
254 return E_NOTIMPL; 504 // This method just returns S_OK, and the subsequently called
505 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
506 return S_OK;
255 } 507 }
256 508
257 STDMETHODIMP TsfTextStore::RetrieveRequestedAttrs( 509 STDMETHODIMP TsfTextStore::RetrieveRequestedAttrs(
258 ULONG attribute_buffer_size, 510 ULONG attribute_buffer_size,
259 TS_ATTRVAL* attribute_buffer, 511 TS_ATTRVAL* attribute_buffer,
260 ULONG* attribute_buffer_copied) { 512 ULONG* attribute_buffer_copied) {
261 NOTIMPLEMENTED(); 513 if (attribute_buffer_copied == NULL)
262 return E_NOTIMPL; 514 return E_INVALIDARG;
515 // We does not support any document attributes.
516 attribute_buffer_copied = 0;
517 return S_OK;
263 } 518 }
264 519
265 STDMETHODIMP TsfTextStore::SetSelection( 520 STDMETHODIMP TsfTextStore::SetSelection(
266 ULONG selection_buffer_size, 521 ULONG selection_buffer_size,
267 const TS_SELECTION_ACP* selection_buffer) { 522 const TS_SELECTION_ACP* selection_buffer) {
268 NOTIMPLEMENTED(); 523 if (!WriterLocked())
269 return E_NOTIMPL; 524 return TF_E_NOLOCK;
525 if (selection_buffer_size > 0) {
526 if ((selection_buffer[0].acpStart < 0) ||
527 (static_cast<LONG>(status_.string_buffer_.length()) <
528 selection_buffer[0].acpStart) ||
529 (selection_buffer[0].acpEnd < selection_buffer[0].acpStart) ||
530 (static_cast<LONG>(status_.string_buffer_.length())
531 < selection_buffer[0].acpEnd)){
Seigo Nonaka 2012/08/21 12:22:41 Plz be consistent the operator position. BTW, this
horo 2012/08/21 13:59:57 Done.
532 return TF_E_INVALIDPOS;
533 }
534 status_.MoveSelection(selection_buffer[0].acpStart,
535 selection_buffer[0].acpEnd);
536 }
537 return S_OK;
270 } 538 }
271 539
272 STDMETHODIMP TsfTextStore::SetText(DWORD flags, 540 STDMETHODIMP TsfTextStore::SetText(DWORD flags,
273 LONG acp_start, 541 LONG acp_start,
274 LONG acp_end, 542 LONG acp_end,
275 const wchar_t* text_buffer, 543 const wchar_t* text_buffer,
276 ULONG text_buffer_size, 544 ULONG text_buffer_size,
277 TS_TEXTCHANGE* text_change) { 545 TS_TEXTCHANGE* text_change) {
278 NOTIMPLEMENTED(); 546 if (!WriterLocked())
279 return E_NOTIMPL; 547 return TS_E_NOLOCK;
548 if (acp_start < static_cast<LONG>(status_.commited_size_))
549 return TS_E_INVALIDPOS;
550 if (static_cast<LONG>(status_.string_buffer_.length()) < acp_start)
551 return TS_E_INVALIDPOS;
552 if (acp_end < acp_start)
553 return E_INVALIDARG;
554 if (static_cast<LONG>(status_.string_buffer_.length()) < acp_end)
555 return TS_E_INVALIDPOS;
556
557 TS_SELECTION_ACP selection;
558 selection.acpStart = acp_start;
559 selection.acpEnd = acp_end;
560 selection.style.ase = TS_AE_NONE;
561 selection.style.fInterimChar = 0;
562 if (SetSelection(1, &selection) != S_OK) {
Seigo Nonaka 2012/08/21 12:22:41 nit: remove braces.
horo 2012/08/21 13:59:57 Done.
563 return E_UNEXPECTED;
564 }
565 TS_TEXTCHANGE change;
566 if (InsertTextAtSelection(0, text_buffer, text_buffer_size,
567 &acp_start, &acp_end, &change) != S_OK) {
568 return E_UNEXPECTED;
569 }
570 if (text_change)
571 *text_change = change;
572
573 return S_OK;
280 } 574 }
281 575
282 STDMETHODIMP TsfTextStore::UnadviseSink(IUnknown* unknown) { 576 STDMETHODIMP TsfTextStore::UnadviseSink(IUnknown* unknown) {
283 if (!text_store_acp_sink_.IsSameObject(unknown)) 577 if (!text_store_acp_sink_.IsSameObject(unknown))
284 return CONNECT_E_NOCONNECTION; 578 return CONNECT_E_NOCONNECTION;
285 text_store_acp_sink_.Release(); 579 text_store_acp_sink_.Release();
286 text_store_acp_sink_mask_ = 0; 580 text_store_acp_sink_mask_ = 0;
287 return S_OK; 581 return S_OK;
288 } 582 }
289 583
290 STDMETHODIMP TsfTextStore::OnStartComposition( 584 STDMETHODIMP TsfTextStore::OnStartComposition(
291 ITfCompositionView* composition_view, 585 ITfCompositionView* composition_view,
292 BOOL* ok) { 586 BOOL* ok) {
293 if (!ok) 587 if (ok)
294 *ok = TRUE; 588 *ok = TRUE;
295 return S_OK; 589 return S_OK;
296 } 590 }
297 591
298 STDMETHODIMP TsfTextStore::OnUpdateComposition( 592 STDMETHODIMP TsfTextStore::OnUpdateComposition(
299 ITfCompositionView* composition_view, 593 ITfCompositionView* composition_view,
300 ITfRange* range) { 594 ITfRange* range) {
301 return S_OK; 595 return S_OK;
302 } 596 }
303 597
304 STDMETHODIMP TsfTextStore::OnEndComposition( 598 STDMETHODIMP TsfTextStore::OnEndComposition(
305 ITfCompositionView* composition_view) { 599 ITfCompositionView* composition_view) {
306 return S_OK; 600 return S_OK;
307 } 601 }
308 602
309 STDMETHODIMP TsfTextStore::OnEndEdit(ITfContext* context, 603 STDMETHODIMP TsfTextStore::OnEndEdit(ITfContext* context,
310 TfEditCookie read_only_edit_cookie, 604 TfEditCookie read_only_edit_cookie,
311 ITfEditRecord* edit_record) { 605 ITfEditRecord* edit_record) {
606 if (!context || !edit_record)
607 return E_INVALIDARG;
608
609 size_t commited_size;
610 CompositionUnderlines undelines;
611 if (!GetCompositionStatus(context, read_only_edit_cookie, &commited_size,
612 &undelines)) {
613 return S_OK;
614 }
615 status_.composition_undelines_ = undelines;
616 status_.commited_size_ = commited_size;
617 status_.edit_flag_ = true;
312 return S_OK; 618 return S_OK;
313 } 619 }
314 620
315 } // namespace ui 621 bool TsfTextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
622 TF_DISPLAYATTRIBUTE* attribute) {
623 GUID guid;
624 if (FAILED(category_mgr_->GetGUID(guid_atom, &guid))) {
Seigo Nonaka 2012/08/21 12:22:41 nit: remove braces.
horo 2012/08/21 13:59:57 Done.
625 return false;
626 }
627 base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info;
628 if (FAILED(display_attribute_mgr_->GetDisplayAttributeInfo(
629 guid, display_attribute_info.Receive(), NULL))) {
Seigo Nonaka 2012/08/21 12:22:41 nit:align
horo 2012/08/21 13:59:57 Done.
630 return false;
631 }
632 return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
633 }
634
635 bool TsfTextStore::GetCompositionStatus(
636 ITfContext* context, const TfEditCookie read_only_edit_cookie,
Seigo Nonaka 2012/08/21 12:22:41 nit: one line one variable.
horo 2012/08/21 13:59:57 Done.
637 size_t* committed_size, CompositionUnderlines* undelines) {
638 DCHECK(context);
639 DCHECK(committed_size);
640 DCHECK(undelines);
641 const GUID *rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
Seigo Nonaka 2012/08/21 12:22:41 nit: /GUID */GUID* /
horo 2012/08/21 13:59:57 Done.
642 base::win::ScopedComPtr<ITfReadOnlyProperty> track_property;
643 if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0,
644 track_property.Receive()))) {
645 return false;
646 }
647
648 *committed_size = 0;
649 undelines->clear();
650 base::win::ScopedComPtr<ITfRange> start_to_end_range;
651 base::win::ScopedComPtr<ITfRange> end_range;
652 context->GetStart(read_only_edit_cookie, start_to_end_range.Receive());
Seigo Nonaka 2012/08/21 12:22:41 Plz check the returned value, and plz do elsewhere
horo 2012/08/21 13:59:57 Done.
653 context->GetEnd(read_only_edit_cookie, end_range.Receive());
654 start_to_end_range->ShiftEndToRange(read_only_edit_cookie, end_range,
655 TF_ANCHOR_END);
656
657 base::win::ScopedComPtr<IEnumTfRanges> ranges;
658 track_property->EnumRanges(read_only_edit_cookie, ranges.Receive(),
659 start_to_end_range);
660
661 base::win::ScopedComPtr<ITfRange> range;
662 while (ranges->Next(1, range.Receive(), NULL) == S_OK) {
663 base::win::ScopedVariant value;
664 base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value;
665 track_property->GetValue(read_only_edit_cookie, range, value.Receive());
666 enum_prop_value.QueryFrom(value.AsInput()->punkVal);
667
668 TF_PROPERTYVAL property_value;
669 bool is_composition = false;
670 bool has_display_attribute = false;
671 TF_DISPLAYATTRIBUTE display_attribute;
672 while (enum_prop_value->Next(1, &property_value, NULL) == S_OK) {
673 if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) {
674 is_composition = (property_value.varValue.lVal == TRUE);
675 } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) {
676 TfGuidAtom guid_atom = (TfGuidAtom) property_value.varValue.lVal;
Seigo Nonaka 2012/08/21 12:22:41 nit: static_cast?
horo 2012/08/21 13:59:57 Done.
677 if (GetDisplayAttribute(guid_atom, &display_attribute)) {
Seigo Nonaka 2012/08/21 12:22:41 nit: remove braces. and plz do elsewhere
horo 2012/08/21 13:59:57 Done.
678 has_display_attribute = true;
679 }
680 }
681 VariantClear(&property_value.varValue);
682 }
683
684 base::win::ScopedComPtr<ITfRangeACP> range_acp;
685 range_acp.QueryFrom(range);
686 LONG start_pos, length;
687 range_acp->GetExtent(&start_pos, &length);
688 if (!is_composition) {
689 if (*committed_size < static_cast<size_t>(start_pos + length)) {
690 *committed_size = start_pos + length;
691 }
692 } else {
693 CompositionUnderline underline;
694 underline.start_offset = start_pos;
695 underline.end_offset = start_pos + length;
696 underline.color = SK_ColorBLACK;
697 if (has_display_attribute) {
698 underline.thick = !!display_attribute.fBoldLine;
699 }
700 undelines->push_back(underline);
701 }
702 range.Release();
703 }
704 return true;
705 }
706
707 void TsfTextStore::SetFocusedTextInputClient(
708 HWND focused_window, TextInputClient* text_input_client) {
Seigo Nonaka 2012/08/21 12:22:41 nit: one line one variable
horo 2012/08/21 13:59:57 Done.
709 hwnd_ = focused_window;
710 text_input_client_ = text_input_client;
711 }
712
713 void TsfTextStore::RemoveFocusedTextInputClient(
714 TextInputClient* text_input_client) {
715 if (text_input_client_ == text_input_client) {
716 hwnd_ = 0;
717 text_input_client_ = NULL;
718 }
719 }
720
721 bool TsfTextStore::ReaderLocked() const {
722 return (current_lock_type_ & TS_LF_READ) == TS_LF_READ;
723 }
724
725 bool TsfTextStore::WriterLocked() const {
726 return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE;
727 }
728 } // namespace ui
OLDNEW
« 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