OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <msctf.h> | 5 #include <msctf.h> |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/memory/singleton.h" | |
13 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
14 #include "base/threading/thread_local_storage.h" | 13 #include "base/threading/thread_local_storage.h" |
15 #include "base/win/scoped_comptr.h" | 14 #include "base/win/scoped_comptr.h" |
16 #include "base/win/scoped_variant.h" | 15 #include "base/win/scoped_variant.h" |
17 #include "ui/base/ime/text_input_client.h" | 16 #include "ui/base/ime/text_input_client.h" |
18 #include "ui/base/ime/win/tsf_bridge.h" | 17 #include "ui/base/ime/win/tsf_bridge.h" |
19 #include "ui/base/ime/win/tsf_text_store.h" | 18 #include "ui/base/ime/win/tsf_text_store.h" |
20 | 19 |
21 namespace ui { | 20 namespace ui { |
22 | 21 |
23 namespace { | 22 namespace { |
24 | 23 |
25 // We use thread local storage for TSFBridge lifespan management. | 24 // We use thread local storage for TSFBridge lifespan management. |
26 base::ThreadLocalStorage::StaticSlot tls_tsf_bridge = TLS_INITIALIZER; | 25 base::ThreadLocalStorage::StaticSlot tls_tsf_bridge = TLS_INITIALIZER; |
27 | 26 |
28 | 27 |
29 // TsfBridgeDelegate ----------------------------------------------------------- | 28 // TsfBridgeDelegate ----------------------------------------------------------- |
30 | 29 |
31 // A TLS implementation of TSFBridge. | 30 // A TLS implementation of TSFBridge. |
32 class TSFBridgeDelegate : public TSFBridge { | 31 class TSFBridgeDelegate : public TSFBridge { |
33 public: | 32 public: |
34 TSFBridgeDelegate(); | 33 TSFBridgeDelegate(); |
35 virtual ~TSFBridgeDelegate(); | 34 virtual ~TSFBridgeDelegate(); |
36 | 35 |
37 bool Initialize(); | 36 bool Initialize(); |
38 | 37 |
39 // TsfBridge: | 38 // TsfBridge: |
40 virtual void Shutdown() OVERRIDE; | |
41 virtual void OnTextInputTypeChanged(TextInputClient* client) OVERRIDE; | 39 virtual void OnTextInputTypeChanged(TextInputClient* client) OVERRIDE; |
42 virtual void OnTextLayoutChanged() OVERRIDE; | 40 virtual void OnTextLayoutChanged() OVERRIDE; |
43 virtual bool CancelComposition() OVERRIDE; | 41 virtual bool CancelComposition() OVERRIDE; |
44 virtual void SetFocusedClient(HWND focused_window, | 42 virtual void SetFocusedClient(HWND focused_window, |
45 TextInputClient* client) OVERRIDE; | 43 TextInputClient* client) OVERRIDE; |
46 virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE; | 44 virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE; |
47 virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE; | 45 virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE; |
48 virtual TextInputClient* GetFocusedTextInputClient() const OVERRIDE; | 46 virtual TextInputClient* GetFocusedTextInputClient() const OVERRIDE; |
49 | 47 |
50 private: | 48 private: |
51 friend struct DefaultSingletonTraits<TSFBridgeDelegate>; | |
52 | |
53 // Returns true if |tsf_document_map_| is successfully initialized. This | 49 // Returns true if |tsf_document_map_| is successfully initialized. This |
54 // method should be called from and only from Initialize(). | 50 // method should be called from and only from Initialize(). |
55 bool InitializeDocumentMapInternal(); | 51 bool InitializeDocumentMapInternal(); |
56 | 52 |
57 // Returns true if |context| is successfully updated to be a disabled | 53 // Returns true if |context| is successfully updated to be a disabled |
58 // context, where an IME should be deactivated. This is suitable for some | 54 // context, where an IME should be deactivated. This is suitable for some |
59 // special input context such as password fields. | 55 // special input context such as password fields. |
60 bool InitializeDisabledContext(ITfContext* context); | 56 bool InitializeDisabledContext(ITfContext* context); |
61 | 57 |
62 // Returns true if a TSF document manager and a TSF context is successfully | 58 // Returns true if a TSF document manager and a TSF context is successfully |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 | 111 |
116 DISALLOW_COPY_AND_ASSIGN(TSFBridgeDelegate); | 112 DISALLOW_COPY_AND_ASSIGN(TSFBridgeDelegate); |
117 }; | 113 }; |
118 | 114 |
119 TSFBridgeDelegate::TSFBridgeDelegate() | 115 TSFBridgeDelegate::TSFBridgeDelegate() |
120 : client_id_(TF_CLIENTID_NULL), | 116 : client_id_(TF_CLIENTID_NULL), |
121 client_(NULL) { | 117 client_(NULL) { |
122 } | 118 } |
123 | 119 |
124 TSFBridgeDelegate::~TSFBridgeDelegate() { | 120 TSFBridgeDelegate::~TSFBridgeDelegate() { |
| 121 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); |
| 122 if (!IsInitialized()) |
| 123 return; |
| 124 for (TSFDocumentMap::iterator it = tsf_document_map_.begin(); |
| 125 it != tsf_document_map_.end(); ++it) { |
| 126 base::win::ScopedComPtr<ITfContext> context; |
| 127 base::win::ScopedComPtr<ITfSource> source; |
| 128 if (it->second.cookie != TF_INVALID_COOKIE && |
| 129 SUCCEEDED(it->second.document_manager->GetBase(context.Receive())) && |
| 130 SUCCEEDED(source.QueryFrom(context))) { |
| 131 source->UnadviseSink(it->second.cookie); |
| 132 } |
| 133 } |
| 134 tsf_document_map_.clear(); |
| 135 |
| 136 client_id_ = TF_CLIENTID_NULL; |
125 } | 137 } |
126 | 138 |
127 bool TSFBridgeDelegate::Initialize() { | 139 bool TSFBridgeDelegate::Initialize() { |
128 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); | 140 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); |
129 if (client_id_ != TF_CLIENTID_NULL) { | 141 if (client_id_ != TF_CLIENTID_NULL) { |
130 DVLOG(1) << "Already initialized."; | 142 DVLOG(1) << "Already initialized."; |
131 return false; | 143 return false; |
132 } | 144 } |
133 | 145 |
134 if (FAILED(thread_manager_.CreateInstance(CLSID_TF_ThreadMgr))) { | 146 if (FAILED(thread_manager_.CreateInstance(CLSID_TF_ThreadMgr))) { |
(...skipping 30 matching lines...) Expand all Loading... |
165 base::win::ScopedVariant sentence_variant; | 177 base::win::ScopedVariant sentence_variant; |
166 sentence_variant.Set(TF_SENTENCEMODE_PHRASEPREDICT); | 178 sentence_variant.Set(TF_SENTENCEMODE_PHRASEPREDICT); |
167 if (FAILED(sentence_compartment->SetValue(client_id_, &sentence_variant))) { | 179 if (FAILED(sentence_compartment->SetValue(client_id_, &sentence_variant))) { |
168 DVLOG(1) << "Failed to change the sentence mode."; | 180 DVLOG(1) << "Failed to change the sentence mode."; |
169 return false; | 181 return false; |
170 } | 182 } |
171 | 183 |
172 return true; | 184 return true; |
173 } | 185 } |
174 | 186 |
175 void TSFBridgeDelegate::Shutdown() { | |
176 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); | |
177 if (!IsInitialized()) | |
178 return; | |
179 for (TSFDocumentMap::iterator it = tsf_document_map_.begin(); | |
180 it != tsf_document_map_.end(); ++it) { | |
181 base::win::ScopedComPtr<ITfContext> context; | |
182 base::win::ScopedComPtr<ITfSource> source; | |
183 if (it->second.cookie != TF_INVALID_COOKIE && | |
184 SUCCEEDED(it->second.document_manager->GetBase(context.Receive())) && | |
185 SUCCEEDED(source.QueryFrom(context))) { | |
186 source->UnadviseSink(it->second.cookie); | |
187 } | |
188 } | |
189 tsf_document_map_.clear(); | |
190 | |
191 client_id_ = TF_CLIENTID_NULL; | |
192 } | |
193 | |
194 void TSFBridgeDelegate::OnTextInputTypeChanged(TextInputClient* client) { | 187 void TSFBridgeDelegate::OnTextInputTypeChanged(TextInputClient* client) { |
195 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); | 188 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); |
196 DCHECK(IsInitialized()); | 189 DCHECK(IsInitialized()); |
197 | 190 |
198 if (client != client_) { | 191 if (client != client_) { |
199 // Called from not focusing client. Do nothing. | 192 // Called from not focusing client. Do nothing. |
200 return; | 193 return; |
201 } | 194 } |
202 | 195 |
203 TSFDocument* document = GetAssociatedDocument(); | 196 TSFDocument* document = GetAssociatedDocument(); |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 } | 446 } |
454 | 447 |
455 // static | 448 // static |
456 bool TSFBridge::Initialize() { | 449 bool TSFBridge::Initialize() { |
457 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { | 450 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { |
458 DVLOG(1) << "Do not use TSFBridge without UI thread."; | 451 DVLOG(1) << "Do not use TSFBridge without UI thread."; |
459 return false; | 452 return false; |
460 } | 453 } |
461 if (!tls_tsf_bridge.initialized()) { | 454 if (!tls_tsf_bridge.initialized()) { |
462 tls_tsf_bridge.Initialize(TSFBridge::Finalize); | 455 tls_tsf_bridge.Initialize(TSFBridge::Finalize); |
463 TSFBridgeDelegate* delegate = new TSFBridgeDelegate(); | |
464 tls_tsf_bridge.Set(delegate); | |
465 return delegate->Initialize(); | |
466 } | 456 } |
467 return true; | 457 TSFBridgeDelegate* delegate = |
| 458 static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); |
| 459 if (delegate) |
| 460 return true; |
| 461 delegate = new TSFBridgeDelegate(); |
| 462 tls_tsf_bridge.Set(delegate); |
| 463 return delegate->Initialize(); |
468 } | 464 } |
469 | 465 |
470 // static | 466 // static |
471 TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) { | 467 TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) { |
472 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { | 468 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { |
473 DVLOG(1) << "Do not use TSFBridge without UI thread."; | 469 DVLOG(1) << "Do not use TSFBridge without UI thread."; |
474 return NULL; | 470 return NULL; |
475 } | 471 } |
476 TSFBridge* old_bridge = TSFBridge::GetInstance(); | 472 TSFBridge* old_bridge = TSFBridge::GetInstance(); |
477 tls_tsf_bridge.Set(bridge); | 473 tls_tsf_bridge.Set(bridge); |
478 return old_bridge; | 474 return old_bridge; |
479 } | 475 } |
480 | 476 |
481 // static | 477 // static |
| 478 void TSFBridge::Shutdown() { |
| 479 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { |
| 480 DVLOG(1) << "Do not use TSFBridge without UI thread."; |
| 481 } |
| 482 if (tls_tsf_bridge.initialized()) { |
| 483 TSFBridgeDelegate* delegate = |
| 484 static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); |
| 485 tls_tsf_bridge.Set(NULL); |
| 486 delete delegate; |
| 487 } |
| 488 } |
| 489 |
| 490 // static |
482 TSFBridge* TSFBridge::GetInstance() { | 491 TSFBridge* TSFBridge::GetInstance() { |
483 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { | 492 if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { |
484 DVLOG(1) << "Do not use TSFBridge without UI thread."; | 493 DVLOG(1) << "Do not use TSFBridge without UI thread."; |
485 return NULL; | 494 return NULL; |
486 } | 495 } |
487 TSFBridgeDelegate* delegate = | 496 TSFBridgeDelegate* delegate = |
488 static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); | 497 static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); |
489 DCHECK(delegate) << "Do no call GetInstance before TSFBridge::Initialize."; | 498 DCHECK(delegate) << "Do no call GetInstance before TSFBridge::Initialize."; |
490 return delegate; | 499 return delegate; |
491 } | 500 } |
492 | 501 |
493 // static | 502 // static |
494 void TSFBridge::Finalize(void* data) { | 503 void TSFBridge::Finalize(void* data) { |
495 TSFBridgeDelegate* delegate = static_cast<TSFBridgeDelegate*>(data); | 504 TSFBridgeDelegate* delegate = static_cast<TSFBridgeDelegate*>(data); |
496 delete delegate; | 505 delete delegate; |
497 } | 506 } |
498 | 507 |
499 } // namespace ui | 508 } // namespace ui |
OLD | NEW |