Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 #include "win8/metro_driver/ime/text_service.h" | 5 #include "win8/metro_driver/ime/text_service.h" |
| 6 | 6 |
| 7 #include <msctf.h> | 7 #include <msctf.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/win/scoped_variant.h" | 10 #include "base/win/scoped_variant.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 } | 169 } |
| 170 | 170 |
| 171 // A class that manages the lifetime of the event callback registration. When | 171 // A class that manages the lifetime of the event callback registration. When |
| 172 // this object is destroyed, corresponding event callback will be unregistered. | 172 // this object is destroyed, corresponding event callback will be unregistered. |
| 173 class EventSink { | 173 class EventSink { |
| 174 public: | 174 public: |
| 175 EventSink(DWORD cookie, base::win::ScopedComPtr<ITfSource> source) | 175 EventSink(DWORD cookie, base::win::ScopedComPtr<ITfSource> source) |
| 176 : cookie_(cookie), | 176 : cookie_(cookie), |
| 177 source_(source) {} | 177 source_(source) {} |
| 178 ~EventSink() { | 178 ~EventSink() { |
| 179 if (!source_ || cookie_ != TF_INVALID_COOKIE) | 179 if (!source_.get() || cookie_ != TF_INVALID_COOKIE) |
| 180 return; | 180 return; |
| 181 source_->UnadviseSink(cookie_); | 181 source_->UnadviseSink(cookie_); |
| 182 cookie_ = TF_INVALID_COOKIE; | 182 cookie_ = TF_INVALID_COOKIE; |
| 183 source_.Release(); | 183 source_.Release(); |
| 184 } | 184 } |
| 185 | 185 |
| 186 private: | 186 private: |
| 187 DWORD cookie_; | 187 DWORD cookie_; |
| 188 base::win::ScopedComPtr<ITfSource> source_; | 188 base::win::ScopedComPtr<ITfSource> source_; |
| 189 DISALLOW_COPY_AND_ASSIGN(EventSink); | 189 DISALLOW_COPY_AND_ASSIGN(EventSink); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 211 // are maintained. | 211 // are maintained. |
| 212 // - TextStore: a COM object that abstracts text buffer. This object is | 212 // - TextStore: a COM object that abstracts text buffer. This object is |
| 213 // actually implemented by us in text_store.cc | 213 // actually implemented by us in text_store.cc |
| 214 // - ITfDocumentMgr: a focusable unit in TSF. This object is implemented by | 214 // - ITfDocumentMgr: a focusable unit in TSF. This object is implemented by |
| 215 // TSF runtime and works as a container of TextStore. | 215 // TSF runtime and works as a container of TextStore. |
| 216 // - EventSink: an object that ensures that the event callback between | 216 // - EventSink: an object that ensures that the event callback between |
| 217 // TSF runtime and TextStore is unregistered when this object is destroyed. | 217 // TSF runtime and TextStore is unregistered when this object is destroyed. |
| 218 class DocumentBinding { | 218 class DocumentBinding { |
| 219 public: | 219 public: |
| 220 ~DocumentBinding() { | 220 ~DocumentBinding() { |
| 221 if (!document_manager_) | 221 if (!document_manager_.get()) |
| 222 return; | 222 return; |
| 223 document_manager_->Pop(TF_POPF_ALL); | 223 document_manager_->Pop(TF_POPF_ALL); |
| 224 } | 224 } |
| 225 | 225 |
| 226 static scoped_ptr<DocumentBinding> Create( | 226 static scoped_ptr<DocumentBinding> Create( |
| 227 ITfThreadMgr* thread_manager, | 227 ITfThreadMgr* thread_manager, |
| 228 TfClientId client_id, | 228 TfClientId client_id, |
| 229 const std::vector<InputScope>& input_scopes, | 229 const std::vector<InputScope>& input_scopes, |
| 230 HWND window_handle, | 230 HWND window_handle, |
| 231 TextStoreDelegate* delegate) { | 231 TextStoreDelegate* delegate) { |
| 232 base::win::ScopedComPtr<ITfDocumentMgr> document_manager; | 232 base::win::ScopedComPtr<ITfDocumentMgr> document_manager; |
| 233 HRESULT hr = thread_manager->CreateDocumentMgr(document_manager.Receive()); | 233 HRESULT hr = thread_manager->CreateDocumentMgr(document_manager.Receive()); |
| 234 if (FAILED(hr)) { | 234 if (FAILED(hr)) { |
| 235 LOG(ERROR) << "ITfThreadMgr::CreateDocumentMgr failed. hr = " << hr; | 235 LOG(ERROR) << "ITfThreadMgr::CreateDocumentMgr failed. hr = " << hr; |
| 236 return scoped_ptr<DocumentBinding>(); | 236 return scoped_ptr<DocumentBinding>(); |
| 237 } | 237 } |
| 238 | 238 |
| 239 // Note: In our IPC protocol, an empty |input_scopes| is used to indicate | 239 // Note: In our IPC protocol, an empty |input_scopes| is used to indicate |
| 240 // that an IME must be disabled in this context. In such case, we need not | 240 // that an IME must be disabled in this context. In such case, we need not |
| 241 // instantiate TextStore. | 241 // instantiate TextStore. |
| 242 const bool use_null_text_store = input_scopes.empty(); | 242 const bool use_null_text_store = input_scopes.empty(); |
| 243 | 243 |
| 244 scoped_refptr<TextStore> text_store; | 244 scoped_refptr<TextStore> text_store; |
| 245 if (!use_null_text_store) { | 245 if (!use_null_text_store) { |
| 246 text_store = TextStore::Create(window_handle, input_scopes, delegate); | 246 text_store = TextStore::Create(window_handle, input_scopes, delegate); |
| 247 if (!text_store) { | 247 if (!text_store.get()) { |
| 248 LOG(ERROR) << "Failed to create TextStore."; | 248 LOG(ERROR) << "Failed to create TextStore."; |
| 249 return scoped_ptr<DocumentBinding>(); | 249 return scoped_ptr<DocumentBinding>(); |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 | 252 |
| 253 base::win::ScopedComPtr<ITfContext> context; | 253 base::win::ScopedComPtr<ITfContext> context; |
| 254 DWORD edit_cookie = TF_INVALID_EDIT_COOKIE; | 254 DWORD edit_cookie = TF_INVALID_EDIT_COOKIE; |
| 255 hr = document_manager->CreateContext( | 255 hr = document_manager->CreateContext( |
| 256 client_id, | 256 client_id, |
| 257 0, | 257 0, |
| 258 static_cast<ITextStoreACP*>(text_store.get()), | 258 static_cast<ITextStoreACP*>(text_store.get()), |
| 259 context.Receive(), | 259 context.Receive(), |
| 260 &edit_cookie); | 260 &edit_cookie); |
| 261 if (FAILED(hr)) { | 261 if (FAILED(hr)) { |
| 262 LOG(ERROR) << "ITfDocumentMgr::CreateContext failed. hr = " << hr; | 262 LOG(ERROR) << "ITfDocumentMgr::CreateContext failed. hr = " << hr; |
| 263 return scoped_ptr<DocumentBinding>(); | 263 return scoped_ptr<DocumentBinding>(); |
| 264 } | 264 } |
| 265 | 265 |
| 266 // If null-TextStore is used or |input_scopes| looks like a password field, | 266 // If null-TextStore is used or |input_scopes| looks like a password field, |
| 267 // set special properties to tell IMEs to be disabled. | 267 // set special properties to tell IMEs to be disabled. |
| 268 if ((use_null_text_store || IsPasswordField(input_scopes)) && | 268 if ((use_null_text_store || IsPasswordField(input_scopes)) && |
| 269 !InitializeDisabledContext(context, client_id)) { | 269 !InitializeDisabledContext(context.get(), client_id)) { |
| 270 LOG(ERROR) << "InitializeDisabledContext failed."; | 270 LOG(ERROR) << "InitializeDisabledContext failed."; |
| 271 return scoped_ptr<DocumentBinding>(); | 271 return scoped_ptr<DocumentBinding>(); |
| 272 } | 272 } |
| 273 | 273 |
| 274 scoped_ptr<EventSink> text_edit_sink; | 274 scoped_ptr<EventSink> text_edit_sink; |
| 275 if (!use_null_text_store) { | 275 if (!use_null_text_store) { |
| 276 text_edit_sink = CreateTextEditSink(context, text_store); | 276 text_edit_sink = CreateTextEditSink(context.get(), text_store.get()); |
| 277 if (!text_edit_sink) { | 277 if (!text_edit_sink) { |
| 278 LOG(ERROR) << "CreateTextEditSink failed."; | 278 LOG(ERROR) << "CreateTextEditSink failed."; |
| 279 return scoped_ptr<DocumentBinding>(); | 279 return scoped_ptr<DocumentBinding>(); |
| 280 } | 280 } |
| 281 } | 281 } |
| 282 hr = document_manager->Push(context); | 282 hr = document_manager->Push(context.get()); |
| 283 if (FAILED(hr)) { | 283 if (FAILED(hr)) { |
| 284 LOG(ERROR) << "ITfDocumentMgr::Push failed. hr = " << hr; | 284 LOG(ERROR) << "ITfDocumentMgr::Push failed. hr = " << hr; |
| 285 return scoped_ptr<DocumentBinding>(); | 285 return scoped_ptr<DocumentBinding>(); |
| 286 } | 286 } |
| 287 return scoped_ptr<DocumentBinding>( | 287 return scoped_ptr<DocumentBinding>( |
| 288 new DocumentBinding(text_store, | 288 new DocumentBinding(text_store, |
| 289 document_manager, | 289 document_manager, |
| 290 text_edit_sink.Pass())); | 290 text_edit_sink.Pass())); |
| 291 } | 291 } |
| 292 | 292 |
| 293 ITfDocumentMgr* document_manager() const { | 293 ITfDocumentMgr* document_manager() const { return document_manager_.get(); } |
| 294 return document_manager_; | |
| 295 } | |
| 296 | 294 |
| 297 scoped_refptr<TextStore> text_store() const { | 295 scoped_refptr<TextStore> text_store() const { |
| 298 return text_store_; | 296 return text_store_; |
| 299 } | 297 } |
| 300 | 298 |
| 301 private: | 299 private: |
| 302 DocumentBinding(scoped_refptr<TextStore> text_store, | 300 DocumentBinding(scoped_refptr<TextStore> text_store, |
| 303 base::win::ScopedComPtr<ITfDocumentMgr> document_manager, | 301 base::win::ScopedComPtr<ITfDocumentMgr> document_manager, |
| 304 scoped_ptr<EventSink> text_edit_sink) | 302 scoped_ptr<EventSink> text_edit_sink) |
| 305 : text_store_(text_store), | 303 : text_store_(text_store), |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 319 TextServiceImpl(ITfThreadMgr* thread_manager, | 317 TextServiceImpl(ITfThreadMgr* thread_manager, |
| 320 TfClientId client_id, | 318 TfClientId client_id, |
| 321 HWND window_handle, | 319 HWND window_handle, |
| 322 TextServiceDelegate* delegate) | 320 TextServiceDelegate* delegate) |
| 323 : client_id_(client_id), | 321 : client_id_(client_id), |
| 324 window_handle_(window_handle), | 322 window_handle_(window_handle), |
| 325 delegate_(delegate), | 323 delegate_(delegate), |
| 326 thread_manager_(thread_manager) { | 324 thread_manager_(thread_manager) { |
| 327 DCHECK_NE(TF_CLIENTID_NULL, client_id); | 325 DCHECK_NE(TF_CLIENTID_NULL, client_id); |
| 328 DCHECK(window_handle != NULL); | 326 DCHECK(window_handle != NULL); |
| 329 DCHECK(thread_manager_); | 327 DCHECK(thread_manager_.get()); |
| 330 } | 328 } |
| 331 virtual ~TextServiceImpl() { | 329 virtual ~TextServiceImpl() { |
| 332 thread_manager_->Deactivate(); | 330 thread_manager_->Deactivate(); |
| 333 } | 331 } |
| 334 | 332 |
| 335 private: | 333 private: |
| 336 // TextService overrides: | 334 // TextService overrides: |
| 337 virtual void CancelComposition() override { | 335 virtual void CancelComposition() override { |
| 338 if (!current_document_) { | 336 if (!current_document_) { |
| 339 VLOG(0) << "|current_document_| is NULL due to the previous error."; | 337 VLOG(0) << "|current_document_| is NULL due to the previous error."; |
| 340 return; | 338 return; |
| 341 } | 339 } |
| 342 TextStore* text_store = current_document_->text_store(); | 340 scoped_refptr<TextStore> text_store = current_document_->text_store(); |
| 343 if (!text_store) | 341 if (!text_store) |
|
grt (UTC plus 2)
2014/11/21 17:28:57
shouldn't this be:
if (!text_store.get())
?
dcheng
2014/11/21 17:35:20
Yeah, I didn't run the tool recursively. Usually I
| |
| 344 return; | 342 return; |
| 345 text_store->CancelComposition(); | 343 text_store->CancelComposition(); |
| 346 } | 344 } |
| 347 | 345 |
| 348 virtual void OnDocumentChanged( | 346 virtual void OnDocumentChanged( |
| 349 const std::vector<int32>& input_scopes, | 347 const std::vector<int32>& input_scopes, |
| 350 const std::vector<metro_viewer::CharacterBounds>& character_bounds) | 348 const std::vector<metro_viewer::CharacterBounds>& character_bounds) |
| 351 override { | 349 override { |
| 352 bool document_type_changed = input_scopes_ != input_scopes; | 350 bool document_type_changed = input_scopes_ != input_scopes; |
| 353 input_scopes_ = input_scopes; | 351 input_scopes_ = input_scopes; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 LOG(ERROR) << "Failed to create instance of CLSID_TF_ThreadMgr. hr = " | 470 LOG(ERROR) << "Failed to create instance of CLSID_TF_ThreadMgr. hr = " |
| 473 << hr; | 471 << hr; |
| 474 return scoped_ptr<TextService>(); | 472 return scoped_ptr<TextService>(); |
| 475 } | 473 } |
| 476 TfClientId client_id = TF_CLIENTID_NULL; | 474 TfClientId client_id = TF_CLIENTID_NULL; |
| 477 hr = thread_manager->Activate(&client_id); | 475 hr = thread_manager->Activate(&client_id); |
| 478 if (FAILED(hr)) { | 476 if (FAILED(hr)) { |
| 479 LOG(ERROR) << "ITfThreadMgr::Activate failed. hr = " << hr; | 477 LOG(ERROR) << "ITfThreadMgr::Activate failed. hr = " << hr; |
| 480 return scoped_ptr<TextService>(); | 478 return scoped_ptr<TextService>(); |
| 481 } | 479 } |
| 482 if (!InitializeSentenceMode(thread_manager, client_id)) { | 480 if (!InitializeSentenceMode(thread_manager.get(), client_id)) { |
| 483 LOG(ERROR) << "InitializeSentenceMode failed."; | 481 LOG(ERROR) << "InitializeSentenceMode failed."; |
| 484 thread_manager->Deactivate(); | 482 thread_manager->Deactivate(); |
| 485 return scoped_ptr<TextService>(); | 483 return scoped_ptr<TextService>(); |
| 486 } | 484 } |
| 487 return scoped_ptr<TextService>(new TextServiceImpl(thread_manager, | 485 return scoped_ptr<TextService>(new TextServiceImpl( |
| 488 client_id, | 486 thread_manager.get(), client_id, window_handle, delegate)); |
| 489 window_handle, | |
| 490 delegate)); | |
| 491 } | 487 } |
| 492 | 488 |
| 493 } // namespace metro_driver | 489 } // namespace metro_driver |
| OLD | NEW |