| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |