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

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

Powered by Google App Engine
This is Rietveld 408576698