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

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