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

Side by Side Diff: win8/metro_driver/ime/text_store.cc

Issue 83233002: Enable basic IME functionality under Ash on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix warnings (that are treated as an error) on 64-bit build Created 7 years 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
« no previous file with comments | « win8/metro_driver/ime/text_store.h ('k') | win8/metro_driver/ime/text_store_delegate.h » ('j') | 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) 2013 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 #define INITGUID // required for GUID_PROP_INPUTSCOPE 5 #define INITGUID // required for GUID_PROP_INPUTSCOPE
6 #include "ui/base/ime/win/tsf_text_store.h" 6 #include "win8/metro_driver/ime/text_store.h"
7 7
8 #include <InputScope.h> 8 #include <InputScope.h>
9 #include <OleCtl.h> 9 #include <OleCtl.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 12
13 #include "base/win/scoped_variant.h" 13 #include "base/win/scoped_variant.h"
14 #include "ui/base/ime/text_input_client.h" 14 #include "win8/metro_driver/ime/input_scope.h"
15 #include "ui/base/ime/win/tsf_input_scope.h" 15 #include "win8/metro_driver/ime/text_store_delegate.h"
16 #include "ui/gfx/rect.h"
17 16
18 namespace ui { 17 namespace metro_driver {
19 namespace { 18 namespace {
20 19
21 // We support only one view. 20 // We support only one view.
22 const TsViewCookie kViewCookie = 1; 21 const TsViewCookie kViewCookie = 1;
23 22
24 } // namespace 23 } // namespace
25 24
26 TSFTextStore::TSFTextStore() 25 TSFTextStore::TSFTextStore(HWND window_handle,
26 ITfCategoryMgr* category_manager,
27 ITfDisplayAttributeMgr* display_attribute_manager,
28 ITfInputScope* input_scope,
29 TextStoreDelegate* delegate)
27 : ref_count_(0), 30 : ref_count_(0),
28 text_store_acp_sink_mask_(0), 31 text_store_acp_sink_mask_(0),
29 window_handle_(NULL), 32 window_handle_(window_handle),
30 text_input_client_(NULL), 33 delegate_(delegate),
31 committed_size_(0), 34 committed_size_(0),
35 selection_start_(0),
36 selection_end_(0),
32 edit_flag_(false), 37 edit_flag_(false),
33 current_lock_type_(0) { 38 current_lock_type_(0),
34 if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) { 39 category_manager_(category_manager),
35 LOG(FATAL) << "Failed to initialize CategoryMgr."; 40 display_attribute_manager_(display_attribute_manager),
36 return; 41 input_scope_(input_scope) {
42 }
43
44 // static
45 scoped_refptr<TSFTextStore> TSFTextStore::Create(
46 HWND window_handle,
47 const std::vector<InputScope>& input_scopes,
48 TextStoreDelegate* delegate) {
49 if (!delegate) {
50 LOG(ERROR) << "|delegate| must be non-NULL.";
51 return scoped_refptr<TSFTextStore>();
37 } 52 }
38 if (FAILED(display_attribute_manager_.CreateInstance( 53 base::win::ScopedComPtr<ITfCategoryMgr> category_manager;
39 CLSID_TF_DisplayAttributeMgr))) { 54 HRESULT hr = category_manager.CreateInstance(CLSID_TF_CategoryMgr);
40 LOG(FATAL) << "Failed to initialize DisplayAttributeMgr."; 55 if (FAILED(hr)) {
41 return; 56 LOG(ERROR) << "Failed to initialize CategoryMgr. hr = " << hr;
57 return scoped_refptr<TSFTextStore>();
42 } 58 }
59 base::win::ScopedComPtr<ITfDisplayAttributeMgr> display_attribute_manager;
60 hr = display_attribute_manager.CreateInstance(CLSID_TF_DisplayAttributeMgr);
61 if (FAILED(hr)) {
62 LOG(ERROR) << "Failed to initialize DisplayAttributeMgr. hr = " << hr;
63 return scoped_refptr<TSFTextStore>();
64 }
65 base::win::ScopedComPtr<ITfInputScope> input_scope =
66 CreteInputScope(input_scopes);
67 if (!input_scope) {
68 LOG(ERROR) << "Failed to initialize InputScope.";
69 return scoped_refptr<TSFTextStore>();
70 }
71 return scoped_refptr<TSFTextStore>(
72 new TSFTextStore(window_handle,
73 category_manager,
74 display_attribute_manager,
75 input_scope,
76 delegate));
43 } 77 }
44 78
45 TSFTextStore::~TSFTextStore() { 79 TSFTextStore::~TSFTextStore() {
46 } 80 }
47 81
48 ULONG STDMETHODCALLTYPE TSFTextStore::AddRef() { 82 ULONG STDMETHODCALLTYPE TSFTextStore::AddRef() {
49 return InterlockedIncrement(&ref_count_); 83 return InterlockedIncrement(&ref_count_);
50 } 84 }
51 85
52 ULONG STDMETHODCALLTYPE TSFTextStore::Release() { 86 ULONG STDMETHODCALLTYPE TSFTextStore::Release() {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 return E_INVALIDARG; 174 return E_INVALIDARG;
141 *unknown = NULL; 175 *unknown = NULL;
142 return E_NOTIMPL; 176 return E_NOTIMPL;
143 } 177 }
144 178
145 STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) { 179 STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) {
146 if (!acp) 180 if (!acp)
147 return E_INVALIDARG; 181 return E_INVALIDARG;
148 if (!HasReadLock()) 182 if (!HasReadLock())
149 return TS_E_NOLOCK; 183 return TS_E_NOLOCK;
150 *acp = string_buffer_.size(); 184 *acp = static_cast<LONG>(string_buffer_.size());
151 return S_OK; 185 return S_OK;
152 } 186 }
153 187
154 STDMETHODIMP TSFTextStore::GetFormattedText(LONG acp_start, LONG acp_end, 188 STDMETHODIMP TSFTextStore::GetFormattedText(LONG acp_start, LONG acp_end,
155 IDataObject** data_object) { 189 IDataObject** data_object) {
156 NOTIMPLEMENTED(); 190 NOTIMPLEMENTED();
157 return E_NOTIMPL; 191 return E_NOTIMPL;
158 } 192 }
159 193
160 STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) { 194 STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) {
161 if (view_cookie != kViewCookie) 195 if (view_cookie != kViewCookie)
162 return E_INVALIDARG; 196 return E_INVALIDARG;
163 if (!rect) 197 if (!rect)
164 return E_INVALIDARG; 198 return E_INVALIDARG;
165 199
166 // {0, 0, 0, 0} means that the document rect is not currently displayed. 200 // {0, 0, 0, 0} means that the document rect is not currently displayed.
167 SetRect(rect, 0, 0, 0, 0); 201 SetRect(rect, 0, 0, 0, 0);
168 202
169 if (!IsWindow(window_handle_))
170 return E_FAIL;
171
172 // Currently ui::TextInputClient does not expose the document rect. So use
173 // the Win32 client rectangle instead.
174 // TODO(yukawa): Upgrade TextInputClient so that the client can retrieve the
175 // document rectangle.
176 RECT client_rect = {}; 203 RECT client_rect = {};
177 if (!GetClientRect(window_handle_, &client_rect)) 204 if (!GetClientRect(window_handle_, &client_rect))
178 return E_FAIL; 205 return E_FAIL;
179 POINT left_top = {client_rect.left, client_rect.top}; 206 POINT left_top = {client_rect.left, client_rect.top};
180 POINT right_bottom = {client_rect.right, client_rect.bottom}; 207 POINT right_bottom = {client_rect.right, client_rect.bottom};
181 if (!ClientToScreen(window_handle_, &left_top)) 208 if (!ClientToScreen(window_handle_, &left_top))
182 return E_FAIL; 209 return E_FAIL;
183 if (!ClientToScreen(window_handle_, &right_bottom)) 210 if (!ClientToScreen(window_handle_, &right_bottom))
184 return E_FAIL; 211 return E_FAIL;
185 212
(...skipping 10 matching lines...) Expand all
196 ULONG* fetched_count) { 223 ULONG* fetched_count) {
197 if (!selection_buffer) 224 if (!selection_buffer)
198 return E_INVALIDARG; 225 return E_INVALIDARG;
199 if (!fetched_count) 226 if (!fetched_count)
200 return E_INVALIDARG; 227 return E_INVALIDARG;
201 if (!HasReadLock()) 228 if (!HasReadLock())
202 return TS_E_NOLOCK; 229 return TS_E_NOLOCK;
203 *fetched_count = 0; 230 *fetched_count = 0;
204 if ((selection_buffer_size > 0) && 231 if ((selection_buffer_size > 0) &&
205 ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) { 232 ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) {
206 selection_buffer[0].acpStart = selection_.start(); 233 selection_buffer[0].acpStart = selection_start_;
207 selection_buffer[0].acpEnd = selection_.end(); 234 selection_buffer[0].acpEnd = selection_end_;
208 selection_buffer[0].style.ase = TS_AE_END; 235 selection_buffer[0].style.ase = TS_AE_END;
209 selection_buffer[0].style.fInterimChar = FALSE; 236 selection_buffer[0].style.fInterimChar = FALSE;
210 *fetched_count = 1; 237 *fetched_count = 1;
211 } 238 }
212 return S_OK; 239 return S_OK;
213 } 240 }
214 241
215 STDMETHODIMP TSFTextStore::GetStatus(TS_STATUS* status) { 242 STDMETHODIMP TSFTextStore::GetStatus(TS_STATUS* status) {
216 if (!status) 243 if (!status)
217 return E_INVALIDARG; 244 return E_INVALIDARG;
(...skipping 17 matching lines...) Expand all
235 if (!text_buffer_copied || !run_info_buffer_copied) 262 if (!text_buffer_copied || !run_info_buffer_copied)
236 return E_INVALIDARG; 263 return E_INVALIDARG;
237 if (!text_buffer && text_buffer_size != 0) 264 if (!text_buffer && text_buffer_size != 0)
238 return E_INVALIDARG; 265 return E_INVALIDARG;
239 if (!run_info_buffer && run_info_buffer_size != 0) 266 if (!run_info_buffer && run_info_buffer_size != 0)
240 return E_INVALIDARG; 267 return E_INVALIDARG;
241 if (!next_acp) 268 if (!next_acp)
242 return E_INVALIDARG; 269 return E_INVALIDARG;
243 if (!HasReadLock()) 270 if (!HasReadLock())
244 return TF_E_NOLOCK; 271 return TF_E_NOLOCK;
245 const LONG string_buffer_size = string_buffer_.size(); 272 const LONG string_buffer_size = static_cast<LONG>(string_buffer_.size());
246 if (acp_end == -1) 273 if (acp_end == -1)
247 acp_end = string_buffer_size; 274 acp_end = string_buffer_size;
248 if (!((0 <= acp_start) && 275 if (!((0 <= acp_start) &&
249 (acp_start <= acp_end) && 276 (acp_start <= acp_end) &&
250 (acp_end <= string_buffer_size))) { 277 (acp_end <= string_buffer_size))) {
251 return TF_E_INVALIDPOS; 278 return TF_E_INVALIDPOS;
252 } 279 }
253 acp_end = std::min(acp_end, acp_start + static_cast<LONG>(text_buffer_size)); 280 acp_end = std::min(acp_end, acp_start + static_cast<LONG>(text_buffer_size));
254 *text_buffer_copied = acp_end - acp_start; 281 *text_buffer_copied = acp_end - acp_start;
255 282
(...skipping 13 matching lines...) Expand all
269 return S_OK; 296 return S_OK;
270 } 297 }
271 298
272 STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, 299 STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie,
273 LONG acp_start, 300 LONG acp_start,
274 LONG acp_end, 301 LONG acp_end,
275 RECT* rect, 302 RECT* rect,
276 BOOL* clipped) { 303 BOOL* clipped) {
277 if (!rect || !clipped) 304 if (!rect || !clipped)
278 return E_INVALIDARG; 305 return E_INVALIDARG;
279 if (!text_input_client_)
280 return E_UNEXPECTED;
281 if (view_cookie != kViewCookie) 306 if (view_cookie != kViewCookie)
282 return E_INVALIDARG; 307 return E_INVALIDARG;
283 if (!HasReadLock()) 308 if (!HasReadLock())
284 return TS_E_NOLOCK; 309 return TS_E_NOLOCK;
285 if (!((static_cast<LONG>(committed_size_) <= acp_start) && 310 if (!((static_cast<LONG>(committed_size_) <= acp_start) &&
286 (acp_start <= acp_end) && 311 (acp_start <= acp_end) &&
287 (acp_end <= static_cast<LONG>(string_buffer_.size())))) { 312 (acp_end <= static_cast<LONG>(string_buffer_.size())))) {
288 return TS_E_INVALIDPOS; 313 return TS_E_INVALIDPOS;
289 } 314 }
290 315
291 // According to a behavior of notepad.exe and wordpad.exe, top left corner of 316 // According to a behavior of notepad.exe and wordpad.exe, top left corner of
292 // rect indicates a first character's one, and bottom right corner of rect 317 // rect indicates a first character's one, and bottom right corner of rect
293 // indicates a last character's one. 318 // indicates a last character's one.
294 // We use RECT instead of gfx::Rect since left position may be bigger than 319 // We use RECT instead of gfx::Rect since left position may be bigger than
295 // right position when composition has multiple lines. 320 // right position when composition has multiple lines.
296 RECT result; 321 RECT result;
297 gfx::Rect tmp_rect; 322 RECT tmp_rect;
298 const uint32 start_pos = acp_start - committed_size_; 323 const uint32 start_pos = acp_start - committed_size_;
299 const uint32 end_pos = acp_end - committed_size_; 324 const uint32 end_pos = acp_end - committed_size_;
300 325
301 if (start_pos == end_pos) { 326 if (start_pos == end_pos) {
302 // According to MSDN document, if |acp_start| and |acp_end| are equal it is 327 // According to MSDN document, if |acp_start| and |acp_end| are equal it is
303 // OK to just return E_INVALIDARG. 328 // OK to just return E_INVALIDARG.
304 // http://msdn.microsoft.com/en-us/library/ms538435 329 // http://msdn.microsoft.com/en-us/library/ms538435
305 // But when using Pinin IME of Windows 8, this method is called with the 330 // But when using Pinin IME of Windows 8, this method is called with the
306 // equal values of |acp_start| and |acp_end|. So we handle this condition. 331 // equal values of |acp_start| and |acp_end|. So we handle this condition.
307 if (start_pos == 0) { 332 if (start_pos == 0) {
308 if (text_input_client_->GetCompositionCharacterBounds(0, &tmp_rect)) { 333 if (delegate_->GetCompositionCharacterBounds(0, &tmp_rect)) {
309 tmp_rect.set_width(0); 334 tmp_rect.right = tmp_rect.right;
310 result = tmp_rect.ToRECT(); 335 result = tmp_rect;
311 } else if (string_buffer_.size() == committed_size_) { 336 } else if (string_buffer_.size() == committed_size_) {
312 result = text_input_client_->GetCaretBounds().ToRECT(); 337 result = delegate_->GetCaretBounds();
313 } else { 338 } else {
314 return TS_E_NOLAYOUT; 339 return TS_E_NOLAYOUT;
315 } 340 }
316 } else if (text_input_client_->GetCompositionCharacterBounds(start_pos - 1, 341 } else if (delegate_->GetCompositionCharacterBounds(start_pos - 1,
317 &tmp_rect)) { 342 &tmp_rect)) {
318 result.left = tmp_rect.right(); 343 tmp_rect.left = tmp_rect.right;
319 result.right = tmp_rect.right(); 344 result = tmp_rect;
320 result.top = tmp_rect.y();
321 result.bottom = tmp_rect.bottom();
322 } else { 345 } else {
323 return TS_E_NOLAYOUT; 346 return TS_E_NOLAYOUT;
324 } 347 }
325 } else { 348 } else {
326 if (text_input_client_->GetCompositionCharacterBounds(start_pos, 349 if (delegate_->GetCompositionCharacterBounds(start_pos, &tmp_rect)) {
327 &tmp_rect)) { 350 result = tmp_rect;
328 result.left = tmp_rect.x(); 351 if (delegate_->GetCompositionCharacterBounds(end_pos - 1, &tmp_rect)) {
329 result.top = tmp_rect.y(); 352 result.right = tmp_rect.right;
330 result.right = tmp_rect.right(); 353 result.bottom = tmp_rect.bottom;
331 result.bottom = tmp_rect.bottom();
332 if (text_input_client_->GetCompositionCharacterBounds(end_pos - 1,
333 &tmp_rect)) {
334 result.right = tmp_rect.right();
335 result.bottom = tmp_rect.bottom();
336 } else { 354 } else {
337 // We may not be able to get the last character bounds, so we use the 355 // We may not be able to get the last character bounds, so we use the
338 // first character bounds instead of returning TS_E_NOLAYOUT. 356 // first character bounds instead of returning TS_E_NOLAYOUT.
339 } 357 }
340 } else { 358 } else {
341 // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so 359 // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so
342 // it's better to return previous caret rectangle instead. 360 // it's better to return previous caret rectangle instead.
343 // TODO(nona, kinaba): Remove this hack. 361 // TODO(nona, kinaba): Remove this hack.
344 if (start_pos == 0) { 362 if (start_pos == 0) {
345 result = text_input_client_->GetCaretBounds().ToRECT(); 363 result = delegate_->GetCaretBounds();
346 } else { 364 } else {
347 return TS_E_NOLAYOUT; 365 return TS_E_NOLAYOUT;
348 } 366 }
349 } 367 }
350 } 368 }
351 369
352 *rect = result; 370 *rect = result;
353 *clipped = FALSE; 371 *clipped = FALSE;
354 return S_OK; 372 return S_OK;
355 } 373 }
(...skipping 27 matching lines...) Expand all
383 NOTIMPLEMENTED(); 401 NOTIMPLEMENTED();
384 return E_NOTIMPL; 402 return E_NOTIMPL;
385 } 403 }
386 404
387 STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags, 405 STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags,
388 const wchar_t* text_buffer, 406 const wchar_t* text_buffer,
389 ULONG text_buffer_size, 407 ULONG text_buffer_size,
390 LONG* acp_start, 408 LONG* acp_start,
391 LONG* acp_end, 409 LONG* acp_end,
392 TS_TEXTCHANGE* text_change) { 410 TS_TEXTCHANGE* text_change) {
393 const LONG start_pos = selection_.start(); 411 const LONG start_pos = selection_start_;
394 const LONG end_pos = selection_.end(); 412 const LONG end_pos = selection_end_;
395 const LONG new_end_pos = start_pos + text_buffer_size; 413 const LONG new_end_pos = start_pos + text_buffer_size;
396 414
397 if (flags & TS_IAS_QUERYONLY) { 415 if (flags & TS_IAS_QUERYONLY) {
398 if (!HasReadLock()) 416 if (!HasReadLock())
399 return TS_E_NOLOCK; 417 return TS_E_NOLOCK;
400 if (acp_start) 418 if (acp_start)
401 *acp_start = start_pos; 419 *acp_start = start_pos;
402 if (acp_end) { 420 if (acp_end) {
403 *acp_end = end_pos; 421 *acp_end = end_pos;
404 } 422 }
(...skipping 11 matching lines...) Expand all
416 string_buffer_.substr(end_pos); 434 string_buffer_.substr(end_pos);
417 if (acp_start) 435 if (acp_start)
418 *acp_start = start_pos; 436 *acp_start = start_pos;
419 if (acp_end) 437 if (acp_end)
420 *acp_end = new_end_pos; 438 *acp_end = new_end_pos;
421 if (text_change) { 439 if (text_change) {
422 text_change->acpStart = start_pos; 440 text_change->acpStart = start_pos;
423 text_change->acpOldEnd = end_pos; 441 text_change->acpOldEnd = end_pos;
424 text_change->acpNewEnd = new_end_pos; 442 text_change->acpNewEnd = new_end_pos;
425 } 443 }
426 selection_.set_start(start_pos); 444 selection_start_ = start_pos;
427 selection_.set_end(new_end_pos); 445 selection_end_ = new_end_pos;
428 return S_OK; 446 return S_OK;
429 } 447 }
430 448
431 STDMETHODIMP TSFTextStore::QueryInsert( 449 STDMETHODIMP TSFTextStore::QueryInsert(
432 LONG acp_test_start, 450 LONG acp_test_start,
433 LONG acp_test_end, 451 LONG acp_test_end,
434 ULONG text_size, 452 ULONG text_size,
435 LONG* acp_result_start, 453 LONG* acp_result_start,
436 LONG* acp_result_end) { 454 LONG* acp_result_end) {
437 if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end) 455 if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end)
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 // Queue the lock request. 511 // Queue the lock request.
494 lock_queue_.push_back(lock_flags & TS_LF_READWRITE); 512 lock_queue_.push_back(lock_flags & TS_LF_READWRITE);
495 *result = TS_S_ASYNC; 513 *result = TS_S_ASYNC;
496 return S_OK; 514 return S_OK;
497 } 515 }
498 516
499 // Lock 517 // Lock
500 current_lock_type_ = (lock_flags & TS_LF_READWRITE); 518 current_lock_type_ = (lock_flags & TS_LF_READWRITE);
501 519
502 edit_flag_ = false; 520 edit_flag_ = false;
503 const size_t last_committed_size = committed_size_; 521 const uint32 last_committed_size = committed_size_;
504 522
505 // Grant the lock. 523 // Grant the lock.
506 *result = text_store_acp_sink_->OnLockGranted(current_lock_type_); 524 *result = text_store_acp_sink_->OnLockGranted(current_lock_type_);
507 525
508 // Unlock 526 // Unlock
509 current_lock_type_ = 0; 527 current_lock_type_ = 0;
510 528
511 // Handles the pending lock requests. 529 // Handles the pending lock requests.
512 while (!lock_queue_.empty()) { 530 while (!lock_queue_.empty()) {
513 current_lock_type_ = lock_queue_.front(); 531 current_lock_type_ = lock_queue_.front();
514 lock_queue_.pop_front(); 532 lock_queue_.pop_front();
515 text_store_acp_sink_->OnLockGranted(current_lock_type_); 533 text_store_acp_sink_->OnLockGranted(current_lock_type_);
516 current_lock_type_ = 0; 534 current_lock_type_ = 0;
517 } 535 }
518 536
519 if (!edit_flag_) { 537 if (!edit_flag_)
520 return S_OK; 538 return S_OK;
521 }
522 539
523 // If the text store is edited in OnLockGranted(), we may need to call 540 // If the text store is edited in OnLockGranted(), we may need to call
524 // TextInputClient::InsertText() or TextInputClient::SetCompositionText(). 541 // TextStoreDelegate::ConfirmComposition() or
525 const size_t new_committed_size = committed_size_; 542 // TextStoreDelegate::SetComposition().
543 const uint32 new_committed_size = committed_size_;
526 const string16& new_committed_string = 544 const string16& new_committed_string =
527 string_buffer_.substr(last_committed_size, 545 string_buffer_.substr(last_committed_size,
528 new_committed_size - last_committed_size); 546 new_committed_size - last_committed_size);
529 const string16& composition_string = 547 const string16& composition_string =
530 string_buffer_.substr(new_committed_size); 548 string_buffer_.substr(new_committed_size);
531 549
532 // If there is new committed string, calls TextInputClient::InsertText(). 550 // If there is new committed string, calls
533 if ((!new_committed_string.empty()) && text_input_client_) { 551 // TextStoreDelegate::ConfirmComposition().
534 text_input_client_->InsertText(new_committed_string); 552 if ((!new_committed_string.empty()))
535 } 553 delegate_->OnTextCommitted(new_committed_string);
536 554
537 // Calls TextInputClient::SetCompositionText(). 555 // Calls TextInputClient::SetCompositionText().
538 CompositionText composition_text; 556 std::vector<metro_viewer::UnderlineInfo> underlines = underlines_;
539 composition_text.text = composition_string;
540 composition_text.underlines = composition_undelines_;
541 // Adjusts the offset. 557 // Adjusts the offset.
542 for (size_t i = 0; i < composition_text.underlines.size(); ++i) { 558 for (size_t i = 0; i < underlines_.size(); ++i) {
543 composition_text.underlines[i].start_offset -= new_committed_size; 559 underlines[i].start_offset -= new_committed_size;
544 composition_text.underlines[i].end_offset -= new_committed_size; 560 underlines[i].end_offset -= new_committed_size;
545 } 561 }
546 if (selection_.start() < new_committed_size) { 562 int32 selection_start = 0;
547 composition_text.selection.set_start(0); 563 int32 selection_end = 0;
548 } else { 564 if (selection_start_ >= new_committed_size)
549 composition_text.selection.set_start( 565 selection_start = selection_start_ - new_committed_size;
550 selection_.start() - new_committed_size); 566 if (selection_end_ >= new_committed_size)
551 } 567 selection_end = selection_end_ - new_committed_size;
552 if (selection_.end() < new_committed_size) { 568 delegate_->OnCompositionChanged(
553 composition_text.selection.set_end(0); 569 composition_string, selection_start, selection_end, underlines);
554 } else {
555 composition_text.selection.set_end(selection_.end() - new_committed_size);
556 }
557 if (text_input_client_)
558 text_input_client_->SetCompositionText(composition_text);
559 570
560 // If there is no composition string, clear the text store status. 571 // If there is no composition string, clear the text store status.
561 // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange(). 572 // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange().
562 if ((composition_string.empty()) && (new_committed_size != 0)) { 573 if ((composition_string.empty()) && (new_committed_size != 0)) {
563 string_buffer_.clear(); 574 string_buffer_.clear();
564 committed_size_ = 0; 575 committed_size_ = 0;
565 selection_.set_start(0); 576 selection_start_ = 0;
566 selection_.set_end(0); 577 selection_end_ = 0;
567 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 578 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
568 text_store_acp_sink_->OnSelectionChange(); 579 text_store_acp_sink_->OnSelectionChange();
569 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 580 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
570 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 581 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
571 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 582 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
572 TS_TEXTCHANGE textChange; 583 TS_TEXTCHANGE textChange;
573 textChange.acpStart = 0; 584 textChange.acpStart = 0;
574 textChange.acpOldEnd = new_committed_size; 585 textChange.acpOldEnd = new_committed_size;
575 textChange.acpNewEnd = 0; 586 textChange.acpNewEnd = 0;
576 text_store_acp_sink_->OnTextChange(0, &textChange); 587 text_store_acp_sink_->OnTextChange(0, &textChange);
577 } 588 }
578 } 589 }
579 590
580 return S_OK; 591 return S_OK;
581 } 592 }
582 593
583 STDMETHODIMP TSFTextStore::RequestSupportedAttrs( 594 STDMETHODIMP TSFTextStore::RequestSupportedAttrs(
584 DWORD /* flags */, // Seems that we should ignore this. 595 DWORD /* flags */, // Seems that we should ignore this.
585 ULONG attribute_buffer_size, 596 ULONG attribute_buffer_size,
586 const TS_ATTRID* attribute_buffer) { 597 const TS_ATTRID* attribute_buffer) {
587 if (!attribute_buffer) 598 if (!attribute_buffer)
588 return E_INVALIDARG; 599 return E_INVALIDARG;
589 if (!text_input_client_) 600 if (!input_scope_)
590 return E_FAIL; 601 return E_FAIL;
591 // We support only input scope attribute. 602 // We support only input scope attribute.
592 for (size_t i = 0; i < attribute_buffer_size; ++i) { 603 for (size_t i = 0; i < attribute_buffer_size; ++i) {
593 if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i])) 604 if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i]))
594 return S_OK; 605 return S_OK;
595 } 606 }
596 return E_FAIL; 607 return E_FAIL;
597 } 608 }
598 609
599 STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs( 610 STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs(
600 ULONG attribute_buffer_size, 611 ULONG attribute_buffer_size,
601 TS_ATTRVAL* attribute_buffer, 612 TS_ATTRVAL* attribute_buffer,
602 ULONG* attribute_buffer_copied) { 613 ULONG* attribute_buffer_copied) {
603 if (!attribute_buffer_copied) 614 if (!attribute_buffer_copied)
604 return E_INVALIDARG; 615 return E_INVALIDARG;
616 *attribute_buffer_copied = 0;
605 if (!attribute_buffer) 617 if (!attribute_buffer)
606 return E_INVALIDARG; 618 return E_INVALIDARG;
607 if (!text_input_client_) 619 if (!input_scope_)
608 return E_UNEXPECTED; 620 return E_UNEXPECTED;
609 // We support only input scope attribute. 621 // We support only input scope attribute.
610 *attribute_buffer_copied = 0; 622 *attribute_buffer_copied = 0;
611 if (attribute_buffer_size == 0) 623 if (attribute_buffer_size == 0)
612 return S_OK; 624 return S_OK;
613 625
614 attribute_buffer[0].dwOverlapId = 0; 626 attribute_buffer[0].dwOverlapId = 0;
615 attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE; 627 attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE;
616 attribute_buffer[0].varValue.vt = VT_UNKNOWN; 628 attribute_buffer[0].varValue.vt = VT_UNKNOWN;
617 attribute_buffer[0].varValue.punkVal = tsf_inputscope::CreateInputScope( 629 attribute_buffer[0].varValue.punkVal = input_scope_.get();
618 text_input_client_->GetTextInputType(),
619 text_input_client_->GetTextInputMode());
620 attribute_buffer[0].varValue.punkVal->AddRef(); 630 attribute_buffer[0].varValue.punkVal->AddRef();
621 *attribute_buffer_copied = 1; 631 *attribute_buffer_copied = 1;
622 return S_OK; 632 return S_OK;
623 } 633 }
624 634
625 STDMETHODIMP TSFTextStore::SetSelection( 635 STDMETHODIMP TSFTextStore::SetSelection(
626 ULONG selection_buffer_size, 636 ULONG selection_buffer_size,
627 const TS_SELECTION_ACP* selection_buffer) { 637 const TS_SELECTION_ACP* selection_buffer) {
628 if (!HasReadWriteLock()) 638 if (!HasReadWriteLock())
629 return TF_E_NOLOCK; 639 return TF_E_NOLOCK;
630 if (selection_buffer_size > 0) { 640 if (selection_buffer_size > 0) {
631 const LONG start_pos = selection_buffer[0].acpStart; 641 const LONG start_pos = selection_buffer[0].acpStart;
632 const LONG end_pos = selection_buffer[0].acpEnd; 642 const LONG end_pos = selection_buffer[0].acpEnd;
633 if (!((static_cast<LONG>(committed_size_) <= start_pos) && 643 if (!((static_cast<LONG>(committed_size_) <= start_pos) &&
634 (start_pos <= end_pos) && 644 (start_pos <= end_pos) &&
635 (end_pos <= static_cast<LONG>(string_buffer_.size())))) { 645 (end_pos <= static_cast<LONG>(string_buffer_.size())))) {
636 return TF_E_INVALIDPOS; 646 return TF_E_INVALIDPOS;
637 } 647 }
638 selection_.set_start(start_pos); 648 selection_start_ = start_pos;
639 selection_.set_end(end_pos); 649 selection_end_ = end_pos;
640 } 650 }
641 return S_OK; 651 return S_OK;
642 } 652 }
643 653
644 STDMETHODIMP TSFTextStore::SetText(DWORD flags, 654 STDMETHODIMP TSFTextStore::SetText(DWORD flags,
645 LONG acp_start, 655 LONG acp_start,
646 LONG acp_end, 656 LONG acp_end,
647 const wchar_t* text_buffer, 657 const wchar_t* text_buffer,
648 ULONG text_buffer_size, 658 ULONG text_buffer_size,
649 TS_TEXTCHANGE* text_change) { 659 TS_TEXTCHANGE* text_change) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 ITfRange* range) { 709 ITfRange* range) {
700 return S_OK; 710 return S_OK;
701 } 711 }
702 712
703 STDMETHODIMP TSFTextStore::OnEndComposition( 713 STDMETHODIMP TSFTextStore::OnEndComposition(
704 ITfCompositionView* composition_view) { 714 ITfCompositionView* composition_view) {
705 return S_OK; 715 return S_OK;
706 } 716 }
707 717
708 STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, 718 STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context,
709 TfEditCookie read_only_edit_cookie, 719 TfEditCookie read_only_edit_cookie,
710 ITfEditRecord* edit_record) { 720 ITfEditRecord* edit_record) {
711 if (!context || !edit_record) 721 if (!context || !edit_record)
712 return E_INVALIDARG; 722 return E_INVALIDARG;
713 723 if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size_,
714 size_t committed_size; 724 &underlines_)) {
715 CompositionUnderlines undelines;
716 if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size,
717 &undelines)) {
718 return S_OK; 725 return S_OK;
719 } 726 }
720 composition_undelines_ = undelines;
721 committed_size_ = committed_size;
722 edit_flag_ = true; 727 edit_flag_ = true;
723 return S_OK; 728 return S_OK;
724 } 729 }
725 730
726 bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom, 731 bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
727 TF_DISPLAYATTRIBUTE* attribute) { 732 TF_DISPLAYATTRIBUTE* attribute) {
728 GUID guid; 733 GUID guid;
729 if (FAILED(category_manager_->GetGUID(guid_atom, &guid))) 734 if (FAILED(category_manager_->GetGUID(guid_atom, &guid)))
730 return false; 735 return false;
731 736
732 base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info; 737 base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info;
733 if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo( 738 if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo(
734 guid, display_attribute_info.Receive(), NULL))) { 739 guid, display_attribute_info.Receive(), NULL))) {
735 return false; 740 return false;
736 } 741 }
737 return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute)); 742 return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
738 } 743 }
739 744
740 bool TSFTextStore::GetCompositionStatus( 745 bool TSFTextStore::GetCompositionStatus(
741 ITfContext* context, 746 ITfContext* context,
742 const TfEditCookie read_only_edit_cookie, 747 const TfEditCookie read_only_edit_cookie,
743 size_t* committed_size, 748 uint32* committed_size,
744 CompositionUnderlines* undelines) { 749 std::vector<metro_viewer::UnderlineInfo>* undelines) {
745 DCHECK(context); 750 DCHECK(context);
746 DCHECK(committed_size); 751 DCHECK(committed_size);
747 DCHECK(undelines); 752 DCHECK(undelines);
748 const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE}; 753 const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
749 base::win::ScopedComPtr<ITfReadOnlyProperty> track_property; 754 base::win::ScopedComPtr<ITfReadOnlyProperty> track_property;
750 if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0, 755 if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0,
751 track_property.Receive()))) { 756 track_property.Receive()))) {
752 return false; 757 return false;
753 } 758 }
754 759
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 } 808 }
804 809
805 base::win::ScopedComPtr<ITfRangeACP> range_acp; 810 base::win::ScopedComPtr<ITfRangeACP> range_acp;
806 range_acp.QueryFrom(range); 811 range_acp.QueryFrom(range);
807 LONG start_pos, length; 812 LONG start_pos, length;
808 range_acp->GetExtent(&start_pos, &length); 813 range_acp->GetExtent(&start_pos, &length);
809 if (!is_composition) { 814 if (!is_composition) {
810 if (*committed_size < static_cast<size_t>(start_pos + length)) 815 if (*committed_size < static_cast<size_t>(start_pos + length))
811 *committed_size = start_pos + length; 816 *committed_size = start_pos + length;
812 } else { 817 } else {
813 CompositionUnderline underline; 818 metro_viewer::UnderlineInfo underline;
814 underline.start_offset = start_pos; 819 underline.start_offset = start_pos;
815 underline.end_offset = start_pos + length; 820 underline.end_offset = start_pos + length;
816 underline.color = SK_ColorBLACK; 821 underline.thick = !!display_attribute.fBoldLine;
817 if (has_display_attribute)
818 underline.thick = !!display_attribute.fBoldLine;
819 undelines->push_back(underline); 822 undelines->push_back(underline);
820 } 823 }
821 } 824 }
822 return true; 825 return true;
823 } 826 }
824 827
825 void TSFTextStore::SetFocusedTextInputClient(
826 HWND focused_window,
827 TextInputClient* text_input_client) {
828 window_handle_ = focused_window;
829 text_input_client_ = text_input_client;
830 }
831
832 void TSFTextStore::RemoveFocusedTextInputClient(
833 TextInputClient* text_input_client) {
834 if (text_input_client_ == text_input_client) {
835 window_handle_ = NULL;
836 text_input_client_ = NULL;
837 }
838 }
839
840 bool TSFTextStore::CancelComposition() { 828 bool TSFTextStore::CancelComposition() {
841 // If there is an on-going document lock, we must not edit the text. 829 // If there is an on-going document lock, we must not edit the text.
842 if (edit_flag_) 830 if (edit_flag_)
843 return false; 831 return false;
844 832
845 if (string_buffer_.empty()) 833 if (string_buffer_.empty())
846 return true; 834 return true;
847 835
848 // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does 836 // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does
849 // not have a dedicated method to cancel composition. However, CUAS actually 837 // not have a dedicated method to cancel composition. However, CUAS actually
850 // has a protocol conversion from CPS_CANCEL into TSF operations. According 838 // has a protocol conversion from CPS_CANCEL into TSF operations. According
851 // to the observations on Windows 7, TIPs are expected to cancel composition 839 // to the observations on Windows 7, TIPs are expected to cancel composition
852 // when an on-going composition text is replaced with an empty string. So 840 // when an on-going composition text is replaced with an empty string. So
853 // we use the same operation to cancel composition here to minimize the risk 841 // we use the same operation to cancel composition here to minimize the risk
854 // of potential compatibility issues. 842 // of potential compatibility issues.
855 843
856 const size_t previous_buffer_size = string_buffer_.size(); 844 const uint32 previous_buffer_size =
845 static_cast<uint32>(string_buffer_.size());
857 string_buffer_.clear(); 846 string_buffer_.clear();
858 committed_size_ = 0; 847 committed_size_ = 0;
859 selection_.set_start(0); 848 selection_start_ = 0;
860 selection_.set_end(0); 849 selection_end_ = 0;
861 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 850 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
862 text_store_acp_sink_->OnSelectionChange(); 851 text_store_acp_sink_->OnSelectionChange();
863 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 852 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
864 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 853 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
865 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 854 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
866 TS_TEXTCHANGE textChange = {}; 855 TS_TEXTCHANGE textChange = {};
867 textChange.acpStart = 0; 856 textChange.acpStart = 0;
868 textChange.acpOldEnd = previous_buffer_size; 857 textChange.acpOldEnd = previous_buffer_size;
869 textChange.acpNewEnd = 0; 858 textChange.acpNewEnd = 0;
870 text_store_acp_sink_->OnTextChange(0, &textChange); 859 text_store_acp_sink_->OnTextChange(0, &textChange);
871 } 860 }
872 return true; 861 return true;
873 } 862 }
874 863
875 bool TSFTextStore::ConfirmComposition() { 864 bool TSFTextStore::ConfirmComposition() {
876 // If there is an on-going document lock, we must not edit the text. 865 // If there is an on-going document lock, we must not edit the text.
877 if (edit_flag_) 866 if (edit_flag_)
878 return false; 867 return false;
879 868
880 if (string_buffer_.empty()) 869 if (string_buffer_.empty())
881 return true; 870 return true;
882 871
883 // See the comment in TSFTextStore::CancelComposition. 872 // See the comment in TSFTextStore::CancelComposition.
884 // This logic is based on the observation about how to emulate 873 // This logic is based on the observation about how to emulate
885 // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS. 874 // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS.
886 875
887 const string16& composition_text = string_buffer_.substr(committed_size_); 876 const string16& composition_text = string_buffer_.substr(committed_size_);
888 if (!composition_text.empty()) 877 if (!composition_text.empty())
889 text_input_client_->InsertText(composition_text); 878 delegate_->OnTextCommitted(composition_text);
890 879
891 const size_t previous_buffer_size = string_buffer_.size(); 880 const uint32 previous_buffer_size =
881 static_cast<uint32>(string_buffer_.size());
892 string_buffer_.clear(); 882 string_buffer_.clear();
893 committed_size_ = 0; 883 committed_size_ = 0;
894 selection_.set_start(0); 884 selection_start_ = 0;
895 selection_.set_end(0); 885 selection_end_ = 0;
896 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 886 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
897 text_store_acp_sink_->OnSelectionChange(); 887 text_store_acp_sink_->OnSelectionChange();
898 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 888 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
899 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 889 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
900 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 890 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
901 TS_TEXTCHANGE textChange = {}; 891 TS_TEXTCHANGE textChange = {};
902 textChange.acpStart = 0; 892 textChange.acpStart = 0;
903 textChange.acpOldEnd = previous_buffer_size; 893 textChange.acpOldEnd = previous_buffer_size;
904 textChange.acpNewEnd = 0; 894 textChange.acpNewEnd = 0;
905 text_store_acp_sink_->OnTextChange(0, &textChange); 895 text_store_acp_sink_->OnTextChange(0, &textChange);
906 } 896 }
907 return true; 897 return true;
908 } 898 }
909 899
910 void TSFTextStore::SendOnLayoutChange() { 900 void TSFTextStore::SendOnLayoutChange() {
911 if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)) 901 if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE))
912 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 902 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
913 } 903 }
914 904
915 bool TSFTextStore::HasReadLock() const { 905 bool TSFTextStore::HasReadLock() const {
916 return (current_lock_type_ & TS_LF_READ) == TS_LF_READ; 906 return (current_lock_type_ & TS_LF_READ) == TS_LF_READ;
917 } 907 }
918 908
919 bool TSFTextStore::HasReadWriteLock() const { 909 bool TSFTextStore::HasReadWriteLock() const {
920 return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE; 910 return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE;
921 } 911 }
922 912
923 } // namespace ui 913 } // namespace metro_driver
OLDNEW
« no previous file with comments | « win8/metro_driver/ime/text_store.h ('k') | win8/metro_driver/ime/text_store_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698