diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/ui/base/ime/win | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ui/base/ime/win')
-rw-r--r-- | chromium/ui/base/ime/win/imm32_manager.cc | 35 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/imm32_manager.h | 16 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/mock_tsf_bridge.cc | 83 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/mock_tsf_bridge.h | 100 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_bridge.cc | 558 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_bridge.h | 97 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_event_router.cc | 307 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_event_router.h | 81 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_input_scope.cc | 4 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_input_scope.h | 13 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_text_store.cc | 923 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_text_store.h | 297 | ||||
-rw-r--r-- | chromium/ui/base/ime/win/tsf_text_store_unittest.cc | 1302 |
13 files changed, 32 insertions, 3784 deletions
diff --git a/chromium/ui/base/ime/win/imm32_manager.cc b/chromium/ui/base/ime/win/imm32_manager.cc index 093b0109366..7ad2d875e4c 100644 --- a/chromium/ui/base/ime/win/imm32_manager.cc +++ b/chromium/ui/base/ime/win/imm32_manager.cc @@ -4,8 +4,6 @@ #include "ui/base/ime/win/imm32_manager.h" -#include <atlbase.h> -#include <atlcom.h> #include <msctf.h> #include "base/basictypes.h" @@ -24,7 +22,7 @@ // Following code requires wchar_t to be same as char16. It should always be // true on Windows. -COMPILE_ASSERT(sizeof(wchar_t) == sizeof(char16), wchar_t__char16_diff); +COMPILE_ASSERT(sizeof(wchar_t) == sizeof(base::char16), wchar_t__char16_diff); /////////////////////////////////////////////////////////////////////////////// // IMM32Manager @@ -85,10 +83,11 @@ void GetCompositionUnderlines(HIMC imm_context, underline.end_offset = clause_data[i+1]; underline.color = SK_ColorBLACK; underline.thick = false; + underline.background_color = SK_ColorTRANSPARENT; // Use thick underline for the target clause. - if (underline.start_offset >= static_cast<unsigned>(target_start) && - underline.end_offset <= static_cast<unsigned>(target_end)) { + if (underline.start_offset >= static_cast<uint32>(target_start) && + underline.end_offset <= static_cast<uint32>(target_end)) { underline.thick = true; } underlines->push_back(underline); @@ -344,21 +343,22 @@ void IMM32Manager::GetCompositionInfo(HIMC imm_context, LPARAM lparam, if (!composition->underlines.size()) { CompositionUnderline underline; underline.color = SK_ColorBLACK; + underline.background_color = SK_ColorTRANSPARENT; if (target_start > 0) { - underline.start_offset = 0; - underline.end_offset = target_start; + underline.start_offset = 0U; + underline.end_offset = static_cast<uint32>(target_start); underline.thick = false; composition->underlines.push_back(underline); } if (target_end > target_start) { - underline.start_offset = target_start; - underline.end_offset = target_end; + underline.start_offset = static_cast<uint32>(target_start); + underline.end_offset = static_cast<uint32>(target_end); underline.thick = true; composition->underlines.push_back(underline); } if (target_end < length) { - underline.start_offset = target_end; - underline.end_offset = length; + underline.start_offset = static_cast<uint32>(target_end); + underline.end_offset = static_cast<uint32>(length); underline.thick = false; composition->underlines.push_back(underline); } @@ -368,7 +368,7 @@ void IMM32Manager::GetCompositionInfo(HIMC imm_context, LPARAM lparam, bool IMM32Manager::GetString(HIMC imm_context, WPARAM lparam, int type, - string16* result) { + base::string16* result) { if (!(lparam & type)) return false; LONG string_size = ::ImmGetCompositionString(imm_context, type, NULL, 0); @@ -381,7 +381,7 @@ bool IMM32Manager::GetString(HIMC imm_context, } bool IMM32Manager::GetResult( - HWND window_handle, LPARAM lparam, string16* result) { + HWND window_handle, LPARAM lparam, base::string16* result) { bool ret = false; HIMC imm_context = ::ImmGetContext(window_handle); if (imm_context) { @@ -487,7 +487,7 @@ std::string IMM32Manager::GetInputLanguageName() const { return std::string(); std::string language; - WideToUTF8(buffer, length - 1, &language); + base::WideToUTF8(buffer, length - 1, &language); if (SUBLANGID(input_language_id_) == SUBLANG_NEUTRAL) return language; @@ -498,15 +498,10 @@ std::string IMM32Manager::GetInputLanguageName() const { return language; std::string region; - WideToUTF8(buffer, length - 1, ®ion); + base::WideToUTF8(buffer, length - 1, ®ion); return language.append(1, '-').append(region); } -base::i18n::TextDirection IMM32Manager::GetTextDirection() const { - return IsRTLPrimaryLangID(PRIMARYLANGID(input_language_id_)) ? - base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT; -} - void IMM32Manager::SetTextInputMode(HWND window_handle, TextInputMode input_mode) { if (input_mode == ui::TEXT_INPUT_MODE_DEFAULT) diff --git a/chromium/ui/base/ime/win/imm32_manager.h b/chromium/ui/base/ime/win/imm32_manager.h index 17892cb7640..3a969fd64a6 100644 --- a/chromium/ui/base/ime/win/imm32_manager.h +++ b/chromium/ui/base/ime/win/imm32_manager.h @@ -14,7 +14,7 @@ #include "base/i18n/rtl.h" #include "base/strings/string16.h" #include "ui/base/ime/text_input_mode.h" -#include "ui/base/ui_export.h" +#include "ui/base/ui_base_export.h" #include "ui/gfx/rect.h" namespace ui { @@ -74,7 +74,7 @@ struct CompositionText; // hand, we can NEVER disable either TSF or CUAS in Windows Vista, i.e. // THIS CLASS IS NOT ONLY USED ON THE INPUT CONTEXTS OF EAST-ASIAN // LANGUAGES BUT ALSO USED ON THE INPUT CONTEXTS OF ALL LANGUAGES. -class UI_EXPORT IMM32Manager { +class UI_BASE_EXPORT IMM32Manager { public: IMM32Manager(); virtual ~IMM32Manager(); @@ -154,7 +154,7 @@ class UI_EXPORT IMM32Manager { // the same parameter of a WM_IME_COMPOSITION message handler. // This parameter is used for checking if the ongoing composition has // its result string, - // * result [out] (string16) + // * result [out] (base::string16) // Represents the object contains the composition result. // Return values // * true @@ -164,7 +164,7 @@ class UI_EXPORT IMM32Manager { // Remarks // This function is designed for being called from WM_IME_COMPOSITION // message handlers. - bool GetResult(HWND window_handle, LPARAM lparam, string16* result); + bool GetResult(HWND window_handle, LPARAM lparam, base::string16* result); // Retrieves the current composition status of the ongoing composition. // Parameters @@ -237,9 +237,6 @@ class UI_EXPORT IMM32Manager { // Returns BCP-47 tag name of the current input language. std::string GetInputLanguageName() const; - // Returns the text direction of the current input language. - base::i18n::TextDirection GetTextDirection() const; - // Sets conversion status corresponding to |input_mode|. virtual void SetTextInputMode(HWND window_handle, TextInputMode input_mode); @@ -274,7 +271,10 @@ class UI_EXPORT IMM32Manager { void CompleteComposition(HWND window_handle, HIMC imm_context); // Retrieves a string from the IMM. - bool GetString(HIMC imm_context, WPARAM lparam, int type, string16* result); + bool GetString(HIMC imm_context, + WPARAM lparam, + int type, + base::string16* result); private: // Represents whether or not there is an ongoing composition in a browser diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.cc b/chromium/ui/base/ime/win/mock_tsf_bridge.cc deleted file mode 100644 index a26a81b1ebb..00000000000 --- a/chromium/ui/base/ime/win/mock_tsf_bridge.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/base/ime/win/mock_tsf_bridge.h" - -#include "ui/base/ime/text_input_client.h" -#include "base/logging.h" - -namespace ui { - -MockTSFBridge::MockTSFBridge() - : enable_ime_call_count_(0), - disalbe_ime_call_count_(0), - cancel_composition_call_count_(0), - confirm_composition_call_count_(0), - on_text_layout_changed_(0), - associate_focus_call_count_(0), - set_focused_client_call_count_(0), - remove_focused_client_call_count_(0), - text_input_client_(NULL), - focused_window_(NULL), - latest_text_input_type_(TEXT_INPUT_TYPE_NONE) { -} - -MockTSFBridge::~MockTSFBridge() { -} - -bool MockTSFBridge::CancelComposition() { - ++cancel_composition_call_count_; - return true; -} - -bool MockTSFBridge::ConfirmComposition() { - ++confirm_composition_call_count_; - return true; -} - -void MockTSFBridge::OnTextInputTypeChanged(const TextInputClient* client) { - latest_text_input_type_ = client->GetTextInputType(); -} - -void MockTSFBridge::OnTextLayoutChanged() { - ++on_text_layout_changed_; -} - -void MockTSFBridge::SetFocusedClient(HWND focused_window, - TextInputClient* client) { - ++set_focused_client_call_count_; - focused_window_ = focused_window; - text_input_client_ = client; -} - -void MockTSFBridge::RemoveFocusedClient(TextInputClient* client) { - ++remove_focused_client_call_count_; - DCHECK_EQ(client, text_input_client_); - text_input_client_ = NULL; - focused_window_ = NULL; -} - -base::win::ScopedComPtr<ITfThreadMgr> MockTSFBridge::GetThreadManager() { - return thread_manager_; -} - -TextInputClient* MockTSFBridge::GetFocusedTextInputClient() const { - return text_input_client_; -} - -void MockTSFBridge::Reset() { - enable_ime_call_count_ = 0; - disalbe_ime_call_count_ = 0; - cancel_composition_call_count_ = 0; - confirm_composition_call_count_ = 0; - on_text_layout_changed_ = 0; - associate_focus_call_count_ = 0; - set_focused_client_call_count_ = 0; - remove_focused_client_call_count_ = 0; - text_input_client_ = NULL; - focused_window_ = NULL; - latest_text_input_type_ = TEXT_INPUT_TYPE_NONE; -} - -} // namespace ui diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.h b/chromium/ui/base/ime/win/mock_tsf_bridge.h deleted file mode 100644 index 1fdfc8ae049..00000000000 --- a/chromium/ui/base/ime/win/mock_tsf_bridge.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_ -#define UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_ - -#include <msctf.h> - -#include "base/compiler_specific.h" -#include "base/win/scoped_comptr.h" -#include "ui/base/ime/text_input_type.h" -#include "ui/base/ime/win/tsf_bridge.h" - -namespace ui { - -class MockTSFBridge : public TSFBridge { - public: - MockTSFBridge(); - virtual ~MockTSFBridge(); - - // TSFBridge: - virtual bool CancelComposition() OVERRIDE; - virtual bool ConfirmComposition() OVERRIDE; - virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE; - virtual void OnTextLayoutChanged() OVERRIDE; - virtual void SetFocusedClient(HWND focused_window, - TextInputClient* client) OVERRIDE; - virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE; - virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE; - virtual TextInputClient* GetFocusedTextInputClient() const OVERRIDE; - - // Resets MockTSFBridge state including function call counter. - void Reset(); - - // Call count of EnableIME(). - int enable_ime_call_count() const { return enable_ime_call_count_; } - - // Call count of DisableIME(). - int disalbe_ime_call_count() const { return disalbe_ime_call_count_; } - - // Call count of CancelComposition(). - int cancel_composition_call_count() const { - return cancel_composition_call_count_; - } - - // Call count of ConfirmComposition(). - int confirm_composition_call_count() const { - return confirm_composition_call_count_; - } - - // Call count of OnTextLayoutChanged(). - int on_text_layout_changed() const { - return on_text_layout_changed_; - } - - // Call count of AssociateFocus(). - int associate_focus_call_count() const { return associate_focus_call_count_; } - - // Call count of SetFocusClient(). - int set_focused_client_call_count() const { - return set_focused_client_call_count_; - } - - // Call count of RemoveFocusedClient(). - int remove_focused_client_call_count() const { - return remove_focused_client_call_count_; - } - - // Returns current TextInputClient. - TextInputClient* text_input_clinet() const { return text_input_client_; } - - // Returns currently focused window handle. - HWND focused_window() const { return focused_window_; } - - // Returns latest text input type. - TextInputType latest_text_iput_type() const { - return latest_text_input_type_; - } - - private: - int enable_ime_call_count_; - int disalbe_ime_call_count_; - int cancel_composition_call_count_; - int confirm_composition_call_count_; - int on_text_layout_changed_; - int associate_focus_call_count_; - int set_focused_client_call_count_; - int remove_focused_client_call_count_; - TextInputClient* text_input_client_; - HWND focused_window_; - TextInputType latest_text_input_type_; - base::win::ScopedComPtr<ITfThreadMgr> thread_manager_; - - DISALLOW_COPY_AND_ASSIGN(MockTSFBridge); -}; - -} // namespace ui - -#endif // UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_ diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc deleted file mode 100644 index bf2820323ef..00000000000 --- a/chromium/ui/base/ime/win/tsf_bridge.cc +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <msctf.h> - -#include <map> - -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_local_storage.h" -#include "base/win/scoped_comptr.h" -#include "base/win/scoped_variant.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/ime/win/tsf_bridge.h" -#include "ui/base/ime/win/tsf_text_store.h" - -namespace ui { - -namespace { - -// We use thread local storage for TSFBridge lifespan management. -base::ThreadLocalStorage::StaticSlot tls_tsf_bridge = TLS_INITIALIZER; - - -// TsfBridgeDelegate ----------------------------------------------------------- - -// A TLS implementation of TSFBridge. -class TSFBridgeDelegate : public TSFBridge { - public: - TSFBridgeDelegate(); - virtual ~TSFBridgeDelegate(); - - bool Initialize(); - - // TsfBridge: - virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE; - virtual void OnTextLayoutChanged() OVERRIDE; - virtual bool CancelComposition() OVERRIDE; - virtual bool ConfirmComposition() OVERRIDE; - virtual void SetFocusedClient(HWND focused_window, - TextInputClient* client) OVERRIDE; - virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE; - virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE; - virtual TextInputClient* GetFocusedTextInputClient() const OVERRIDE; - - private: - // Returns true if |tsf_document_map_| is successfully initialized. This - // method should be called from and only from Initialize(). - bool InitializeDocumentMapInternal(); - - // Returns true if |context| is successfully updated to be a disabled - // context, where an IME should be deactivated. This is suitable for some - // special input context such as password fields. - bool InitializeDisabledContext(ITfContext* context); - - // Returns true if a TSF document manager and a TSF context is successfully - // created with associating with given |text_store|. The returned - // |source_cookie| indicates the binding between |text_store| and |context|. - // You can pass NULL to |text_store| and |source_cookie| when text store is - // not necessary. - bool CreateDocumentManager(TSFTextStore* text_store, - ITfDocumentMgr** document_manager, - ITfContext** context, - DWORD* source_cookie); - - // Returns true if |document_manager| is the focused document manager. - bool IsFocused(ITfDocumentMgr* document_manager); - - // Returns true if already initialized. - bool IsInitialized(); - - // Updates or clears the association maintained in the TSF runtime between - // |attached_window_handle_| and the current document manager. Keeping this - // association updated solves some tricky event ordering issues between - // logical text input focus managed by Chrome and native text input focus - // managed by the OS. - // Background: - // TSF runtime monitors some Win32 messages such as WM_ACTIVATE to - // change the focused document manager. This is problematic when - // TSFBridge::SetFocusedClient is called first then the target window - // receives WM_ACTIVATE. This actually occurs in Aura environment where - // WM_NCACTIVATE is used as a trigger to restore text input focus. - // Caveats: - // TSF runtime does not increment the reference count of the attached - // document manager. See the comment inside the method body for - // details. - void UpdateAssociateFocus(); - void ClearAssociateFocus(); - - // A triple of document manager, text store and binding cookie between - // a context owned by the document manager and the text store. This is a - // minimum working set of an editable document in TSF. - struct TSFDocument { - public: - TSFDocument() : cookie(TF_INVALID_COOKIE) {} - TSFDocument(const TSFDocument& src) - : document_manager(src.document_manager), - cookie(src.cookie) {} - base::win::ScopedComPtr<ITfDocumentMgr> document_manager; - scoped_refptr<TSFTextStore> text_store; - DWORD cookie; - }; - - // Returns a pointer to TSFDocument that is associated with the current - // TextInputType of |client_|. - TSFDocument* GetAssociatedDocument(); - - // An ITfThreadMgr object to be used in focus and document management. - base::win::ScopedComPtr<ITfThreadMgr> thread_manager_; - - // A map from TextInputType to an editable document for TSF. We use multiple - // TSF documents that have different InputScopes and TSF attributes based on - // the TextInputType associated with the target document. For a TextInputType - // that is not coverted by this map, a default document, e.g. the document - // for TEXT_INPUT_TYPE_TEXT, should be used. - // Note that some IMEs don't change their state unless the document focus is - // changed. This is why we use multiple documents instead of changing TSF - // metadata of a single document on the fly. - typedef std::map<TextInputType, TSFDocument> TSFDocumentMap; - TSFDocumentMap tsf_document_map_; - - // An identifier of TSF client. - TfClientId client_id_; - - // Current focused text input client. Do not free |client_|. - TextInputClient* client_; - - // Represents the window that is currently owns text input focus. - HWND attached_window_handle_; - - DISALLOW_COPY_AND_ASSIGN(TSFBridgeDelegate); -}; - -TSFBridgeDelegate::TSFBridgeDelegate() - : client_id_(TF_CLIENTID_NULL), - client_(NULL), - attached_window_handle_(NULL) { -} - -TSFBridgeDelegate::~TSFBridgeDelegate() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - if (!IsInitialized()) - return; - for (TSFDocumentMap::iterator it = tsf_document_map_.begin(); - it != tsf_document_map_.end(); ++it) { - base::win::ScopedComPtr<ITfContext> context; - base::win::ScopedComPtr<ITfSource> source; - if (it->second.cookie != TF_INVALID_COOKIE && - SUCCEEDED(it->second.document_manager->GetBase(context.Receive())) && - SUCCEEDED(source.QueryFrom(context))) { - source->UnadviseSink(it->second.cookie); - } - } - tsf_document_map_.clear(); - - client_id_ = TF_CLIENTID_NULL; -} - -bool TSFBridgeDelegate::Initialize() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - if (client_id_ != TF_CLIENTID_NULL) { - DVLOG(1) << "Already initialized."; - return false; - } - - if (FAILED(thread_manager_.CreateInstance(CLSID_TF_ThreadMgr))) { - DVLOG(1) << "Failed to create ThreadManager instance."; - return false; - } - - if (FAILED(thread_manager_->Activate(&client_id_))) { - DVLOG(1) << "Failed to activate Thread Manager."; - return false; - } - - if (!InitializeDocumentMapInternal()) - return false; - - // Japanese IME expects the default value of this compartment is - // TF_SENTENCEMODE_PHRASEPREDICT like IMM32 implementation. This value is - // managed per thread, so that it is enough to set this value at once. This - // value does not affect other language's IME behaviors. - base::win::ScopedComPtr<ITfCompartmentMgr> thread_compartment_manager; - if (FAILED(thread_compartment_manager.QueryFrom(thread_manager_))) { - DVLOG(1) << "Failed to get ITfCompartmentMgr."; - return false; - } - - base::win::ScopedComPtr<ITfCompartment> sentence_compartment; - if (FAILED(thread_compartment_manager->GetCompartment( - GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE, - sentence_compartment.Receive()))) { - DVLOG(1) << "Failed to get sentence compartment."; - return false; - } - - base::win::ScopedVariant sentence_variant; - sentence_variant.Set(TF_SENTENCEMODE_PHRASEPREDICT); - if (FAILED(sentence_compartment->SetValue(client_id_, &sentence_variant))) { - DVLOG(1) << "Failed to change the sentence mode."; - return false; - } - - return true; -} - -void TSFBridgeDelegate::OnTextInputTypeChanged(const TextInputClient* client) { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(IsInitialized()); - - if (client != client_) { - // Called from not focusing client. Do nothing. - return; - } - - UpdateAssociateFocus(); - - TSFDocument* document = GetAssociatedDocument(); - if (!document) - return; - thread_manager_->SetFocus(document->document_manager.get()); - OnTextLayoutChanged(); -} - -void TSFBridgeDelegate::OnTextLayoutChanged() { - TSFDocument* document = GetAssociatedDocument(); - if (!document) - return; - if (!document->text_store) - return; - document->text_store->SendOnLayoutChange(); -} - -bool TSFBridgeDelegate::CancelComposition() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(IsInitialized()); - - TSFDocument* document = GetAssociatedDocument(); - if (!document) - return false; - if (!document->text_store) - return false; - - return document->text_store->CancelComposition(); -} - -bool TSFBridgeDelegate::ConfirmComposition() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(IsInitialized()); - - TSFDocument* document = GetAssociatedDocument(); - if (!document) - return false; - if (!document->text_store) - return false; - - return document->text_store->ConfirmComposition(); -} - -void TSFBridgeDelegate::SetFocusedClient(HWND focused_window, - TextInputClient* client) { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(client); - DCHECK(IsInitialized()); - if (attached_window_handle_ != focused_window) - ClearAssociateFocus(); - client_ = client; - attached_window_handle_ = focused_window; - - for (TSFDocumentMap::iterator it = tsf_document_map_.begin(); - it != tsf_document_map_.end(); ++it) { - if (it->second.text_store.get() == NULL) - continue; - it->second.text_store->SetFocusedTextInputClient(focused_window, - client); - } - - // Synchronize text input type state. - OnTextInputTypeChanged(client); -} - -void TSFBridgeDelegate::RemoveFocusedClient(TextInputClient* client) { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(IsInitialized()); - if (client_ != client) - return; - ClearAssociateFocus(); - client_ = NULL; - attached_window_handle_ = NULL; - for (TSFDocumentMap::iterator it = tsf_document_map_.begin(); - it != tsf_document_map_.end(); ++it) { - if (it->second.text_store.get() == NULL) - continue; - it->second.text_store->SetFocusedTextInputClient(NULL, NULL); - } -} - -TextInputClient* TSFBridgeDelegate::GetFocusedTextInputClient() const { - return client_; -} - -base::win::ScopedComPtr<ITfThreadMgr> TSFBridgeDelegate::GetThreadManager() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); - DCHECK(IsInitialized()); - return thread_manager_; -} - -bool TSFBridgeDelegate::CreateDocumentManager(TSFTextStore* text_store, - ITfDocumentMgr** document_manager, - ITfContext** context, - DWORD* source_cookie) { - if (FAILED(thread_manager_->CreateDocumentMgr(document_manager))) { - DVLOG(1) << "Failed to create Document Manager."; - return false; - } - - DWORD edit_cookie = TF_INVALID_EDIT_COOKIE; - if (FAILED((*document_manager)->CreateContext( - client_id_, - 0, - static_cast<ITextStoreACP*>(text_store), - context, - &edit_cookie))) { - DVLOG(1) << "Failed to create Context."; - return false; - } - - if (FAILED((*document_manager)->Push(*context))) { - DVLOG(1) << "Failed to push context."; - return false; - } - - if (!text_store || !source_cookie) - return true; - - base::win::ScopedComPtr<ITfSource> source; - if (FAILED(source.QueryFrom(*context))) { - DVLOG(1) << "Failed to get source."; - return false; - } - - if (FAILED(source->AdviseSink(IID_ITfTextEditSink, - static_cast<ITfTextEditSink*>(text_store), - source_cookie))) { - DVLOG(1) << "AdviseSink failed."; - return false; - } - - if (*source_cookie == TF_INVALID_COOKIE) { - DVLOG(1) << "The result of cookie is invalid."; - return false; - } - return true; -} - -bool TSFBridgeDelegate::InitializeDocumentMapInternal() { - const TextInputType kTextInputTypes[] = { - TEXT_INPUT_TYPE_NONE, - TEXT_INPUT_TYPE_TEXT, - TEXT_INPUT_TYPE_PASSWORD, - TEXT_INPUT_TYPE_SEARCH, - TEXT_INPUT_TYPE_EMAIL, - TEXT_INPUT_TYPE_NUMBER, - TEXT_INPUT_TYPE_TELEPHONE, - TEXT_INPUT_TYPE_URL, - }; - for (size_t i = 0; i < arraysize(kTextInputTypes); ++i) { - const TextInputType input_type = kTextInputTypes[i]; - base::win::ScopedComPtr<ITfContext> context; - base::win::ScopedComPtr<ITfDocumentMgr> document_manager; - DWORD cookie = TF_INVALID_COOKIE; - const bool use_null_text_store = (input_type == TEXT_INPUT_TYPE_NONE); - DWORD* cookie_ptr = use_null_text_store ? NULL : &cookie; - scoped_refptr<TSFTextStore> text_store = - use_null_text_store ? NULL : new TSFTextStore(); - if (!CreateDocumentManager(text_store, - document_manager.Receive(), - context.Receive(), - cookie_ptr)) - return false; - const bool use_disabled_context = - (input_type == TEXT_INPUT_TYPE_PASSWORD || - input_type == TEXT_INPUT_TYPE_NONE); - if (use_disabled_context && !InitializeDisabledContext(context)) - return false; - tsf_document_map_[input_type].text_store = text_store; - tsf_document_map_[input_type].document_manager = document_manager; - tsf_document_map_[input_type].cookie = cookie; - } - return true; -} - -bool TSFBridgeDelegate::InitializeDisabledContext(ITfContext* context) { - base::win::ScopedComPtr<ITfCompartmentMgr> compartment_mgr; - if (FAILED(compartment_mgr.QueryFrom(context))) { - DVLOG(1) << "Failed to get CompartmentMgr."; - return false; - } - - base::win::ScopedComPtr<ITfCompartment> disabled_compartment; - if (FAILED(compartment_mgr->GetCompartment( - GUID_COMPARTMENT_KEYBOARD_DISABLED, - disabled_compartment.Receive()))) { - DVLOG(1) << "Failed to get keyboard disabled compartment."; - return false; - } - - base::win::ScopedVariant variant; - variant.Set(1); - if (FAILED(disabled_compartment->SetValue(client_id_, &variant))) { - DVLOG(1) << "Failed to disable the DocumentMgr."; - return false; - } - - base::win::ScopedComPtr<ITfCompartment> empty_context; - if (FAILED(compartment_mgr->GetCompartment(GUID_COMPARTMENT_EMPTYCONTEXT, - empty_context.Receive()))) { - DVLOG(1) << "Failed to get empty context compartment."; - return false; - } - base::win::ScopedVariant empty_context_variant; - empty_context_variant.Set(static_cast<int32>(1)); - if (FAILED(empty_context->SetValue(client_id_, &empty_context_variant))) { - DVLOG(1) << "Failed to set empty context."; - return false; - } - - return true; -} - -bool TSFBridgeDelegate::IsFocused(ITfDocumentMgr* document_manager) { - base::win::ScopedComPtr<ITfDocumentMgr> focused_document_manager; - if (FAILED(thread_manager_->GetFocus(focused_document_manager.Receive()))) - return false; - return focused_document_manager.IsSameObject(document_manager); -} - -bool TSFBridgeDelegate::IsInitialized() { - return client_id_ != TF_CLIENTID_NULL; -} - -void TSFBridgeDelegate::UpdateAssociateFocus() { - if (attached_window_handle_ == NULL) - return; - TSFDocument* document = GetAssociatedDocument(); - if (document == NULL) { - ClearAssociateFocus(); - return; - } - // NOTE: ITfThreadMgr::AssociateFocus does not increment the ref count of - // the document manager to be attached. It is our responsibility to make sure - // the attached document manager will not be destroyed while it is attached. - // This should be true as long as TSFBridge::Shutdown() is called late phase - // of UI thread shutdown. - base::win::ScopedComPtr<ITfDocumentMgr> previous_focus; - thread_manager_->AssociateFocus( - attached_window_handle_, document->document_manager.get(), - previous_focus.Receive()); -} - -void TSFBridgeDelegate::ClearAssociateFocus() { - if (attached_window_handle_ == NULL) - return; - base::win::ScopedComPtr<ITfDocumentMgr> previous_focus; - thread_manager_->AssociateFocus( - attached_window_handle_, NULL, previous_focus.Receive()); -} - -TSFBridgeDelegate::TSFDocument* TSFBridgeDelegate::GetAssociatedDocument() { - if (!client_) - return NULL; - TSFDocumentMap::iterator it = - tsf_document_map_.find(client_->GetTextInputType()); - if (it == tsf_document_map_.end()) { - it = tsf_document_map_.find(TEXT_INPUT_TYPE_TEXT); - // This check is necessary because it's possible that we failed to - // initialize |tsf_document_map_| and it has no TEXT_INPUT_TYPE_TEXT. - if (it == tsf_document_map_.end()) - return NULL; - } - return &it->second; -} - -} // namespace - - -// TsfBridge ----------------------------------------------------------------- - -TSFBridge::TSFBridge() { -} - -TSFBridge::~TSFBridge() { -} - -// static -bool TSFBridge::Initialize() { - if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - DVLOG(1) << "Do not use TSFBridge without UI thread."; - return false; - } - if (!tls_tsf_bridge.initialized()) { - tls_tsf_bridge.Initialize(TSFBridge::Finalize); - } - TSFBridgeDelegate* delegate = - static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); - if (delegate) - return true; - delegate = new TSFBridgeDelegate(); - tls_tsf_bridge.Set(delegate); - return delegate->Initialize(); -} - -// static -TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) { - if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - DVLOG(1) << "Do not use TSFBridge without UI thread."; - return NULL; - } - TSFBridge* old_bridge = TSFBridge::GetInstance(); - tls_tsf_bridge.Set(bridge); - return old_bridge; -} - -// static -void TSFBridge::Shutdown() { - if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - DVLOG(1) << "Do not use TSFBridge without UI thread."; - } - if (tls_tsf_bridge.initialized()) { - TSFBridgeDelegate* delegate = - static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); - tls_tsf_bridge.Set(NULL); - delete delegate; - } -} - -// static -TSFBridge* TSFBridge::GetInstance() { - if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - DVLOG(1) << "Do not use TSFBridge without UI thread."; - return NULL; - } - TSFBridgeDelegate* delegate = - static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get()); - DCHECK(delegate) << "Do no call GetInstance before TSFBridge::Initialize."; - return delegate; -} - -// static -void TSFBridge::Finalize(void* data) { - TSFBridgeDelegate* delegate = static_cast<TSFBridgeDelegate*>(data); - delete delegate; -} - -} // namespace ui diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h deleted file mode 100644 index 6256fac166a..00000000000 --- a/chromium/ui/base/ime/win/tsf_bridge.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_WIN_TSF_BRIDGE_H_ -#define UI_BASE_IME_WIN_TSF_BRIDGE_H_ - -#include <Windows.h> -#include <msctf.h> - -#include "base/basictypes.h" -#include "base/win/scoped_comptr.h" -#include "ui/base/ui_export.h" - -namespace ui { -class TextInputClient; - -// TSFBridge provides high level IME related operations on top of Text Services -// Framework (TSF). TSFBridge is managed by TLS because TSF related stuff is -// associated with each thread and not allowed to access across thread boundary. -// To be consistent with IMM32 behavior, TSFBridge is shared in the same thread. -// TSFBridge is used by the web content text inputting field, for example -// DisableIME() should be called if a password field is focused. -// -// TSFBridge also manages connectivity between TSFTextStore which is the backend -// of text inputting and current focused TextInputClient. -// -// All methods in this class must be used in UI thread. -class UI_EXPORT TSFBridge { - public: - virtual ~TSFBridge(); - - // Returns the thread local TSFBridge instance. Initialize() must be called - // first. Do not cache this pointer and use it after TSFBridge Shutdown(). - static TSFBridge* GetInstance(); - - // Sets the thread local instance. Must be called before any calls to - // GetInstance(). - static bool Initialize(); - - // Injects an alternative TSFBridge such as MockTSFBridge for testing. The - // injected object should be released by the caller. This function returns - // previous TSFBridge pointer with ownership. - static TSFBridge* ReplaceForTesting(TSFBridge* bridge); - - // Destroys the thread local instance. - static void Shutdown(); - - // Handles TextInputTypeChanged event. RWHVW is responsible for calling this - // handler whenever renderer's input text type is changed. Does nothing - // unless |client| is focused. - virtual void OnTextInputTypeChanged(const TextInputClient* client) = 0; - - // Sends an event to TSF manager that the text layout should be updated. - virtual void OnTextLayoutChanged() = 0; - - // Cancels the ongoing composition if exists. - // Returns true if there is no composition. - // Returns false if an edit session is on-going. - // Returns false if an error occures. - virtual bool CancelComposition() = 0; - - // Confirms the ongoing composition if exists. - // Returns true if there is no composition. - // Returns false if an edit session is on-going. - // Returns false if an error occures. - virtual bool ConfirmComposition() = 0; - - // Sets currently focused TextInputClient. - // Caller must free |client|. - virtual void SetFocusedClient(HWND focused_window, - TextInputClient* client) = 0; - - // Removes currently focused TextInputClient. - // Caller must free |client|. - virtual void RemoveFocusedClient(TextInputClient* client) = 0; - - // Obtains current thread manager. - virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() = 0; - - // Returns the focused text input client. - virtual TextInputClient* GetFocusedTextInputClient() const = 0; - - protected: - // Uses GetInstance() instead. - TSFBridge(); - - private: - // Releases TLS instance. - static void Finalize(void* data); - - DISALLOW_COPY_AND_ASSIGN(TSFBridge); -}; - -} // namespace ui - -#endif // UI_BASE_IME_WIN_TSF_BRIDGE_H_ diff --git a/chromium/ui/base/ime/win/tsf_event_router.cc b/chromium/ui/base/ime/win/tsf_event_router.cc deleted file mode 100644 index 4f34a048eec..00000000000 --- a/chromium/ui/base/ime/win/tsf_event_router.cc +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/base/ime/win/tsf_event_router.h" - -#include <msctf.h> -#include <set> -#include <utility> - -#include "base/bind.h" -#include "base/win/scoped_comptr.h" -#include "base/win/metro.h" -#include "ui/base/win/atl_module.h" -#include "ui/gfx/range/range.h" - -namespace ui { - - -// TSFEventRouter::Delegate ------------------------------------ - -// The implementation class of ITfUIElementSink, whose member functions will be -// called back by TSF when the UI element status is changed, for example when -// the candidate window is opened or closed. This class also implements -// ITfTextEditSink, whose member function is called back by TSF when the text -// editting session is finished. -class ATL_NO_VTABLE TSFEventRouter::Delegate - : public ATL::CComObjectRootEx<CComSingleThreadModel>, - public ITfUIElementSink, - public ITfTextEditSink { - public: - BEGIN_COM_MAP(Delegate) - COM_INTERFACE_ENTRY(ITfUIElementSink) - COM_INTERFACE_ENTRY(ITfTextEditSink) - END_COM_MAP() - - Delegate(); - ~Delegate(); - - // ITfTextEditSink: - STDMETHOD(OnEndEdit)(ITfContext* context, TfEditCookie read_only_cookie, - ITfEditRecord* edit_record) OVERRIDE; - - // ITfUiElementSink: - STDMETHOD(BeginUIElement)(DWORD element_id, BOOL* is_show) OVERRIDE; - STDMETHOD(UpdateUIElement)(DWORD element_id) OVERRIDE; - STDMETHOD(EndUIElement)(DWORD element_id) OVERRIDE; - - // Sets |thread_manager| to be monitored. |thread_manager| can be NULL. - void SetManager(ITfThreadMgr* thread_manager); - - // Returns true if the IME is composing text. - bool IsImeComposing(); - - // Sets |router| to be forwarded TSF-related events. - void SetRouter(TSFEventRouter* router); - - private: - // Returns current composition range. Returns gfx::Range::InvalidRange if - // there is no composition. - static gfx::Range GetCompositionRange(ITfContext* context); - - // Returns true if the given |element_id| represents the candidate window. - bool IsCandidateWindowInternal(DWORD element_id); - - // A context associated with this class. - base::win::ScopedComPtr<ITfContext> context_; - - // The ITfSource associated with |context_|. - base::win::ScopedComPtr<ITfSource> context_source_; - - // The cookie for |context_source_|. - DWORD context_source_cookie_; - - // A UIElementMgr associated with this class. - base::win::ScopedComPtr<ITfUIElementMgr> ui_element_manager_; - - // The ITfSouce associated with |ui_element_manager_|. - base::win::ScopedComPtr<ITfSource> ui_source_; - - // The set of currently opened candidate window ids. - std::set<DWORD> open_candidate_window_ids_; - - // The cookie for |ui_source_|. - DWORD ui_source_cookie_; - - TSFEventRouter* router_; - gfx::Range previous_composition_range_; - - DISALLOW_COPY_AND_ASSIGN(Delegate); -}; - -TSFEventRouter::Delegate::Delegate() - : context_source_cookie_(TF_INVALID_COOKIE), - ui_source_cookie_(TF_INVALID_COOKIE), - router_(NULL), - previous_composition_range_(gfx::Range::InvalidRange()) { -} - -TSFEventRouter::Delegate::~Delegate() {} - -void TSFEventRouter::Delegate::SetRouter(TSFEventRouter* router) { - router_ = router; -} - -STDMETHODIMP TSFEventRouter::Delegate::OnEndEdit(ITfContext* context, - TfEditCookie read_only_cookie, - ITfEditRecord* edit_record) { - if (!edit_record || !context) - return E_INVALIDARG; - if (!router_) - return S_OK; - - // |edit_record| can be used to obtain updated ranges in terms of text - // contents and/or text attributes. Here we are interested only in text update - // so we use TF_GTP_INCL_TEXT and check if there is any range which contains - // updated text. - base::win::ScopedComPtr<IEnumTfRanges> ranges; - if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, - ranges.Receive()))) - return S_OK; // Don't care about failures. - - ULONG fetched_count = 0; - base::win::ScopedComPtr<ITfRange> range; - if (FAILED(ranges->Next(1, range.Receive(), &fetched_count))) - return S_OK; // Don't care about failures. - - const gfx::Range composition_range = GetCompositionRange(context); - - if (!previous_composition_range_.IsValid() && composition_range.IsValid()) - router_->OnTSFStartComposition(); - - // |fetched_count| != 0 means there is at least one range that contains - // updated text. - if (fetched_count != 0) - router_->OnTextUpdated(composition_range); - - if (previous_composition_range_.IsValid() && !composition_range.IsValid()) - router_->OnTSFEndComposition(); - - previous_composition_range_ = composition_range; - return S_OK; -} - -STDMETHODIMP TSFEventRouter::Delegate::BeginUIElement(DWORD element_id, - BOOL* is_show) { - if (is_show) - *is_show = TRUE; // Without this the UI element will not be shown. - - if (!IsCandidateWindowInternal(element_id)) - return S_OK; - - std::pair<std::set<DWORD>::iterator, bool> insert_result = - open_candidate_window_ids_.insert(element_id); - // Don't call if |router_| is null or |element_id| is already handled. - if (router_ && insert_result.second) - router_->OnCandidateWindowCountChanged(open_candidate_window_ids_.size()); - - return S_OK; -} - -STDMETHODIMP TSFEventRouter::Delegate::UpdateUIElement( - DWORD element_id) { - return S_OK; -} - -STDMETHODIMP TSFEventRouter::Delegate::EndUIElement( - DWORD element_id) { - if ((open_candidate_window_ids_.erase(element_id) != 0) && router_) - router_->OnCandidateWindowCountChanged(open_candidate_window_ids_.size()); - return S_OK; -} - -void TSFEventRouter::Delegate::SetManager( - ITfThreadMgr* thread_manager) { - context_.Release(); - - if (context_source_) { - context_source_->UnadviseSink(context_source_cookie_); - context_source_.Release(); - } - context_source_cookie_ = TF_INVALID_COOKIE; - - ui_element_manager_.Release(); - if (ui_source_) { - ui_source_->UnadviseSink(ui_source_cookie_); - ui_source_.Release(); - } - ui_source_cookie_ = TF_INVALID_COOKIE; - - if (!thread_manager) - return; - - base::win::ScopedComPtr<ITfDocumentMgr> document_manager; - if (FAILED(thread_manager->GetFocus(document_manager.Receive())) || - !document_manager.get() || - FAILED(document_manager->GetBase(context_.Receive())) || - FAILED(context_source_.QueryFrom(context_))) - return; - context_source_->AdviseSink(IID_ITfTextEditSink, - static_cast<ITfTextEditSink*>(this), - &context_source_cookie_); - - if (FAILED(ui_element_manager_.QueryFrom(thread_manager)) || - FAILED(ui_source_.QueryFrom(ui_element_manager_))) - return; - ui_source_->AdviseSink(IID_ITfUIElementSink, - static_cast<ITfUIElementSink*>(this), - &ui_source_cookie_); -} - -bool TSFEventRouter::Delegate::IsImeComposing() { - return context_ && GetCompositionRange(context_).IsValid(); -} - -// static -gfx::Range TSFEventRouter::Delegate::GetCompositionRange( - ITfContext* context) { - DCHECK(context); - base::win::ScopedComPtr<ITfContextComposition> context_composition; - if (FAILED(context_composition.QueryFrom(context))) - return gfx::Range::InvalidRange(); - base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view; - if (FAILED(context_composition->EnumCompositions( - enum_composition_view.Receive()))) - return gfx::Range::InvalidRange(); - base::win::ScopedComPtr<ITfCompositionView> composition_view; - if (enum_composition_view->Next(1, composition_view.Receive(), - NULL) != S_OK) - return gfx::Range::InvalidRange(); - - base::win::ScopedComPtr<ITfRange> range; - if (FAILED(composition_view->GetRange(range.Receive()))) - return gfx::Range::InvalidRange(); - - base::win::ScopedComPtr<ITfRangeACP> range_acp; - if (FAILED(range_acp.QueryFrom(range))) - return gfx::Range::InvalidRange(); - - LONG start = 0; - LONG length = 0; - if (FAILED(range_acp->GetExtent(&start, &length))) - return gfx::Range::InvalidRange(); - - return gfx::Range(start, start + length); -} - -bool TSFEventRouter::Delegate::IsCandidateWindowInternal(DWORD element_id) { - DCHECK(ui_element_manager_.get()); - base::win::ScopedComPtr<ITfUIElement> ui_element; - if (FAILED(ui_element_manager_->GetUIElement(element_id, - ui_element.Receive()))) - return false; - base::win::ScopedComPtr<ITfCandidateListUIElement> candidate_list_ui_element; - return SUCCEEDED(candidate_list_ui_element.QueryFrom(ui_element)); -} - - -// TSFEventRouter ------------------------------------------------------------ - -TSFEventRouter::TSFEventRouter(TSFEventRouterObserver* observer) - : observer_(observer), - delegate_(NULL) { - DCHECK(base::win::IsTSFAwareRequired()) - << "Do not use TSFEventRouter without TSF environment."; - DCHECK(observer_); - CComObject<Delegate>* delegate; - ui::win::CreateATLModuleIfNeeded(); - if (SUCCEEDED(CComObject<Delegate>::CreateInstance(&delegate))) { - delegate->AddRef(); - delegate_.Attach(delegate); - delegate_->SetRouter(this); - } -} - -TSFEventRouter::~TSFEventRouter() { - if (delegate_) { - delegate_->SetManager(NULL); - delegate_->SetRouter(NULL); - } -} - -bool TSFEventRouter::IsImeComposing() { - return delegate_->IsImeComposing(); -} - -void TSFEventRouter::OnCandidateWindowCountChanged(size_t window_count) { - observer_->OnCandidateWindowCountChanged(window_count); -} - -void TSFEventRouter::OnTSFStartComposition() { - observer_->OnTSFStartComposition(); -} - -void TSFEventRouter::OnTextUpdated(const gfx::Range& composition_range) { - observer_->OnTextUpdated(composition_range); -} - -void TSFEventRouter::OnTSFEndComposition() { - observer_->OnTSFEndComposition(); -} - -void TSFEventRouter::SetManager(ITfThreadMgr* thread_manager) { - delegate_->SetManager(thread_manager); -} - -} // namespace ui diff --git a/chromium/ui/base/ime/win/tsf_event_router.h b/chromium/ui/base/ime/win/tsf_event_router.h deleted file mode 100644 index 04a2a1e9eb0..00000000000 --- a/chromium/ui/base/ime/win/tsf_event_router.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_ -#define UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_ - -#include <atlbase.h> -#include <atlcom.h> -#include <msctf.h> - -#include <set> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "ui/base/ime/text_input_type.h" -#include "ui/base/ui_export.h" -#include "ui/gfx/range/range.h" - -struct ITfDocumentMgr; - -namespace ui { - -class TSFEventRouterObserver { - public: - TSFEventRouterObserver() {} - - // Called when the number of currently opened candidate windows changes. - virtual void OnCandidateWindowCountChanged(size_t window_count) {} - - // Called when a composition is started. - virtual void OnTSFStartComposition() {} - - // Called when the text contents are updated. If there is no composition, - // gfx::Range::InvalidRange is passed to |composition_range|. - virtual void OnTextUpdated(const gfx::Range& composition_range) {} - - // Called when a composition is terminated. - virtual void OnTSFEndComposition() {} - - protected: - virtual ~TSFEventRouterObserver() {} - - private: - DISALLOW_COPY_AND_ASSIGN(TSFEventRouterObserver); -}; - -// This class monitores TSF related events and forwards them to given -// |observer|. -class UI_EXPORT TSFEventRouter { - public: - // Do not pass NULL to |observer|. - explicit TSFEventRouter(TSFEventRouterObserver* observer); - virtual ~TSFEventRouter(); - - // Returns true if the IME is composing text. - bool IsImeComposing(); - - // Callbacks from the TSFEventRouterDelegate: - void OnCandidateWindowCountChanged(size_t window_count); - void OnTSFStartComposition(); - void OnTextUpdated(const gfx::Range& composition_range); - void OnTSFEndComposition(); - - // Sets |thread_manager| to be monitored. |thread_manager| can be NULL. - void SetManager(ITfThreadMgr* thread_manager); - - private: - class Delegate; - - CComPtr<Delegate> delegate_; - - TSFEventRouterObserver* observer_; - - DISALLOW_COPY_AND_ASSIGN(TSFEventRouter); -}; - -} // namespace ui - -#endif // UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_ diff --git a/chromium/ui/base/ime/win/tsf_input_scope.cc b/chromium/ui/base/ime/win/tsf_input_scope.cc index 06481e9d8f0..f40f928a5f7 100644 --- a/chromium/ui/base/ime/win/tsf_input_scope.cc +++ b/chromium/ui/base/ime/win/tsf_input_scope.cc @@ -29,7 +29,7 @@ void AppendNonTrivialInputScope(std::vector<InputScope>* input_scopes, input_scopes->push_back(input_scope); } -class TSFInputScope : public ITfInputScope { +class TSFInputScope FINAL : public ITfInputScope { public: explicit TSFInputScope(const std::vector<InputScope>& input_scopes) : input_scopes_(input_scopes), @@ -116,7 +116,7 @@ SetInputScopesFunc g_set_input_scopes = NULL; bool g_get_proc_done = false; SetInputScopesFunc GetSetInputScopes() { - DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); + DCHECK(base::MessageLoopForUI::IsCurrent()); // Thread safety is not required because this function is under UI thread. if (!g_get_proc_done) { g_get_proc_done = true; diff --git a/chromium/ui/base/ime/win/tsf_input_scope.h b/chromium/ui/base/ime/win/tsf_input_scope.h index 2e5856c60d8..536d395dce1 100644 --- a/chromium/ui/base/ime/win/tsf_input_scope.h +++ b/chromium/ui/base/ime/win/tsf_input_scope.h @@ -12,7 +12,7 @@ #include "base/basictypes.h" #include "ui/base/ime/text_input_mode.h" #include "ui/base/ime/text_input_type.h" -#include "ui/base/ui_export.h" +#include "ui/base/ui_base_export.h" namespace ui { namespace tsf_inputscope { @@ -20,8 +20,9 @@ namespace tsf_inputscope { // Returns InputScope list corresoponding to ui::TextInputType and // ui::TextInputMode. // This function is only used from following functions but declared for test. -UI_EXPORT std::vector<InputScope> GetInputScopes(TextInputType text_input_type, - TextInputMode text_input_mode); +UI_BASE_EXPORT std::vector<InputScope> GetInputScopes( + TextInputType text_input_type, + TextInputMode text_input_mode); // Returns an instance of ITfInputScope, which is the Windows-specific // category representation corresponding to ui::TextInputType and @@ -29,14 +30,14 @@ UI_EXPORT std::vector<InputScope> GetInputScopes(TextInputType text_input_type, // in the target field. // The returned instance has 0 reference count. The caller must maintain its // reference count. -UI_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type, - TextInputMode text_input_mode); +UI_BASE_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type, + TextInputMode text_input_mode); // A wrapper of the SetInputScopes API exported by msctf.dll. // http://msdn.microsoft.com/en-us/library/windows/desktop/ms629026.aspx // Does nothing on Windows XP in case TSF is disabled. // NOTE: For TSF-aware window, you should use ITfInputScope instead. -UI_EXPORT void SetInputScopeForTsfUnawareWindow( +UI_BASE_EXPORT void SetInputScopeForTsfUnawareWindow( HWND window_handle, TextInputType text_input_type, TextInputMode text_input_mode); diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc deleted file mode 100644 index 0ef34b5be89..00000000000 --- a/chromium/ui/base/ime/win/tsf_text_store.cc +++ /dev/null @@ -1,923 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#define INITGUID // required for GUID_PROP_INPUTSCOPE -#include "ui/base/ime/win/tsf_text_store.h" - -#include <InputScope.h> -#include <OleCtl.h> - -#include <algorithm> - -#include "base/win/scoped_variant.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/ime/win/tsf_input_scope.h" -#include "ui/gfx/rect.h" - -namespace ui { -namespace { - -// We support only one view. -const TsViewCookie kViewCookie = 1; - -} // namespace - -TSFTextStore::TSFTextStore() - : ref_count_(0), - text_store_acp_sink_mask_(0), - window_handle_(NULL), - text_input_client_(NULL), - committed_size_(0), - edit_flag_(false), - current_lock_type_(0) { - if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) { - LOG(FATAL) << "Failed to initialize CategoryMgr."; - return; - } - if (FAILED(display_attribute_manager_.CreateInstance( - CLSID_TF_DisplayAttributeMgr))) { - LOG(FATAL) << "Failed to initialize DisplayAttributeMgr."; - return; - } -} - -TSFTextStore::~TSFTextStore() { -} - -ULONG STDMETHODCALLTYPE TSFTextStore::AddRef() { - return InterlockedIncrement(&ref_count_); -} - -ULONG STDMETHODCALLTYPE TSFTextStore::Release() { - const LONG count = InterlockedDecrement(&ref_count_); - if (!count) { - delete this; - return 0; - } - return static_cast<ULONG>(count); -} - -STDMETHODIMP TSFTextStore::QueryInterface(REFIID iid, void** result) { - if (iid == IID_IUnknown || iid == IID_ITextStoreACP) { - *result = static_cast<ITextStoreACP*>(this); - } else if (iid == IID_ITfContextOwnerCompositionSink) { - *result = static_cast<ITfContextOwnerCompositionSink*>(this); - } else if (iid == IID_ITfTextEditSink) { - *result = static_cast<ITfTextEditSink*>(this); - } else { - *result = NULL; - return E_NOINTERFACE; - } - AddRef(); - return S_OK; -} - -STDMETHODIMP TSFTextStore::AdviseSink(REFIID iid, - IUnknown* unknown, - DWORD mask) { - if (!IsEqualGUID(iid, IID_ITextStoreACPSink)) - return E_INVALIDARG; - if (text_store_acp_sink_) { - if (text_store_acp_sink_.IsSameObject(unknown)) { - text_store_acp_sink_mask_ = mask; - return S_OK; - } else { - return CONNECT_E_ADVISELIMIT; - } - } - if (FAILED(text_store_acp_sink_.QueryFrom(unknown))) - return E_UNEXPECTED; - text_store_acp_sink_mask_ = mask; - - return S_OK; -} - -STDMETHODIMP TSFTextStore::FindNextAttrTransition( - LONG acp_start, - LONG acp_halt, - ULONG num_filter_attributes, - const TS_ATTRID* filter_attributes, - DWORD flags, - LONG* acp_next, - BOOL* found, - LONG* found_offset) { - if (!acp_next || !found || !found_offset) - return E_INVALIDARG; - // We don't support any attributes. - // So we always return "not found". - *acp_next = 0; - *found = FALSE; - *found_offset = 0; - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetACPFromPoint(TsViewCookie view_cookie, - const POINT* point, - DWORD flags, - LONG* acp) { - NOTIMPLEMENTED(); - if (view_cookie != kViewCookie) - return E_INVALIDARG; - return E_NOTIMPL; -} - -STDMETHODIMP TSFTextStore::GetActiveView(TsViewCookie* view_cookie) { - if (!view_cookie) - return E_INVALIDARG; - // We support only one view. - *view_cookie = kViewCookie; - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetEmbedded(LONG acp_pos, - REFGUID service, - REFIID iid, - IUnknown** unknown) { - // We don't support any embedded objects. - NOTIMPLEMENTED(); - if (!unknown) - return E_INVALIDARG; - *unknown = NULL; - return E_NOTIMPL; -} - -STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) { - if (!acp) - return E_INVALIDARG; - if (!HasReadLock()) - return TS_E_NOLOCK; - *acp = string_buffer_.size(); - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetFormattedText(LONG acp_start, LONG acp_end, - IDataObject** data_object) { - NOTIMPLEMENTED(); - return E_NOTIMPL; -} - -STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) { - if (view_cookie != kViewCookie) - return E_INVALIDARG; - if (!rect) - return E_INVALIDARG; - - // {0, 0, 0, 0} means that the document rect is not currently displayed. - SetRect(rect, 0, 0, 0, 0); - - if (!IsWindow(window_handle_)) - return E_FAIL; - - // Currently ui::TextInputClient does not expose the document rect. So use - // the Win32 client rectangle instead. - // TODO(yukawa): Upgrade TextInputClient so that the client can retrieve the - // document rectangle. - RECT client_rect = {}; - if (!GetClientRect(window_handle_, &client_rect)) - return E_FAIL; - POINT left_top = {client_rect.left, client_rect.top}; - POINT right_bottom = {client_rect.right, client_rect.bottom}; - if (!ClientToScreen(window_handle_, &left_top)) - return E_FAIL; - if (!ClientToScreen(window_handle_, &right_bottom)) - return E_FAIL; - - rect->left = left_top.x; - rect->top = left_top.y; - rect->right = right_bottom.x; - rect->bottom = right_bottom.y; - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetSelection(ULONG selection_index, - ULONG selection_buffer_size, - TS_SELECTION_ACP* selection_buffer, - ULONG* fetched_count) { - if (!selection_buffer) - return E_INVALIDARG; - if (!fetched_count) - return E_INVALIDARG; - if (!HasReadLock()) - return TS_E_NOLOCK; - *fetched_count = 0; - if ((selection_buffer_size > 0) && - ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) { - selection_buffer[0].acpStart = selection_.start(); - selection_buffer[0].acpEnd = selection_.end(); - selection_buffer[0].style.ase = TS_AE_END; - selection_buffer[0].style.fInterimChar = FALSE; - *fetched_count = 1; - } - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetStatus(TS_STATUS* status) { - if (!status) - return E_INVALIDARG; - - status->dwDynamicFlags = 0; - // We use transitory contexts and we don't support hidden text. - status->dwStaticFlags = TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT; - - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetText(LONG acp_start, - LONG acp_end, - wchar_t* text_buffer, - ULONG text_buffer_size, - ULONG* text_buffer_copied, - TS_RUNINFO* run_info_buffer, - ULONG run_info_buffer_size, - ULONG* run_info_buffer_copied, - LONG* next_acp) { - if (!text_buffer_copied || !run_info_buffer_copied) - return E_INVALIDARG; - if (!text_buffer && text_buffer_size != 0) - return E_INVALIDARG; - if (!run_info_buffer && run_info_buffer_size != 0) - return E_INVALIDARG; - if (!next_acp) - return E_INVALIDARG; - if (!HasReadLock()) - return TF_E_NOLOCK; - const LONG string_buffer_size = string_buffer_.size(); - if (acp_end == -1) - acp_end = string_buffer_size; - if (!((0 <= acp_start) && - (acp_start <= acp_end) && - (acp_end <= string_buffer_size))) { - return TF_E_INVALIDPOS; - } - acp_end = std::min(acp_end, acp_start + static_cast<LONG>(text_buffer_size)); - *text_buffer_copied = acp_end - acp_start; - - const string16& result = - string_buffer_.substr(acp_start, *text_buffer_copied); - for (size_t i = 0; i < result.size(); ++i) { - text_buffer[i] = result[i]; - } - - if (run_info_buffer_size) { - run_info_buffer[0].uCount = *text_buffer_copied; - run_info_buffer[0].type = TS_RT_PLAIN; - *run_info_buffer_copied = 1; - } - - *next_acp = acp_end; - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, - LONG acp_start, - LONG acp_end, - RECT* rect, - BOOL* clipped) { - if (!rect || !clipped) - return E_INVALIDARG; - if (!text_input_client_) - return E_UNEXPECTED; - if (view_cookie != kViewCookie) - return E_INVALIDARG; - if (!HasReadLock()) - return TS_E_NOLOCK; - if (!((static_cast<LONG>(committed_size_) <= acp_start) && - (acp_start <= acp_end) && - (acp_end <= static_cast<LONG>(string_buffer_.size())))) { - return TS_E_INVALIDPOS; - } - - // According to a behavior of notepad.exe and wordpad.exe, top left corner of - // rect indicates a first character's one, and bottom right corner of rect - // indicates a last character's one. - // We use RECT instead of gfx::Rect since left position may be bigger than - // right position when composition has multiple lines. - RECT result; - gfx::Rect tmp_rect; - const uint32 start_pos = acp_start - committed_size_; - const uint32 end_pos = acp_end - committed_size_; - - if (start_pos == end_pos) { - // According to MSDN document, if |acp_start| and |acp_end| are equal it is - // OK to just return E_INVALIDARG. - // http://msdn.microsoft.com/en-us/library/ms538435 - // But when using Pinin IME of Windows 8, this method is called with the - // equal values of |acp_start| and |acp_end|. So we handle this condition. - if (start_pos == 0) { - if (text_input_client_->GetCompositionCharacterBounds(0, &tmp_rect)) { - tmp_rect.set_width(0); - result = tmp_rect.ToRECT(); - } else if (string_buffer_.size() == committed_size_) { - result = text_input_client_->GetCaretBounds().ToRECT(); - } else { - return TS_E_NOLAYOUT; - } - } else if (text_input_client_->GetCompositionCharacterBounds(start_pos - 1, - &tmp_rect)) { - result.left = tmp_rect.right(); - result.right = tmp_rect.right(); - result.top = tmp_rect.y(); - result.bottom = tmp_rect.bottom(); - } else { - return TS_E_NOLAYOUT; - } - } else { - if (text_input_client_->GetCompositionCharacterBounds(start_pos, - &tmp_rect)) { - result.left = tmp_rect.x(); - result.top = tmp_rect.y(); - result.right = tmp_rect.right(); - result.bottom = tmp_rect.bottom(); - if (text_input_client_->GetCompositionCharacterBounds(end_pos - 1, - &tmp_rect)) { - result.right = tmp_rect.right(); - result.bottom = tmp_rect.bottom(); - } else { - // We may not be able to get the last character bounds, so we use the - // first character bounds instead of returning TS_E_NOLAYOUT. - } - } else { - // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so - // it's better to return previous caret rectangle instead. - // TODO(nona, kinaba): Remove this hack. - if (start_pos == 0) { - result = text_input_client_->GetCaretBounds().ToRECT(); - } else { - return TS_E_NOLAYOUT; - } - } - } - - *rect = result; - *clipped = FALSE; - return S_OK; -} - -STDMETHODIMP TSFTextStore::GetWnd(TsViewCookie view_cookie, - HWND* window_handle) { - if (!window_handle) - return E_INVALIDARG; - if (view_cookie != kViewCookie) - return E_INVALIDARG; - *window_handle = window_handle_; - return S_OK; -} - -STDMETHODIMP TSFTextStore::InsertEmbedded(DWORD flags, - LONG acp_start, - LONG acp_end, - IDataObject* data_object, - TS_TEXTCHANGE* change) { - // We don't support any embedded objects. - NOTIMPLEMENTED(); - return E_NOTIMPL; -} - -STDMETHODIMP TSFTextStore::InsertEmbeddedAtSelection(DWORD flags, - IDataObject* data_object, - LONG* acp_start, - LONG* acp_end, - TS_TEXTCHANGE* change) { - // We don't support any embedded objects. - NOTIMPLEMENTED(); - return E_NOTIMPL; -} - -STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags, - const wchar_t* text_buffer, - ULONG text_buffer_size, - LONG* acp_start, - LONG* acp_end, - TS_TEXTCHANGE* text_change) { - const LONG start_pos = selection_.start(); - const LONG end_pos = selection_.end(); - const LONG new_end_pos = start_pos + text_buffer_size; - - if (flags & TS_IAS_QUERYONLY) { - if (!HasReadLock()) - return TS_E_NOLOCK; - if (acp_start) - *acp_start = start_pos; - if (acp_end) { - *acp_end = end_pos; - } - return S_OK; - } - - if (!HasReadWriteLock()) - return TS_E_NOLOCK; - if (!text_buffer) - return E_INVALIDARG; - - DCHECK_LE(start_pos, end_pos); - string_buffer_ = string_buffer_.substr(0, start_pos) + - string16(text_buffer, text_buffer + text_buffer_size) + - string_buffer_.substr(end_pos); - if (acp_start) - *acp_start = start_pos; - if (acp_end) - *acp_end = new_end_pos; - if (text_change) { - text_change->acpStart = start_pos; - text_change->acpOldEnd = end_pos; - text_change->acpNewEnd = new_end_pos; - } - selection_.set_start(start_pos); - selection_.set_end(new_end_pos); - return S_OK; -} - -STDMETHODIMP TSFTextStore::QueryInsert( - LONG acp_test_start, - LONG acp_test_end, - ULONG text_size, - LONG* acp_result_start, - LONG* acp_result_end) { - if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end) - return E_INVALIDARG; - const LONG committed_size = static_cast<LONG>(committed_size_); - const LONG buffer_size = static_cast<LONG>(string_buffer_.size()); - *acp_result_start = std::min(std::max(committed_size, acp_test_start), - buffer_size); - *acp_result_end = std::min(std::max(committed_size, acp_test_end), - buffer_size); - return S_OK; -} - -STDMETHODIMP TSFTextStore::QueryInsertEmbedded(const GUID* service, - const FORMATETC* format, - BOOL* insertable) { - if (!format) - return E_INVALIDARG; - // We don't support any embedded objects. - if (insertable) - *insertable = FALSE; - return S_OK; -} - -STDMETHODIMP TSFTextStore::RequestAttrsAtPosition( - LONG acp_pos, - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer, - DWORD flags) { - // We don't support any document attributes. - // This method just returns S_OK, and the subsequently called - // RetrieveRequestedAttrs() returns 0 as the number of supported attributes. - return S_OK; -} - -STDMETHODIMP TSFTextStore::RequestAttrsTransitioningAtPosition( - LONG acp_pos, - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer, - DWORD flags) { - // We don't support any document attributes. - // This method just returns S_OK, and the subsequently called - // RetrieveRequestedAttrs() returns 0 as the number of supported attributes. - return S_OK; -} - -STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { - if (!text_store_acp_sink_.get()) - return E_FAIL; - if (!result) - return E_INVALIDARG; - - if (current_lock_type_ != 0) { - if (lock_flags & TS_LF_SYNC) { - // Can't lock synchronously. - *result = TS_E_SYNCHRONOUS; - return S_OK; - } - // Queue the lock request. - lock_queue_.push_back(lock_flags & TS_LF_READWRITE); - *result = TS_S_ASYNC; - return S_OK; - } - - // Lock - current_lock_type_ = (lock_flags & TS_LF_READWRITE); - - edit_flag_ = false; - const size_t last_committed_size = committed_size_; - - // Grant the lock. - *result = text_store_acp_sink_->OnLockGranted(current_lock_type_); - - // Unlock - current_lock_type_ = 0; - - // Handles the pending lock requests. - while (!lock_queue_.empty()) { - current_lock_type_ = lock_queue_.front(); - lock_queue_.pop_front(); - text_store_acp_sink_->OnLockGranted(current_lock_type_); - current_lock_type_ = 0; - } - - if (!edit_flag_) { - return S_OK; - } - - // If the text store is edited in OnLockGranted(), we may need to call - // TextInputClient::InsertText() or TextInputClient::SetCompositionText(). - const size_t new_committed_size = committed_size_; - const string16& new_committed_string = - string_buffer_.substr(last_committed_size, - new_committed_size - last_committed_size); - const string16& composition_string = - string_buffer_.substr(new_committed_size); - - // If there is new committed string, calls TextInputClient::InsertText(). - if ((!new_committed_string.empty()) && text_input_client_) { - text_input_client_->InsertText(new_committed_string); - } - - // Calls TextInputClient::SetCompositionText(). - CompositionText composition_text; - composition_text.text = composition_string; - composition_text.underlines = composition_undelines_; - // Adjusts the offset. - for (size_t i = 0; i < composition_text.underlines.size(); ++i) { - composition_text.underlines[i].start_offset -= new_committed_size; - composition_text.underlines[i].end_offset -= new_committed_size; - } - if (selection_.start() < new_committed_size) { - composition_text.selection.set_start(0); - } else { - composition_text.selection.set_start( - selection_.start() - new_committed_size); - } - if (selection_.end() < new_committed_size) { - composition_text.selection.set_end(0); - } else { - composition_text.selection.set_end(selection_.end() - new_committed_size); - } - if (text_input_client_) - text_input_client_->SetCompositionText(composition_text); - - // If there is no composition string, clear the text store status. - // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange(). - if ((composition_string.empty()) && (new_committed_size != 0)) { - string_buffer_.clear(); - committed_size_ = 0; - selection_.set_start(0); - selection_.set_end(0); - if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) - text_store_acp_sink_->OnSelectionChange(); - if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); - if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { - TS_TEXTCHANGE textChange; - textChange.acpStart = 0; - textChange.acpOldEnd = new_committed_size; - textChange.acpNewEnd = 0; - text_store_acp_sink_->OnTextChange(0, &textChange); - } - } - - return S_OK; -} - -STDMETHODIMP TSFTextStore::RequestSupportedAttrs( - DWORD /* flags */, // Seems that we should ignore this. - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer) { - if (!attribute_buffer) - return E_INVALIDARG; - if (!text_input_client_) - return E_FAIL; - // We support only input scope attribute. - for (size_t i = 0; i < attribute_buffer_size; ++i) { - if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i])) - return S_OK; - } - return E_FAIL; -} - -STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs( - ULONG attribute_buffer_size, - TS_ATTRVAL* attribute_buffer, - ULONG* attribute_buffer_copied) { - if (!attribute_buffer_copied) - return E_INVALIDARG; - if (!attribute_buffer) - return E_INVALIDARG; - if (!text_input_client_) - return E_UNEXPECTED; - // We support only input scope attribute. - *attribute_buffer_copied = 0; - if (attribute_buffer_size == 0) - return S_OK; - - attribute_buffer[0].dwOverlapId = 0; - attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE; - attribute_buffer[0].varValue.vt = VT_UNKNOWN; - attribute_buffer[0].varValue.punkVal = tsf_inputscope::CreateInputScope( - text_input_client_->GetTextInputType(), - text_input_client_->GetTextInputMode()); - attribute_buffer[0].varValue.punkVal->AddRef(); - *attribute_buffer_copied = 1; - return S_OK; -} - -STDMETHODIMP TSFTextStore::SetSelection( - ULONG selection_buffer_size, - const TS_SELECTION_ACP* selection_buffer) { - if (!HasReadWriteLock()) - return TF_E_NOLOCK; - if (selection_buffer_size > 0) { - const LONG start_pos = selection_buffer[0].acpStart; - const LONG end_pos = selection_buffer[0].acpEnd; - if (!((static_cast<LONG>(committed_size_) <= start_pos) && - (start_pos <= end_pos) && - (end_pos <= static_cast<LONG>(string_buffer_.size())))) { - return TF_E_INVALIDPOS; - } - selection_.set_start(start_pos); - selection_.set_end(end_pos); - } - return S_OK; -} - -STDMETHODIMP TSFTextStore::SetText(DWORD flags, - LONG acp_start, - LONG acp_end, - const wchar_t* text_buffer, - ULONG text_buffer_size, - TS_TEXTCHANGE* text_change) { - if (!HasReadWriteLock()) - return TS_E_NOLOCK; - if (!((static_cast<LONG>(committed_size_) <= acp_start) && - (acp_start <= acp_end) && - (acp_end <= static_cast<LONG>(string_buffer_.size())))) { - return TS_E_INVALIDPOS; - } - - TS_SELECTION_ACP selection; - selection.acpStart = acp_start; - selection.acpEnd = acp_end; - selection.style.ase = TS_AE_NONE; - selection.style.fInterimChar = 0; - - HRESULT ret; - ret = SetSelection(1, &selection); - if (ret != S_OK) - return ret; - - TS_TEXTCHANGE change; - ret = InsertTextAtSelection(0, text_buffer, text_buffer_size, - &acp_start, &acp_end, &change); - if (ret != S_OK) - return ret; - - if (text_change) - *text_change = change; - - return S_OK; -} - -STDMETHODIMP TSFTextStore::UnadviseSink(IUnknown* unknown) { - if (!text_store_acp_sink_.IsSameObject(unknown)) - return CONNECT_E_NOCONNECTION; - text_store_acp_sink_.Release(); - text_store_acp_sink_mask_ = 0; - return S_OK; -} - -STDMETHODIMP TSFTextStore::OnStartComposition( - ITfCompositionView* composition_view, - BOOL* ok) { - if (ok) - *ok = TRUE; - return S_OK; -} - -STDMETHODIMP TSFTextStore::OnUpdateComposition( - ITfCompositionView* composition_view, - ITfRange* range) { - return S_OK; -} - -STDMETHODIMP TSFTextStore::OnEndComposition( - ITfCompositionView* composition_view) { - return S_OK; -} - -STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, - TfEditCookie read_only_edit_cookie, - ITfEditRecord* edit_record) { - if (!context || !edit_record) - return E_INVALIDARG; - - size_t committed_size; - CompositionUnderlines undelines; - if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size, - &undelines)) { - return S_OK; - } - composition_undelines_ = undelines; - committed_size_ = committed_size; - edit_flag_ = true; - return S_OK; -} - -bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom, - TF_DISPLAYATTRIBUTE* attribute) { - GUID guid; - if (FAILED(category_manager_->GetGUID(guid_atom, &guid))) - return false; - - base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info; - if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo( - guid, display_attribute_info.Receive(), NULL))) { - return false; - } - return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute)); -} - -bool TSFTextStore::GetCompositionStatus( - ITfContext* context, - const TfEditCookie read_only_edit_cookie, - size_t* committed_size, - CompositionUnderlines* undelines) { - DCHECK(context); - DCHECK(committed_size); - DCHECK(undelines); - const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE}; - base::win::ScopedComPtr<ITfReadOnlyProperty> track_property; - if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0, - track_property.Receive()))) { - return false; - } - - *committed_size = 0; - undelines->clear(); - base::win::ScopedComPtr<ITfRange> start_to_end_range; - base::win::ScopedComPtr<ITfRange> end_range; - if (FAILED(context->GetStart(read_only_edit_cookie, - start_to_end_range.Receive()))) { - return false; - } - if (FAILED(context->GetEnd(read_only_edit_cookie, end_range.Receive()))) - return false; - if (FAILED(start_to_end_range->ShiftEndToRange(read_only_edit_cookie, - end_range, TF_ANCHOR_END))) { - return false; - } - - base::win::ScopedComPtr<IEnumTfRanges> ranges; - if (FAILED(track_property->EnumRanges(read_only_edit_cookie, ranges.Receive(), - start_to_end_range))) { - return false; - } - - while (true) { - base::win::ScopedComPtr<ITfRange> range; - if (ranges->Next(1, range.Receive(), NULL) != S_OK) - break; - base::win::ScopedVariant value; - base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value; - if (FAILED(track_property->GetValue(read_only_edit_cookie, range, - value.Receive()))) { - return false; - } - if (FAILED(enum_prop_value.QueryFrom(value.AsInput()->punkVal))) - return false; - - TF_PROPERTYVAL property_value; - bool is_composition = false; - bool has_display_attribute = false; - TF_DISPLAYATTRIBUTE display_attribute; - while (enum_prop_value->Next(1, &property_value, NULL) == S_OK) { - if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) { - is_composition = (property_value.varValue.lVal == TRUE); - } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) { - TfGuidAtom guid_atom = - static_cast<TfGuidAtom>(property_value.varValue.lVal); - if (GetDisplayAttribute(guid_atom, &display_attribute)) - has_display_attribute = true; - } - VariantClear(&property_value.varValue); - } - - base::win::ScopedComPtr<ITfRangeACP> range_acp; - range_acp.QueryFrom(range); - LONG start_pos, length; - range_acp->GetExtent(&start_pos, &length); - if (!is_composition) { - if (*committed_size < static_cast<size_t>(start_pos + length)) - *committed_size = start_pos + length; - } else { - CompositionUnderline underline; - underline.start_offset = start_pos; - underline.end_offset = start_pos + length; - underline.color = SK_ColorBLACK; - if (has_display_attribute) - underline.thick = !!display_attribute.fBoldLine; - undelines->push_back(underline); - } - } - return true; -} - -void TSFTextStore::SetFocusedTextInputClient( - HWND focused_window, - TextInputClient* text_input_client) { - window_handle_ = focused_window; - text_input_client_ = text_input_client; -} - -void TSFTextStore::RemoveFocusedTextInputClient( - TextInputClient* text_input_client) { - if (text_input_client_ == text_input_client) { - window_handle_ = NULL; - text_input_client_ = NULL; - } -} - -bool TSFTextStore::CancelComposition() { - // If there is an on-going document lock, we must not edit the text. - if (edit_flag_) - return false; - - if (string_buffer_.empty()) - return true; - - // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does - // not have a dedicated method to cancel composition. However, CUAS actually - // has a protocol conversion from CPS_CANCEL into TSF operations. According - // to the observations on Windows 7, TIPs are expected to cancel composition - // when an on-going composition text is replaced with an empty string. So - // we use the same operation to cancel composition here to minimize the risk - // of potential compatibility issues. - - const size_t previous_buffer_size = string_buffer_.size(); - string_buffer_.clear(); - committed_size_ = 0; - selection_.set_start(0); - selection_.set_end(0); - if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) - text_store_acp_sink_->OnSelectionChange(); - if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); - if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { - TS_TEXTCHANGE textChange = {}; - textChange.acpStart = 0; - textChange.acpOldEnd = previous_buffer_size; - textChange.acpNewEnd = 0; - text_store_acp_sink_->OnTextChange(0, &textChange); - } - return true; -} - -bool TSFTextStore::ConfirmComposition() { - // If there is an on-going document lock, we must not edit the text. - if (edit_flag_) - return false; - - if (string_buffer_.empty()) - return true; - - // See the comment in TSFTextStore::CancelComposition. - // This logic is based on the observation about how to emulate - // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS. - - const string16& composition_text = string_buffer_.substr(committed_size_); - if (!composition_text.empty()) - text_input_client_->InsertText(composition_text); - - const size_t previous_buffer_size = string_buffer_.size(); - string_buffer_.clear(); - committed_size_ = 0; - selection_.set_start(0); - selection_.set_end(0); - if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) - text_store_acp_sink_->OnSelectionChange(); - if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); - if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { - TS_TEXTCHANGE textChange = {}; - textChange.acpStart = 0; - textChange.acpOldEnd = previous_buffer_size; - textChange.acpNewEnd = 0; - text_store_acp_sink_->OnTextChange(0, &textChange); - } - return true; -} - -void TSFTextStore::SendOnLayoutChange() { - if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); -} - -bool TSFTextStore::HasReadLock() const { - return (current_lock_type_ & TS_LF_READ) == TS_LF_READ; -} - -bool TSFTextStore::HasReadWriteLock() const { - return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE; -} - -} // namespace ui diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h deleted file mode 100644 index 87cd6b42991..00000000000 --- a/chromium/ui/base/ime/win/tsf_text_store.h +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_WIN_TSF_TEXT_STORE_H_ -#define UI_BASE_IME_WIN_TSF_TEXT_STORE_H_ - -#include <msctf.h> -#include <deque> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/strings/string16.h" -#include "base/win/scoped_comptr.h" -#include "ui/base/ime/composition_underline.h" -#include "ui/base/ui_export.h" -#include "ui/gfx/range/range.h" - -namespace ui { -class TextInputClient; - -// TSFTextStore is used to interact with the input method via TSF manager. -// TSFTextStore have a string buffer which is manipulated by TSF manager through -// ITextStoreACP interface methods such as SetText(). -// When the input method updates the composition, TSFTextStore calls -// TextInputClient::SetCompositionText(). And when the input method finishes the -// composition, TSFTextStore calls TextInputClient::InsertText() and clears the -// buffer. -// -// How TSFTextStore works: -// - The user enters "a". -// - The input method set composition as "a". -// - TSF manager calls TSFTextStore::RequestLock(). -// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted(). -// - In OnLockGranted(), TSF manager calls -// - TSFTextStore::OnStartComposition() -// - TSFTextStore::SetText() -// The string buffer is set as "a". -// - TSFTextStore::OnUpdateComposition() -// - TSFTextStore::OnEndEdit() -// TSFTextStore can get the composition information such as underlines. -// - TSFTextStore calls TextInputClient::SetCompositionText(). -// "a" is shown with an underline as composition string. -// - The user enters <space>. -// - The input method set composition as "A". -// - TSF manager calls TSFTextStore::RequestLock(). -// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted(). -// - In OnLockGranted(), TSF manager calls -// - TSFTextStore::SetText() -// The string buffer is set as "A". -// - TSFTextStore::OnUpdateComposition() -// - TSFTextStore::OnEndEdit() -// - TSFTextStore calls TextInputClient::SetCompositionText(). -// "A" is shown with an underline as composition string. -// - The user enters <enter>. -// - The input method commits "A". -// - TSF manager calls TSFTextStore::RequestLock(). -// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted(). -// - In OnLockGranted(), TSF manager calls -// - TSFTextStore::OnEndComposition() -// - TSFTextStore::OnEndEdit() -// TSFTextStore knows "A" is committed. -// - TSFTextStore calls TextInputClient::InsertText(). -// "A" is shown as committed string. -// - TSFTextStore clears the string buffer. -// - TSFTextStore calls OnSelectionChange(), OnLayoutChange() and -// OnTextChange() of ITextStoreACPSink to let TSF manager know that the -// string buffer has been changed. -// -// About the locking scheme: -// When TSF manager manipulates the string buffer it calls RequestLock() to get -// the lock of the document. If TSFTextStore can grant the lock request, it -// callbacks ITextStoreACPSink::OnLockGranted(). -// RequestLock() is called from only one thread, but called recursively in -// OnLockGranted() or OnSelectionChange() or OnLayoutChange() or OnTextChange(). -// If the document is locked and the lock request is asynchronous, TSFTextStore -// queues the request. The queued requests will be handled after the current -// lock is removed. -// More information about document locks can be found here: -// http://msdn.microsoft.com/en-us/library/ms538064 -// -// More information about TSF can be found here: -// http://msdn.microsoft.com/en-us/library/ms629032 -class UI_EXPORT TSFTextStore : public ITextStoreACP, - public ITfContextOwnerCompositionSink, - public ITfTextEditSink { - public: - TSFTextStore(); - virtual ~TSFTextStore(); - - // ITextStoreACP: - STDMETHOD_(ULONG, AddRef)() OVERRIDE; - STDMETHOD_(ULONG, Release)() OVERRIDE; - STDMETHOD(QueryInterface)(REFIID iid, void** ppv) OVERRIDE; - STDMETHOD(AdviseSink)(REFIID iid, IUnknown* unknown, DWORD mask) OVERRIDE; - STDMETHOD(FindNextAttrTransition)(LONG acp_start, - LONG acp_halt, - ULONG num_filter_attributes, - const TS_ATTRID* filter_attributes, - DWORD flags, - LONG* acp_next, - BOOL* found, - LONG* found_offset) OVERRIDE; - STDMETHOD(GetACPFromPoint)(TsViewCookie view_cookie, - const POINT* point, - DWORD flags, - LONG* acp) OVERRIDE; - STDMETHOD(GetActiveView)(TsViewCookie* view_cookie) OVERRIDE; - STDMETHOD(GetEmbedded)(LONG acp_pos, - REFGUID service, - REFIID iid, - IUnknown** unknown) OVERRIDE; - STDMETHOD(GetEndACP)(LONG* acp) OVERRIDE; - STDMETHOD(GetFormattedText)(LONG acp_start, - LONG acp_end, - IDataObject** data_object) OVERRIDE; - STDMETHOD(GetScreenExt)(TsViewCookie view_cookie, RECT* rect) OVERRIDE; - STDMETHOD(GetSelection)(ULONG selection_index, - ULONG selection_buffer_size, - TS_SELECTION_ACP* selection_buffer, - ULONG* fetched_count) OVERRIDE; - STDMETHOD(GetStatus)(TS_STATUS* pdcs) OVERRIDE; - STDMETHOD(GetText)(LONG acp_start, - LONG acp_end, - wchar_t* text_buffer, - ULONG text_buffer_size, - ULONG* text_buffer_copied, - TS_RUNINFO* run_info_buffer, - ULONG run_info_buffer_size, - ULONG* run_info_buffer_copied, - LONG* next_acp) OVERRIDE; - STDMETHOD(GetTextExt)(TsViewCookie view_cookie, - LONG acp_start, - LONG acp_end, - RECT* rect, - BOOL* clipped) OVERRIDE; - STDMETHOD(GetWnd)(TsViewCookie view_cookie, HWND* window_handle) OVERRIDE; - STDMETHOD(InsertEmbedded)(DWORD flags, - LONG acp_start, - LONG acp_end, - IDataObject* data_object, - TS_TEXTCHANGE* change) OVERRIDE; - STDMETHOD(InsertEmbeddedAtSelection)(DWORD flags, - IDataObject* data_object, - LONG* acp_start, - LONG* acp_end, - TS_TEXTCHANGE* change) OVERRIDE; - STDMETHOD(InsertTextAtSelection)(DWORD flags, - const wchar_t* text_buffer, - ULONG text_buffer_size, - LONG* acp_start, - LONG* acp_end, - TS_TEXTCHANGE* text_change) OVERRIDE; - STDMETHOD(QueryInsert)(LONG acp_test_start, - LONG acp_test_end, - ULONG text_size, - LONG* acp_result_start, - LONG* acp_result_end) OVERRIDE; - STDMETHOD(QueryInsertEmbedded)(const GUID* service, - const FORMATETC* format, - BOOL* insertable) OVERRIDE; - STDMETHOD(RequestAttrsAtPosition)(LONG acp_pos, - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer, - DWORD flags) OVERRIDE; - STDMETHOD(RequestAttrsTransitioningAtPosition)( - LONG acp_pos, - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer, - DWORD flags) OVERRIDE; - STDMETHOD(RequestLock)(DWORD lock_flags, HRESULT* result) OVERRIDE; - STDMETHOD(RequestSupportedAttrs)(DWORD flags, - ULONG attribute_buffer_size, - const TS_ATTRID* attribute_buffer) OVERRIDE; - STDMETHOD(RetrieveRequestedAttrs)(ULONG attribute_buffer_size, - TS_ATTRVAL* attribute_buffer, - ULONG* attribute_buffer_copied) OVERRIDE; - STDMETHOD(SetSelection)(ULONG selection_buffer_size, - const TS_SELECTION_ACP* selection_buffer) OVERRIDE; - STDMETHOD(SetText)(DWORD flags, - LONG acp_start, - LONG acp_end, - const wchar_t* text_buffer, - ULONG text_buffer_size, - TS_TEXTCHANGE* text_change) OVERRIDE; - STDMETHOD(UnadviseSink)(IUnknown* unknown) OVERRIDE; - - // ITfContextOwnerCompositionSink: - STDMETHOD(OnStartComposition)(ITfCompositionView* composition_view, - BOOL* ok) OVERRIDE; - STDMETHOD(OnUpdateComposition)(ITfCompositionView* composition_view, - ITfRange* range) OVERRIDE; - STDMETHOD(OnEndComposition)(ITfCompositionView* composition_view) OVERRIDE; - - // ITfTextEditSink: - STDMETHOD(OnEndEdit)(ITfContext* context, TfEditCookie read_only_edit_cookie, - ITfEditRecord* edit_record) OVERRIDE; - - // Sets currently focused TextInputClient. - void SetFocusedTextInputClient(HWND focused_window, - TextInputClient* text_input_client); - // Removes currently focused TextInputClient. - void RemoveFocusedTextInputClient(TextInputClient* text_input_client); - - // Cancels the ongoing composition if exists. - bool CancelComposition(); - - // Confirms the ongoing composition if exists. - bool ConfirmComposition(); - - // Sends OnLayoutChange() via |text_store_acp_sink_|. - void SendOnLayoutChange(); - - private: - friend class TSFTextStoreTest; - friend class TSFTextStoreTestCallback; - - // Checks if the document has a read-only lock. - bool HasReadLock() const; - - // Checks if the document has a read and write lock. - bool HasReadWriteLock() const; - - // Gets the display attribute structure. - bool GetDisplayAttribute(TfGuidAtom guid_atom, - TF_DISPLAYATTRIBUTE* attribute); - - // Gets the committed string size and underline information of the context. - bool GetCompositionStatus(ITfContext* context, - const TfEditCookie read_only_edit_cookie, - size_t* committed_size, - CompositionUnderlines* undelines); - - // The refrence count of this instance. - volatile LONG ref_count_; - - // A pointer of ITextStoreACPSink, this instance is given in AdviseSink. - base::win::ScopedComPtr<ITextStoreACPSink> text_store_acp_sink_; - - // The current mask of |text_store_acp_sink_|. - DWORD text_store_acp_sink_mask_; - - // HWND of the current view window which is set in SetFocusedTextInputClient. - HWND window_handle_; - - // Current TextInputClient which is set in SetFocusedTextInputClient. - TextInputClient* text_input_client_; - - // |string_buffer_| contains committed string and composition string. - // Example: "aoi" is committed, and "umi" is under composition. - // |string_buffer_|: "aoiumi" - // |committed_size_|: 3 - string16 string_buffer_; - size_t committed_size_; - - // |selection_start_| and |selection_end_| indicates the selection range. - // Example: "iue" is selected - // |string_buffer_|: "aiueo" - // |selection_.start()|: 1 - // |selection_.end()|: 4 - gfx::Range selection_; - - // |start_offset| and |end_offset| of |composition_undelines_| indicates - // the offsets in |string_buffer_|. - // Example: "aoi" is committed. There are two underlines in "umi" and "no". - // |string_buffer_|: "aoiumino" - // |committed_size_|: 3 - // composition_undelines_.underlines[0].start_offset: 3 - // composition_undelines_.underlines[0].end_offset: 6 - // composition_undelines_.underlines[1].start_offset: 6 - // composition_undelines_.underlines[1].end_offset: 8 - CompositionUnderlines composition_undelines_; - - // |edit_flag_| indicates that the status is edited during - // ITextStoreACPSink::OnLockGranted(). - bool edit_flag_; - - // The type of current lock. - // 0: No lock. - // TS_LF_READ: read-only lock. - // TS_LF_READWRITE: read/write lock. - DWORD current_lock_type_; - - // Queue of the lock request used in RequestLock(). - std::deque<DWORD> lock_queue_; - - // Category manager and Display attribute manager are used to obtain the - // attributes of the composition string. - base::win::ScopedComPtr<ITfCategoryMgr> category_manager_; - base::win::ScopedComPtr<ITfDisplayAttributeMgr> display_attribute_manager_; - - DISALLOW_COPY_AND_ASSIGN(TSFTextStore); -}; - -} // namespace ui - -#endif // UI_BASE_IME_WIN_TSF_TEXT_STORE_H_ diff --git a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc deleted file mode 100644 index 33812a4e01e..00000000000 --- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc +++ /dev/null @@ -1,1302 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/base/ime/win/tsf_text_store.h" - -#include <initguid.h> // for GUID_NULL and GUID_PROP_INPUTSCOPE -#include <InputScope.h> -#include <OleCtl.h> - -#include "base/memory/ref_counted.h" -#include "base/win/scoped_com_initializer.h" -#include "base/win/scoped_variant.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/gfx/rect.h" - -using testing::_; -using testing::Invoke; -using testing::Return; - -namespace ui { -namespace { - -class MockTextInputClient : public TextInputClient { - public: - ~MockTextInputClient() {} - MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&)); - MOCK_METHOD0(ConfirmCompositionText, void()); - MOCK_METHOD0(ClearCompositionText, void()); - MOCK_METHOD1(InsertText, void(const string16&)); - MOCK_METHOD2(InsertChar, void(char16, int)); - MOCK_CONST_METHOD0(GetAttachedWindow, gfx::NativeWindow()); - MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType()); - MOCK_CONST_METHOD0(GetTextInputMode, ui::TextInputMode()); - MOCK_CONST_METHOD0(CanComposeInline, bool()); - MOCK_CONST_METHOD0(GetCaretBounds, gfx::Rect()); - MOCK_CONST_METHOD2(GetCompositionCharacterBounds, bool(uint32, gfx::Rect*)); - MOCK_CONST_METHOD0(HasCompositionText, bool()); - MOCK_CONST_METHOD1(GetTextRange, bool(gfx::Range*)); - MOCK_CONST_METHOD1(GetCompositionTextRange, bool(gfx::Range*)); - MOCK_CONST_METHOD1(GetSelectionRange, bool(gfx::Range*)); - MOCK_METHOD1(SetSelectionRange, bool(const gfx::Range&)); - MOCK_METHOD1(DeleteRange, bool(const gfx::Range&)); - MOCK_CONST_METHOD2(GetTextFromRange, bool(const gfx::Range&, string16*)); - MOCK_METHOD0(OnInputMethodChanged, void()); - MOCK_METHOD1(ChangeTextDirectionAndLayoutAlignment, - bool(base::i18n::TextDirection)); - MOCK_METHOD2(ExtendSelectionAndDelete, void(size_t, size_t)); - MOCK_METHOD1(EnsureCaretInRect, void(const gfx::Rect&)); - MOCK_METHOD0(OnCandidateWindowShown, void()); - MOCK_METHOD0(OnCandidateWindowUpdated, void()); - MOCK_METHOD0(OnCandidateWindowHidden, void()); -}; - -class MockStoreACPSink : public ITextStoreACPSink { - public: - MockStoreACPSink() : ref_count_(0) {} - - // IUnknown - virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE { - return InterlockedIncrement(&ref_count_); - } - virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE { - const LONG count = InterlockedDecrement(&ref_count_); - if (!count) { - delete this; - return 0; - } - return static_cast<ULONG>(count); - } - virtual HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID iid, void** report) OVERRIDE { - if (iid == IID_IUnknown || iid == IID_ITextStoreACPSink) { - *report = static_cast<ITextStoreACPSink*>(this); - } else { - *report = NULL; - return E_NOINTERFACE; - } - AddRef(); - return S_OK; - } - - // ITextStoreACPSink - MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnTextChange, - HRESULT(DWORD, const TS_TEXTCHANGE*)); - MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnSelectionChange, - HRESULT()); - MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLayoutChange, - HRESULT(TsLayoutCode, TsViewCookie)); - MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStatusChange, - HRESULT(DWORD)); - MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE, OnAttrsChange, - HRESULT(LONG, LONG, ULONG, const TS_ATTRID*)); - MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLockGranted, - HRESULT(DWORD)); - MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStartEditTransaction, - HRESULT()); - MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnEndEditTransaction, - HRESULT()); - - private: - virtual ~MockStoreACPSink() {} - - volatile LONG ref_count_; -}; - -const HWND kWindowHandle = reinterpret_cast<HWND>(1); - -} // namespace - -class TSFTextStoreTest : public testing::Test { - protected: - virtual void SetUp() OVERRIDE { - text_store_ = new TSFTextStore(); - sink_ = new MockStoreACPSink(); - EXPECT_EQ(S_OK, text_store_->AdviseSink(IID_ITextStoreACPSink, - sink_, TS_AS_ALL_SINKS)); - text_store_->SetFocusedTextInputClient(kWindowHandle, - &text_input_client_); - } - - virtual void TearDown() OVERRIDE { - EXPECT_EQ(S_OK, text_store_->UnadviseSink(sink_)); - sink_ = NULL; - text_store_ = NULL; - } - - // Accessors to the internal state of TSFTextStore. - string16* string_buffer() { return &text_store_->string_buffer_; } - size_t* committed_size() { return &text_store_->committed_size_; } - - base::win::ScopedCOMInitializer com_initializer_; - MockTextInputClient text_input_client_; - scoped_refptr<TSFTextStore> text_store_; - scoped_refptr<MockStoreACPSink> sink_; -}; - -class TSFTextStoreTestCallback { - public: - explicit TSFTextStoreTestCallback(TSFTextStore* text_store) - : text_store_(text_store) { - CHECK(text_store_); - } - virtual ~TSFTextStoreTestCallback() {} - - protected: - // Accessors to the internal state of TSFTextStore. - bool* edit_flag() { return &text_store_->edit_flag_; } - string16* string_buffer() { return &text_store_->string_buffer_; } - size_t* committed_size() { return &text_store_->committed_size_; } - gfx::Range* selection() { return &text_store_->selection_; } - CompositionUnderlines* composition_undelines() { - return &text_store_->composition_undelines_; - } - - void SetInternalState(const string16& new_string_buffer, - LONG new_committed_size, LONG new_selection_start, - LONG new_selection_end) { - ASSERT_LE(0, new_committed_size); - ASSERT_LE(new_committed_size, new_selection_start); - ASSERT_LE(new_selection_start, new_selection_end); - ASSERT_LE(new_selection_end, static_cast<LONG>(new_string_buffer.size())); - *string_buffer() = new_string_buffer; - *committed_size() = new_committed_size; - selection()->set_start(new_selection_start); - selection()->set_end(new_selection_end); - } - - bool HasReadLock() const { return text_store_->HasReadLock(); } - bool HasReadWriteLock() const { return text_store_->HasReadWriteLock(); } - - void GetSelectionTest(LONG expected_acp_start, LONG expected_acp_end) { - TS_SELECTION_ACP selection = {}; - ULONG fetched = 0; - EXPECT_EQ(S_OK, text_store_->GetSelection(0, 1, &selection, &fetched)); - EXPECT_EQ(1, fetched); - EXPECT_EQ(expected_acp_start, selection.acpStart); - EXPECT_EQ(expected_acp_end, selection.acpEnd); - } - - void SetSelectionTest(LONG acp_start, LONG acp_end, HRESULT expected_result) { - TS_SELECTION_ACP selection = {}; - selection.acpStart = acp_start; - selection.acpEnd = acp_end; - selection.style.ase = TS_AE_NONE; - selection.style.fInterimChar = 0; - EXPECT_EQ(expected_result, text_store_->SetSelection(1, &selection)); - if (expected_result == S_OK) { - GetSelectionTest(acp_start, acp_end); - } - } - - void SetTextTest(LONG acp_start, LONG acp_end, - const string16& text, HRESULT error_code) { - TS_TEXTCHANGE change = {}; - ASSERT_EQ(error_code, - text_store_->SetText(0, acp_start, acp_end, - text.c_str(), text.size(), &change)); - if (error_code == S_OK) { - EXPECT_EQ(acp_start, change.acpStart); - EXPECT_EQ(acp_end, change.acpOldEnd); - EXPECT_EQ(acp_start + text.size(), change.acpNewEnd); - } - } - - void GetTextTest(LONG acp_start, LONG acp_end, - const string16& expected_string, - LONG expected_next_acp) { - wchar_t buffer[1024] = {}; - ULONG text_buffer_copied = 0; - TS_RUNINFO run_info = {}; - ULONG run_info_buffer_copied = 0; - LONG next_acp = 0; - ASSERT_EQ(S_OK, - text_store_->GetText(acp_start, acp_end, buffer, 1024, - &text_buffer_copied, - &run_info, 1, &run_info_buffer_copied, - &next_acp)); - ASSERT_EQ(expected_string.size(), text_buffer_copied); - EXPECT_EQ(expected_string, string16(buffer, buffer + text_buffer_copied)); - EXPECT_EQ(1, run_info_buffer_copied); - EXPECT_EQ(expected_string.size(), run_info.uCount); - EXPECT_EQ(TS_RT_PLAIN, run_info.type); - EXPECT_EQ(expected_next_acp, next_acp); - } - - void GetTextErrorTest(LONG acp_start, LONG acp_end, HRESULT error_code) { - wchar_t buffer[1024] = {}; - ULONG text_buffer_copied = 0; - TS_RUNINFO run_info = {}; - ULONG run_info_buffer_copied = 0; - LONG next_acp = 0; - EXPECT_EQ(error_code, - text_store_->GetText(acp_start, acp_end, buffer, 1024, - &text_buffer_copied, - &run_info, 1, &run_info_buffer_copied, - &next_acp)); - } - - void InsertTextAtSelectionTest(const wchar_t* buffer, ULONG buffer_size, - LONG expected_start, LONG expected_end, - LONG expected_change_start, - LONG expected_change_old_end, - LONG expected_change_new_end) { - LONG start = 0; - LONG end = 0; - TS_TEXTCHANGE change = {}; - EXPECT_EQ(S_OK, - text_store_->InsertTextAtSelection(0, buffer, buffer_size, - &start, &end, &change)); - EXPECT_EQ(expected_start, start); - EXPECT_EQ(expected_end, end); - EXPECT_EQ(expected_change_start, change.acpStart); - EXPECT_EQ(expected_change_old_end, change.acpOldEnd); - EXPECT_EQ(expected_change_new_end, change.acpNewEnd); - } - - void InsertTextAtSelectionQueryOnlyTest(const wchar_t* buffer, - ULONG buffer_size, - LONG expected_start, - LONG expected_end) { - LONG start = 0; - LONG end = 0; - EXPECT_EQ(S_OK, - text_store_->InsertTextAtSelection(TS_IAS_QUERYONLY, buffer, - buffer_size, &start, &end, - NULL)); - EXPECT_EQ(expected_start, start); - EXPECT_EQ(expected_end, end); - } - - void GetTextExtTest(TsViewCookie view_cookie, LONG acp_start, LONG acp_end, - LONG expected_left, LONG expected_top, - LONG expected_right, LONG expected_bottom) { - RECT rect = {}; - BOOL clipped = FALSE; - EXPECT_EQ(S_OK, text_store_->GetTextExt(view_cookie, acp_start, acp_end, - &rect, &clipped)); - EXPECT_EQ(expected_left, rect.left); - EXPECT_EQ(expected_top, rect.top); - EXPECT_EQ(expected_right, rect.right); - EXPECT_EQ(expected_bottom, rect.bottom); - EXPECT_EQ(FALSE, clipped); - } - - void GetTextExtNoLayoutTest(TsViewCookie view_cookie, LONG acp_start, - LONG acp_end) { - RECT rect = {}; - BOOL clipped = FALSE; - EXPECT_EQ(TS_E_NOLAYOUT, - text_store_->GetTextExt(view_cookie, acp_start, acp_end, - &rect, &clipped)); - } - - scoped_refptr<TSFTextStore> text_store_; - - private: - DISALLOW_COPY_AND_ASSIGN(TSFTextStoreTestCallback); -}; - -namespace { - -const HRESULT kInvalidResult = 0x12345678; - -TEST_F(TSFTextStoreTest, GetStatusTest) { - TS_STATUS status = {}; - EXPECT_EQ(S_OK, text_store_->GetStatus(&status)); - EXPECT_EQ(0, status.dwDynamicFlags); - EXPECT_EQ(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT, status.dwStaticFlags); -} - -TEST_F(TSFTextStoreTest, QueryInsertTest) { - LONG result_start = 0; - LONG result_end = 0; - *string_buffer() = L""; - *committed_size() = 0; - EXPECT_EQ(E_INVALIDARG, - text_store_->QueryInsert(0, 0, 0, NULL, &result_end)); - EXPECT_EQ(E_INVALIDARG, - text_store_->QueryInsert(0, 0, 0, &result_start, NULL)); - EXPECT_EQ(S_OK, - text_store_->QueryInsert(0, 0, 0, &result_start, &result_end)); - EXPECT_EQ(0, result_start); - EXPECT_EQ(0, result_end); - *string_buffer() = L"1234"; - *committed_size() = 1; - EXPECT_EQ(S_OK, - text_store_->QueryInsert(0, 1, 0, &result_start, &result_end)); - EXPECT_EQ(1, result_start); - EXPECT_EQ(1, result_end); - EXPECT_EQ(E_INVALIDARG, - text_store_->QueryInsert(1, 0, 0, &result_start, &result_end)); - EXPECT_EQ(S_OK, - text_store_->QueryInsert(2, 2, 0, &result_start, &result_end)); - EXPECT_EQ(2, result_start); - EXPECT_EQ(2, result_end); - EXPECT_EQ(S_OK, - text_store_->QueryInsert(2, 3, 0, &result_start, &result_end)); - EXPECT_EQ(2, result_start); - EXPECT_EQ(3, result_end); - EXPECT_EQ(E_INVALIDARG, - text_store_->QueryInsert(3, 2, 0, &result_start, &result_end)); - EXPECT_EQ(S_OK, - text_store_->QueryInsert(3, 4, 0, &result_start, &result_end)); - EXPECT_EQ(3, result_start); - EXPECT_EQ(4, result_end); - EXPECT_EQ(S_OK, - text_store_->QueryInsert(3, 5, 0, &result_start, &result_end)); - EXPECT_EQ(3, result_start); - EXPECT_EQ(4, result_end); -} - -class SyncRequestLockTestCallback : public TSFTextStoreTestCallback { - public: - explicit SyncRequestLockTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store) {} - - HRESULT LockGranted1(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - return S_OK; - } - - HRESULT LockGranted2(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - return S_OK; - } - - HRESULT LockGranted3(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); - EXPECT_EQ(TS_E_SYNCHRONOUS, result); - return S_OK; - } - - HRESULT LockGranted4(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, - text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); - EXPECT_EQ(TS_E_SYNCHRONOUS, result); - return S_OK; - } - - HRESULT LockGranted5(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); - EXPECT_EQ(TS_E_SYNCHRONOUS, result); - return S_OK; - } - - HRESULT LockGranted6(DWORD flags) { - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, - text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); - EXPECT_EQ(TS_E_SYNCHRONOUS, result); - return S_OK; - } - - private: - DISALLOW_COPY_AND_ASSIGN(SyncRequestLockTestCallback); -}; - -TEST_F(TSFTextStoreTest, SynchronousRequestLockTest) { - SyncRequestLockTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted1)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted2)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted3)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted4)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted5)) - .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted6)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, - text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); - - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); - - result = kInvalidResult; - EXPECT_EQ(S_OK, - text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, - text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result)); - EXPECT_EQ(S_OK, result); -} - -class AsyncRequestLockTestCallback : public TSFTextStoreTestCallback { - public: - explicit AsyncRequestLockTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store), - state_(0) {} - - HRESULT LockGranted1(DWORD flags) { - EXPECT_EQ(0, state_); - state_ = 1; - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(TS_S_ASYNC, result); - EXPECT_EQ(1, state_); - state_ = 2; - return S_OK; - } - - HRESULT LockGranted2(DWORD flags) { - EXPECT_EQ(2, state_); - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(TS_S_ASYNC, result); - EXPECT_EQ(2, state_); - state_ = 3; - return S_OK; - } - - HRESULT LockGranted3(DWORD flags) { - EXPECT_EQ(3, state_); - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(TS_S_ASYNC, result); - EXPECT_EQ(3, state_); - state_ = 4; - return S_OK; - } - - HRESULT LockGranted4(DWORD flags) { - EXPECT_EQ(4, state_); - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(TS_S_ASYNC, result); - EXPECT_EQ(4, state_); - state_ = 5; - return S_OK; - } - - HRESULT LockGranted5(DWORD flags) { - EXPECT_EQ(5, state_); - EXPECT_TRUE(HasReadLock()); - EXPECT_FALSE(HasReadWriteLock()); - state_ = 6; - return S_OK; - } - - private: - int state_; - - DISALLOW_COPY_AND_ASSIGN(AsyncRequestLockTestCallback); -}; - -TEST_F(TSFTextStoreTest, AsynchronousRequestLockTest) { - AsyncRequestLockTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted1)) - .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted2)) - .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted3)) - .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted4)) - .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted5)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(S_OK, result); -} - -class RequestLockTextChangeTestCallback : public TSFTextStoreTestCallback { - public: - explicit RequestLockTextChangeTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store), - state_(0) {} - - HRESULT LockGranted1(DWORD flags) { - EXPECT_EQ(0, state_); - state_ = 1; - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - - *edit_flag() = true; - SetInternalState(L"012345", 6, 6, 6); - composition_undelines()->clear(); - - state_ = 2; - return S_OK; - } - - void InsertText(const string16& text) { - EXPECT_EQ(2, state_); - EXPECT_EQ(L"012345", text); - state_ = 3; - } - - void SetCompositionText(const ui::CompositionText& composition) { - EXPECT_EQ(3, state_); - EXPECT_EQ(L"", composition.text); - EXPECT_EQ(0, composition.selection.start()); - EXPECT_EQ(0, composition.selection.end()); - EXPECT_EQ(0, composition.underlines.size()); - state_ = 4; - } - - HRESULT OnTextChange(DWORD flags, const TS_TEXTCHANGE* change) { - EXPECT_EQ(4, state_); - HRESULT result = kInvalidResult; - state_ = 5; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); - EXPECT_EQ(6, state_); - state_ = 7; - return S_OK; - } - - HRESULT LockGranted2(DWORD flags) { - EXPECT_EQ(5, state_); - EXPECT_TRUE(HasReadLock()); - EXPECT_TRUE(HasReadWriteLock()); - state_ = 6; - return S_OK; - } - - private: - int state_; - - DISALLOW_COPY_AND_ASSIGN(RequestLockTextChangeTestCallback); -}; - -TEST_F(TSFTextStoreTest, RequestLockOnTextChangeTest) { - RequestLockTextChangeTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, - &RequestLockTextChangeTestCallback::LockGranted1)) - .WillOnce(Invoke(&callback, - &RequestLockTextChangeTestCallback::LockGranted2)); - - EXPECT_CALL(*sink_, OnSelectionChange()) - .WillOnce(Return(S_OK)); - EXPECT_CALL(*sink_, OnLayoutChange(_, _)) - .WillOnce(Return(S_OK)); - EXPECT_CALL(*sink_, OnTextChange(_, _)) - .WillOnce(Invoke(&callback, - &RequestLockTextChangeTestCallback::OnTextChange)); - EXPECT_CALL(text_input_client_, InsertText(_)) - .WillOnce(Invoke(&callback, - &RequestLockTextChangeTestCallback::InsertText)); - EXPECT_CALL(text_input_client_, SetCompositionText(_)) - .WillOnce(Invoke(&callback, - &RequestLockTextChangeTestCallback::SetCompositionText)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); -} - -class SelectionTestCallback : public TSFTextStoreTestCallback { - public: - explicit SelectionTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store) {} - - HRESULT ReadLockGranted(DWORD flags) { - SetInternalState(L"", 0, 0, 0); - - GetSelectionTest(0, 0); - SetSelectionTest(0, 0, TF_E_NOLOCK); - - SetInternalState(L"012345", 0, 0, 3); - - GetSelectionTest(0, 3); - SetSelectionTest(0, 0, TF_E_NOLOCK); - - return S_OK; - } - - HRESULT ReadWriteLockGranted(DWORD flags) { - SetInternalState(L"", 0, 0, 0); - - SetSelectionTest(0, 0, S_OK); - GetSelectionTest(0, 0); - SetSelectionTest(0, 1, TF_E_INVALIDPOS); - SetSelectionTest(1, 0, TF_E_INVALIDPOS); - SetSelectionTest(1, 1, TF_E_INVALIDPOS); - - SetInternalState(L"0123456", 3, 3, 3); - - SetSelectionTest(0, 0, TF_E_INVALIDPOS); - SetSelectionTest(0, 1, TF_E_INVALIDPOS); - SetSelectionTest(0, 3, TF_E_INVALIDPOS); - SetSelectionTest(0, 6, TF_E_INVALIDPOS); - SetSelectionTest(0, 7, TF_E_INVALIDPOS); - SetSelectionTest(0, 8, TF_E_INVALIDPOS); - - SetSelectionTest(1, 0, TF_E_INVALIDPOS); - SetSelectionTest(1, 1, TF_E_INVALIDPOS); - SetSelectionTest(1, 3, TF_E_INVALIDPOS); - SetSelectionTest(1, 6, TF_E_INVALIDPOS); - SetSelectionTest(1, 7, TF_E_INVALIDPOS); - SetSelectionTest(1, 8, TF_E_INVALIDPOS); - - SetSelectionTest(3, 0, TF_E_INVALIDPOS); - SetSelectionTest(3, 1, TF_E_INVALIDPOS); - SetSelectionTest(3, 3, S_OK); - SetSelectionTest(3, 6, S_OK); - SetSelectionTest(3, 7, S_OK); - SetSelectionTest(3, 8, TF_E_INVALIDPOS); - - SetSelectionTest(6, 0, TF_E_INVALIDPOS); - SetSelectionTest(6, 1, TF_E_INVALIDPOS); - SetSelectionTest(6, 3, TF_E_INVALIDPOS); - SetSelectionTest(6, 6, S_OK); - SetSelectionTest(6, 7, S_OK); - SetSelectionTest(6, 8, TF_E_INVALIDPOS); - - SetSelectionTest(7, 0, TF_E_INVALIDPOS); - SetSelectionTest(7, 1, TF_E_INVALIDPOS); - SetSelectionTest(7, 3, TF_E_INVALIDPOS); - SetSelectionTest(7, 6, TF_E_INVALIDPOS); - SetSelectionTest(7, 7, S_OK); - SetSelectionTest(7, 8, TF_E_INVALIDPOS); - - SetSelectionTest(8, 0, TF_E_INVALIDPOS); - SetSelectionTest(8, 1, TF_E_INVALIDPOS); - SetSelectionTest(8, 3, TF_E_INVALIDPOS); - SetSelectionTest(8, 6, TF_E_INVALIDPOS); - SetSelectionTest(8, 7, TF_E_INVALIDPOS); - SetSelectionTest(8, 8, TF_E_INVALIDPOS); - - return S_OK; - } -}; - -TEST_F(TSFTextStoreTest, SetGetSelectionTest) { - SelectionTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &SelectionTestCallback::ReadLockGranted)) - .WillOnce(Invoke(&callback, - &SelectionTestCallback::ReadWriteLockGranted)); - - TS_SELECTION_ACP selection_buffer = {}; - ULONG fetched_count = 0; - EXPECT_EQ(TS_E_NOLOCK, - text_store_->GetSelection(0, 1, &selection_buffer, - &fetched_count)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); -} - -class SetGetTextTestCallback : public TSFTextStoreTestCallback { - public: - explicit SetGetTextTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store) {} - - HRESULT ReadLockGranted(DWORD flags) { - SetTextTest(0, 0, L"", TF_E_NOLOCK); - - GetTextTest(0, -1, L"", 0); - GetTextTest(0, 0, L"", 0); - GetTextErrorTest(0, 1, TF_E_INVALIDPOS); - - SetInternalState(L"0123456", 3, 3, 3); - - GetTextErrorTest(-1, -1, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 0, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 1, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 3, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 6, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 7, TF_E_INVALIDPOS); - GetTextErrorTest(-1, 8, TF_E_INVALIDPOS); - - GetTextTest(0, -1, L"0123456", 7); - GetTextTest(0, 0, L"", 0); - GetTextTest(0, 1, L"0", 1); - GetTextTest(0, 3, L"012", 3); - GetTextTest(0, 6, L"012345", 6); - GetTextTest(0, 7, L"0123456", 7); - GetTextErrorTest(0, 8, TF_E_INVALIDPOS); - - GetTextTest(1, -1, L"123456", 7); - GetTextErrorTest(1, 0, TF_E_INVALIDPOS); - GetTextTest(1, 1, L"", 1); - GetTextTest(1, 3, L"12", 3); - GetTextTest(1, 6, L"12345", 6); - GetTextTest(1, 7, L"123456", 7); - GetTextErrorTest(1, 8, TF_E_INVALIDPOS); - - GetTextTest(3, -1, L"3456", 7); - GetTextErrorTest(3, 0, TF_E_INVALIDPOS); - GetTextErrorTest(3, 1, TF_E_INVALIDPOS); - GetTextTest(3, 3, L"", 3); - GetTextTest(3, 6, L"345", 6); - GetTextTest(3, 7, L"3456", 7); - GetTextErrorTest(3, 8, TF_E_INVALIDPOS); - - GetTextTest(6, -1, L"6", 7); - GetTextErrorTest(6, 0, TF_E_INVALIDPOS); - GetTextErrorTest(6, 1, TF_E_INVALIDPOS); - GetTextErrorTest(6, 3, TF_E_INVALIDPOS); - GetTextTest(6, 6, L"", 6); - GetTextTest(6, 7, L"6", 7); - GetTextErrorTest(6, 8, TF_E_INVALIDPOS); - - GetTextTest(7, -1, L"", 7); - GetTextErrorTest(7, 0, TF_E_INVALIDPOS); - GetTextErrorTest(7, 1, TF_E_INVALIDPOS); - GetTextErrorTest(7, 3, TF_E_INVALIDPOS); - GetTextErrorTest(7, 6, TF_E_INVALIDPOS); - GetTextTest(7, 7, L"", 7); - GetTextErrorTest(7, 8, TF_E_INVALIDPOS); - - GetTextErrorTest(8, -1, TF_E_INVALIDPOS); - GetTextErrorTest(8, 0, TF_E_INVALIDPOS); - GetTextErrorTest(8, 1, TF_E_INVALIDPOS); - GetTextErrorTest(8, 3, TF_E_INVALIDPOS); - GetTextErrorTest(8, 6, TF_E_INVALIDPOS); - GetTextErrorTest(8, 7, TF_E_INVALIDPOS); - GetTextErrorTest(8, 8, TF_E_INVALIDPOS); - - return S_OK; - } - - HRESULT ReadWriteLockGranted(DWORD flags) { - SetInternalState(L"", 0, 0, 0); - SetTextTest(0, 0, L"", S_OK); - - SetInternalState(L"", 0, 0, 0); - SetTextTest(0, 1, L"", TS_E_INVALIDPOS); - - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(0, 0, L"", TS_E_INVALIDPOS); - SetTextTest(0, 1, L"", TS_E_INVALIDPOS); - SetTextTest(0, 3, L"", TS_E_INVALIDPOS); - SetTextTest(0, 6, L"", TS_E_INVALIDPOS); - SetTextTest(0, 7, L"", TS_E_INVALIDPOS); - SetTextTest(0, 8, L"", TS_E_INVALIDPOS); - - SetTextTest(1, 0, L"", TS_E_INVALIDPOS); - SetTextTest(1, 1, L"", TS_E_INVALIDPOS); - SetTextTest(1, 3, L"", TS_E_INVALIDPOS); - SetTextTest(1, 6, L"", TS_E_INVALIDPOS); - SetTextTest(1, 7, L"", TS_E_INVALIDPOS); - SetTextTest(1, 8, L"", TS_E_INVALIDPOS); - - SetTextTest(3, 0, L"", TS_E_INVALIDPOS); - SetTextTest(3, 1, L"", TS_E_INVALIDPOS); - - SetTextTest(3, 3, L"", S_OK); - GetTextTest(0, -1, L"0123456", 7); - GetSelectionTest(3, 3); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(3, 6, L"", S_OK); - GetTextTest(0, -1, L"0126", 4); - GetSelectionTest(3, 3); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(3, 7, L"", S_OK); - GetTextTest(0, -1, L"012", 3); - GetSelectionTest(3, 3); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(3, 8, L"", TS_E_INVALIDPOS); - - SetTextTest(6, 0, L"", TS_E_INVALIDPOS); - SetTextTest(6, 1, L"", TS_E_INVALIDPOS); - SetTextTest(6, 3, L"", TS_E_INVALIDPOS); - - SetTextTest(6, 6, L"", S_OK); - GetTextTest(0, -1, L"0123456", 7); - GetSelectionTest(6, 6); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(6, 7, L"", S_OK); - GetTextTest(0, -1, L"012345", 6); - GetSelectionTest(6, 6); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(6, 8, L"", TS_E_INVALIDPOS); - - SetTextTest(7, 0, L"", TS_E_INVALIDPOS); - SetTextTest(7, 1, L"", TS_E_INVALIDPOS); - SetTextTest(7, 3, L"", TS_E_INVALIDPOS); - SetTextTest(7, 6, L"", TS_E_INVALIDPOS); - - SetTextTest(7, 7, L"", S_OK); - GetTextTest(0, -1, L"0123456", 7); - GetSelectionTest(7, 7); - SetInternalState(L"0123456", 3, 3, 3); - - SetTextTest(7, 8, L"", TS_E_INVALIDPOS); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(3, 3, L"abc", S_OK); - GetTextTest(0, -1, L"012abc3456", 10); - GetSelectionTest(3, 6); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(3, 6, L"abc", S_OK); - GetTextTest(0, -1, L"012abc6", 7); - GetSelectionTest(3, 6); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(3, 7, L"abc", S_OK); - GetTextTest(0, -1, L"012abc", 6); - GetSelectionTest(3, 6); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(6, 6, L"abc", S_OK); - GetTextTest(0, -1, L"012345abc6", 10); - GetSelectionTest(6, 9); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(6, 7, L"abc", S_OK); - GetTextTest(0, -1, L"012345abc", 9); - GetSelectionTest(6, 9); - - SetInternalState(L"0123456", 3, 3, 3); - SetTextTest(7, 7, L"abc", S_OK); - GetTextTest(0, -1, L"0123456abc", 10); - GetSelectionTest(7, 10); - - return S_OK; - } - - private: - DISALLOW_COPY_AND_ASSIGN(SetGetTextTestCallback); -}; - -TEST_F(TSFTextStoreTest, SetGetTextTest) { - SetGetTextTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &SetGetTextTestCallback::ReadLockGranted)) - .WillOnce(Invoke(&callback, - &SetGetTextTestCallback::ReadWriteLockGranted)); - - wchar_t buffer[1024] = {}; - ULONG text_buffer_copied = 0; - TS_RUNINFO run_info = {}; - ULONG run_info_buffer_copied = 0; - LONG next_acp = 0; - EXPECT_EQ(TF_E_NOLOCK, - text_store_->GetText(0, -1, buffer, 1024, &text_buffer_copied, - &run_info, 1, &run_info_buffer_copied, - &next_acp)); - TS_TEXTCHANGE change = {}; - EXPECT_EQ(TF_E_NOLOCK, text_store_->SetText(0, 0, 0, L"abc", 3, &change)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); -} - -class InsertTextAtSelectionTestCallback : public TSFTextStoreTestCallback { - public: - explicit InsertTextAtSelectionTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store) {} - - HRESULT ReadLockGranted(DWORD flags) { - const wchar_t kBuffer[] = L"0123456789"; - - SetInternalState(L"abcedfg", 0, 0, 0); - InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0); - GetSelectionTest(0, 0); - InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0); - - SetInternalState(L"abcedfg", 0, 2, 5); - InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 2, 5); - GetSelectionTest(2, 5); - InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 2, 5); - - LONG start = 0; - LONG end = 0; - TS_TEXTCHANGE change = {}; - EXPECT_EQ(TS_E_NOLOCK, - text_store_->InsertTextAtSelection(0, kBuffer, 10, - &start, &end, &change)); - return S_OK; - } - - HRESULT ReadWriteLockGranted(DWORD flags) { - SetInternalState(L"abcedfg", 0, 0, 0); - - const wchar_t kBuffer[] = L"0123456789"; - InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0); - GetSelectionTest(0, 0); - InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0); - - SetInternalState(L"", 0, 0, 0); - InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10); - GetSelectionTest(0, 10); - GetTextTest(0, -1, L"0123456789", 10); - - SetInternalState(L"abcedfg", 0, 0, 0); - InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10); - GetSelectionTest(0, 10); - GetTextTest(0, -1, L"0123456789abcedfg", 17); - - SetInternalState(L"abcedfg", 0, 0, 3); - InsertTextAtSelectionTest(kBuffer, 0, 0, 0, 0, 3, 0); - GetSelectionTest(0, 0); - GetTextTest(0, -1, L"edfg", 4); - - SetInternalState(L"abcedfg", 0, 3, 7); - InsertTextAtSelectionTest(kBuffer, 10, 3, 13, 3, 7, 13); - GetSelectionTest(3, 13); - GetTextTest(0, -1, L"abc0123456789", 13); - - SetInternalState(L"abcedfg", 0, 7, 7); - InsertTextAtSelectionTest(kBuffer, 10, 7, 17, 7, 7, 17); - GetSelectionTest(7, 17); - GetTextTest(0, -1, L"abcedfg0123456789", 17); - - return S_OK; - } - - private: - DISALLOW_COPY_AND_ASSIGN(InsertTextAtSelectionTestCallback); -}; - -TEST_F(TSFTextStoreTest, InsertTextAtSelectionTest) { - InsertTextAtSelectionTestCallback callback(text_store_); - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, - &InsertTextAtSelectionTestCallback::ReadLockGranted)) - .WillOnce( - Invoke(&callback, - &InsertTextAtSelectionTestCallback::ReadWriteLockGranted)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); -} - -class ScenarioTestCallback : public TSFTextStoreTestCallback { - public: - explicit ScenarioTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store) {} - - HRESULT LockGranted1(DWORD flags) { - SetSelectionTest(0, 0, S_OK); - - SetTextTest(0, 0, L"abc", S_OK); - SetTextTest(1, 2, L"xyz", S_OK); - - GetTextTest(0, -1, L"axyzc", 5); - - composition_undelines()->clear(); - CompositionUnderline underline; - underline.start_offset = 0; - underline.end_offset = 5; - underline.color = SK_ColorBLACK; - underline.thick = false; - composition_undelines()->push_back(underline); - *edit_flag() = true; - *committed_size() = 0; - return S_OK; - } - - void SetCompositionText1(const ui::CompositionText& composition) { - EXPECT_EQ(L"axyzc", composition.text); - EXPECT_EQ(1, composition.selection.start()); - EXPECT_EQ(4, composition.selection.end()); - ASSERT_EQ(1, composition.underlines.size()); - EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); - EXPECT_EQ(0, composition.underlines[0].start_offset); - EXPECT_EQ(5, composition.underlines[0].end_offset); - EXPECT_FALSE(composition.underlines[0].thick); - } - - HRESULT LockGranted2(DWORD flags) { - SetTextTest(3, 4, L"ZCP", S_OK); - GetTextTest(0, -1, L"axyZCPc", 7); - - composition_undelines()->clear(); - CompositionUnderline underline; - underline.start_offset = 3; - underline.end_offset = 5; - underline.color = SK_ColorBLACK; - underline.thick = true; - composition_undelines()->push_back(underline); - underline.start_offset = 5; - underline.end_offset = 7; - underline.color = SK_ColorBLACK; - underline.thick = false; - composition_undelines()->push_back(underline); - - *edit_flag() = true; - *committed_size() = 3; - - return S_OK; - } - - void InsertText2(const string16& text) { - EXPECT_EQ(L"axy", text); - } - - void SetCompositionText2(const ui::CompositionText& composition) { - EXPECT_EQ(L"ZCPc", composition.text); - EXPECT_EQ(0, composition.selection.start()); - EXPECT_EQ(3, composition.selection.end()); - ASSERT_EQ(2, composition.underlines.size()); - EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color); - EXPECT_EQ(0, composition.underlines[0].start_offset); - EXPECT_EQ(2, composition.underlines[0].end_offset); - EXPECT_TRUE(composition.underlines[0].thick); - EXPECT_EQ(SK_ColorBLACK, composition.underlines[1].color); - EXPECT_EQ(2, composition.underlines[1].start_offset); - EXPECT_EQ(4, composition.underlines[1].end_offset); - EXPECT_FALSE(composition.underlines[1].thick); - } - - HRESULT LockGranted3(DWORD flags) { - GetTextTest(0, -1, L"axyZCPc", 7); - - composition_undelines()->clear(); - *edit_flag() = true; - *committed_size() = 7; - - return S_OK; - } - - void InsertText3(const string16& text) { - EXPECT_EQ(L"ZCPc", text); - } - - void SetCompositionText3(const ui::CompositionText& composition) { - EXPECT_EQ(L"", composition.text); - EXPECT_EQ(0, composition.selection.start()); - EXPECT_EQ(0, composition.selection.end()); - EXPECT_EQ(0, composition.underlines.size()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ScenarioTestCallback); -}; - -TEST_F(TSFTextStoreTest, ScenarioTest) { - ScenarioTestCallback callback(text_store_); - EXPECT_CALL(text_input_client_, SetCompositionText(_)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText1)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText2)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText3)); - - EXPECT_CALL(text_input_client_, InsertText(_)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText2)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText3)); - - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted1)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted2)) - .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted3)); - - // OnSelectionChange will be called once after LockGranted3(). - EXPECT_CALL(*sink_, OnSelectionChange()) - .WillOnce(Return(S_OK)); - - // OnLayoutChange will be called once after LockGranted3(). - EXPECT_CALL(*sink_, OnLayoutChange(_, _)) - .WillOnce(Return(S_OK)); - - // OnTextChange will be called once after LockGranted3(). - EXPECT_CALL(*sink_, OnTextChange(_, _)) - .WillOnce(Return(S_OK)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); - result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result)); - EXPECT_EQ(S_OK, result); -} - -class GetTextExtTestCallback : public TSFTextStoreTestCallback { - public: - explicit GetTextExtTestCallback(TSFTextStore* text_store) - : TSFTextStoreTestCallback(text_store), - layout_prepared_character_num_(0) {} - - HRESULT LockGranted(DWORD flags) { - SetInternalState(L"0123456789012", 0, 0, 0); - layout_prepared_character_num_ = 13; - - TsViewCookie view_cookie = 0; - EXPECT_EQ(S_OK, text_store_->GetActiveView(&view_cookie)); - GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20); - GetTextExtTest(view_cookie, 0, 1, 11, 12, 20, 20); - GetTextExtTest(view_cookie, 0, 2, 11, 12, 30, 20); - GetTextExtTest(view_cookie, 9, 9, 100, 12, 100, 20); - GetTextExtTest(view_cookie, 9, 10, 101, 12, 110, 20); - GetTextExtTest(view_cookie, 10, 10, 110, 12, 110, 20); - GetTextExtTest(view_cookie, 11, 11, 20, 112, 20, 120); - GetTextExtTest(view_cookie, 11, 12, 21, 112, 30, 120); - GetTextExtTest(view_cookie, 9, 12, 101, 12, 30, 120); - GetTextExtTest(view_cookie, 9, 13, 101, 12, 40, 120); - GetTextExtTest(view_cookie, 0, 13, 11, 12, 40, 120); - GetTextExtTest(view_cookie, 13, 13, 40, 112, 40, 120); - - layout_prepared_character_num_ = 12; - GetTextExtNoLayoutTest(view_cookie, 13, 13); - - layout_prepared_character_num_ = 0; - GetTextExtNoLayoutTest(view_cookie, 0, 0); - - SetInternalState(L"", 0, 0, 0); - GetTextExtTest(view_cookie, 0, 0, 1, 2, 4, 6); - - // Last character is not availabe due to timing issue of async API. - // In this case, we will get first character bounds instead of whole text - // bounds. - SetInternalState(L"abc", 0, 0, 3); - layout_prepared_character_num_ = 2; - GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20); - - // TODO(nona, kinaba): Remove following test case after PPAPI supporting - // GetCompositionCharacterBounds. - SetInternalState(L"a", 0, 0, 1); - layout_prepared_character_num_ = 0; - GetTextExtTest(view_cookie, 0, 1, 1, 2, 4, 6); - return S_OK; - } - - bool GetCompositionCharacterBounds(uint32 index, gfx::Rect* rect) { - if (index >= layout_prepared_character_num_) - return false; - rect->set_x((index % 10) * 10 + 11); - rect->set_y((index / 10) * 100 + 12); - rect->set_width(9); - rect->set_height(8); - return true; - } - - gfx::Rect GetCaretBounds() { - return gfx::Rect(1, 2, 3, 4); - } - - private: - uint32 layout_prepared_character_num_; - - DISALLOW_COPY_AND_ASSIGN(GetTextExtTestCallback); -}; - -TEST_F(TSFTextStoreTest, GetTextExtTest) { - GetTextExtTestCallback callback(text_store_); - EXPECT_CALL(text_input_client_, GetCaretBounds()) - .WillRepeatedly(Invoke(&callback, - &GetTextExtTestCallback::GetCaretBounds)); - - EXPECT_CALL(text_input_client_, GetCompositionCharacterBounds(_, _)) - .WillRepeatedly( - Invoke(&callback, - &GetTextExtTestCallback::GetCompositionCharacterBounds)); - - EXPECT_CALL(*sink_, OnLockGranted(_)) - .WillOnce(Invoke(&callback, &GetTextExtTestCallback::LockGranted)); - - HRESULT result = kInvalidResult; - EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result)); - EXPECT_EQ(S_OK, result); -} - -TEST_F(TSFTextStoreTest, RequestSupportedAttrs) { - EXPECT_CALL(text_input_client_, GetTextInputType()) - .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT)); - EXPECT_CALL(text_input_client_, GetTextInputMode()) - .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT)); - - EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 1, NULL)); - - const TS_ATTRID kUnknownAttributes[] = {GUID_NULL}; - EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs( - 0, arraysize(kUnknownAttributes), kUnknownAttributes)) - << "Must fail for unknown attributes"; - - const TS_ATTRID kAttributes[] = {GUID_NULL, GUID_PROP_INPUTSCOPE, GUID_NULL}; - EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs( - 0, arraysize(kAttributes), kAttributes)) - << "InputScope must be supported"; - - { - SCOPED_TRACE("Check if RequestSupportedAttrs fails while focus is lost"); - // Emulate focus lost - text_store_->SetFocusedTextInputClient(NULL, NULL); - EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 0, NULL)); - EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs( - 0, arraysize(kAttributes), kAttributes)); - } -} - -TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) { - EXPECT_CALL(text_input_client_, GetTextInputType()) - .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT)); - EXPECT_CALL(text_input_client_, GetTextInputMode()) - .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT)); - - ULONG num_copied = 0xfffffff; - EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs( - 1, NULL, &num_copied)); - - { - SCOPED_TRACE("Make sure if InputScope is supported"); - TS_ATTRVAL buffer[2] = {}; - num_copied = 0xfffffff; - ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs( - arraysize(buffer), buffer, &num_copied)); - bool input_scope_found = false; - for (size_t i = 0; i < num_copied; ++i) { - base::win::ScopedVariant variant; - // Move ownership from |buffer[i].varValue| to |variant|. - std::swap(*variant.Receive(), buffer[i].varValue); - if (IsEqualGUID(buffer[i].idAttr, GUID_PROP_INPUTSCOPE)) { - EXPECT_EQ(VT_UNKNOWN, variant.type()); - base::win::ScopedComPtr<ITfInputScope> input_scope; - EXPECT_HRESULT_SUCCEEDED(input_scope.QueryFrom((&variant)->punkVal)); - input_scope_found = true; - // we do not break here to clean up all the retrieved VARIANTs. - } - } - EXPECT_TRUE(input_scope_found); - } - { - SCOPED_TRACE("Check if RetrieveRequestedAttrs fails while focus is lost"); - // Emulate focus lost - text_store_->SetFocusedTextInputClient(NULL, NULL); - num_copied = 0xfffffff; - TS_ATTRVAL buffer[2] = {}; - EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs( - arraysize(buffer), buffer, &num_copied)); - } -} - -} // namespace -} // namespace ui |