author | Masayuki Nakano <masayuki@d-toybox.com> |
Tue, 02 Sep 2014 09:27:25 +0900 | |
changeset 202838 | f9e2e2b2b065c5f49dea5419e9c87e11d575ca28 |
parent 202837 | a8c91093e63193105385650ee9bce8b38eb75dad |
child 202839 | ea981f4abf43fb6f54ba79d5343d1c9a034d236a |
push id | 48511 |
push user | masayuki@d-toybox.com |
push date | Tue, 02 Sep 2014 00:27:30 +0000 |
treeherder | mozilla-inbound@7b7c24a989fa [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | emk |
bugs | 1052343 |
milestone | 34.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
widget/windows/nsTextStore.cpp | file | annotate | diff | comparison | revisions | |
widget/windows/nsTextStore.h | file | annotate | diff | comparison | revisions |
--- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -47,116 +47,16 @@ static const char* kPrefNameForceEnableT * "TSF: 0x%p nsFoo::Bar(" * In an internal method, start with following text: * "TSF: 0x%p nsFoo::Bar(" * When a static method is called, start with following text: * "TSF: nsFoo::Bar(" */ PRLogModuleInfo* sTextStoreLog = nullptr; -#endif // #ifdef PR_LOGGING - -/******************************************************************/ -/* InputScopeImpl */ -/******************************************************************/ - -class InputScopeImpl MOZ_FINAL : public ITfInputScope -{ - ~InputScopeImpl() {} - -public: - InputScopeImpl(const nsTArray<InputScope>& aList) - : mInputScopes(aList) - { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p InputScopeImpl()", this)); - } - - NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(InputScopeImpl) - - STDMETHODIMP QueryInterface(REFIID riid, void** ppv) - { - *ppv=nullptr; - if ( (IID_IUnknown == riid) || (IID_ITfInputScope == riid) ) { - *ppv = static_cast<ITfInputScope*>(this); - } - if (*ppv) { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; - } - - STDMETHODIMP GetInputScopes(InputScope** pprgInputScopes, UINT* pcCount) - { - uint32_t count = (mInputScopes.IsEmpty() ? 1 : mInputScopes.Length()); - - InputScope* pScope = (InputScope*) CoTaskMemAlloc(sizeof(InputScope) * count); - NS_ENSURE_TRUE(pScope, E_OUTOFMEMORY); - - if (mInputScopes.IsEmpty()) { - *pScope = IS_DEFAULT; - *pcCount = 1; - *pprgInputScopes = pScope; - return S_OK; - } - - *pcCount = 0; - - for (uint32_t idx = 0; idx < count; idx++) { - *(pScope + idx) = mInputScopes[idx]; - (*pcCount)++; - } - - *pprgInputScopes = pScope; - return S_OK; - } - - STDMETHODIMP GetPhrase(BSTR **ppbstrPhrases, UINT *pcCount) { return E_NOTIMPL; } - STDMETHODIMP GetRegularExpression(BSTR *pbstrRegExp) { return E_NOTIMPL; } - STDMETHODIMP GetSRGS(BSTR *pbstrSRGS) { return E_NOTIMPL; } - STDMETHODIMP GetXML(BSTR *pbstrXML) { return E_NOTIMPL; } - -private: - nsTArray<InputScope> mInputScopes; -}; - -/******************************************************************/ -/* nsTextStore */ -/******************************************************************/ - -ITfThreadMgr* nsTextStore::sTsfThreadMgr = nullptr; -ITfMessagePump* nsTextStore::sMessagePump = nullptr; -ITfKeystrokeMgr* nsTextStore::sKeystrokeMgr = nullptr; -ITfDisplayAttributeMgr* nsTextStore::sDisplayAttrMgr = nullptr; -ITfCategoryMgr* nsTextStore::sCategoryMgr = nullptr; -ITfDocumentMgr* nsTextStore::sTsfDisabledDocumentMgr = nullptr; -ITfContext* nsTextStore::sTsfDisabledContext = nullptr; -ITfInputProcessorProfiles* nsTextStore::sInputProcessorProfiles = nullptr; -DWORD nsTextStore::sTsfClientId = 0; -StaticRefPtr<nsTextStore> nsTextStore::sEnabledTextStore; - -bool nsTextStore::sCreateNativeCaretForATOK = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToFreeChangJie = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false; - -#define TIP_NAME_BEGINS_WITH_ATOK \ - (NS_LITERAL_STRING("ATOK ")) -// NOTE: Free ChangJie 2010 missspells its name... -#define TIP_NAME_FREE_CHANG_JIE_2010 \ - (NS_LITERAL_STRING("Free CangJie IME 10")) -#define TIP_NAME_EASY_CHANGJEI \ - (NS_LITERAL_STRING( \ - "\x4E2D\x6587 (\x7E41\x9AD4) - \x6613\x9821\x8F38\x5165\x6CD5")) - -UINT nsTextStore::sFlushTIPInputMessage = 0; - -#define TEXTSTORE_DEFAULT_VIEW (1) - -#ifdef PR_LOGGING static const char* GetBoolName(bool aBool) { return aBool ? "true" : "false"; } static void @@ -724,153 +624,593 @@ GetModifiersName(Modifiers aModifiers) ADD_SEPARATOR_IF_NECESSARY(names); names += NS_DOM_KEYNAME_OS; } return names; } #endif // #ifdef PR_LOGGING -nsTextStore::nsTextStore() - : mLockedContent(mComposition, mSelection) - , mEditCookie(0) - , mIPProfileCookie(TF_INVALID_COOKIE) +/******************************************************************/ +/* InputScopeImpl */ +/******************************************************************/ + +class InputScopeImpl MOZ_FINAL : public ITfInputScope +{ + ~InputScopeImpl() {} + +public: + InputScopeImpl(const nsTArray<InputScope>& aList) + : mInputScopes(aList) + { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p InputScopeImpl()", this)); + } + + NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(InputScopeImpl) + + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) + { + *ppv=nullptr; + if ( (IID_IUnknown == riid) || (IID_ITfInputScope == riid) ) { + *ppv = static_cast<ITfInputScope*>(this); + } + if (*ppv) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + + STDMETHODIMP GetInputScopes(InputScope** pprgInputScopes, UINT* pcCount) + { + uint32_t count = (mInputScopes.IsEmpty() ? 1 : mInputScopes.Length()); + + InputScope* pScope = (InputScope*) CoTaskMemAlloc(sizeof(InputScope) * count); + NS_ENSURE_TRUE(pScope, E_OUTOFMEMORY); + + if (mInputScopes.IsEmpty()) { + *pScope = IS_DEFAULT; + *pcCount = 1; + *pprgInputScopes = pScope; + return S_OK; + } + + *pcCount = 0; + + for (uint32_t idx = 0; idx < count; idx++) { + *(pScope + idx) = mInputScopes[idx]; + (*pcCount)++; + } + + *pprgInputScopes = pScope; + return S_OK; + } + + STDMETHODIMP GetPhrase(BSTR **ppbstrPhrases, UINT *pcCount) { return E_NOTIMPL; } + STDMETHODIMP GetRegularExpression(BSTR *pbstrRegExp) { return E_NOTIMPL; } + STDMETHODIMP GetSRGS(BSTR *pbstrSRGS) { return E_NOTIMPL; } + STDMETHODIMP GetXML(BSTR *pbstrXML) { return E_NOTIMPL; } + +private: + nsTArray<InputScope> mInputScopes; +}; + +/******************************************************************/ +/* TSFStaticSink */ +/******************************************************************/ + +class TSFStaticSink MOZ_FINAL : public ITfActiveLanguageProfileNotifySink + , public ITfInputProcessorProfileActivationSink +{ +public: + static TSFStaticSink* GetInstance() + { + if (!sInstance) { + NS_ADDREF(sInstance = new TSFStaticSink()); + } + return sInstance; + } + + static void Shutdown() + { + if (sInstance) { + sInstance->Destroy(); + NS_RELEASE(sInstance); + } + } + + bool Init(ITfThreadMgr* aThreadMgr, + ITfInputProcessorProfiles* aInputProcessorProfiles); + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) + { + *ppv = nullptr; + if (IID_IUnknown == riid || + IID_ITfActiveLanguageProfileNotifySink == riid) { + *ppv = static_cast<ITfActiveLanguageProfileNotifySink*>(this); + } else if (IID_ITfInputProcessorProfileActivationSink == riid) { + *ppv = static_cast<ITfInputProcessorProfileActivationSink*>(this); + } + if (*ppv) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + + NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFStaticSink) + + const nsString& GetActiveTIPKeyboardDescription() const + { + return mActiveTIPKeyboardDescription; + } + + static bool IsIMM_IME() + { + if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) { + return IsIMM_IME(::GetKeyboardLayout(0)); + } + return sInstance->mIsIMM_IME; + } + + static bool IsIMM_IME(HKL aHKL) + { + return (::ImmGetIMEFileNameW(aHKL, nullptr, 0) > 0); + } + + bool EnsureInitActiveTIPKeyboard(); + +public: // ITfActiveLanguageProfileNotifySink + STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile, + BOOL fActivated); + +public: // ITfInputProcessorProfileActivationSink + STDMETHODIMP OnActivated(DWORD, LANGID, REFCLSID, REFGUID, REFGUID, + HKL, DWORD); + +private: + TSFStaticSink(); + virtual ~TSFStaticSink() {} + + void Destroy(); + + void GetTIPDescription(REFCLSID aTextService, LANGID aLangID, + REFGUID aProfile, nsAString& aDescription); + bool IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, + REFGUID aProfile); + + // Cookie of installing ITfInputProcessorProfileActivationSink + DWORD mIPProfileCookie; + // Cookie of installing ITfActiveLanguageProfileNotifySink + DWORD mLangProfileCookie; + + // True if current IME is implemented with IMM. + bool mIsIMM_IME; + // True if OnActivated() is already called + bool mOnActivatedCalled; + + nsRefPtr<ITfThreadMgr> mThreadMgr; + nsRefPtr<ITfInputProcessorProfiles> mInputProcessorProfiles; + + // Active TIP keyboard's description. If active language profile isn't TIP, + // i.e., IMM-IME or just a keyboard layout, this is empty. + nsString mActiveTIPKeyboardDescription; + + static TSFStaticSink* sInstance; +}; + +TSFStaticSink* TSFStaticSink::sInstance = nullptr; + +TSFStaticSink::TSFStaticSink() + : mIPProfileCookie(TF_INVALID_COOKIE) , mLangProfileCookie(TF_INVALID_COOKIE) - , mSinkMask(0) - , mLock(0) - , mLockQueued(0) - , mRequestedAttrValues(false) - , mIsRecordingActionsWithoutLock(false) - , mPendingOnSelectionChange(false) - , mPendingOnLayoutChange(false) - , mNativeCaretIsCreated(false) , mIsIMM_IME(false) , mOnActivatedCalled(false) { - for (int32_t i = 0; i < NUM_OF_SUPPORTED_ATTRS; i++) { - mRequestedAttrs[i] = false; - } - - // We hope that 5 or more actions don't occur at once. - mPendingActions.SetCapacity(5); - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::nsTestStore() SUCCEEDED", this)); } bool -nsTextStore::Init(ITfThreadMgr* aThreadMgr) +TSFStaticSink::Init(ITfThreadMgr* aThreadMgr, + ITfInputProcessorProfiles* aInputProcessorProfiles) { + MOZ_ASSERT(!mThreadMgr && !mInputProcessorProfiles, + "TSFStaticSink::Init() must be called only once"); + + mThreadMgr = aThreadMgr; + mInputProcessorProfiles = aInputProcessorProfiles; + nsRefPtr<ITfSource> source; HRESULT hr = - aThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); + mThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); if (FAILED(hr)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Init() FAILED to get ITfSource instance " - "(0x%08X)", this, hr)); + ("TSF: 0x%p TSFStaticSink::Init() FAILED to get ITfSource " + "instance (0x%08X)", this, hr)); return false; } // On Vista or later, Windows let us know activate IME changed only with // ITfInputProcessorProfileActivationSink. However, it's not available on XP. // On XP, ITfActiveLanguageProfileNotifySink is available for it. // NOTE: Each OnActivated() should be called when TSF becomes available. if (IsVistaOrLater()) { hr = source->AdviseSink(IID_ITfInputProcessorProfileActivationSink, static_cast<ITfInputProcessorProfileActivationSink*>(this), &mIPProfileCookie); if (FAILED(hr) || mIPProfileCookie == TF_INVALID_COOKIE) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Init() FAILED to install " + ("TSF: 0x%p TSFStaticSink::Init() FAILED to install " "ITfInputProcessorProfileActivationSink (0x%08X)", this, hr)); return false; } } else { hr = source->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, static_cast<ITfActiveLanguageProfileNotifySink*>(this), &mLangProfileCookie); if (FAILED(hr) || mLangProfileCookie == TF_INVALID_COOKIE) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Init() FAILED to install " + ("TSF: 0x%p TSFStaticSink::Init() FAILED to install " "ITfActiveLanguageProfileNotifySink (0x%08X)", this, hr)); return false; } } PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::Init(), " + ("TSF: 0x%p TSFStaticSink::Init(), " "mIPProfileCookie=0x%08X, mLangProfileCookie=0x%08X", this, mIPProfileCookie, mLangProfileCookie)); - return true; } -nsTextStore::~nsTextStore() -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore instance is destroyed", this)); -} - void -nsTextStore::Shutdown() +TSFStaticSink::Destroy() { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::Shutdown() " - "mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p, mIPProfileCookie=0x%08X, " - "mLangProfileCookie=0x%08X", - this, mWidget.get(), mDocumentMgr.get(), mContext.get(), - mIPProfileCookie, mLangProfileCookie)); + ("TSF: 0x%p TSFStaticSink::Shutdown() " + "mIPProfileCookie=0x%08X, mLangProfileCookie=0x%08X", + this, mIPProfileCookie, mLangProfileCookie)); if (mIPProfileCookie != TF_INVALID_COOKIE) { nsRefPtr<ITfSource> source; HRESULT hr = - sTsfThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); + mThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); if (FAILED(hr)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Shutdown() FAILED to get " + ("TSF: 0x%p TSFStaticSink::Shutdown() FAILED to get " "ITfSource instance (0x%08X)", this, hr)); } else { hr = source->UnadviseSink(mIPProfileCookie); if (FAILED(hr)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::Shutdown() FAILED to uninstall " "ITfInputProcessorProfileActivationSink (0x%08X)", this, hr)); } } } if (mLangProfileCookie != TF_INVALID_COOKIE) { nsRefPtr<ITfSource> source; HRESULT hr = - sTsfThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); + mThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); if (FAILED(hr)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Shutdown() FAILED to get " + ("TSF: 0x%p TSFStaticSink::Shutdown() FAILED to get " "ITfSource instance (0x%08X)", this, hr)); } else { hr = source->UnadviseSink(mLangProfileCookie); if (FAILED(hr)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::Shutdown() FAILED to uninstall " + ("TSF: 0x%p TSFStaticSink::Shutdown() FAILED to uninstall " "ITfActiveLanguageProfileNotifySink (0x%08X)", this, hr)); } } } + + mThreadMgr = nullptr; + mInputProcessorProfiles = nullptr; +} + +STDMETHODIMP +TSFStaticSink::OnActivated(REFCLSID clsid, REFGUID guidProfile, + BOOL fActivated) +{ + // NOTE: This is installed only on XP or Server 2003. + if (fActivated) { + // TODO: We should check if the profile's category is keyboard or not. + mOnActivatedCalled = true; + mIsIMM_IME = IsIMM_IME(::GetKeyboardLayout(0)); + + LANGID langID; + HRESULT hr = mInputProcessorProfiles->GetCurrentLanguage(&langID); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: TSFStaticSink::OnActivated() FAILED due to " + "GetCurrentLanguage() failure, hr=0x%08X", hr)); + } else if (IsTIPCategoryKeyboard(clsid, langID, guidProfile)) { + GetTIPDescription(clsid, langID, guidProfile, + mActiveTIPKeyboardDescription); + } else if (clsid == CLSID_NULL || guidProfile == GUID_NULL) { + // Perhaps, this case is that keyboard layout without TIP is activated. + mActiveTIPKeyboardDescription.Truncate(); + } + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::OnActivated(rclsid=%s, guidProfile=%s, " + "fActivated=%s), mIsIMM_IME=%s, mActiveTIPDescription=\"%s\"", + this, GetCLSIDNameStr(clsid).get(), + GetGUIDNameStr(guidProfile).get(), GetBoolName(fActivated), + GetBoolName(mIsIMM_IME), + NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); + return S_OK; +} + +STDMETHODIMP +TSFStaticSink::OnActivated(DWORD dwProfileType, + LANGID langid, + REFCLSID rclsid, + REFGUID catid, + REFGUID guidProfile, + HKL hkl, + DWORD dwFlags) +{ + // NOTE: This is installed only on Vista or later. However, this may be + // called by EnsureInitActiveLanguageProfile() even on XP or Server + // 2003. + if ((dwFlags & TF_IPSINK_FLAG_ACTIVE) && + (dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT || + catid == GUID_TFCAT_TIP_KEYBOARD)) { + mOnActivatedCalled = true; + mIsIMM_IME = IsIMM_IME(hkl); + GetTIPDescription(rclsid, langid, guidProfile, + mActiveTIPKeyboardDescription); + } + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::OnActivated(dwProfileType=%s (0x%08X), " + "langid=0x%08X, rclsid=%s, catid=%s, guidProfile=%s, hkl=0x%08X, " + "dwFlags=0x%08X (TF_IPSINK_FLAG_ACTIVE: %s)), mIsIMM_IME=%s, " + "mActiveTIPDescription=\"%s\"", + this, dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR ? + "TF_PROFILETYPE_INPUTPROCESSOR" : + dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ? + "TF_PROFILETYPE_KEYBOARDLAYOUT" : "Unknown", dwProfileType, + langid, GetCLSIDNameStr(rclsid).get(), GetGUIDNameStr(catid).get(), + GetGUIDNameStr(guidProfile).get(), hkl, dwFlags, + GetBoolName(dwFlags & TF_IPSINK_FLAG_ACTIVE), + GetBoolName(mIsIMM_IME), + NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); + return S_OK; +} + +bool +TSFStaticSink::EnsureInitActiveTIPKeyboard() +{ + if (mOnActivatedCalled) { + return true; + } + + if (IsVistaOrLater()) { + nsRefPtr<ITfInputProcessorProfileMgr> profileMgr; + HRESULT hr = + mInputProcessorProfiles->QueryInterface(IID_ITfInputProcessorProfileMgr, + getter_AddRefs(profileMgr)); + if (FAILED(hr) || !profileMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), FAILED " + "to get input processor profile manager, hr=0x%08X", this, hr)); + return false; + } + + TF_INPUTPROCESSORPROFILE profile; + hr = profileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile); + if (hr == S_FALSE) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), FAILED " + "to get active keyboard layout profile due to no active profile, " + "hr=0x%08X", this, hr)); + // XXX Should we call OnActivated() with arguments like non-TIP in this + // case? + return false; + } + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), FAILED " + "to get active TIP keyboard, hr=0x%08X", this, hr)); + return false; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), " + "calling OnActivated() manually...", this)); + OnActivated(profile.dwProfileType, profile.langid, profile.clsid, + profile.catid, profile.guidProfile, ::GetKeyboardLayout(0), + TF_IPSINK_FLAG_ACTIVE); + return true; + } + + LANGID langID; + HRESULT hr = mInputProcessorProfiles->GetCurrentLanguage(&langID); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), FAILED " + "to get current language ID, hr=0x%08X", this, hr)); + return false; + } + + nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; + hr = mInputProcessorProfiles->EnumLanguageProfiles(langID, + getter_AddRefs(enumLangProfiles)); + if (FAILED(hr) || !enumLangProfiles) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), FAILED " + "to get language profiles enumerator, hr=0x%08X", this, hr)); + return false; + } + + TF_LANGUAGEPROFILE profile; + ULONG fetch = 0; + while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { + if (!profile.fActive || profile.catid != GUID_TFCAT_TIP_KEYBOARD) { + continue; + } + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), " + "calling OnActivated() manually...", this)); + bool isTIP = profile.guidProfile != GUID_NULL; + OnActivated(isTIP ? TF_PROFILETYPE_INPUTPROCESSOR : + TF_PROFILETYPE_KEYBOARDLAYOUT, + profile.langid, profile.clsid, profile.catid, + profile.guidProfile, ::GetKeyboardLayout(0), + TF_IPSINK_FLAG_ACTIVE); + return true; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p TSFStaticSink::EnsureInitActiveLanguageProfile(), " + "calling OnActivated() without active TIP manually...", this)); + OnActivated(TF_PROFILETYPE_KEYBOARDLAYOUT, + langID, CLSID_NULL, GUID_TFCAT_TIP_KEYBOARD, + GUID_NULL, ::GetKeyboardLayout(0), + TF_IPSINK_FLAG_ACTIVE); + return true; +} + +void +TSFStaticSink::GetTIPDescription(REFCLSID aTextService, LANGID aLangID, + REFGUID aProfile, nsAString& aDescription) +{ + aDescription.Truncate(); + + if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { + return; + } + + BSTR description = nullptr; + HRESULT hr = + mInputProcessorProfiles->GetLanguageProfileDescription(aTextService, + aLangID, + aProfile, + &description); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::InitActiveTIPDescription() FAILED " + "due to GetLanguageProfileDescription() failure, hr=0x%08X", + this, hr)); + return; + } + + if (description && description[0]) { + aDescription.Assign(description); + } + ::SysFreeString(description); +} + +bool +TSFStaticSink::IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, + REFGUID aProfile) +{ + if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { + return false; + } + + nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; + HRESULT hr = + mInputProcessorProfiles->EnumLanguageProfiles(aLangID, + getter_AddRefs(enumLangProfiles)); + if (FAILED(hr) || !enumLangProfiles) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p TSFStaticSink::IsTIPCategoryKeyboard(), FAILED " + "to get language profiles enumerator, hr=0x%08X", this, hr)); + return false; + } + + TF_LANGUAGEPROFILE profile; + ULONG fetch = 0; + while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { + // XXX We're not sure a profile is registered with two or more categories. + if (profile.clsid == aTextService && + profile.guidProfile == aProfile && + profile.catid == GUID_TFCAT_TIP_KEYBOARD) { + return true; + } + } + return false; +} + +/******************************************************************/ +/* nsTextStore */ +/******************************************************************/ + +ITfThreadMgr* nsTextStore::sTsfThreadMgr = nullptr; +ITfMessagePump* nsTextStore::sMessagePump = nullptr; +ITfKeystrokeMgr* nsTextStore::sKeystrokeMgr = nullptr; +ITfDisplayAttributeMgr* nsTextStore::sDisplayAttrMgr = nullptr; +ITfCategoryMgr* nsTextStore::sCategoryMgr = nullptr; +ITfDocumentMgr* nsTextStore::sTsfDisabledDocumentMgr = nullptr; +ITfContext* nsTextStore::sTsfDisabledContext = nullptr; +ITfInputProcessorProfiles* nsTextStore::sInputProcessorProfiles = nullptr; +DWORD nsTextStore::sTsfClientId = 0; +StaticRefPtr<nsTextStore> nsTextStore::sEnabledTextStore; + +bool nsTextStore::sCreateNativeCaretForATOK = false; +bool nsTextStore::sDoNotReturnNoLayoutErrorToFreeChangJie = false; +bool nsTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false; + +#define TIP_NAME_BEGINS_WITH_ATOK \ + (NS_LITERAL_STRING("ATOK ")) +// NOTE: Free ChangJie 2010 missspells its name... +#define TIP_NAME_FREE_CHANG_JIE_2010 \ + (NS_LITERAL_STRING("Free CangJie IME 10")) +#define TIP_NAME_EASY_CHANGJEI \ + (NS_LITERAL_STRING( \ + "\x4E2D\x6587 (\x7E41\x9AD4) - \x6613\x9821\x8F38\x5165\x6CD5")) + +UINT nsTextStore::sFlushTIPInputMessage = 0; + +#define TEXTSTORE_DEFAULT_VIEW (1) + +nsTextStore::nsTextStore() + : mLockedContent(mComposition, mSelection) + , mEditCookie(0) + , mSinkMask(0) + , mLock(0) + , mLockQueued(0) + , mRequestedAttrValues(false) + , mIsRecordingActionsWithoutLock(false) + , mPendingOnSelectionChange(false) + , mPendingOnLayoutChange(false) + , mNativeCaretIsCreated(false) +{ + for (int32_t i = 0; i < NUM_OF_SUPPORTED_ATTRS; i++) { + mRequestedAttrs[i] = false; + } + + // We hope that 5 or more actions don't occur at once. + mPendingActions.SetCapacity(5); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::nsTestStore() SUCCEEDED", this)); +} + +nsTextStore::~nsTextStore() +{ + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore instance is destroyed", this)); } bool nsTextStore::Create(nsWindowBase* aWidget) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::Create(aWidget=0x%p)", this, aWidget)); - EnsureInitActiveTIPKeyboard(); + TSFStaticSink::GetInstance()->EnsureInitActiveTIPKeyboard(); if (mDocumentMgr) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::Create() FAILED due to already initialized", this)); return false; } @@ -969,20 +1309,16 @@ STDMETHODIMP nsTextStore::QueryInterface(REFIID riid, void** ppv) { *ppv=nullptr; if ( (IID_IUnknown == riid) || (IID_ITextStoreACP == riid) ) { *ppv = static_cast<ITextStoreACP*>(this); } else if (IID_ITfContextOwnerCompositionSink == riid) { *ppv = static_cast<ITfContextOwnerCompositionSink*>(this); - } else if (IID_ITfActiveLanguageProfileNotifySink == riid) { - *ppv = static_cast<ITfActiveLanguageProfileNotifySink*>(this); - } else if (IID_ITfInputProcessorProfileActivationSink == riid) { - *ppv = static_cast<ITfInputProcessorProfileActivationSink*>(this); } else if (IID_ITfMouseTrackerACP == riid) { *ppv = static_cast<ITfMouseTrackerACP*>(this); } if (*ppv) { AddRef(); return S_OK; } @@ -2813,20 +3149,22 @@ nsTextStore::GetTextExt(TsViewCookie vcV return TS_E_INVALIDPOS; } // Free ChangJie 2010 and Easy Changjei 1.0.12.0 doesn't handle // ITfContextView::GetTextExt() properly. Prehaps, it's due to a bug of TSF. // TSF (at least on Win 8.1) doesn't return TS_E_NOLAYOUT to the caller // even if we return it. It's converted to just E_FAIL. // TODO: On Win 9, we need to check this hack is still necessary. + const nsString& activeTIPKeyboardDescription = + TSFStaticSink::GetInstance()->GetActiveTIPKeyboardDescription(); if ((sDoNotReturnNoLayoutErrorToFreeChangJie && - mActiveTIPKeyboardDescription.Equals(TIP_NAME_FREE_CHANG_JIE_2010)) || + activeTIPKeyboardDescription.Equals(TIP_NAME_FREE_CHANG_JIE_2010)) || (sDoNotReturnNoLayoutErrorToEasyChangjei && - mActiveTIPKeyboardDescription.Equals(TIP_NAME_EASY_CHANGJEI)) && + activeTIPKeyboardDescription.Equals(TIP_NAME_EASY_CHANGJEI)) && mComposition.IsComposing() && mLockedContent.IsLayoutChangedAfter(acpEnd) && mComposition.mStart < acpEnd) { acpEnd = mComposition.mStart; acpStart = std::min(acpStart, acpEnd); PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::GetTextExt() hacked the offsets for TIP " "acpStart=%d, acpEnd=%d", this, acpStart, acpEnd)); @@ -2892,17 +3230,17 @@ nsTextStore::GetTextExt(TsViewCookie vcV // not equal if text rect was clipped *pfClipped = !::EqualRect(prc, &textRect); // ATOK refers native caret position and size on Desktop applications for // deciding candidate window. Therefore, we need to create native caret // for hacking the bug. if (sCreateNativeCaretForATOK && StringBeginsWith( - mActiveTIPKeyboardDescription, TIP_NAME_BEGINS_WITH_ATOK) && + activeTIPKeyboardDescription, TIP_NAME_BEGINS_WITH_ATOK) && mComposition.IsComposing() && mComposition.mStart <= acpStart && mComposition.EndOffset() >= acpStart && mComposition.mStart <= acpEnd && mComposition.EndOffset() >= acpEnd) { if (mNativeCaretIsCreated) { ::DestroyCaret(); mNativeCaretIsCreated = false; } CreateNativeCaret(); @@ -3480,88 +3818,16 @@ nsTextStore::OnEndComposition(ITfComposi } PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this)); return S_OK; } STDMETHODIMP -nsTextStore::OnActivated(REFCLSID clsid, REFGUID guidProfile, - BOOL fActivated) -{ - // NOTE: This is installed only on XP or Server 2003. - if (fActivated) { - // TODO: We should check if the profile's category is keyboard or not. - mOnActivatedCalled = true; - mIsIMM_IME = IsIMM_IME(::GetKeyboardLayout(0)); - - LANGID langID; - HRESULT hr = sInputProcessorProfiles->GetCurrentLanguage(&langID); - if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: nsTextStore::OnActivated() FAILED due to " - "GetCurrentLanguage() failure, hr=0x%08X", hr)); - } else if (IsTIPCategoryKeyboard(clsid, langID, guidProfile)) { - GetTIPDescription(clsid, langID, guidProfile, - mActiveTIPKeyboardDescription); - } else if (clsid == CLSID_NULL || guidProfile == GUID_NULL) { - // Perhaps, this case is that keyboard layout without TIP is activated. - mActiveTIPKeyboardDescription.Truncate(); - } - } - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::OnActivated(rclsid=%s, guidProfile=%s, " - "fActivated=%s), mIsIMM_IME=%s, mActiveTIPDescription=\"%s\"", - this, GetCLSIDNameStr(clsid).get(), - GetGUIDNameStr(guidProfile).get(), GetBoolName(fActivated), - GetBoolName(mIsIMM_IME), - NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); - return S_OK; -} - -STDMETHODIMP -nsTextStore::OnActivated(DWORD dwProfileType, - LANGID langid, - REFCLSID rclsid, - REFGUID catid, - REFGUID guidProfile, - HKL hkl, - DWORD dwFlags) -{ - // NOTE: This is installed only on Vista or later. However, this may be - // called by EnsureInitActiveLanguageProfile() even on XP or Server - // 2003. - if ((dwFlags & TF_IPSINK_FLAG_ACTIVE) && - (dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT || - catid == GUID_TFCAT_TIP_KEYBOARD)) { - mOnActivatedCalled = true; - mIsIMM_IME = IsIMM_IME(hkl); - GetTIPDescription(rclsid, langid, guidProfile, - mActiveTIPKeyboardDescription); - } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::OnActivated(dwProfileType=%s (0x%08X), " - "langid=0x%08X, rclsid=%s, catid=%s, guidProfile=%s, hkl=0x%08X, " - "dwFlags=0x%08X (TF_IPSINK_FLAG_ACTIVE: %s)), mIsIMM_IME=%s, " - "mActiveTIPDescription=\"%s\"", - this, dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR ? - "TF_PROFILETYPE_INPUTPROCESSOR" : - dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ? - "TF_PROFILETYPE_KEYBOARDLAYOUT" : "Unknown", dwProfileType, - langid, GetCLSIDNameStr(rclsid).get(), GetGUIDNameStr(catid).get(), - GetGUIDNameStr(guidProfile).get(), hkl, dwFlags, - GetBoolName(dwFlags & TF_IPSINK_FLAG_ACTIVE), - GetBoolName(mIsIMM_IME), - NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); - return S_OK; -} - -STDMETHODIMP nsTextStore::AdviseMouseSink(ITfRangeACP* range, ITfMouseSink* pSink, DWORD* pdwCookie) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::AdviseMouseSink(range=0x%p, pSink=0x%p, " "pdwCookie=0x%p)", this, range, pSink, pdwCookie)); @@ -3989,109 +4255,16 @@ nsTextStore::CreateNativeCaret() if (toplevelWindow != window) { caretRect.MoveBy(toplevelWindow->WidgetToScreenOffset()); caretRect.MoveBy(-window->WidgetToScreenOffset()); } ::SetCaretPos(caretRect.x, caretRect.y); } -bool -nsTextStore::EnsureInitActiveTIPKeyboard() -{ - if (mOnActivatedCalled) { - return true; - } - - if (IsVistaOrLater()) { - nsRefPtr<ITfInputProcessorProfileMgr> profileMgr; - HRESULT hr = - sInputProcessorProfiles->QueryInterface(IID_ITfInputProcessorProfileMgr, - getter_AddRefs(profileMgr)); - if (FAILED(hr) || !profileMgr) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " - "to get input processor profile manager, hr=0x%08X", this, hr)); - return false; - } - - TF_INPUTPROCESSORPROFILE profile; - hr = profileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile); - if (hr == S_FALSE) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " - "to get active keyboard layout profile due to no active profile, " - "hr=0x%08X", this, hr)); - // XXX Should we call OnActivated() with arguments like non-TIP in this - // case? - return false; - } - if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " - "to get active TIP keyboard, hr=0x%08X", this, hr)); - return false; - } - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " - "calling OnActivated() manually...", this)); - OnActivated(profile.dwProfileType, profile.langid, profile.clsid, - profile.catid, profile.guidProfile, ::GetKeyboardLayout(0), - TF_IPSINK_FLAG_ACTIVE); - return true; - } - - LANGID langID; - HRESULT hr = sInputProcessorProfiles->GetCurrentLanguage(&langID); - if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " - "to get current language ID, hr=0x%08X", this, hr)); - return false; - } - - nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; - hr = sInputProcessorProfiles->EnumLanguageProfiles(langID, - getter_AddRefs(enumLangProfiles)); - if (FAILED(hr) || !enumLangProfiles) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " - "to get language profiles enumerator, hr=0x%08X", this, hr)); - return false; - } - - TF_LANGUAGEPROFILE profile; - ULONG fetch = 0; - while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { - if (!profile.fActive || profile.catid != GUID_TFCAT_TIP_KEYBOARD) { - continue; - } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " - "calling OnActivated() manually...", this)); - bool isTIP = profile.guidProfile != GUID_NULL; - OnActivated(isTIP ? TF_PROFILETYPE_INPUTPROCESSOR : - TF_PROFILETYPE_KEYBOARDLAYOUT, - profile.langid, profile.clsid, profile.catid, - profile.guidProfile, ::GetKeyboardLayout(0), - TF_IPSINK_FLAG_ACTIVE); - return true; - } - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " - "calling OnActivated() without active TIP manually...", this)); - OnActivated(TF_PROFILETYPE_KEYBOARDLAYOUT, - langID, CLSID_NULL, GUID_TFCAT_TIP_KEYBOARD, - GUID_NULL, ::GetKeyboardLayout(0), - TF_IPSINK_FLAG_ACTIVE); - return true; -} - void nsTextStore::CommitCompositionInternal(bool aDiscard) { PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), " "mSink=0x%p, mContext=0x%p, mComposition.mView=0x%p, " "mComposition.mString=\"%s\"", this, GetBoolName(aDiscard), mSink.get(), mContext.get(), @@ -4279,79 +4452,16 @@ nsTextStore::MarkContextAsEmpty(ITfConte PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: nsTextStore::MarkContextAsEmpty(), setting " "to mark empty context 0x%p...", aContext)); comp->SetValue(sTsfClientId, &variant_int4_value1); } // static -bool -nsTextStore::IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, - REFGUID aProfile) -{ - if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { - return false; - } - - nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; - HRESULT hr = - sInputProcessorProfiles->EnumLanguageProfiles(aLangID, - getter_AddRefs(enumLangProfiles)); - if (FAILED(hr) || !enumLangProfiles) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: nsTextStore::IsTIPCategoryKeyboard(), FAILED " - "to get language profiles enumerator, hr=0x%08X", hr)); - return false; - } - - TF_LANGUAGEPROFILE profile; - ULONG fetch = 0; - while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { - // XXX We're not sure a profile is registered with two or more categories. - if (profile.clsid == aTextService && - profile.guidProfile == aProfile && - profile.catid == GUID_TFCAT_TIP_KEYBOARD) { - return true; - } - } - return false; -} - -// static -void -nsTextStore::GetTIPDescription(REFCLSID aTextService, LANGID aLangID, - REFGUID aProfile, nsAString& aDescription) -{ - aDescription.Truncate(); - - if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { - return; - } - - BSTR description = nullptr; - HRESULT hr = - sInputProcessorProfiles->GetLanguageProfileDescription(aTextService, - aLangID, - aProfile, - &description); - if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: nsTextStore::InitActiveTIPDescription() FAILED due to " - "GetLanguageProfileDescription() failure, hr=0x%08X", hr)); - return; - } - - if (description && description[0]) { - aDescription.Assign(description); - } - ::SysFreeString(description); -} - -// static void nsTextStore::Initialize() { #ifdef PR_LOGGING if (!sTextStoreLog) { sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets"); } #endif @@ -4473,24 +4583,30 @@ nsTextStore::Initialize() return; } MarkContextAsKeyboardDisabled(disabledContext); MarkContextAsEmpty(disabledContext); PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: nsTextStore::Initialize() is creating " + "a TSFStaticSink instance...")); + TSFStaticSink* staticSink = TSFStaticSink::GetInstance(); + if (!staticSink->Init(threadMgr, inputProcessorProfiles)) { + TSFStaticSink::Shutdown(); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: nsTextStore::Initialize() FAILED to initialize TSFStaticSink " + "instance")); + return; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize() is creating " "an nsTextStore instance...")); nsRefPtr<nsTextStore> textStore = new nsTextStore(); - if (!textStore->Init(threadMgr)) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: nsTextStore::Initialize() FAILED to initialize nsTextStore " - "instance")); - return; - } inputProcessorProfiles.swap(sInputProcessorProfiles); threadMgr.swap(sTsfThreadMgr); messagePump.swap(sMessagePump); keystrokeMgr.swap(sKeystrokeMgr); displayAttributeMgr.swap(sDisplayAttrMgr); categoryMgr.swap(sCategoryMgr); disabledDocumentMgr.swap(sTsfDisabledDocumentMgr); @@ -4524,19 +4640,17 @@ nsTextStore::Initialize() } // static void nsTextStore::Terminate(void) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: nsTextStore::Terminate()")); - if (sEnabledTextStore) { - sEnabledTextStore->Shutdown(); - } + TSFStaticSink::Shutdown(); NS_IF_RELEASE(sDisplayAttrMgr); NS_IF_RELEASE(sCategoryMgr); sEnabledTextStore = nullptr; NS_IF_RELEASE(sTsfDisabledDocumentMgr); NS_IF_RELEASE(sTsfDisabledContext); NS_IF_RELEASE(sInputProcessorProfiles); sTsfClientId = 0; @@ -4600,16 +4714,23 @@ nsTextStore::ProcessMessage(nsWindowBase if (!IsComposingOn(aWindow)) { break; } CommitComposition(false); break; } } +// static +bool +nsTextStore::IsIMM_IME() +{ + return TSFStaticSink::IsIMM_IME(); +} + /******************************************************************/ /* nsTextStore::Composition */ /******************************************************************/ void nsTextStore::Composition::Start(ITfCompositionView* aCompositionView, LONG aCompositionStartOffset, const nsAString& aCompositionString)
--- a/widget/windows/nsTextStore.h +++ b/widget/windows/nsTextStore.h @@ -36,31 +36,30 @@ struct ITfThreadMgr; struct ITfDocumentMgr; struct ITfDisplayAttributeMgr; struct ITfCategoryMgr; class nsWindow; #ifdef MOZ_METRO class MetroWidget; #endif +class TSFStaticSink; namespace mozilla { namespace widget { struct MSGResult; } // namespace widget } // namespace mozilla /* * Text Services Framework text store */ class nsTextStore MOZ_FINAL : public ITextStoreACP , public ITfContextOwnerCompositionSink - , public ITfActiveLanguageProfileNotifySink - , public ITfInputProcessorProfileActivationSink , public ITfMouseTrackerACP { public: /*IUnknown*/ STDMETHODIMP QueryInterface(REFIID, void**); NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(nsTextStore) public: /*ITextStoreACP*/ @@ -96,24 +95,16 @@ public: /*ITextStoreACP*/ STDMETHODIMP InsertEmbeddedAtSelection(DWORD, IDataObject*, LONG*, LONG*, TS_TEXTCHANGE*); public: /*ITfContextOwnerCompositionSink*/ STDMETHODIMP OnStartComposition(ITfCompositionView*, BOOL*); STDMETHODIMP OnUpdateComposition(ITfCompositionView*, ITfRange*); STDMETHODIMP OnEndComposition(ITfCompositionView*); -public: /*ITfActiveLanguageProfileNotifySink*/ - STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile, - BOOL fActivated); - -public: /*ITfInputProcessorProfileActivationSink*/ - STDMETHODIMP OnActivated(DWORD, LANGID, REFCLSID, REFGUID, REFGUID, - HKL, DWORD); - public: /*ITfMouseTrackerACP*/ STDMETHODIMP AdviseMouseSink(ITfRangeACP*, ITfMouseSink*, DWORD*); STDMETHODIMP UnadviseMouseSink(DWORD); protected: typedef mozilla::widget::IMENotification IMENotification; typedef mozilla::widget::IMEState IMEState; typedef mozilla::widget::InputContext InputContext; @@ -219,50 +210,30 @@ public: return (sEnabledTextStore && sEnabledTextStore->mComposition.IsComposing()); } static bool IsComposingOn(nsWindowBase* aWidget) { return (IsComposing() && sEnabledTextStore->mWidget == aWidget); } - static bool IsIMM_IME() - { - if (!sEnabledTextStore || - !sEnabledTextStore->EnsureInitActiveTIPKeyboard()) { - return IsIMM_IME(::GetKeyboardLayout(0)); - } - return sEnabledTextStore->mIsIMM_IME; - } - - static bool IsIMM_IME(HKL aHKL) - { - return (::ImmGetIMEFileNameW(aHKL, nullptr, 0) > 0); - } + static bool IsIMM_IME(); #ifdef DEBUG // Returns true when keyboard layout has IME (TIP). static bool CurrentKeyboardLayoutHasIME(); #endif // #ifdef DEBUG protected: nsTextStore(); ~nsTextStore(); - bool Init(ITfThreadMgr* aThreadMgr); - void Shutdown(); - static void MarkContextAsKeyboardDisabled(ITfContext* aContext); static void MarkContextAsEmpty(ITfContext* aContext); - static bool IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, - REFGUID aProfile); - static void GetTIPDescription(REFCLSID aTextService, LANGID aLangID, - REFGUID aProfile, nsAString& aDescription); - bool Create(nsWindowBase* aWidget); bool Destroy(void); bool IsReadLock(DWORD aLock) const { return (TS_LF_READ == (aLock & TS_LF_READ)); } bool IsReadWriteLock(DWORD aLock) const @@ -313,41 +284,32 @@ protected: ULONG aFilterCount, const TS_ATTRID* aFilterAttrs); void SetInputScope(const nsString& aHTMLInputType); // Creates native caret over our caret. This method only works on desktop // application. Otherwise, this does nothing. void CreateNativeCaret(); - bool EnsureInitActiveTIPKeyboard(); - // Holds the pointer to our current win32 or metro widget nsRefPtr<nsWindowBase> mWidget; // Document manager for the currently focused editor nsRefPtr<ITfDocumentMgr> mDocumentMgr; // Edit cookie associated with the current editing context DWORD mEditCookie; - // Cookie of installing ITfInputProcessorProfileActivationSink - DWORD mIPProfileCookie; - // Cookie of installing ITfActiveLanguageProfileNotifySink - DWORD mLangProfileCookie; // Editing context at the bottom of mDocumentMgr's context stack nsRefPtr<ITfContext> mContext; // Currently installed notification sink nsRefPtr<ITextStoreACPSink> mSink; // TS_AS_* mask of what events to notify DWORD mSinkMask; // 0 if not locked, otherwise TS_LF_* indicating the current lock DWORD mLock; // 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock DWORD mLockQueued; - // Active TIP keyboard's description. If active language profile isn't TIP, - // i.e., IMM-IME or just a keyboard layout, this is empty. - nsString mActiveTIPKeyboardDescription; class Composition MOZ_FINAL { public: // nullptr if no composition is active, otherwise the current composition nsRefPtr<ITfCompositionView> mView; // Current copy of the active composition string. Only mString is @@ -766,21 +728,16 @@ protected: // calculated yet, these methods return TS_E_NOLAYOUT. Then, RequestLock() // will call mSink->OnLayoutChange() and // ITfContextOwnerServices::OnLayoutChange() after the layout is fixed and // the document is unlocked. bool mPendingOnLayoutChange; // While there is native caret, this is true. Otherwise, false. bool mNativeCaretIsCreated; - // True if current IME is implemented with IMM. - bool mIsIMM_IME; - // True if OnActivated() is already called - bool mOnActivatedCalled; - // TSF thread manager object for the current application static ITfThreadMgr* sTsfThreadMgr; // sMessagePump is QI'ed from sTsfThreadMgr static ITfMessagePump* sMessagePump; // sKeystrokeMgr is QI'ed from sTsfThreadMgr static ITfKeystrokeMgr* sKeystrokeMgr; // TSF display attribute manager static ITfDisplayAttributeMgr* sDisplayAttrMgr;