1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsTextStore.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4124 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <olectl.h> 1.10 +#include <algorithm> 1.11 + 1.12 +#ifdef MOZ_LOGGING 1.13 +#define FORCE_PR_LOG /* Allow logging in the release build */ 1.14 +#endif // MOZ_LOGGING 1.15 +#include "prlog.h" 1.16 + 1.17 +#include "nscore.h" 1.18 +#include "nsWindow.h" 1.19 +#ifdef MOZ_METRO 1.20 +#include "winrt/MetroWidget.h" 1.21 +#endif 1.22 +#include "nsPrintfCString.h" 1.23 +#include "WinUtils.h" 1.24 +#include "mozilla/Preferences.h" 1.25 +#include "mozilla/TextEvents.h" 1.26 +#include "mozilla/WindowsVersion.h" 1.27 + 1.28 +#define INPUTSCOPE_INIT_GUID 1.29 +#include "nsTextStore.h" 1.30 + 1.31 +using namespace mozilla; 1.32 +using namespace mozilla::widget; 1.33 + 1.34 +static const char* kPrefNameTSFEnabled = "intl.tsf.enable"; 1.35 + 1.36 +static const char* kLegacyPrefNameTSFEnabled = "intl.enable_tsf_support"; 1.37 + 1.38 +#ifdef PR_LOGGING 1.39 +/** 1.40 + * TSF related code should log its behavior even on release build especially 1.41 + * in the interface methods. 1.42 + * 1.43 + * In interface methods, use PR_LOG_ALWAYS. 1.44 + * In internal methods, use PR_LOG_DEBUG for logging normal behavior. 1.45 + * For logging error, use PR_LOG_ERROR. 1.46 + * 1.47 + * When an instance method is called, start with following text: 1.48 + * "TSF: 0x%p nsFoo::Bar(", the 0x%p should be the "this" of the nsFoo. 1.49 + * after that, start with: 1.50 + * "TSF: 0x%p nsFoo::Bar(" 1.51 + * In an internal method, start with following text: 1.52 + * "TSF: 0x%p nsFoo::Bar(" 1.53 + * When a static method is called, start with following text: 1.54 + * "TSF: nsFoo::Bar(" 1.55 + */ 1.56 + 1.57 +PRLogModuleInfo* sTextStoreLog = nullptr; 1.58 +#endif // #ifdef PR_LOGGING 1.59 + 1.60 +/******************************************************************/ 1.61 +/* InputScopeImpl */ 1.62 +/******************************************************************/ 1.63 + 1.64 +class InputScopeImpl MOZ_FINAL : public ITfInputScope 1.65 +{ 1.66 +public: 1.67 + InputScopeImpl(const nsTArray<InputScope>& aList) : 1.68 + mRefCnt(1), 1.69 + mInputScopes(aList) 1.70 + { 1.71 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.72 + ("TSF: 0x%p InputScopeImpl()", this)); 1.73 + } 1.74 + 1.75 + STDMETHODIMP_(ULONG) AddRef(void) { return ++mRefCnt; } 1.76 + 1.77 + STDMETHODIMP_(ULONG) Release(void) 1.78 + { 1.79 + --mRefCnt; 1.80 + if (mRefCnt) { 1.81 + return mRefCnt; 1.82 + } 1.83 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.84 + ("TSF: 0x%p InputScopeImpl::Release() final", this)); 1.85 + delete this; 1.86 + return 0; 1.87 + } 1.88 + 1.89 + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) 1.90 + { 1.91 + *ppv=nullptr; 1.92 + if ( (IID_IUnknown == riid) || (IID_ITfInputScope == riid) ) { 1.93 + *ppv = static_cast<ITfInputScope*>(this); 1.94 + } 1.95 + if (*ppv) { 1.96 + AddRef(); 1.97 + return S_OK; 1.98 + } 1.99 + return E_NOINTERFACE; 1.100 + } 1.101 + 1.102 + STDMETHODIMP GetInputScopes(InputScope** pprgInputScopes, UINT* pcCount) 1.103 + { 1.104 + uint32_t count = (mInputScopes.IsEmpty() ? 1 : mInputScopes.Length()); 1.105 + 1.106 + InputScope* pScope = (InputScope*) CoTaskMemAlloc(sizeof(InputScope) * count); 1.107 + NS_ENSURE_TRUE(pScope, E_OUTOFMEMORY); 1.108 + 1.109 + if (mInputScopes.IsEmpty()) { 1.110 + *pScope = IS_DEFAULT; 1.111 + *pcCount = 1; 1.112 + *pprgInputScopes = pScope; 1.113 + return S_OK; 1.114 + } 1.115 + 1.116 + *pcCount = 0; 1.117 + 1.118 + for (uint32_t idx = 0; idx < count; idx++) { 1.119 + *(pScope + idx) = mInputScopes[idx]; 1.120 + (*pcCount)++; 1.121 + } 1.122 + 1.123 + *pprgInputScopes = pScope; 1.124 + return S_OK; 1.125 + } 1.126 + 1.127 + STDMETHODIMP GetPhrase(BSTR **ppbstrPhrases, UINT *pcCount) { return E_NOTIMPL; } 1.128 + STDMETHODIMP GetRegularExpression(BSTR *pbstrRegExp) { return E_NOTIMPL; } 1.129 + STDMETHODIMP GetSRGS(BSTR *pbstrSRGS) { return E_NOTIMPL; } 1.130 + STDMETHODIMP GetXML(BSTR *pbstrXML) { return E_NOTIMPL; } 1.131 + 1.132 +private: 1.133 + DWORD mRefCnt; 1.134 + nsTArray<InputScope> mInputScopes; 1.135 +}; 1.136 + 1.137 +/******************************************************************/ 1.138 +/* nsTextStore */ 1.139 +/******************************************************************/ 1.140 + 1.141 +ITfThreadMgr* nsTextStore::sTsfThreadMgr = nullptr; 1.142 +ITfMessagePump* nsTextStore::sMessagePump = nullptr; 1.143 +ITfKeystrokeMgr* nsTextStore::sKeystrokeMgr = nullptr; 1.144 +ITfDisplayAttributeMgr* nsTextStore::sDisplayAttrMgr = nullptr; 1.145 +ITfCategoryMgr* nsTextStore::sCategoryMgr = nullptr; 1.146 +ITfDocumentMgr* nsTextStore::sTsfDisabledDocumentMgr = nullptr; 1.147 +ITfContext* nsTextStore::sTsfDisabledContext = nullptr; 1.148 +ITfInputProcessorProfiles* nsTextStore::sInputProcessorProfiles = nullptr; 1.149 +DWORD nsTextStore::sTsfClientId = 0; 1.150 +nsTextStore* nsTextStore::sTsfTextStore = nullptr; 1.151 + 1.152 +bool nsTextStore::sCreateNativeCaretForATOK = false; 1.153 + 1.154 +UINT nsTextStore::sFlushTIPInputMessage = 0; 1.155 + 1.156 +#define TEXTSTORE_DEFAULT_VIEW (1) 1.157 + 1.158 +#ifdef PR_LOGGING 1.159 + 1.160 +static const char* 1.161 +GetBoolName(bool aBool) 1.162 +{ 1.163 + return aBool ? "true" : "false"; 1.164 +} 1.165 + 1.166 +static void 1.167 +HandleSeparator(nsCString& aDesc) 1.168 +{ 1.169 + if (!aDesc.IsEmpty()) { 1.170 + aDesc.AppendLiteral(" | "); 1.171 + } 1.172 +} 1.173 + 1.174 +static const nsCString 1.175 +GetFindFlagName(DWORD aFindFlag) 1.176 +{ 1.177 + nsAutoCString description; 1.178 + if (!aFindFlag) { 1.179 + description.AppendLiteral("no flags (0)"); 1.180 + return description; 1.181 + } 1.182 + if (aFindFlag & TS_ATTR_FIND_BACKWARDS) { 1.183 + description.AppendLiteral("TS_ATTR_FIND_BACKWARDS"); 1.184 + } 1.185 + if (aFindFlag & TS_ATTR_FIND_WANT_OFFSET) { 1.186 + HandleSeparator(description); 1.187 + description.AppendLiteral("TS_ATTR_FIND_WANT_OFFSET"); 1.188 + } 1.189 + if (aFindFlag & TS_ATTR_FIND_UPDATESTART) { 1.190 + HandleSeparator(description); 1.191 + description.AppendLiteral("TS_ATTR_FIND_UPDATESTART"); 1.192 + } 1.193 + if (aFindFlag & TS_ATTR_FIND_WANT_VALUE) { 1.194 + HandleSeparator(description); 1.195 + description.AppendLiteral("TS_ATTR_FIND_WANT_VALUE"); 1.196 + } 1.197 + if (aFindFlag & TS_ATTR_FIND_WANT_END) { 1.198 + HandleSeparator(description); 1.199 + description.AppendLiteral("TS_ATTR_FIND_WANT_END"); 1.200 + } 1.201 + if (aFindFlag & TS_ATTR_FIND_HIDDEN) { 1.202 + HandleSeparator(description); 1.203 + description.AppendLiteral("TS_ATTR_FIND_HIDDEN"); 1.204 + } 1.205 + if (description.IsEmpty()) { 1.206 + description.AppendLiteral("Unknown ("); 1.207 + description.AppendInt(static_cast<uint32_t>(aFindFlag)); 1.208 + description.AppendLiteral(")"); 1.209 + } 1.210 + return description; 1.211 +} 1.212 + 1.213 +static const char* 1.214 +GetIMEEnabledName(IMEState::Enabled aIMEEnabled) 1.215 +{ 1.216 + switch (aIMEEnabled) { 1.217 + case IMEState::DISABLED: 1.218 + return "DISABLED"; 1.219 + case IMEState::ENABLED: 1.220 + return "ENABLED"; 1.221 + case IMEState::PASSWORD: 1.222 + return "PASSWORD"; 1.223 + case IMEState::PLUGIN: 1.224 + return "PLUGIN"; 1.225 + default: 1.226 + return "Invalid"; 1.227 + } 1.228 +} 1.229 + 1.230 +static const char* 1.231 +GetFocusChangeName(InputContextAction::FocusChange aFocusChange) 1.232 +{ 1.233 + switch (aFocusChange) { 1.234 + case InputContextAction::FOCUS_NOT_CHANGED: 1.235 + return "FOCUS_NOT_CHANGED"; 1.236 + case InputContextAction::GOT_FOCUS: 1.237 + return "GOT_FOCUS"; 1.238 + case InputContextAction::LOST_FOCUS: 1.239 + return "LOST_FOCUS"; 1.240 + case InputContextAction::MENU_GOT_PSEUDO_FOCUS: 1.241 + return "MENU_GOT_PSEUDO_FOCUS"; 1.242 + case InputContextAction::MENU_LOST_PSEUDO_FOCUS: 1.243 + return "MENU_LOST_PSEUDO_FOCUS"; 1.244 + default: 1.245 + return "Unknown"; 1.246 + } 1.247 +} 1.248 + 1.249 +static nsCString 1.250 +GetCLSIDNameStr(REFCLSID aCLSID) 1.251 +{ 1.252 + LPOLESTR str = nullptr; 1.253 + HRESULT hr = ::StringFromCLSID(aCLSID, &str); 1.254 + if (FAILED(hr) || !str || !str[0]) { 1.255 + return EmptyCString(); 1.256 + } 1.257 + 1.258 + nsAutoCString result; 1.259 + result = NS_ConvertUTF16toUTF8(str); 1.260 + ::CoTaskMemFree(str); 1.261 + return result; 1.262 +} 1.263 + 1.264 +static nsCString 1.265 +GetGUIDNameStr(REFGUID aGUID) 1.266 +{ 1.267 + OLECHAR str[40]; 1.268 + int len = ::StringFromGUID2(aGUID, str, ArrayLength(str)); 1.269 + if (!len || !str[0]) { 1.270 + return EmptyCString(); 1.271 + } 1.272 + 1.273 + return NS_ConvertUTF16toUTF8(str); 1.274 +} 1.275 + 1.276 +static nsCString 1.277 +GetRIIDNameStr(REFIID aRIID) 1.278 +{ 1.279 + LPOLESTR str = nullptr; 1.280 + HRESULT hr = ::StringFromIID(aRIID, &str); 1.281 + if (FAILED(hr) || !str || !str[0]) { 1.282 + return EmptyCString(); 1.283 + } 1.284 + 1.285 + nsAutoString key(L"Interface\\"); 1.286 + key += str; 1.287 + 1.288 + nsAutoCString result; 1.289 + wchar_t buf[256]; 1.290 + if (WinUtils::GetRegistryKey(HKEY_CLASSES_ROOT, key.get(), nullptr, 1.291 + buf, sizeof(buf))) { 1.292 + result = NS_ConvertUTF16toUTF8(buf); 1.293 + } else { 1.294 + result = NS_ConvertUTF16toUTF8(str); 1.295 + } 1.296 + 1.297 + ::CoTaskMemFree(str); 1.298 + return result; 1.299 +} 1.300 + 1.301 +static const char* 1.302 +GetCommonReturnValueName(HRESULT aResult) 1.303 +{ 1.304 + switch (aResult) { 1.305 + case S_OK: 1.306 + return "S_OK"; 1.307 + case E_ABORT: 1.308 + return "E_ABORT"; 1.309 + case E_ACCESSDENIED: 1.310 + return "E_ACCESSDENIED"; 1.311 + case E_FAIL: 1.312 + return "E_FAIL"; 1.313 + case E_HANDLE: 1.314 + return "E_HANDLE"; 1.315 + case E_INVALIDARG: 1.316 + return "E_INVALIDARG"; 1.317 + case E_NOINTERFACE: 1.318 + return "E_NOINTERFACE"; 1.319 + case E_NOTIMPL: 1.320 + return "E_NOTIMPL"; 1.321 + case E_OUTOFMEMORY: 1.322 + return "E_OUTOFMEMORY"; 1.323 + case E_POINTER: 1.324 + return "E_POINTER"; 1.325 + case E_UNEXPECTED: 1.326 + return "E_UNEXPECTED"; 1.327 + default: 1.328 + return SUCCEEDED(aResult) ? "Succeeded" : "Failed"; 1.329 + } 1.330 +} 1.331 + 1.332 +static const char* 1.333 +GetTextStoreReturnValueName(HRESULT aResult) 1.334 +{ 1.335 + switch (aResult) { 1.336 + case TS_E_FORMAT: 1.337 + return "TS_E_FORMAT"; 1.338 + case TS_E_INVALIDPOINT: 1.339 + return "TS_E_INVALIDPOINT"; 1.340 + case TS_E_INVALIDPOS: 1.341 + return "TS_E_INVALIDPOS"; 1.342 + case TS_E_NOINTERFACE: 1.343 + return "TS_E_NOINTERFACE"; 1.344 + case TS_E_NOLAYOUT: 1.345 + return "TS_E_NOLAYOUT"; 1.346 + case TS_E_NOLOCK: 1.347 + return "TS_E_NOLOCK"; 1.348 + case TS_E_NOOBJECT: 1.349 + return "TS_E_NOOBJECT"; 1.350 + case TS_E_NOSELECTION: 1.351 + return "TS_E_NOSELECTION"; 1.352 + case TS_E_NOSERVICE: 1.353 + return "TS_E_NOSERVICE"; 1.354 + case TS_E_READONLY: 1.355 + return "TS_E_READONLY"; 1.356 + case TS_E_SYNCHRONOUS: 1.357 + return "TS_E_SYNCHRONOUS"; 1.358 + case TS_S_ASYNC: 1.359 + return "TS_S_ASYNC"; 1.360 + default: 1.361 + return GetCommonReturnValueName(aResult); 1.362 + } 1.363 +} 1.364 + 1.365 +static const nsCString 1.366 +GetSinkMaskNameStr(DWORD aSinkMask) 1.367 +{ 1.368 + nsAutoCString description; 1.369 + if (aSinkMask & TS_AS_TEXT_CHANGE) { 1.370 + description.AppendLiteral("TS_AS_TEXT_CHANGE"); 1.371 + } 1.372 + if (aSinkMask & TS_AS_SEL_CHANGE) { 1.373 + HandleSeparator(description); 1.374 + description.AppendLiteral("TS_AS_SEL_CHANGE"); 1.375 + } 1.376 + if (aSinkMask & TS_AS_LAYOUT_CHANGE) { 1.377 + HandleSeparator(description); 1.378 + description.AppendLiteral("TS_AS_LAYOUT_CHANGE"); 1.379 + } 1.380 + if (aSinkMask & TS_AS_ATTR_CHANGE) { 1.381 + HandleSeparator(description); 1.382 + description.AppendLiteral("TS_AS_ATTR_CHANGE"); 1.383 + } 1.384 + if (aSinkMask & TS_AS_STATUS_CHANGE) { 1.385 + HandleSeparator(description); 1.386 + description.AppendLiteral("TS_AS_STATUS_CHANGE"); 1.387 + } 1.388 + if (description.IsEmpty()) { 1.389 + description.AppendLiteral("not-specified"); 1.390 + } 1.391 + return description; 1.392 +} 1.393 + 1.394 +static const char* 1.395 +GetActiveSelEndName(TsActiveSelEnd aSelEnd) 1.396 +{ 1.397 + return aSelEnd == TS_AE_NONE ? "TS_AE_NONE" : 1.398 + aSelEnd == TS_AE_START ? "TS_AE_START" : 1.399 + aSelEnd == TS_AE_END ? "TS_AE_END" : "Unknown"; 1.400 +} 1.401 + 1.402 +static const nsCString 1.403 +GetLockFlagNameStr(DWORD aLockFlags) 1.404 +{ 1.405 + nsAutoCString description; 1.406 + if ((aLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) { 1.407 + description.AppendLiteral("TS_LF_READWRITE"); 1.408 + } else if (aLockFlags & TS_LF_READ) { 1.409 + description.AppendLiteral("TS_LF_READ"); 1.410 + } 1.411 + if (aLockFlags & TS_LF_SYNC) { 1.412 + if (!description.IsEmpty()) { 1.413 + description.AppendLiteral(" | "); 1.414 + } 1.415 + description.AppendLiteral("TS_LF_SYNC"); 1.416 + } 1.417 + if (description.IsEmpty()) { 1.418 + description.AppendLiteral("not-specified"); 1.419 + } 1.420 + return description; 1.421 +} 1.422 + 1.423 +static const char* 1.424 +GetTextRunTypeName(TsRunType aRunType) 1.425 +{ 1.426 + switch (aRunType) { 1.427 + case TS_RT_PLAIN: 1.428 + return "TS_RT_PLAIN"; 1.429 + case TS_RT_HIDDEN: 1.430 + return "TS_RT_HIDDEN"; 1.431 + case TS_RT_OPAQUE: 1.432 + return "TS_RT_OPAQUE"; 1.433 + default: 1.434 + return "Unknown"; 1.435 + } 1.436 +} 1.437 + 1.438 +static nsCString 1.439 +GetColorName(const TF_DA_COLOR &aColor) 1.440 +{ 1.441 + switch (aColor.type) { 1.442 + case TF_CT_NONE: 1.443 + return NS_LITERAL_CSTRING("TF_CT_NONE"); 1.444 + case TF_CT_SYSCOLOR: 1.445 + return nsPrintfCString("TF_CT_SYSCOLOR, nIndex:0x%08X", 1.446 + static_cast<int32_t>(aColor.nIndex)); 1.447 + case TF_CT_COLORREF: 1.448 + return nsPrintfCString("TF_CT_COLORREF, cr:0x%08X", 1.449 + static_cast<int32_t>(aColor.cr)); 1.450 + break; 1.451 + default: 1.452 + return nsPrintfCString("Unknown(%08X)", 1.453 + static_cast<int32_t>(aColor.type)); 1.454 + } 1.455 +} 1.456 + 1.457 +static nsCString 1.458 +GetLineStyleName(TF_DA_LINESTYLE aLineStyle) 1.459 +{ 1.460 + switch (aLineStyle) { 1.461 + case TF_LS_NONE: 1.462 + return NS_LITERAL_CSTRING("TF_LS_NONE"); 1.463 + case TF_LS_SOLID: 1.464 + return NS_LITERAL_CSTRING("TF_LS_SOLID"); 1.465 + case TF_LS_DOT: 1.466 + return NS_LITERAL_CSTRING("TF_LS_DOT"); 1.467 + case TF_LS_DASH: 1.468 + return NS_LITERAL_CSTRING("TF_LS_DASH"); 1.469 + case TF_LS_SQUIGGLE: 1.470 + return NS_LITERAL_CSTRING("TF_LS_SQUIGGLE"); 1.471 + default: { 1.472 + return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aLineStyle)); 1.473 + } 1.474 + } 1.475 +} 1.476 + 1.477 +static nsCString 1.478 +GetClauseAttrName(TF_DA_ATTR_INFO aAttr) 1.479 +{ 1.480 + switch (aAttr) { 1.481 + case TF_ATTR_INPUT: 1.482 + return NS_LITERAL_CSTRING("TF_ATTR_INPUT"); 1.483 + case TF_ATTR_TARGET_CONVERTED: 1.484 + return NS_LITERAL_CSTRING("TF_ATTR_TARGET_CONVERTED"); 1.485 + case TF_ATTR_CONVERTED: 1.486 + return NS_LITERAL_CSTRING("TF_ATTR_CONVERTED"); 1.487 + case TF_ATTR_TARGET_NOTCONVERTED: 1.488 + return NS_LITERAL_CSTRING("TF_ATTR_TARGET_NOTCONVERTED"); 1.489 + case TF_ATTR_INPUT_ERROR: 1.490 + return NS_LITERAL_CSTRING("TF_ATTR_INPUT_ERROR"); 1.491 + case TF_ATTR_FIXEDCONVERTED: 1.492 + return NS_LITERAL_CSTRING("TF_ATTR_FIXEDCONVERTED"); 1.493 + case TF_ATTR_OTHER: 1.494 + return NS_LITERAL_CSTRING("TF_ATTR_OTHER"); 1.495 + default: { 1.496 + return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aAttr)); 1.497 + } 1.498 + } 1.499 +} 1.500 + 1.501 +static nsCString 1.502 +GetDisplayAttrStr(const TF_DISPLAYATTRIBUTE &aDispAttr) 1.503 +{ 1.504 + nsAutoCString str; 1.505 + str = "crText:{ "; 1.506 + str += GetColorName(aDispAttr.crText); 1.507 + str += " }, crBk:{ "; 1.508 + str += GetColorName(aDispAttr.crBk); 1.509 + str += " }, lsStyle: "; 1.510 + str += GetLineStyleName(aDispAttr.lsStyle); 1.511 + str += ", fBoldLine: "; 1.512 + str += GetBoolName(aDispAttr.fBoldLine); 1.513 + str += ", crLine:{ "; 1.514 + str += GetColorName(aDispAttr.crLine); 1.515 + str += " }, bAttr: "; 1.516 + str += GetClauseAttrName(aDispAttr.bAttr); 1.517 + return str; 1.518 +} 1.519 + 1.520 +#endif // #ifdef PR_LOGGING 1.521 + 1.522 +nsTextStore::nsTextStore() 1.523 + : mContent(mComposition, mSelection) 1.524 +{ 1.525 + mRefCnt = 1; 1.526 + mEditCookie = 0; 1.527 + mIPProfileCookie = TF_INVALID_COOKIE; 1.528 + mLangProfileCookie = TF_INVALID_COOKIE; 1.529 + mSinkMask = 0; 1.530 + mLock = 0; 1.531 + mLockQueued = 0; 1.532 + mInputScopeDetected = false; 1.533 + mInputScopeRequested = false; 1.534 + mIsRecordingActionsWithoutLock = false; 1.535 + mPendingOnSelectionChange = false; 1.536 + mPendingOnLayoutChange = false; 1.537 + mNativeCaretIsCreated = false; 1.538 + mIsIMM_IME = false; 1.539 + mOnActivatedCalled = false; 1.540 + // We hope that 5 or more actions don't occur at once. 1.541 + mPendingActions.SetCapacity(5); 1.542 + 1.543 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.544 + ("TSF: 0x%p nsTextStore::nsTestStore() SUCCEEDED", this)); 1.545 +} 1.546 + 1.547 +bool 1.548 +nsTextStore::Init(ITfThreadMgr* aThreadMgr) 1.549 +{ 1.550 + nsRefPtr<ITfSource> source; 1.551 + HRESULT hr = 1.552 + aThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); 1.553 + if (FAILED(hr)) { 1.554 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.555 + ("TSF: 0x%p nsTextStore::Init() FAILED to get ITfSource instance " 1.556 + "(0x%08X)", this, hr)); 1.557 + return false; 1.558 + } 1.559 + 1.560 + // On Vista or later, Windows let us know activate IME changed only with 1.561 + // ITfInputProcessorProfileActivationSink. However, it's not available on XP. 1.562 + // On XP, ITfActiveLanguageProfileNotifySink is available for it. 1.563 + // NOTE: Each OnActivated() should be called when TSF becomes available. 1.564 + if (IsVistaOrLater()) { 1.565 + hr = source->AdviseSink(IID_ITfInputProcessorProfileActivationSink, 1.566 + static_cast<ITfInputProcessorProfileActivationSink*>(this), 1.567 + &mIPProfileCookie); 1.568 + if (FAILED(hr) || mIPProfileCookie == TF_INVALID_COOKIE) { 1.569 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.570 + ("TSF: 0x%p nsTextStore::Init() FAILED to install " 1.571 + "ITfInputProcessorProfileActivationSink (0x%08X)", this, hr)); 1.572 + return false; 1.573 + } 1.574 + } else { 1.575 + hr = source->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, 1.576 + static_cast<ITfActiveLanguageProfileNotifySink*>(this), 1.577 + &mLangProfileCookie); 1.578 + if (FAILED(hr) || mLangProfileCookie == TF_INVALID_COOKIE) { 1.579 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.580 + ("TSF: 0x%p nsTextStore::Init() FAILED to install " 1.581 + "ITfActiveLanguageProfileNotifySink (0x%08X)", this, hr)); 1.582 + return false; 1.583 + } 1.584 + } 1.585 + 1.586 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.587 + ("TSF: 0x%p nsTextStore::Init(), " 1.588 + "mIPProfileCookie=0x%08X, mLangProfileCookie=0x%08X", 1.589 + this, mIPProfileCookie, mLangProfileCookie)); 1.590 + 1.591 + return true; 1.592 +} 1.593 + 1.594 +nsTextStore::~nsTextStore() 1.595 +{ 1.596 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.597 + ("TSF: 0x%p nsTextStore instance is destroyed, " 1.598 + "mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p, mIPProfileCookie=0x%08X, " 1.599 + "mLangProfileCookie=0x%08X", 1.600 + this, mWidget.get(), mDocumentMgr.get(), mContext.get(), 1.601 + mIPProfileCookie, mLangProfileCookie)); 1.602 + 1.603 + if (mIPProfileCookie != TF_INVALID_COOKIE) { 1.604 + nsRefPtr<ITfSource> source; 1.605 + HRESULT hr = 1.606 + sTsfThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); 1.607 + if (FAILED(hr)) { 1.608 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.609 + ("TSF: 0x%p ~nsTextStore FAILED to get ITfSource instance " 1.610 + "(0x%08X)", this, hr)); 1.611 + } else { 1.612 + hr = source->UnadviseSink(mIPProfileCookie); 1.613 + if (FAILED(hr)) { 1.614 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.615 + ("TSF: 0x%p ~nsTextStore FAILED to uninstall " 1.616 + "ITfInputProcessorProfileActivationSink (0x%08X)", 1.617 + this, hr)); 1.618 + } 1.619 + } 1.620 + } 1.621 + 1.622 + if (mLangProfileCookie != TF_INVALID_COOKIE) { 1.623 + nsRefPtr<ITfSource> source; 1.624 + HRESULT hr = 1.625 + sTsfThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source)); 1.626 + if (FAILED(hr)) { 1.627 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.628 + ("TSF: 0x%p ~nsTextStore FAILED to get ITfSource instance " 1.629 + "(0x%08X)", this, hr)); 1.630 + } else { 1.631 + hr = source->UnadviseSink(mLangProfileCookie); 1.632 + if (FAILED(hr)) { 1.633 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.634 + ("TSF: 0x%p ~nsTextStore FAILED to uninstall " 1.635 + "ITfActiveLanguageProfileNotifySink (0x%08X)", 1.636 + this, hr)); 1.637 + } 1.638 + } 1.639 + } 1.640 +} 1.641 + 1.642 +bool 1.643 +nsTextStore::Create(nsWindowBase* aWidget) 1.644 +{ 1.645 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.646 + ("TSF: 0x%p nsTextStore::Create(aWidget=0x%p)", 1.647 + this, aWidget)); 1.648 + 1.649 + EnsureInitActiveTIPKeyboard(); 1.650 + 1.651 + if (mDocumentMgr) { 1.652 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.653 + ("TSF: 0x%p nsTextStore::Create() FAILED due to already initialized", 1.654 + this)); 1.655 + return false; 1.656 + } 1.657 + 1.658 + // Create document manager 1.659 + HRESULT hr = sTsfThreadMgr->CreateDocumentMgr( 1.660 + getter_AddRefs(mDocumentMgr)); 1.661 + if (FAILED(hr)) { 1.662 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.663 + ("TSF: 0x%p nsTextStore::Create() FAILED to create DocumentMgr " 1.664 + "(0x%08X)", this, hr)); 1.665 + return false; 1.666 + } 1.667 + mWidget = aWidget; 1.668 + 1.669 + // Create context and add it to document manager 1.670 + hr = mDocumentMgr->CreateContext(sTsfClientId, 0, 1.671 + static_cast<ITextStoreACP*>(this), 1.672 + getter_AddRefs(mContext), &mEditCookie); 1.673 + if (FAILED(hr)) { 1.674 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.675 + ("TSF: 0x%p nsTextStore::Create() FAILED to create the context " 1.676 + "(0x%08X)", this, hr)); 1.677 + mDocumentMgr = nullptr; 1.678 + return false; 1.679 + } 1.680 + 1.681 + hr = mDocumentMgr->Push(mContext); 1.682 + if (FAILED(hr)) { 1.683 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.684 + ("TSF: 0x%p nsTextStore::Create() FAILED to push the context (0x%08X)", 1.685 + this, hr)); 1.686 + // XXX Why don't we use NS_IF_RELEASE() here?? 1.687 + mContext = nullptr; 1.688 + mDocumentMgr = nullptr; 1.689 + return false; 1.690 + } 1.691 + 1.692 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.693 + ("TSF: 0x%p nsTextStore::Create() succeeded: " 1.694 + "mDocumentMgr=0x%p, mContext=0x%p, mEditCookie=0x%08X", 1.695 + this, mDocumentMgr.get(), mContext.get(), mEditCookie)); 1.696 + 1.697 + return true; 1.698 +} 1.699 + 1.700 +bool 1.701 +nsTextStore::Destroy(void) 1.702 +{ 1.703 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.704 + ("TSF: 0x%p nsTextStore::Destroy(), mComposition.IsComposing()=%s", 1.705 + this, GetBoolName(mComposition.IsComposing()))); 1.706 + 1.707 + // If there is composition, TSF keeps the composition even after the text 1.708 + // store destroyed. So, we should clear the composition here. 1.709 + if (mComposition.IsComposing()) { 1.710 + NS_WARNING("Composition is still alive at destroying the text store"); 1.711 + CommitCompositionInternal(false); 1.712 + } 1.713 + 1.714 + mContent.Clear(); 1.715 + mSelection.MarkDirty(); 1.716 + 1.717 + if (mWidget) { 1.718 + // When blurred, Tablet Input Panel posts "blur" messages 1.719 + // and try to insert text when the message is retrieved later. 1.720 + // But by that time the text store is already destroyed, 1.721 + // so try to get the message early 1.722 + MSG msg; 1.723 + if (WinUtils::PeekMessage(&msg, mWidget->GetWindowHandle(), 1.724 + sFlushTIPInputMessage, sFlushTIPInputMessage, 1.725 + PM_REMOVE)) { 1.726 + ::DispatchMessageW(&msg); 1.727 + } 1.728 + } 1.729 + mContext = nullptr; 1.730 + if (mDocumentMgr) { 1.731 + mDocumentMgr->Pop(TF_POPF_ALL); 1.732 + mDocumentMgr = nullptr; 1.733 + } 1.734 + mSink = nullptr; 1.735 + mWidget = nullptr; 1.736 + 1.737 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.738 + ("TSF: 0x%p nsTextStore::Destroy() succeeded", this)); 1.739 + return true; 1.740 +} 1.741 + 1.742 +STDMETHODIMP 1.743 +nsTextStore::QueryInterface(REFIID riid, 1.744 + void** ppv) 1.745 +{ 1.746 + *ppv=nullptr; 1.747 + if ( (IID_IUnknown == riid) || (IID_ITextStoreACP == riid) ) { 1.748 + *ppv = static_cast<ITextStoreACP*>(this); 1.749 + } else if (IID_ITfContextOwnerCompositionSink == riid) { 1.750 + *ppv = static_cast<ITfContextOwnerCompositionSink*>(this); 1.751 + } else if (IID_ITfActiveLanguageProfileNotifySink == riid) { 1.752 + *ppv = static_cast<ITfActiveLanguageProfileNotifySink*>(this); 1.753 + } else if (IID_ITfInputProcessorProfileActivationSink == riid) { 1.754 + *ppv = static_cast<ITfInputProcessorProfileActivationSink*>(this); 1.755 + } 1.756 + if (*ppv) { 1.757 + AddRef(); 1.758 + return S_OK; 1.759 + } 1.760 + 1.761 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.762 + ("TSF: 0x%p nsTextStore::QueryInterface() FAILED, riid=%s", 1.763 + this, GetRIIDNameStr(riid).get())); 1.764 + return E_NOINTERFACE; 1.765 +} 1.766 + 1.767 +STDMETHODIMP_(ULONG) nsTextStore::AddRef() 1.768 +{ 1.769 + return ++mRefCnt; 1.770 +} 1.771 + 1.772 +STDMETHODIMP_(ULONG) nsTextStore::Release() 1.773 +{ 1.774 + --mRefCnt; 1.775 + if (0 != mRefCnt) 1.776 + return mRefCnt; 1.777 + delete this; 1.778 + return 0; 1.779 +} 1.780 + 1.781 +STDMETHODIMP 1.782 +nsTextStore::AdviseSink(REFIID riid, 1.783 + IUnknown *punk, 1.784 + DWORD dwMask) 1.785 +{ 1.786 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.787 + ("TSF: 0x%p nsTextStore::AdviseSink(riid=%s, punk=0x%p, dwMask=%s), " 1.788 + "mSink=0x%p, mSinkMask=%s", 1.789 + this, GetRIIDNameStr(riid).get(), punk, GetSinkMaskNameStr(dwMask).get(), 1.790 + mSink.get(), GetSinkMaskNameStr(mSinkMask).get())); 1.791 + 1.792 + if (!punk) { 1.793 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.794 + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to the null punk", 1.795 + this)); 1.796 + return E_UNEXPECTED; 1.797 + } 1.798 + 1.799 + if (IID_ITextStoreACPSink != riid) { 1.800 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.801 + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " 1.802 + "unsupported interface", this)); 1.803 + return E_INVALIDARG; // means unsupported interface. 1.804 + } 1.805 + 1.806 + if (!mSink) { 1.807 + // Install sink 1.808 + punk->QueryInterface(IID_ITextStoreACPSink, getter_AddRefs(mSink)); 1.809 + if (!mSink) { 1.810 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.811 + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " 1.812 + "punk not having the interface", this)); 1.813 + return E_UNEXPECTED; 1.814 + } 1.815 + } else { 1.816 + // If sink is already installed we check to see if they are the same 1.817 + // Get IUnknown from both sides for comparison 1.818 + nsRefPtr<IUnknown> comparison1, comparison2; 1.819 + punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); 1.820 + mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); 1.821 + if (comparison1 != comparison2) { 1.822 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.823 + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " 1.824 + "the sink being different from the stored sink", this)); 1.825 + return CONNECT_E_ADVISELIMIT; 1.826 + } 1.827 + } 1.828 + // Update mask either for a new sink or an existing sink 1.829 + mSinkMask = dwMask; 1.830 + return S_OK; 1.831 +} 1.832 + 1.833 +STDMETHODIMP 1.834 +nsTextStore::UnadviseSink(IUnknown *punk) 1.835 +{ 1.836 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.837 + ("TSF: 0x%p nsTextStore::UnadviseSink(punk=0x%p), mSink=0x%p", 1.838 + this, punk, mSink.get())); 1.839 + 1.840 + if (!punk) { 1.841 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.842 + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to the null punk", 1.843 + this)); 1.844 + return E_INVALIDARG; 1.845 + } 1.846 + if (!mSink) { 1.847 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.848 + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " 1.849 + "any sink not stored", this)); 1.850 + return CONNECT_E_NOCONNECTION; 1.851 + } 1.852 + // Get IUnknown from both sides for comparison 1.853 + nsRefPtr<IUnknown> comparison1, comparison2; 1.854 + punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); 1.855 + mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); 1.856 + // Unadvise only if sinks are the same 1.857 + if (comparison1 != comparison2) { 1.858 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.859 + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " 1.860 + "the sink being different from the stored sink", this)); 1.861 + return CONNECT_E_NOCONNECTION; 1.862 + } 1.863 + mSink = nullptr; 1.864 + mSinkMask = 0; 1.865 + return S_OK; 1.866 +} 1.867 + 1.868 +STDMETHODIMP 1.869 +nsTextStore::RequestLock(DWORD dwLockFlags, 1.870 + HRESULT *phrSession) 1.871 +{ 1.872 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.873 + ("TSF: 0x%p nsTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), " 1.874 + "mLock=%s", this, GetLockFlagNameStr(dwLockFlags).get(), phrSession, 1.875 + GetLockFlagNameStr(mLock).get())); 1.876 + 1.877 + if (!mSink) { 1.878 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.879 + ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " 1.880 + "any sink not stored", this)); 1.881 + return E_FAIL; 1.882 + } 1.883 + if (!phrSession) { 1.884 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.885 + ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " 1.886 + "null phrSession", this)); 1.887 + return E_INVALIDARG; 1.888 + } 1.889 + 1.890 + if (!mLock) { 1.891 + // put on lock 1.892 + mLock = dwLockFlags & (~TS_LF_SYNC); 1.893 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.894 + ("TSF: 0x%p Locking (%s) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" 1.895 + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", 1.896 + this, GetLockFlagNameStr(mLock).get())); 1.897 + *phrSession = mSink->OnLockGranted(mLock); 1.898 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.899 + ("TSF: 0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" 1.900 + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", 1.901 + this, GetLockFlagNameStr(mLock).get())); 1.902 + DidLockGranted(); 1.903 + while (mLockQueued) { 1.904 + mLock = mLockQueued; 1.905 + mLockQueued = 0; 1.906 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.907 + ("TSF: 0x%p Locking for the request in the queue (%s) >>>>>>>>>>>>>>" 1.908 + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", 1.909 + this, GetLockFlagNameStr(mLock).get())); 1.910 + mSink->OnLockGranted(mLock); 1.911 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.912 + ("TSF: 0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" 1.913 + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", 1.914 + this, GetLockFlagNameStr(mLock).get())); 1.915 + DidLockGranted(); 1.916 + } 1.917 + 1.918 + // The document is now completely unlocked. 1.919 + mLock = 0; 1.920 + 1.921 + if (mPendingOnLayoutChange) { 1.922 + mPendingOnLayoutChange = false; 1.923 + if (mSink) { 1.924 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.925 + ("TSF: 0x%p nsTextStore::RequestLock(), " 1.926 + "calling ITextStoreACPSink::OnLayoutChange()...", this)); 1.927 + mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW); 1.928 + } 1.929 + // The layout change caused by composition string change should cause 1.930 + // calling ITfContextOwnerServices::OnLayoutChange() too. 1.931 + if (mContext) { 1.932 + nsRefPtr<ITfContextOwnerServices> service; 1.933 + mContext->QueryInterface(IID_ITfContextOwnerServices, 1.934 + getter_AddRefs(service)); 1.935 + if (service) { 1.936 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.937 + ("TSF: 0x%p nsTextStore::RequestLock(), " 1.938 + "calling ITfContextOwnerServices::OnLayoutChange()...", 1.939 + this)); 1.940 + service->OnLayoutChange(); 1.941 + } 1.942 + } 1.943 + } 1.944 + 1.945 + if (mPendingOnSelectionChange) { 1.946 + mPendingOnSelectionChange = false; 1.947 + if (mSink) { 1.948 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.949 + ("TSF: 0x%p nsTextStore::RequestLock(), " 1.950 + "calling ITextStoreACPSink::OnSelectionChange()...", this)); 1.951 + mSink->OnSelectionChange(); 1.952 + } 1.953 + } 1.954 + 1.955 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.956 + ("TSF: 0x%p nsTextStore::RequestLock() succeeded: *phrSession=%s", 1.957 + this, GetTextStoreReturnValueName(*phrSession))); 1.958 + return S_OK; 1.959 + } 1.960 + 1.961 + // only time when reentrant lock is allowed is when caller holds a 1.962 + // read-only lock and is requesting an async write lock 1.963 + if (IsReadLocked() && !IsReadWriteLocked() && IsReadWriteLock(dwLockFlags) && 1.964 + !(dwLockFlags & TS_LF_SYNC)) { 1.965 + *phrSession = TS_S_ASYNC; 1.966 + mLockQueued = dwLockFlags & (~TS_LF_SYNC); 1.967 + 1.968 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.969 + ("TSF: 0x%p nsTextStore::RequestLock() stores the request in the " 1.970 + "queue, *phrSession=TS_S_ASYNC", this)); 1.971 + return S_OK; 1.972 + } 1.973 + 1.974 + // no more locks allowed 1.975 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.976 + ("TSF: 0x%p nsTextStore::RequestLock() didn't allow to lock, " 1.977 + "*phrSession=TS_E_SYNCHRONOUS", this)); 1.978 + *phrSession = TS_E_SYNCHRONOUS; 1.979 + return E_FAIL; 1.980 +} 1.981 + 1.982 +void 1.983 +nsTextStore::DidLockGranted() 1.984 +{ 1.985 + if (mNativeCaretIsCreated) { 1.986 + ::DestroyCaret(); 1.987 + mNativeCaretIsCreated = false; 1.988 + } 1.989 + if (IsReadWriteLocked()) { 1.990 + FlushPendingActions(); 1.991 + } 1.992 + 1.993 + // If the widget has gone, we don't need to notify anything. 1.994 + if (!mWidget || mWidget->Destroyed()) { 1.995 + mPendingOnSelectionChange = false; 1.996 + mPendingOnLayoutChange = false; 1.997 + } 1.998 +} 1.999 + 1.1000 +void 1.1001 +nsTextStore::FlushPendingActions() 1.1002 +{ 1.1003 + if (!mWidget || mWidget->Destroyed()) { 1.1004 + mPendingActions.Clear(); 1.1005 + mContent.Clear(); 1.1006 + mPendingOnSelectionChange = false; 1.1007 + mPendingOnLayoutChange = false; 1.1008 + return; 1.1009 + } 1.1010 + 1.1011 + mContent.Clear(); 1.1012 + 1.1013 + nsRefPtr<nsWindowBase> kungFuDeathGrip(mWidget); 1.1014 + for (uint32_t i = 0; i < mPendingActions.Length(); i++) { 1.1015 + PendingAction& action = mPendingActions[i]; 1.1016 + switch (action.mType) { 1.1017 + case PendingAction::COMPOSITION_START: { 1.1018 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1019 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1020 + "flushing COMPOSITION_START={ mSelectionStart=%d, " 1.1021 + "mSelectionLength=%d }", 1.1022 + this, action.mSelectionStart, action.mSelectionLength)); 1.1023 + 1.1024 + MOZ_ASSERT(mComposition.mLastData.IsEmpty()); 1.1025 + 1.1026 + // Select composition range so the new composition replaces the range 1.1027 + WidgetSelectionEvent selectionSet(true, NS_SELECTION_SET, mWidget); 1.1028 + mWidget->InitEvent(selectionSet); 1.1029 + selectionSet.mOffset = static_cast<uint32_t>(action.mSelectionStart); 1.1030 + selectionSet.mLength = static_cast<uint32_t>(action.mSelectionLength); 1.1031 + selectionSet.mReversed = false; 1.1032 + mWidget->DispatchWindowEvent(&selectionSet); 1.1033 + if (!selectionSet.mSucceeded) { 1.1034 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1035 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1036 + "FAILED due to NS_SELECTION_SET failure", this)); 1.1037 + break; 1.1038 + } 1.1039 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1040 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1041 + "dispatching compositionstart event...", this)); 1.1042 + WidgetCompositionEvent compositionStart(true, NS_COMPOSITION_START, 1.1043 + mWidget); 1.1044 + mWidget->InitEvent(compositionStart); 1.1045 + mWidget->DispatchWindowEvent(&compositionStart); 1.1046 + if (!mWidget || mWidget->Destroyed()) { 1.1047 + break; 1.1048 + } 1.1049 + break; 1.1050 + } 1.1051 + case PendingAction::COMPOSITION_UPDATE: { 1.1052 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1053 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1054 + "flushing COMPOSITION_UPDATE={ mData=\"%s\", " 1.1055 + "mRanges=0x%p, mRanges->Length()=%d }", 1.1056 + this, NS_ConvertUTF16toUTF8(action.mData).get(), action.mRanges.get(), 1.1057 + action.mRanges ? action.mRanges->Length() : 0)); 1.1058 + 1.1059 + if (!action.mRanges) { 1.1060 + NS_WARNING("How does this case occur?"); 1.1061 + action.mRanges = new TextRangeArray(); 1.1062 + } 1.1063 + 1.1064 + // Adjust offsets in the ranges for XP linefeed character (only \n). 1.1065 + // XXX Following code is the safest approach. However, it wastes 1.1066 + // a little performance. For ensuring the clauses do not 1.1067 + // overlap each other, we should redesign TextRange later. 1.1068 + for (uint32_t i = 0; i < action.mRanges->Length(); ++i) { 1.1069 + TextRange& range = action.mRanges->ElementAt(i); 1.1070 + TextRange nativeRange = range; 1.1071 + if (nativeRange.mStartOffset > 0) { 1.1072 + nsAutoString preText( 1.1073 + Substring(action.mData, 0, nativeRange.mStartOffset)); 1.1074 + preText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), 1.1075 + NS_LITERAL_STRING("\n")); 1.1076 + range.mStartOffset = preText.Length(); 1.1077 + } 1.1078 + if (nativeRange.Length() == 0) { 1.1079 + range.mEndOffset = range.mStartOffset; 1.1080 + } else { 1.1081 + nsAutoString clause( 1.1082 + Substring(action.mData, 1.1083 + nativeRange.mStartOffset, nativeRange.Length())); 1.1084 + clause.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), 1.1085 + NS_LITERAL_STRING("\n")); 1.1086 + range.mEndOffset = range.mStartOffset + clause.Length(); 1.1087 + } 1.1088 + } 1.1089 + 1.1090 + action.mData.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), 1.1091 + NS_LITERAL_STRING("\n")); 1.1092 + 1.1093 + if (action.mData != mComposition.mLastData) { 1.1094 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1095 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1096 + "dispatching compositionupdate event...", this)); 1.1097 + WidgetCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, 1.1098 + mWidget); 1.1099 + mWidget->InitEvent(compositionUpdate); 1.1100 + compositionUpdate.data = action.mData; 1.1101 + mComposition.mLastData = compositionUpdate.data; 1.1102 + mWidget->DispatchWindowEvent(&compositionUpdate); 1.1103 + if (!mWidget || mWidget->Destroyed()) { 1.1104 + break; 1.1105 + } 1.1106 + } 1.1107 + 1.1108 + MOZ_ASSERT(action.mData == mComposition.mLastData); 1.1109 + 1.1110 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1111 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1112 + "dispatching text event...", this)); 1.1113 + WidgetTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); 1.1114 + mWidget->InitEvent(textEvent); 1.1115 + textEvent.theText = mComposition.mLastData; 1.1116 + if (action.mRanges->IsEmpty()) { 1.1117 + TextRange wholeRange; 1.1118 + wholeRange.mStartOffset = 0; 1.1119 + wholeRange.mEndOffset = textEvent.theText.Length(); 1.1120 + wholeRange.mRangeType = NS_TEXTRANGE_RAWINPUT; 1.1121 + action.mRanges->AppendElement(wholeRange); 1.1122 + } 1.1123 + textEvent.mRanges = action.mRanges; 1.1124 + mWidget->DispatchWindowEvent(&textEvent); 1.1125 + // Be aware, the mWidget might already have been destroyed. 1.1126 + break; 1.1127 + } 1.1128 + case PendingAction::COMPOSITION_END: { 1.1129 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1130 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1131 + "flushing COMPOSITION_END={ mData=\"%s\" }", 1.1132 + this, NS_ConvertUTF16toUTF8(action.mData).get())); 1.1133 + 1.1134 + action.mData.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), 1.1135 + NS_LITERAL_STRING("\n")); 1.1136 + if (action.mData != mComposition.mLastData) { 1.1137 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1138 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1139 + "dispatching compositionupdate event...", this)); 1.1140 + WidgetCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, 1.1141 + mWidget); 1.1142 + mWidget->InitEvent(compositionUpdate); 1.1143 + compositionUpdate.data = action.mData; 1.1144 + mComposition.mLastData = compositionUpdate.data; 1.1145 + mWidget->DispatchWindowEvent(&compositionUpdate); 1.1146 + if (!mWidget || mWidget->Destroyed()) { 1.1147 + break; 1.1148 + } 1.1149 + } 1.1150 + 1.1151 + MOZ_ASSERT(action.mData == mComposition.mLastData); 1.1152 + 1.1153 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1154 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1155 + "dispatching text event...", this)); 1.1156 + WidgetTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); 1.1157 + mWidget->InitEvent(textEvent); 1.1158 + textEvent.theText = mComposition.mLastData; 1.1159 + mWidget->DispatchWindowEvent(&textEvent); 1.1160 + if (!mWidget || mWidget->Destroyed()) { 1.1161 + break; 1.1162 + } 1.1163 + 1.1164 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1165 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1166 + "dispatching compositionend event...", this)); 1.1167 + WidgetCompositionEvent compositionEnd(true, NS_COMPOSITION_END, 1.1168 + mWidget); 1.1169 + compositionEnd.data = mComposition.mLastData; 1.1170 + mWidget->InitEvent(compositionEnd); 1.1171 + mWidget->DispatchWindowEvent(&compositionEnd); 1.1172 + if (!mWidget || mWidget->Destroyed()) { 1.1173 + break; 1.1174 + } 1.1175 + mComposition.mLastData.Truncate(); 1.1176 + break; 1.1177 + } 1.1178 + case PendingAction::SELECTION_SET: { 1.1179 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1180 + ("TSF: 0x%p nsTextStore::FlushPendingActions() " 1.1181 + "flushing SELECTION_SET={ mSelectionStart=%d, " 1.1182 + "mSelectionLength=%d, mSelectionReversed=%s }", 1.1183 + this, action.mSelectionStart, action.mSelectionLength, 1.1184 + GetBoolName(action.mSelectionReversed))); 1.1185 + 1.1186 + WidgetSelectionEvent selectionSet(true, NS_SELECTION_SET, mWidget); 1.1187 + selectionSet.mOffset = 1.1188 + static_cast<uint32_t>(action.mSelectionStart); 1.1189 + selectionSet.mLength = 1.1190 + static_cast<uint32_t>(action.mSelectionLength); 1.1191 + selectionSet.mReversed = action.mSelectionReversed; 1.1192 + break; 1.1193 + } 1.1194 + default: 1.1195 + MOZ_CRASH("unexpected action type"); 1.1196 + } 1.1197 + 1.1198 + if (mWidget && !mWidget->Destroyed()) { 1.1199 + continue; 1.1200 + } 1.1201 + 1.1202 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1203 + ("TSF: 0x%p nsTextStore::FlushPendingActions(), " 1.1204 + "qutting since the mWidget has gone", this)); 1.1205 + break; 1.1206 + } 1.1207 + mPendingActions.Clear(); 1.1208 +} 1.1209 + 1.1210 +STDMETHODIMP 1.1211 +nsTextStore::GetStatus(TS_STATUS *pdcs) 1.1212 +{ 1.1213 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1214 + ("TSF: 0x%p nsTextStore::GetStatus(pdcs=0x%p)", this, pdcs)); 1.1215 + 1.1216 + if (!pdcs) { 1.1217 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1218 + ("TSF: 0x%p nsTextStore::GetStatus() FAILED due to null pdcs", this)); 1.1219 + return E_INVALIDARG; 1.1220 + } 1.1221 + pdcs->dwDynamicFlags = 0; 1.1222 + // we use a "flat" text model for TSF support so no hidden text 1.1223 + pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT; 1.1224 + return S_OK; 1.1225 +} 1.1226 + 1.1227 +STDMETHODIMP 1.1228 +nsTextStore::QueryInsert(LONG acpTestStart, 1.1229 + LONG acpTestEnd, 1.1230 + ULONG cch, 1.1231 + LONG *pacpResultStart, 1.1232 + LONG *pacpResultEnd) 1.1233 +{ 1.1234 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1235 + ("TSF: 0x%p nsTextStore::QueryInsert(acpTestStart=%ld, " 1.1236 + "acpTestEnd=%ld, cch=%lu, pacpResultStart=0x%p, pacpResultEnd=0x%p)", 1.1237 + this, acpTestStart, acpTestEnd, cch, acpTestStart, acpTestEnd)); 1.1238 + 1.1239 + if (!pacpResultStart || !pacpResultEnd) { 1.1240 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1241 + ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " 1.1242 + "the null argument", this)); 1.1243 + return E_INVALIDARG; 1.1244 + } 1.1245 + 1.1246 + if (acpTestStart < 0 || acpTestStart > acpTestEnd) { 1.1247 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1248 + ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " 1.1249 + "wrong argument", this)); 1.1250 + return E_INVALIDARG; 1.1251 + } 1.1252 + 1.1253 + // XXX need to adjust to cluster boundary 1.1254 + // Assume we are given good offsets for now 1.1255 + *pacpResultStart = acpTestStart; 1.1256 + *pacpResultEnd = acpTestStart + cch; 1.1257 + 1.1258 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1259 + ("TSF: 0x%p nsTextStore::QueryInsert() succeeded: " 1.1260 + "*pacpResultStart=%ld, *pacpResultEnd=%ld)", 1.1261 + this, *pacpResultStart, *pacpResultEnd)); 1.1262 + return S_OK; 1.1263 +} 1.1264 + 1.1265 +STDMETHODIMP 1.1266 +nsTextStore::GetSelection(ULONG ulIndex, 1.1267 + ULONG ulCount, 1.1268 + TS_SELECTION_ACP *pSelection, 1.1269 + ULONG *pcFetched) 1.1270 +{ 1.1271 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1272 + ("TSF: 0x%p nsTextStore::GetSelection(ulIndex=%lu, ulCount=%lu, " 1.1273 + "pSelection=0x%p, pcFetched=0x%p)", 1.1274 + this, ulIndex, ulCount, pSelection, pcFetched)); 1.1275 + 1.1276 + if (!IsReadLocked()) { 1.1277 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1278 + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to not locked", 1.1279 + this)); 1.1280 + return TS_E_NOLOCK; 1.1281 + } 1.1282 + if (!ulCount || !pSelection || !pcFetched) { 1.1283 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1284 + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " 1.1285 + "null argument", this)); 1.1286 + return E_INVALIDARG; 1.1287 + } 1.1288 + 1.1289 + *pcFetched = 0; 1.1290 + 1.1291 + if (ulIndex != static_cast<ULONG>(TS_DEFAULT_SELECTION) && 1.1292 + ulIndex != 0) { 1.1293 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1294 + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " 1.1295 + "unsupported selection", this)); 1.1296 + return TS_E_NOSELECTION; 1.1297 + } 1.1298 + 1.1299 + Selection& currentSel = CurrentSelection(); 1.1300 + if (currentSel.IsDirty()) { 1.1301 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1302 + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " 1.1303 + "CurrentSelection() failure", this)); 1.1304 + return E_FAIL; 1.1305 + } 1.1306 + *pSelection = currentSel.ACP(); 1.1307 + *pcFetched = 1; 1.1308 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1309 + ("TSF: 0x%p nsTextStore::GetSelection() succeeded", this)); 1.1310 + return S_OK; 1.1311 +} 1.1312 + 1.1313 +nsTextStore::Content& 1.1314 +nsTextStore::CurrentContent() 1.1315 +{ 1.1316 + Selection& currentSel = CurrentSelection(); 1.1317 + if (currentSel.IsDirty()) { 1.1318 + mContent.Clear(); 1.1319 + return mContent; 1.1320 + } 1.1321 + 1.1322 + if (!mContent.IsInitialized()) { 1.1323 + MOZ_ASSERT(mWidget && !mWidget->Destroyed()); 1.1324 + 1.1325 + WidgetQueryContentEvent queryText(true, NS_QUERY_TEXT_CONTENT, mWidget); 1.1326 + queryText.InitForQueryTextContent(0, UINT32_MAX); 1.1327 + mWidget->InitEvent(queryText); 1.1328 + mWidget->DispatchWindowEvent(&queryText); 1.1329 + NS_ENSURE_TRUE(queryText.mSucceeded, mContent); 1.1330 + 1.1331 + mContent.Init(queryText.mReply.mString); 1.1332 + } 1.1333 + 1.1334 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1335 + ("TSF: 0x%p nsTextStore::CurrentContent(): " 1.1336 + "mContent={ mText.Length()=%d }", 1.1337 + this, mContent.Text().Length())); 1.1338 + 1.1339 + return mContent; 1.1340 +} 1.1341 + 1.1342 +nsTextStore::Selection& 1.1343 +nsTextStore::CurrentSelection() 1.1344 +{ 1.1345 + if (mSelection.IsDirty()) { 1.1346 + // If the window has never been available, we should crash since working 1.1347 + // with broken values may make TIP confused. 1.1348 + if (!mWidget || mWidget->Destroyed()) { 1.1349 + MOZ_CRASH(); 1.1350 + } 1.1351 + 1.1352 + WidgetQueryContentEvent querySelection(true, NS_QUERY_SELECTED_TEXT, 1.1353 + mWidget); 1.1354 + mWidget->InitEvent(querySelection); 1.1355 + mWidget->DispatchWindowEvent(&querySelection); 1.1356 + NS_ENSURE_TRUE(querySelection.mSucceeded, mSelection); 1.1357 + 1.1358 + mSelection.SetSelection(querySelection.mReply.mOffset, 1.1359 + querySelection.mReply.mString.Length(), 1.1360 + querySelection.mReply.mReversed); 1.1361 + } 1.1362 + 1.1363 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1364 + ("TSF: 0x%p nsTextStore::CurrentSelection(): " 1.1365 + "acpStart=%d, acpEnd=%d (length=%d), reverted=%s", 1.1366 + this, mSelection.StartOffset(), mSelection.EndOffset(), 1.1367 + mSelection.Length(), 1.1368 + GetBoolName(mSelection.IsReversed()))); 1.1369 + 1.1370 + return mSelection; 1.1371 +} 1.1372 + 1.1373 +static HRESULT 1.1374 +GetRangeExtent(ITfRange* aRange, LONG* aStart, LONG* aLength) 1.1375 +{ 1.1376 + nsRefPtr<ITfRangeACP> rangeACP; 1.1377 + aRange->QueryInterface(IID_ITfRangeACP, getter_AddRefs(rangeACP)); 1.1378 + NS_ENSURE_TRUE(rangeACP, E_FAIL); 1.1379 + return rangeACP->GetExtent(aStart, aLength); 1.1380 +} 1.1381 + 1.1382 +static uint32_t 1.1383 +GetGeckoSelectionValue(TF_DISPLAYATTRIBUTE &aDisplayAttr) 1.1384 +{ 1.1385 + uint32_t result; 1.1386 + switch (aDisplayAttr.bAttr) { 1.1387 + case TF_ATTR_TARGET_CONVERTED: 1.1388 + result = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT; 1.1389 + break; 1.1390 + case TF_ATTR_CONVERTED: 1.1391 + result = NS_TEXTRANGE_CONVERTEDTEXT; 1.1392 + break; 1.1393 + case TF_ATTR_TARGET_NOTCONVERTED: 1.1394 + result = NS_TEXTRANGE_SELECTEDRAWTEXT; 1.1395 + break; 1.1396 + default: 1.1397 + result = NS_TEXTRANGE_RAWINPUT; 1.1398 + break; 1.1399 + } 1.1400 + return result; 1.1401 +} 1.1402 + 1.1403 +HRESULT 1.1404 +nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, 1.1405 + ITfRange* aRange, 1.1406 + TF_DISPLAYATTRIBUTE* aResult) 1.1407 +{ 1.1408 + NS_ENSURE_TRUE(aAttrProperty, E_FAIL); 1.1409 + NS_ENSURE_TRUE(aRange, E_FAIL); 1.1410 + NS_ENSURE_TRUE(aResult, E_FAIL); 1.1411 + 1.1412 + HRESULT hr; 1.1413 + 1.1414 +#ifdef PR_LOGGING 1.1415 + if (PR_LOG_TEST(sTextStoreLog, PR_LOG_DEBUG)) { 1.1416 + LONG start = 0, length = 0; 1.1417 + hr = GetRangeExtent(aRange, &start, &length); 1.1418 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1419 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute(): " 1.1420 + "GetDisplayAttribute range=%ld-%ld (hr=%s)", 1.1421 + this, start - mComposition.mStart, 1.1422 + start - mComposition.mStart + length, 1.1423 + GetCommonReturnValueName(hr))); 1.1424 + } 1.1425 +#endif 1.1426 + 1.1427 + VARIANT propValue; 1.1428 + ::VariantInit(&propValue); 1.1429 + hr = aAttrProperty->GetValue(TfEditCookie(mEditCookie), aRange, &propValue); 1.1430 + if (FAILED(hr)) { 1.1431 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1432 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " 1.1433 + "ITfProperty::GetValue() failed", this)); 1.1434 + return hr; 1.1435 + } 1.1436 + if (VT_I4 != propValue.vt) { 1.1437 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1438 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " 1.1439 + "ITfProperty::GetValue() returns non-VT_I4 value", this)); 1.1440 + ::VariantClear(&propValue); 1.1441 + return E_FAIL; 1.1442 + } 1.1443 + 1.1444 + NS_ENSURE_TRUE(sCategoryMgr, E_FAIL); 1.1445 + GUID guid; 1.1446 + hr = sCategoryMgr->GetGUID(DWORD(propValue.lVal), &guid); 1.1447 + ::VariantClear(&propValue); 1.1448 + if (FAILED(hr)) { 1.1449 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1450 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " 1.1451 + "ITfCategoryMgr::GetGUID() failed", this)); 1.1452 + return hr; 1.1453 + } 1.1454 + 1.1455 + NS_ENSURE_TRUE(sDisplayAttrMgr, E_FAIL); 1.1456 + nsRefPtr<ITfDisplayAttributeInfo> info; 1.1457 + hr = sDisplayAttrMgr->GetDisplayAttributeInfo(guid, getter_AddRefs(info), 1.1458 + nullptr); 1.1459 + if (FAILED(hr) || !info) { 1.1460 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1461 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " 1.1462 + "ITfDisplayAttributeMgr::GetDisplayAttributeInfo() failed", this)); 1.1463 + return hr; 1.1464 + } 1.1465 + 1.1466 + hr = info->GetAttributeInfo(aResult); 1.1467 + if (FAILED(hr)) { 1.1468 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1469 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " 1.1470 + "ITfDisplayAttributeInfo::GetAttributeInfo() failed", this)); 1.1471 + return hr; 1.1472 + } 1.1473 + 1.1474 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1475 + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() succeeded: " 1.1476 + "Result={ %s }", this, GetDisplayAttrStr(*aResult).get())); 1.1477 + return S_OK; 1.1478 +} 1.1479 + 1.1480 +HRESULT 1.1481 +nsTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) 1.1482 +{ 1.1483 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1484 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary(" 1.1485 + "aRangeNew=0x%p), mComposition.mView=0x%p", 1.1486 + this, aRangeNew, mComposition.mView.get())); 1.1487 + 1.1488 + if (!mComposition.IsComposing()) { 1.1489 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1490 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " 1.1491 + "due to no composition view", this)); 1.1492 + return E_FAIL; 1.1493 + } 1.1494 + 1.1495 + HRESULT hr; 1.1496 + nsRefPtr<ITfCompositionView> pComposition(mComposition.mView); 1.1497 + nsRefPtr<ITfRange> composingRange(aRangeNew); 1.1498 + if (!composingRange) { 1.1499 + hr = pComposition->GetRange(getter_AddRefs(composingRange)); 1.1500 + if (FAILED(hr)) { 1.1501 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1502 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " 1.1503 + "due to pComposition->GetRange() failure", this)); 1.1504 + return hr; 1.1505 + } 1.1506 + } 1.1507 + 1.1508 + // Get starting offset of the composition 1.1509 + LONG compStart = 0, compLength = 0; 1.1510 + hr = GetRangeExtent(composingRange, &compStart, &compLength); 1.1511 + if (FAILED(hr)) { 1.1512 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1513 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " 1.1514 + "due to GetRangeExtent() failure", this)); 1.1515 + return hr; 1.1516 + } 1.1517 + 1.1518 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1519 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary(), " 1.1520 + "range=%ld-%ld, mComposition={ mStart=%ld, mString.Length()=%lu }", 1.1521 + this, compStart, compStart + compLength, mComposition.mStart, 1.1522 + mComposition.mString.Length())); 1.1523 + 1.1524 + if (mComposition.mStart != compStart || 1.1525 + mComposition.mString.Length() != (ULONG)compLength) { 1.1526 + // If the queried composition length is different from the length 1.1527 + // of our composition string, OnUpdateComposition is being called 1.1528 + // because a part of the original composition was committed. 1.1529 + // Reflect that by committing existing composition and starting 1.1530 + // a new one. RecordCompositionEndAction() followed by 1.1531 + // RecordCompositionStartAction() will accomplish this automagically. 1.1532 + RecordCompositionEndAction(); 1.1533 + RecordCompositionStartAction(pComposition, composingRange, true); 1.1534 + } 1.1535 + 1.1536 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1537 + ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() succeeded", 1.1538 + this)); 1.1539 + return S_OK; 1.1540 +} 1.1541 + 1.1542 +static bool 1.1543 +GetColor(const TF_DA_COLOR &aTSFColor, nscolor &aResult) 1.1544 +{ 1.1545 + switch (aTSFColor.type) { 1.1546 + case TF_CT_SYSCOLOR: { 1.1547 + DWORD sysColor = ::GetSysColor(aTSFColor.nIndex); 1.1548 + aResult = NS_RGB(GetRValue(sysColor), GetGValue(sysColor), 1.1549 + GetBValue(sysColor)); 1.1550 + return true; 1.1551 + } 1.1552 + case TF_CT_COLORREF: 1.1553 + aResult = NS_RGB(GetRValue(aTSFColor.cr), GetGValue(aTSFColor.cr), 1.1554 + GetBValue(aTSFColor.cr)); 1.1555 + return true; 1.1556 + case TF_CT_NONE: 1.1557 + default: 1.1558 + return false; 1.1559 + } 1.1560 +} 1.1561 + 1.1562 +static bool 1.1563 +GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, uint8_t &aTextRangeLineStyle) 1.1564 +{ 1.1565 + switch (aTSFLineStyle) { 1.1566 + case TF_LS_NONE: 1.1567 + aTextRangeLineStyle = TextRangeStyle::LINESTYLE_NONE; 1.1568 + return true; 1.1569 + case TF_LS_SOLID: 1.1570 + aTextRangeLineStyle = TextRangeStyle::LINESTYLE_SOLID; 1.1571 + return true; 1.1572 + case TF_LS_DOT: 1.1573 + aTextRangeLineStyle = TextRangeStyle::LINESTYLE_DOTTED; 1.1574 + return true; 1.1575 + case TF_LS_DASH: 1.1576 + aTextRangeLineStyle = TextRangeStyle::LINESTYLE_DASHED; 1.1577 + return true; 1.1578 + case TF_LS_SQUIGGLE: 1.1579 + aTextRangeLineStyle = TextRangeStyle::LINESTYLE_WAVY; 1.1580 + return true; 1.1581 + default: 1.1582 + return false; 1.1583 + } 1.1584 +} 1.1585 + 1.1586 +HRESULT 1.1587 +nsTextStore::RecordCompositionUpdateAction() 1.1588 +{ 1.1589 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1590 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction(), " 1.1591 + "mComposition={ mView=0x%p, mString=\"%s\" }", 1.1592 + this, mComposition.mView.get(), 1.1593 + NS_ConvertUTF16toUTF8(mComposition.mString).get())); 1.1594 + 1.1595 + if (!mComposition.IsComposing()) { 1.1596 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1597 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " 1.1598 + "due to no composition view", this)); 1.1599 + return E_FAIL; 1.1600 + } 1.1601 + 1.1602 + // Getting display attributes is *really* complicated! 1.1603 + // We first get the context and the property objects to query for 1.1604 + // attributes, but since a big range can have a variety of values for 1.1605 + // the attribute, we have to find out all the ranges that have distinct 1.1606 + // attribute values. Then we query for what the value represents through 1.1607 + // the display attribute manager and translate that to TextRange to be 1.1608 + // sent in NS_TEXT_TEXT 1.1609 + 1.1610 + nsRefPtr<ITfProperty> attrPropetry; 1.1611 + HRESULT hr = mContext->GetProperty(GUID_PROP_ATTRIBUTE, 1.1612 + getter_AddRefs(attrPropetry)); 1.1613 + if (FAILED(hr) || !attrPropetry) { 1.1614 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1615 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " 1.1616 + "due to mContext->GetProperty() failure", this)); 1.1617 + return FAILED(hr) ? hr : E_FAIL; 1.1618 + } 1.1619 + 1.1620 + nsRefPtr<ITfRange> composingRange; 1.1621 + hr = mComposition.mView->GetRange(getter_AddRefs(composingRange)); 1.1622 + if (FAILED(hr)) { 1.1623 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1624 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " 1.1625 + "FAILED due to mComposition.mView->GetRange() failure", this)); 1.1626 + return hr; 1.1627 + } 1.1628 + 1.1629 + nsRefPtr<IEnumTfRanges> enumRanges; 1.1630 + hr = attrPropetry->EnumRanges(TfEditCookie(mEditCookie), 1.1631 + getter_AddRefs(enumRanges), composingRange); 1.1632 + if (FAILED(hr) || !enumRanges) { 1.1633 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1634 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " 1.1635 + "due to attrPropetry->EnumRanges() failure", this)); 1.1636 + return FAILED(hr) ? hr : E_FAIL; 1.1637 + } 1.1638 + 1.1639 + // First, put the log of content and selection here. 1.1640 + Selection& currentSel = CurrentSelection(); 1.1641 + if (currentSel.IsDirty()) { 1.1642 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1643 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " 1.1644 + "due to CurrentSelection() failure", this)); 1.1645 + return E_FAIL; 1.1646 + } 1.1647 + 1.1648 + PendingAction* action = GetPendingCompositionUpdate(); 1.1649 + action->mData = mComposition.mString; 1.1650 + // The ranges might already have been initialized, however, if this is 1.1651 + // called again, that means we need to overwrite the ranges with current 1.1652 + // information. 1.1653 + action->mRanges->Clear(); 1.1654 + 1.1655 + TextRange newRange; 1.1656 + // No matter if we have display attribute info or not, 1.1657 + // we always pass in at least one range to NS_TEXT_TEXT 1.1658 + newRange.mStartOffset = 0; 1.1659 + newRange.mEndOffset = action->mData.Length(); 1.1660 + newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; 1.1661 + action->mRanges->AppendElement(newRange); 1.1662 + 1.1663 + nsRefPtr<ITfRange> range; 1.1664 + while (S_OK == enumRanges->Next(1, getter_AddRefs(range), nullptr) && range) { 1.1665 + 1.1666 + LONG start = 0, length = 0; 1.1667 + if (FAILED(GetRangeExtent(range, &start, &length))) 1.1668 + continue; 1.1669 + 1.1670 + TextRange newRange; 1.1671 + newRange.mStartOffset = uint32_t(start - mComposition.mStart); 1.1672 + // The end of the last range in the array is 1.1673 + // always kept at the end of composition 1.1674 + newRange.mEndOffset = mComposition.mString.Length(); 1.1675 + 1.1676 + TF_DISPLAYATTRIBUTE attr; 1.1677 + hr = GetDisplayAttribute(attrPropetry, range, &attr); 1.1678 + if (FAILED(hr)) { 1.1679 + newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; 1.1680 + } else { 1.1681 + newRange.mRangeType = GetGeckoSelectionValue(attr); 1.1682 + if (GetColor(attr.crText, newRange.mRangeStyle.mForegroundColor)) { 1.1683 + newRange.mRangeStyle.mDefinedStyles |= 1.1684 + TextRangeStyle::DEFINED_FOREGROUND_COLOR; 1.1685 + } 1.1686 + if (GetColor(attr.crBk, newRange.mRangeStyle.mBackgroundColor)) { 1.1687 + newRange.mRangeStyle.mDefinedStyles |= 1.1688 + TextRangeStyle::DEFINED_BACKGROUND_COLOR; 1.1689 + } 1.1690 + if (GetColor(attr.crLine, newRange.mRangeStyle.mUnderlineColor)) { 1.1691 + newRange.mRangeStyle.mDefinedStyles |= 1.1692 + TextRangeStyle::DEFINED_UNDERLINE_COLOR; 1.1693 + } 1.1694 + if (GetLineStyle(attr.lsStyle, newRange.mRangeStyle.mLineStyle)) { 1.1695 + newRange.mRangeStyle.mDefinedStyles |= 1.1696 + TextRangeStyle::DEFINED_LINESTYLE; 1.1697 + newRange.mRangeStyle.mIsBoldLine = attr.fBoldLine != 0; 1.1698 + } 1.1699 + } 1.1700 + 1.1701 + TextRange& lastRange = action->mRanges->LastElement(); 1.1702 + if (lastRange.mStartOffset == newRange.mStartOffset) { 1.1703 + // Replace range if last range is the same as this one 1.1704 + // So that ranges don't overlap and confuse the editor 1.1705 + lastRange = newRange; 1.1706 + } else { 1.1707 + lastRange.mEndOffset = newRange.mStartOffset; 1.1708 + action->mRanges->AppendElement(newRange); 1.1709 + } 1.1710 + } 1.1711 + 1.1712 + // We need to hack for Korean Input System which is Korean standard TIP. 1.1713 + // It sets no change style to IME selection (the selection is always only 1.1714 + // one). So, the composition string looks like normal (or committed) string. 1.1715 + // At this time, current selection range is same as the composition string 1.1716 + // range. Other applications set a wide caret which covers the composition 1.1717 + // string, however, Gecko doesn't support the wide caret drawing now (Gecko 1.1718 + // doesn't support XOR drawing), unfortunately. For now, we should change 1.1719 + // the range style to undefined. 1.1720 + if (!currentSel.IsCollapsed() && action->mRanges->Length() == 1) { 1.1721 + TextRange& range = action->mRanges->ElementAt(0); 1.1722 + LONG start = currentSel.MinOffset(); 1.1723 + LONG end = currentSel.MaxOffset(); 1.1724 + if ((LONG)range.mStartOffset == start - mComposition.mStart && 1.1725 + (LONG)range.mEndOffset == end - mComposition.mStart && 1.1726 + range.mRangeStyle.IsNoChangeStyle()) { 1.1727 + range.mRangeStyle.Clear(); 1.1728 + // The looks of selected type is better than others. 1.1729 + range.mRangeType = NS_TEXTRANGE_SELECTEDRAWTEXT; 1.1730 + } 1.1731 + } 1.1732 + 1.1733 + // The caret position has to be collapsed. 1.1734 + LONG caretPosition = currentSel.MaxOffset(); 1.1735 + caretPosition -= mComposition.mStart; 1.1736 + TextRange caretRange; 1.1737 + caretRange.mStartOffset = caretRange.mEndOffset = uint32_t(caretPosition); 1.1738 + caretRange.mRangeType = NS_TEXTRANGE_CARETPOSITION; 1.1739 + action->mRanges->AppendElement(caretRange); 1.1740 + 1.1741 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1742 + ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " 1.1743 + "succeeded", this)); 1.1744 + 1.1745 + return S_OK; 1.1746 +} 1.1747 + 1.1748 +HRESULT 1.1749 +nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, 1.1750 + bool aDispatchTextEvent) 1.1751 +{ 1.1752 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.1753 + ("TSF: 0x%p nsTextStore::SetSelectionInternal(pSelection={ " 1.1754 + "acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s} }, " 1.1755 + "aDispatchTextEvent=%s), mComposition.IsComposing()=%s", 1.1756 + this, pSelection->acpStart, pSelection->acpEnd, 1.1757 + GetActiveSelEndName(pSelection->style.ase), 1.1758 + GetBoolName(pSelection->style.fInterimChar), 1.1759 + GetBoolName(aDispatchTextEvent), 1.1760 + GetBoolName(mComposition.IsComposing()))); 1.1761 + 1.1762 + MOZ_ASSERT(IsReadWriteLocked()); 1.1763 + 1.1764 + Selection& currentSel = CurrentSelection(); 1.1765 + if (currentSel.IsDirty()) { 1.1766 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1767 + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " 1.1768 + "CurrentSelection() failure", this)); 1.1769 + return E_FAIL; 1.1770 + } 1.1771 + 1.1772 + if (mComposition.IsComposing()) { 1.1773 + if (aDispatchTextEvent) { 1.1774 + HRESULT hr = RestartCompositionIfNecessary(); 1.1775 + if (FAILED(hr)) { 1.1776 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1777 + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " 1.1778 + "RestartCompositionIfNecessary() failure", this)); 1.1779 + return hr; 1.1780 + } 1.1781 + } 1.1782 + if (pSelection->acpStart < mComposition.mStart || 1.1783 + pSelection->acpEnd > mComposition.EndOffset()) { 1.1784 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1785 + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " 1.1786 + "the selection being out of the composition string", this)); 1.1787 + return TS_E_INVALIDPOS; 1.1788 + } 1.1789 + // Emulate selection during compositions 1.1790 + currentSel.SetSelection(*pSelection); 1.1791 + if (aDispatchTextEvent) { 1.1792 + HRESULT hr = RecordCompositionUpdateAction(); 1.1793 + if (FAILED(hr)) { 1.1794 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1795 + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " 1.1796 + "RecordCompositionUpdateAction() failure", this)); 1.1797 + return hr; 1.1798 + } 1.1799 + } 1.1800 + return S_OK; 1.1801 + } 1.1802 + 1.1803 + PendingAction* action = mPendingActions.AppendElement(); 1.1804 + action->mType = PendingAction::SELECTION_SET; 1.1805 + action->mSelectionStart = pSelection->acpStart; 1.1806 + action->mSelectionLength = pSelection->acpEnd - pSelection->acpStart; 1.1807 + action->mSelectionReversed = (pSelection->style.ase == TS_AE_START); 1.1808 + 1.1809 + currentSel.SetSelection(*pSelection); 1.1810 + 1.1811 + return S_OK; 1.1812 +} 1.1813 + 1.1814 +STDMETHODIMP 1.1815 +nsTextStore::SetSelection(ULONG ulCount, 1.1816 + const TS_SELECTION_ACP *pSelection) 1.1817 +{ 1.1818 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1819 + ("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu, pSelection=%p { " 1.1820 + "acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s } }), " 1.1821 + "mComposition.IsComposing()=%s", 1.1822 + this, ulCount, pSelection, 1.1823 + pSelection ? pSelection->acpStart : 0, 1.1824 + pSelection ? pSelection->acpEnd : 0, 1.1825 + pSelection ? GetActiveSelEndName(pSelection->style.ase) : "", 1.1826 + pSelection ? GetBoolName(pSelection->style.fInterimChar) : "", 1.1827 + GetBoolName(mComposition.IsComposing()))); 1.1828 + 1.1829 + if (!IsReadWriteLocked()) { 1.1830 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1831 + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " 1.1832 + "not locked (read-write)", this)); 1.1833 + return TS_E_NOLOCK; 1.1834 + } 1.1835 + if (ulCount != 1) { 1.1836 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1837 + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " 1.1838 + "trying setting multiple selection", this)); 1.1839 + return E_INVALIDARG; 1.1840 + } 1.1841 + if (!pSelection) { 1.1842 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1843 + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " 1.1844 + "null argument", this)); 1.1845 + return E_INVALIDARG; 1.1846 + } 1.1847 + 1.1848 + HRESULT hr = SetSelectionInternal(pSelection, true); 1.1849 + if (FAILED(hr)) { 1.1850 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1851 + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " 1.1852 + "SetSelectionInternal() failure", this)); 1.1853 + } else { 1.1854 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1855 + ("TSF: 0x%p nsTextStore::SetSelection() succeeded", this)); 1.1856 + } 1.1857 + return hr; 1.1858 +} 1.1859 + 1.1860 +STDMETHODIMP 1.1861 +nsTextStore::GetText(LONG acpStart, 1.1862 + LONG acpEnd, 1.1863 + WCHAR *pchPlain, 1.1864 + ULONG cchPlainReq, 1.1865 + ULONG *pcchPlainOut, 1.1866 + TS_RUNINFO *prgRunInfo, 1.1867 + ULONG ulRunInfoReq, 1.1868 + ULONG *pulRunInfoOut, 1.1869 + LONG *pacpNext) 1.1870 +{ 1.1871 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1872 + ("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, " 1.1873 + "cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, " 1.1874 + "pulRunInfoOut=0x%p, pacpNext=0x%p), mComposition={ mStart=%ld, " 1.1875 + "mString.Length()=%lu, IsComposing()=%s }", 1.1876 + this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut, 1.1877 + prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext, 1.1878 + mComposition.mStart, mComposition.mString.Length(), 1.1879 + GetBoolName(mComposition.IsComposing()))); 1.1880 + 1.1881 + if (!IsReadLocked()) { 1.1882 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1883 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1884 + "not locked (read)", this)); 1.1885 + return TS_E_NOLOCK; 1.1886 + } 1.1887 + 1.1888 + if (!pcchPlainOut || (!pchPlain && !prgRunInfo) || 1.1889 + !cchPlainReq != !pchPlain || !ulRunInfoReq != !prgRunInfo) { 1.1890 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1891 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1892 + "invalid argument", this)); 1.1893 + return E_INVALIDARG; 1.1894 + } 1.1895 + 1.1896 + if (acpStart < 0 || acpEnd < -1 || (acpEnd != -1 && acpStart > acpEnd)) { 1.1897 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1898 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1899 + "invalid position", this)); 1.1900 + return TS_E_INVALIDPOS; 1.1901 + } 1.1902 + 1.1903 + // Making sure to null-terminate string just to be on the safe side 1.1904 + *pcchPlainOut = 0; 1.1905 + if (pchPlain && cchPlainReq) *pchPlain = 0; 1.1906 + if (pulRunInfoOut) *pulRunInfoOut = 0; 1.1907 + if (pacpNext) *pacpNext = acpStart; 1.1908 + if (prgRunInfo && ulRunInfoReq) { 1.1909 + prgRunInfo->uCount = 0; 1.1910 + prgRunInfo->type = TS_RT_PLAIN; 1.1911 + } 1.1912 + 1.1913 + Content& currentContent = CurrentContent(); 1.1914 + if (!currentContent.IsInitialized()) { 1.1915 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1916 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1917 + "CurrentContent() failure", this)); 1.1918 + return E_FAIL; 1.1919 + } 1.1920 + if (currentContent.Text().Length() < static_cast<uint32_t>(acpStart)) { 1.1921 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1922 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1923 + "acpStart is larger offset than the actual text length", this)); 1.1924 + return TS_E_INVALIDPOS; 1.1925 + } 1.1926 + if (acpEnd != -1 && 1.1927 + currentContent.Text().Length() < static_cast<uint32_t>(acpEnd)) { 1.1928 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1929 + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " 1.1930 + "acpEnd is larger offset than the actual text length", this)); 1.1931 + return TS_E_INVALIDPOS; 1.1932 + } 1.1933 + uint32_t length = (acpEnd == -1) ? 1.1934 + currentContent.Text().Length() - static_cast<uint32_t>(acpStart) : 1.1935 + static_cast<uint32_t>(acpEnd - acpStart); 1.1936 + if (cchPlainReq && cchPlainReq - 1 < length) { 1.1937 + length = cchPlainReq - 1; 1.1938 + } 1.1939 + if (length) { 1.1940 + if (pchPlain && cchPlainReq) { 1.1941 + const char16_t* startChar = 1.1942 + currentContent.Text().BeginReading() + acpStart; 1.1943 + memcpy(pchPlain, startChar, length * sizeof(*pchPlain)); 1.1944 + pchPlain[length] = 0; 1.1945 + *pcchPlainOut = length; 1.1946 + } 1.1947 + if (prgRunInfo && ulRunInfoReq) { 1.1948 + prgRunInfo->uCount = length; 1.1949 + prgRunInfo->type = TS_RT_PLAIN; 1.1950 + if (pulRunInfoOut) *pulRunInfoOut = 1; 1.1951 + } 1.1952 + if (pacpNext) *pacpNext = acpStart + length; 1.1953 + } 1.1954 + 1.1955 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1956 + ("TSF: 0x%p nsTextStore::GetText() succeeded: pcchPlainOut=0x%p, " 1.1957 + "*prgRunInfo={ uCount=%lu, type=%s }, *pulRunInfoOut=%lu, " 1.1958 + "*pacpNext=%ld)", 1.1959 + this, pcchPlainOut, prgRunInfo ? prgRunInfo->uCount : 0, 1.1960 + prgRunInfo ? GetTextRunTypeName(prgRunInfo->type) : "N/A", 1.1961 + pulRunInfoOut ? pulRunInfoOut : 0, pacpNext ? pacpNext : 0)); 1.1962 + return S_OK; 1.1963 +} 1.1964 + 1.1965 +STDMETHODIMP 1.1966 +nsTextStore::SetText(DWORD dwFlags, 1.1967 + LONG acpStart, 1.1968 + LONG acpEnd, 1.1969 + const WCHAR *pchText, 1.1970 + ULONG cch, 1.1971 + TS_TEXTCHANGE *pChange) 1.1972 +{ 1.1973 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.1974 + ("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, " 1.1975 + "acpEnd=%ld, pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), " 1.1976 + "mComposition.IsComposing()=%s", 1.1977 + this, dwFlags == TS_ST_CORRECTION ? "TS_ST_CORRECTION" : 1.1978 + "not-specified", 1.1979 + acpStart, acpEnd, pchText, 1.1980 + pchText && cch ? 1.1981 + NS_ConvertUTF16toUTF8(pchText, cch).get() : "", 1.1982 + cch, pChange, GetBoolName(mComposition.IsComposing()))); 1.1983 + 1.1984 + // Per SDK documentation, and since we don't have better 1.1985 + // ways to do this, this method acts as a helper to 1.1986 + // call SetSelection followed by InsertTextAtSelection 1.1987 + if (!IsReadWriteLocked()) { 1.1988 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.1989 + ("TSF: 0x%p nsTextStore::SetText() FAILED due to " 1.1990 + "not locked (read)", this)); 1.1991 + return TS_E_NOLOCK; 1.1992 + } 1.1993 + 1.1994 + TS_SELECTION_ACP selection; 1.1995 + selection.acpStart = acpStart; 1.1996 + selection.acpEnd = acpEnd; 1.1997 + selection.style.ase = TS_AE_END; 1.1998 + selection.style.fInterimChar = 0; 1.1999 + // Set selection to desired range 1.2000 + HRESULT hr = SetSelectionInternal(&selection); 1.2001 + if (FAILED(hr)) { 1.2002 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2003 + ("TSF: 0x%p nsTextStore::SetText() FAILED due to " 1.2004 + "SetSelectionInternal() failure", this)); 1.2005 + return hr; 1.2006 + } 1.2007 + // Replace just selected text 1.2008 + if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), 1.2009 + pChange)) { 1.2010 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2011 + ("TSF: 0x%p nsTextStore::SetText() FAILED due to " 1.2012 + "InsertTextAtSelectionInternal() failure", this)); 1.2013 + return E_FAIL; 1.2014 + } 1.2015 + 1.2016 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2017 + ("TSF: 0x%p nsTextStore::SetText() succeeded: pChange={ " 1.2018 + "acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }", 1.2019 + this, pChange ? pChange->acpStart : 0, 1.2020 + pChange ? pChange->acpOldEnd : 0, pChange ? pChange->acpNewEnd : 0)); 1.2021 + return S_OK; 1.2022 +} 1.2023 + 1.2024 +STDMETHODIMP 1.2025 +nsTextStore::GetFormattedText(LONG acpStart, 1.2026 + LONG acpEnd, 1.2027 + IDataObject **ppDataObject) 1.2028 +{ 1.2029 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2030 + ("TSF: 0x%p nsTextStore::GetFormattedText() called " 1.2031 + "but not supported (E_NOTIMPL)", this)); 1.2032 + 1.2033 + // no support for formatted text 1.2034 + return E_NOTIMPL; 1.2035 +} 1.2036 + 1.2037 +STDMETHODIMP 1.2038 +nsTextStore::GetEmbedded(LONG acpPos, 1.2039 + REFGUID rguidService, 1.2040 + REFIID riid, 1.2041 + IUnknown **ppunk) 1.2042 +{ 1.2043 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2044 + ("TSF: 0x%p nsTextStore::GetEmbedded() called " 1.2045 + "but not supported (E_NOTIMPL)", this)); 1.2046 + 1.2047 + // embedded objects are not supported 1.2048 + return E_NOTIMPL; 1.2049 +} 1.2050 + 1.2051 +STDMETHODIMP 1.2052 +nsTextStore::QueryInsertEmbedded(const GUID *pguidService, 1.2053 + const FORMATETC *pFormatEtc, 1.2054 + BOOL *pfInsertable) 1.2055 +{ 1.2056 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2057 + ("TSF: 0x%p nsTextStore::QueryInsertEmbedded() called " 1.2058 + "but not supported, *pfInsertable=FALSE (S_OK)", this)); 1.2059 + 1.2060 + // embedded objects are not supported 1.2061 + *pfInsertable = FALSE; 1.2062 + return S_OK; 1.2063 +} 1.2064 + 1.2065 +STDMETHODIMP 1.2066 +nsTextStore::InsertEmbedded(DWORD dwFlags, 1.2067 + LONG acpStart, 1.2068 + LONG acpEnd, 1.2069 + IDataObject *pDataObject, 1.2070 + TS_TEXTCHANGE *pChange) 1.2071 +{ 1.2072 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2073 + ("TSF: 0x%p nsTextStore::InsertEmbedded() called " 1.2074 + "but not supported (E_NOTIMPL)", this)); 1.2075 + 1.2076 + // embedded objects are not supported 1.2077 + return E_NOTIMPL; 1.2078 +} 1.2079 + 1.2080 +void 1.2081 +nsTextStore::SetInputScope(const nsString& aHTMLInputType) 1.2082 +{ 1.2083 + mInputScopes.Clear(); 1.2084 + if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) { 1.2085 + return; 1.2086 + } 1.2087 + 1.2088 + // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html 1.2089 + if (aHTMLInputType.EqualsLiteral("url")) { 1.2090 + mInputScopes.AppendElement(IS_URL); 1.2091 + } else if (aHTMLInputType.EqualsLiteral("search")) { 1.2092 + mInputScopes.AppendElement(IS_SEARCH); 1.2093 + } else if (aHTMLInputType.EqualsLiteral("email")) { 1.2094 + mInputScopes.AppendElement(IS_EMAIL_SMTPEMAILADDRESS); 1.2095 + } else if (aHTMLInputType.EqualsLiteral("password")) { 1.2096 + mInputScopes.AppendElement(IS_PASSWORD); 1.2097 + } else if (aHTMLInputType.EqualsLiteral("datetime") || 1.2098 + aHTMLInputType.EqualsLiteral("datetime-local")) { 1.2099 + mInputScopes.AppendElement(IS_DATE_FULLDATE); 1.2100 + mInputScopes.AppendElement(IS_TIME_FULLTIME); 1.2101 + } else if (aHTMLInputType.EqualsLiteral("date") || 1.2102 + aHTMLInputType.EqualsLiteral("month") || 1.2103 + aHTMLInputType.EqualsLiteral("week")) { 1.2104 + mInputScopes.AppendElement(IS_DATE_FULLDATE); 1.2105 + } else if (aHTMLInputType.EqualsLiteral("time")) { 1.2106 + mInputScopes.AppendElement(IS_TIME_FULLTIME); 1.2107 + } else if (aHTMLInputType.EqualsLiteral("tel")) { 1.2108 + mInputScopes.AppendElement(IS_TELEPHONE_FULLTELEPHONENUMBER); 1.2109 + mInputScopes.AppendElement(IS_TELEPHONE_LOCALNUMBER); 1.2110 + } else if (aHTMLInputType.EqualsLiteral("number")) { 1.2111 + mInputScopes.AppendElement(IS_NUMBER); 1.2112 + } 1.2113 +} 1.2114 + 1.2115 +HRESULT 1.2116 +nsTextStore::ProcessScopeRequest(DWORD dwFlags, 1.2117 + ULONG cFilterAttrs, 1.2118 + const TS_ATTRID *paFilterAttrs) 1.2119 +{ 1.2120 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2121 + ("TSF: 0x%p nsTextStore::ProcessScopeRequest(dwFlags=%s, " 1.2122 + "cFilterAttrs=%ld", 1.2123 + this, GetFindFlagName(dwFlags).get(), cFilterAttrs)); 1.2124 + 1.2125 + // This is a little weird! RequestSupportedAttrs gives us advanced notice 1.2126 + // of a support query via RetrieveRequestedAttrs for a specific attribute. 1.2127 + // RetrieveRequestedAttrs needs to return valid data for all attributes we 1.2128 + // support, but the text service will only want the input scope object 1.2129 + // returned in RetrieveRequestedAttrs if the dwFlags passed in here contains 1.2130 + // TS_ATTR_FIND_WANT_VALUE. 1.2131 + mInputScopeDetected = mInputScopeRequested = false; 1.2132 + 1.2133 + // Currently we only support GUID_PROP_INPUTSCOPE 1.2134 + for (uint32_t idx = 0; idx < cFilterAttrs; ++idx) { 1.2135 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2136 + ("TSF: 0x%p nsTextStore::ProcessScopeRequest() " 1.2137 + "requested attr=%s", 1.2138 + this, GetCLSIDNameStr(paFilterAttrs[idx]).get())); 1.2139 + if (IsEqualGUID(paFilterAttrs[idx], GUID_PROP_INPUTSCOPE)) { 1.2140 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2141 + ("TSF: 0x%p nsTextStore::ProcessScopeRequest() " 1.2142 + "GUID_PROP_INPUTSCOPE queried", this)); 1.2143 + mInputScopeDetected = true; 1.2144 + if (dwFlags & TS_ATTR_FIND_WANT_VALUE) { 1.2145 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2146 + ("TSF: 0x%p nsTextStore::ProcessScopeRequest() " 1.2147 + "TS_ATTR_FIND_WANT_VALUE specified", this)); 1.2148 + mInputScopeRequested = true; 1.2149 + } 1.2150 + break; 1.2151 + } 1.2152 + } 1.2153 + return S_OK; 1.2154 +} 1.2155 + 1.2156 +STDMETHODIMP 1.2157 +nsTextStore::RequestSupportedAttrs(DWORD dwFlags, 1.2158 + ULONG cFilterAttrs, 1.2159 + const TS_ATTRID *paFilterAttrs) 1.2160 +{ 1.2161 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2162 + ("TSF: 0x%p nsTextStore::RequestSupportedAttrs(dwFlags=%s, " 1.2163 + "cFilterAttrs=%lu)", 1.2164 + this, GetFindFlagName(dwFlags).get(), cFilterAttrs)); 1.2165 + 1.2166 + return ProcessScopeRequest(dwFlags, cFilterAttrs, paFilterAttrs); 1.2167 +} 1.2168 + 1.2169 +STDMETHODIMP 1.2170 +nsTextStore::RequestAttrsAtPosition(LONG acpPos, 1.2171 + ULONG cFilterAttrs, 1.2172 + const TS_ATTRID *paFilterAttrs, 1.2173 + DWORD dwFlags) 1.2174 +{ 1.2175 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2176 + ("TSF: 0x%p nsTextStore::RequestAttrsAtPosition(acpPos=%ld, " 1.2177 + "cFilterAttrs=%lu, dwFlags=%s)", 1.2178 + this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get())); 1.2179 + 1.2180 + return ProcessScopeRequest(dwFlags | TS_ATTR_FIND_WANT_VALUE, 1.2181 + cFilterAttrs, paFilterAttrs); 1.2182 +} 1.2183 + 1.2184 +STDMETHODIMP 1.2185 +nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, 1.2186 + ULONG cFilterAttrs, 1.2187 + const TS_ATTRID *paFilterAttr, 1.2188 + DWORD dwFlags) 1.2189 +{ 1.2190 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2191 + ("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition(" 1.2192 + "acpPos=%ld, cFilterAttrs=%lu, dwFlags=%s) called but not supported " 1.2193 + "(S_OK)", 1.2194 + this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get())); 1.2195 + 1.2196 + // no per character attributes defined 1.2197 + return S_OK; 1.2198 +} 1.2199 + 1.2200 +STDMETHODIMP 1.2201 +nsTextStore::FindNextAttrTransition(LONG acpStart, 1.2202 + LONG acpHalt, 1.2203 + ULONG cFilterAttrs, 1.2204 + const TS_ATTRID *paFilterAttrs, 1.2205 + DWORD dwFlags, 1.2206 + LONG *pacpNext, 1.2207 + BOOL *pfFound, 1.2208 + LONG *plFoundOffset) 1.2209 +{ 1.2210 + if (!pacpNext || !pfFound || !plFoundOffset) { 1.2211 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2212 + ("TSF: 0x%p nsTextStore::FindNextAttrTransition() FAILED due to " 1.2213 + "null argument", this)); 1.2214 + return E_INVALIDARG; 1.2215 + } 1.2216 + 1.2217 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2218 + ("TSF: 0x%p nsTextStore::FindNextAttrTransition() called " 1.2219 + "but not supported (S_OK)", this)); 1.2220 + 1.2221 + // no per character attributes defined 1.2222 + *pacpNext = *plFoundOffset = acpHalt; 1.2223 + *pfFound = FALSE; 1.2224 + return S_OK; 1.2225 +} 1.2226 + 1.2227 +STDMETHODIMP 1.2228 +nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, 1.2229 + TS_ATTRVAL *paAttrVals, 1.2230 + ULONG *pcFetched) 1.2231 +{ 1.2232 + if (!pcFetched || !ulCount || !paAttrVals) { 1.2233 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2234 + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() FAILED due to " 1.2235 + "null argument", this)); 1.2236 + return E_INVALIDARG; 1.2237 + } 1.2238 + 1.2239 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2240 + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called " 1.2241 + "ulCount=%d", this, ulCount)); 1.2242 + 1.2243 + if (mInputScopeDetected || mInputScopeRequested) { 1.2244 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2245 + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() for " 1.2246 + "GUID_PROP_INPUTSCOPE: " 1.2247 + "mInputScopeDetected=%s mInputScopeRequested=%s", 1.2248 + this, GetBoolName(mInputScopeDetected), 1.2249 + GetBoolName(mInputScopeRequested))); 1.2250 + 1.2251 + paAttrVals->idAttr = GUID_PROP_INPUTSCOPE; 1.2252 + paAttrVals->dwOverlapId = 0; 1.2253 + paAttrVals->varValue.vt = VT_EMPTY; 1.2254 + *pcFetched = 1; 1.2255 + 1.2256 + if (mInputScopeRequested) { 1.2257 + paAttrVals->varValue.vt = VT_UNKNOWN; 1.2258 + paAttrVals->varValue.punkVal = (IUnknown*) new InputScopeImpl(mInputScopes); 1.2259 + } 1.2260 + 1.2261 + mInputScopeDetected = mInputScopeRequested = false; 1.2262 + return S_OK; 1.2263 + } 1.2264 + 1.2265 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2266 + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called " 1.2267 + "for unknown TS_ATTRVAL, *pcFetched=0 (S_OK)", this)); 1.2268 + 1.2269 + paAttrVals->dwOverlapId = 0; 1.2270 + paAttrVals->varValue.vt = VT_EMPTY; 1.2271 + *pcFetched = 0; 1.2272 + return S_OK; 1.2273 +} 1.2274 + 1.2275 +STDMETHODIMP 1.2276 +nsTextStore::GetEndACP(LONG *pacp) 1.2277 +{ 1.2278 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2279 + ("TSF: 0x%p nsTextStore::GetEndACP(pacp=0x%p)", this, pacp)); 1.2280 + 1.2281 + if (!IsReadLocked()) { 1.2282 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2283 + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " 1.2284 + "not locked (read)", this)); 1.2285 + return TS_E_NOLOCK; 1.2286 + } 1.2287 + 1.2288 + if (!pacp) { 1.2289 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2290 + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " 1.2291 + "null argument", this)); 1.2292 + return E_INVALIDARG; 1.2293 + } 1.2294 + 1.2295 + Content& currentContent = CurrentContent(); 1.2296 + if (!currentContent.IsInitialized()) { 1.2297 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2298 + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " 1.2299 + "CurrentContent() failure", this)); 1.2300 + return E_FAIL; 1.2301 + } 1.2302 + *pacp = static_cast<LONG>(currentContent.Text().Length()); 1.2303 + return S_OK; 1.2304 +} 1.2305 + 1.2306 +STDMETHODIMP 1.2307 +nsTextStore::GetActiveView(TsViewCookie *pvcView) 1.2308 +{ 1.2309 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2310 + ("TSF: 0x%p nsTextStore::GetActiveView(pvcView=0x%p)", this, pvcView)); 1.2311 + 1.2312 + if (!pvcView) { 1.2313 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2314 + ("TSF: 0x%p nsTextStore::GetActiveView() FAILED due to " 1.2315 + "null argument", this)); 1.2316 + return E_INVALIDARG; 1.2317 + } 1.2318 + 1.2319 + *pvcView = TEXTSTORE_DEFAULT_VIEW; 1.2320 + 1.2321 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2322 + ("TSF: 0x%p nsTextStore::GetActiveView() succeeded: *pvcView=%ld", 1.2323 + this, *pvcView)); 1.2324 + return S_OK; 1.2325 +} 1.2326 + 1.2327 +STDMETHODIMP 1.2328 +nsTextStore::GetACPFromPoint(TsViewCookie vcView, 1.2329 + const POINT *pt, 1.2330 + DWORD dwFlags, 1.2331 + LONG *pacp) 1.2332 +{ 1.2333 + if (!IsReadLocked()) { 1.2334 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2335 + ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " 1.2336 + "not locked (read)", this)); 1.2337 + return TS_E_NOLOCK; 1.2338 + } 1.2339 + 1.2340 + if (vcView != TEXTSTORE_DEFAULT_VIEW) { 1.2341 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2342 + ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " 1.2343 + "called with invalid view", this)); 1.2344 + return E_INVALIDARG; 1.2345 + } 1.2346 + 1.2347 + if (mContent.IsLayoutChanged()) { 1.2348 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2349 + ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " 1.2350 + "layout not recomputed", this)); 1.2351 + mPendingOnLayoutChange = true; 1.2352 + return TS_E_NOLAYOUT; 1.2353 + } 1.2354 + 1.2355 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2356 + ("TSF: 0x%p nsTextStore::GetACPFromPoint(vcView=%ld, " 1.2357 + "pt(0x%p)={ x=%ld, y=%ld }, dwFlags=%s, pacp=0x%p) called " 1.2358 + "but not supported (E_NOTIMPL)", this)); 1.2359 + 1.2360 + // not supported for now 1.2361 + return E_NOTIMPL; 1.2362 +} 1.2363 + 1.2364 +STDMETHODIMP 1.2365 +nsTextStore::GetTextExt(TsViewCookie vcView, 1.2366 + LONG acpStart, 1.2367 + LONG acpEnd, 1.2368 + RECT *prc, 1.2369 + BOOL *pfClipped) 1.2370 +{ 1.2371 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2372 + ("TSF: 0x%p nsTextStore::GetTextExt(vcView=%ld, " 1.2373 + "acpStart=%ld, acpEnd=%ld, prc=0x%p, pfClipped=0x%p)", 1.2374 + this, vcView, acpStart, acpEnd, prc, pfClipped)); 1.2375 + 1.2376 + if (!IsReadLocked()) { 1.2377 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2378 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2379 + "not locked (read)", this)); 1.2380 + return TS_E_NOLOCK; 1.2381 + } 1.2382 + 1.2383 + if (vcView != TEXTSTORE_DEFAULT_VIEW) { 1.2384 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2385 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2386 + "called with invalid view", this)); 1.2387 + return E_INVALIDARG; 1.2388 + } 1.2389 + 1.2390 + if (!prc || !pfClipped) { 1.2391 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2392 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2393 + "null argument", this)); 1.2394 + return E_INVALIDARG; 1.2395 + } 1.2396 + 1.2397 + if (acpStart < 0 || acpEnd < acpStart) { 1.2398 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2399 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2400 + "invalid position", this)); 1.2401 + return TS_E_INVALIDPOS; 1.2402 + } 1.2403 + 1.2404 + if (mContent.IsLayoutChangedAfter(acpEnd)) { 1.2405 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2406 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2407 + "layout not recomputed at %d", this, acpEnd)); 1.2408 + mPendingOnLayoutChange = true; 1.2409 + return TS_E_NOLAYOUT; 1.2410 + } 1.2411 + 1.2412 + // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates 1.2413 + WidgetQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWidget); 1.2414 + mWidget->InitEvent(event); 1.2415 + event.InitForQueryTextRect(acpStart, acpEnd - acpStart); 1.2416 + mWidget->DispatchWindowEvent(&event); 1.2417 + if (!event.mSucceeded) { 1.2418 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2419 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2420 + "NS_QUERY_TEXT_RECT failure", this)); 1.2421 + return TS_E_INVALIDPOS; // but unexpected failure, maybe. 1.2422 + } 1.2423 + // IMEs don't like empty rects, fix here 1.2424 + if (event.mReply.mRect.width <= 0) 1.2425 + event.mReply.mRect.width = 1; 1.2426 + if (event.mReply.mRect.height <= 0) 1.2427 + event.mReply.mRect.height = 1; 1.2428 + 1.2429 + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) { 1.2430 + // convert to unclipped screen rect 1.2431 + nsWindow* refWindow = static_cast<nsWindow*>( 1.2432 + event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWidget); 1.2433 + // Result rect is in top level widget coordinates 1.2434 + refWindow = refWindow->GetTopLevelWindow(false); 1.2435 + if (!refWindow) { 1.2436 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2437 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2438 + "no top level window", this)); 1.2439 + return E_FAIL; 1.2440 + } 1.2441 + 1.2442 + event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset()); 1.2443 + } 1.2444 + 1.2445 + // get bounding screen rect to test for clipping 1.2446 + if (!GetScreenExtInternal(*prc)) { 1.2447 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2448 + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " 1.2449 + "GetScreenExtInternal() failure", this)); 1.2450 + return E_FAIL; 1.2451 + } 1.2452 + 1.2453 + // clip text rect to bounding rect 1.2454 + RECT textRect; 1.2455 + ::SetRect(&textRect, event.mReply.mRect.x, event.mReply.mRect.y, 1.2456 + event.mReply.mRect.XMost(), event.mReply.mRect.YMost()); 1.2457 + if (!::IntersectRect(prc, prc, &textRect)) 1.2458 + // Text is not visible 1.2459 + ::SetRectEmpty(prc); 1.2460 + 1.2461 + // not equal if text rect was clipped 1.2462 + *pfClipped = !::EqualRect(prc, &textRect); 1.2463 + 1.2464 + // ATOK refers native caret position and size on Desktop applications for 1.2465 + // deciding candidate window. Therefore, we need to create native caret 1.2466 + // for hacking the bug. 1.2467 + if (sCreateNativeCaretForATOK && 1.2468 + StringBeginsWith( 1.2469 + mActiveTIPKeyboardDescription, NS_LITERAL_STRING("ATOK ")) && 1.2470 + mComposition.IsComposing() && 1.2471 + mComposition.mStart <= acpStart && mComposition.EndOffset() >= acpStart && 1.2472 + mComposition.mStart <= acpEnd && mComposition.EndOffset() >= acpEnd) { 1.2473 + if (mNativeCaretIsCreated) { 1.2474 + ::DestroyCaret(); 1.2475 + mNativeCaretIsCreated = false; 1.2476 + } 1.2477 + CreateNativeCaret(); 1.2478 + } 1.2479 + 1.2480 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2481 + ("TSF: 0x%p nsTextStore::GetTextExt() succeeded: " 1.2482 + "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }, *pfClipped=%s", 1.2483 + this, prc->left, prc->top, prc->right, prc->bottom, 1.2484 + GetBoolName(*pfClipped))); 1.2485 + 1.2486 + return S_OK; 1.2487 +} 1.2488 + 1.2489 +STDMETHODIMP 1.2490 +nsTextStore::GetScreenExt(TsViewCookie vcView, 1.2491 + RECT *prc) 1.2492 +{ 1.2493 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2494 + ("TSF: 0x%p nsTextStore::GetScreenExt(vcView=%ld, prc=0x%p)", 1.2495 + this, vcView, prc)); 1.2496 + 1.2497 + if (vcView != TEXTSTORE_DEFAULT_VIEW) { 1.2498 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2499 + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " 1.2500 + "called with invalid view", this)); 1.2501 + return E_INVALIDARG; 1.2502 + } 1.2503 + 1.2504 + if (!prc) { 1.2505 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2506 + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " 1.2507 + "null argument", this)); 1.2508 + return E_INVALIDARG; 1.2509 + } 1.2510 + 1.2511 + if (!GetScreenExtInternal(*prc)) { 1.2512 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2513 + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " 1.2514 + "GetScreenExtInternal() failure", this)); 1.2515 + return E_FAIL; 1.2516 + } 1.2517 + 1.2518 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2519 + ("TSF: 0x%p nsTextStore::GetScreenExt() succeeded: " 1.2520 + "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }", 1.2521 + this, prc->left, prc->top, prc->right, prc->bottom)); 1.2522 + return S_OK; 1.2523 +} 1.2524 + 1.2525 +bool 1.2526 +nsTextStore::GetScreenExtInternal(RECT &aScreenExt) 1.2527 +{ 1.2528 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2529 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal()", this)); 1.2530 + 1.2531 + // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates 1.2532 + WidgetQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWidget); 1.2533 + mWidget->InitEvent(event); 1.2534 + mWidget->DispatchWindowEvent(&event); 1.2535 + if (!event.mSucceeded) { 1.2536 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2537 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " 1.2538 + "NS_QUERY_EDITOR_RECT failure", this)); 1.2539 + return false; 1.2540 + } 1.2541 + 1.2542 + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { 1.2543 + nsIntRect boundRect; 1.2544 + if (NS_FAILED(mWidget->GetClientBounds(boundRect))) { 1.2545 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2546 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " 1.2547 + "failed to get the client bounds", this)); 1.2548 + return false; 1.2549 + } 1.2550 + ::SetRect(&aScreenExt, boundRect.x, boundRect.y, 1.2551 + boundRect.XMost(), boundRect.YMost()); 1.2552 + } else { 1.2553 + NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop, 1.2554 + "environment isn't WindowsEnvironmentType_Desktop!"); 1.2555 + nsWindow* refWindow = static_cast<nsWindow*>( 1.2556 + event.mReply.mFocusedWidget ? 1.2557 + event.mReply.mFocusedWidget : mWidget); 1.2558 + // Result rect is in top level widget coordinates 1.2559 + refWindow = refWindow->GetTopLevelWindow(false); 1.2560 + if (!refWindow) { 1.2561 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2562 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " 1.2563 + "no top level window", this)); 1.2564 + return false; 1.2565 + } 1.2566 + 1.2567 + nsIntRect boundRect; 1.2568 + if (NS_FAILED(refWindow->GetClientBounds(boundRect))) { 1.2569 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2570 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " 1.2571 + "failed to get the client bounds", this)); 1.2572 + return false; 1.2573 + } 1.2574 + 1.2575 + boundRect.MoveTo(0, 0); 1.2576 + 1.2577 + // Clip frame rect to window rect 1.2578 + boundRect.IntersectRect(event.mReply.mRect, boundRect); 1.2579 + if (!boundRect.IsEmpty()) { 1.2580 + boundRect.MoveBy(refWindow->WidgetToScreenOffset()); 1.2581 + ::SetRect(&aScreenExt, boundRect.x, boundRect.y, 1.2582 + boundRect.XMost(), boundRect.YMost()); 1.2583 + } else { 1.2584 + ::SetRectEmpty(&aScreenExt); 1.2585 + } 1.2586 + } 1.2587 + 1.2588 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2589 + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() succeeded: " 1.2590 + "aScreenExt={ left=%ld, top=%ld, right=%ld, bottom=%ld }", 1.2591 + this, aScreenExt.left, aScreenExt.top, 1.2592 + aScreenExt.right, aScreenExt.bottom)); 1.2593 + return true; 1.2594 +} 1.2595 + 1.2596 +STDMETHODIMP 1.2597 +nsTextStore::GetWnd(TsViewCookie vcView, 1.2598 + HWND *phwnd) 1.2599 +{ 1.2600 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2601 + ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), " 1.2602 + "mWidget=0x%p", 1.2603 + this, vcView, phwnd, mWidget.get())); 1.2604 + 1.2605 + if (vcView != TEXTSTORE_DEFAULT_VIEW) { 1.2606 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2607 + ("TSF: 0x%p nsTextStore::GetWnd() FAILED due to " 1.2608 + "called with invalid view", this)); 1.2609 + return E_INVALIDARG; 1.2610 + } 1.2611 + 1.2612 + if (!phwnd) { 1.2613 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2614 + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " 1.2615 + "null argument", this)); 1.2616 + return E_INVALIDARG; 1.2617 + } 1.2618 + 1.2619 + *phwnd = mWidget->GetWindowHandle(); 1.2620 + 1.2621 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2622 + ("TSF: 0x%p nsTextStore::GetWnd() succeeded: *phwnd=0x%p", 1.2623 + this, static_cast<void*>(*phwnd))); 1.2624 + return S_OK; 1.2625 +} 1.2626 + 1.2627 +STDMETHODIMP 1.2628 +nsTextStore::InsertTextAtSelection(DWORD dwFlags, 1.2629 + const WCHAR *pchText, 1.2630 + ULONG cch, 1.2631 + LONG *pacpStart, 1.2632 + LONG *pacpEnd, 1.2633 + TS_TEXTCHANGE *pChange) 1.2634 +{ 1.2635 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2636 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection(dwFlags=%s, " 1.2637 + "pchText=0x%p \"%s\", cch=%lu, pacpStart=0x%p, pacpEnd=0x%p, " 1.2638 + "pChange=0x%p), IsComposing()=%s", 1.2639 + this, dwFlags == 0 ? "0" : 1.2640 + dwFlags == TF_IAS_NOQUERY ? "TF_IAS_NOQUERY" : 1.2641 + dwFlags == TF_IAS_QUERYONLY ? "TF_IAS_QUERYONLY" : "Unknown", 1.2642 + pchText, 1.2643 + pchText && cch ? NS_ConvertUTF16toUTF8(pchText, cch).get() : "", 1.2644 + cch, pacpStart, pacpEnd, pChange, 1.2645 + GetBoolName(mComposition.IsComposing()))); 1.2646 + 1.2647 + if (cch && !pchText) { 1.2648 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2649 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2650 + "null pchText", this)); 1.2651 + return E_INVALIDARG; 1.2652 + } 1.2653 + 1.2654 + if (TS_IAS_QUERYONLY == dwFlags) { 1.2655 + if (!IsReadLocked()) { 1.2656 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2657 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2658 + "not locked (read)", this)); 1.2659 + return TS_E_NOLOCK; 1.2660 + } 1.2661 + 1.2662 + if (!pacpStart || !pacpEnd) { 1.2663 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2664 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2665 + "null argument", this)); 1.2666 + return E_INVALIDARG; 1.2667 + } 1.2668 + 1.2669 + // Get selection first 1.2670 + Selection& currentSel = CurrentSelection(); 1.2671 + if (currentSel.IsDirty()) { 1.2672 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2673 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2674 + "CurrentSelection() failure", this)); 1.2675 + return E_FAIL; 1.2676 + } 1.2677 + 1.2678 + // Simulate text insertion 1.2679 + *pacpStart = currentSel.StartOffset(); 1.2680 + *pacpEnd = currentSel.EndOffset(); 1.2681 + if (pChange) { 1.2682 + pChange->acpStart = currentSel.StartOffset(); 1.2683 + pChange->acpOldEnd = currentSel.EndOffset(); 1.2684 + pChange->acpNewEnd = currentSel.StartOffset() + static_cast<LONG>(cch); 1.2685 + } 1.2686 + } else { 1.2687 + if (!IsReadWriteLocked()) { 1.2688 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2689 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2690 + "not locked (read-write)", this)); 1.2691 + return TS_E_NOLOCK; 1.2692 + } 1.2693 + 1.2694 + if (!pChange) { 1.2695 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2696 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2697 + "null pChange", this)); 1.2698 + return E_INVALIDARG; 1.2699 + } 1.2700 + 1.2701 + if (TS_IAS_NOQUERY != dwFlags && (!pacpStart || !pacpEnd)) { 1.2702 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2703 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2704 + "null argument", this)); 1.2705 + return E_INVALIDARG; 1.2706 + } 1.2707 + 1.2708 + if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), 1.2709 + pChange)) { 1.2710 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2711 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " 1.2712 + "InsertTextAtSelectionInternal() failure", this)); 1.2713 + return E_FAIL; 1.2714 + } 1.2715 + 1.2716 + if (TS_IAS_NOQUERY != dwFlags) { 1.2717 + *pacpStart = pChange->acpStart; 1.2718 + *pacpEnd = pChange->acpNewEnd; 1.2719 + } 1.2720 + } 1.2721 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2722 + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() succeeded: " 1.2723 + "*pacpStart=%ld, *pacpEnd=%ld, " 1.2724 + "*pChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld })", 1.2725 + this, pacpStart ? *pacpStart : 0, pacpEnd ? *pacpEnd : 0, 1.2726 + pChange ? pChange->acpStart: 0, pChange ? pChange->acpOldEnd : 0, 1.2727 + pChange ? pChange->acpNewEnd : 0)); 1.2728 + return S_OK; 1.2729 +} 1.2730 + 1.2731 +bool 1.2732 +nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, 1.2733 + TS_TEXTCHANGE* aTextChange) 1.2734 +{ 1.2735 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2736 + ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal(" 1.2737 + "aInsertStr=\"%s\", aTextChange=0x%p), IsComposing=%s", 1.2738 + this, NS_ConvertUTF16toUTF8(aInsertStr).get(), aTextChange, 1.2739 + GetBoolName(mComposition.IsComposing()))); 1.2740 + 1.2741 + Content& currentContent = CurrentContent(); 1.2742 + if (!currentContent.IsInitialized()) { 1.2743 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2744 + ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() failed " 1.2745 + "due to CurrentContent() failure()", this)); 1.2746 + return false; 1.2747 + } 1.2748 + 1.2749 + TS_SELECTION_ACP oldSelection = currentContent.Selection().ACP(); 1.2750 + if (!mComposition.IsComposing()) { 1.2751 + // Use a temporary composition to contain the text 1.2752 + PendingAction* compositionStart = mPendingActions.AppendElement(); 1.2753 + compositionStart->mType = PendingAction::COMPOSITION_START; 1.2754 + compositionStart->mSelectionStart = oldSelection.acpStart; 1.2755 + compositionStart->mSelectionLength = 1.2756 + oldSelection.acpEnd - oldSelection.acpStart; 1.2757 + 1.2758 + PendingAction* compositionEnd = mPendingActions.AppendElement(); 1.2759 + compositionEnd->mType = PendingAction::COMPOSITION_END; 1.2760 + compositionEnd->mData = aInsertStr; 1.2761 + } 1.2762 + 1.2763 + currentContent.ReplaceSelectedTextWith(aInsertStr); 1.2764 + 1.2765 + if (aTextChange) { 1.2766 + aTextChange->acpStart = oldSelection.acpStart; 1.2767 + aTextChange->acpOldEnd = oldSelection.acpEnd; 1.2768 + aTextChange->acpNewEnd = currentContent.Selection().EndOffset(); 1.2769 + } 1.2770 + 1.2771 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2772 + ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: " 1.2773 + "mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ acpStart=%ld, " 1.2774 + "acpOldEnd=%ld, acpNewEnd=%ld }", 1.2775 + this, mWidget.get(), 1.2776 + GetBoolName(mWidget ? mWidget->Destroyed() : true), 1.2777 + aTextChange ? aTextChange->acpStart : 0, 1.2778 + aTextChange ? aTextChange->acpOldEnd : 0, 1.2779 + aTextChange ? aTextChange->acpNewEnd : 0)); 1.2780 + return true; 1.2781 +} 1.2782 + 1.2783 +STDMETHODIMP 1.2784 +nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, 1.2785 + IDataObject *pDataObject, 1.2786 + LONG *pacpStart, 1.2787 + LONG *pacpEnd, 1.2788 + TS_TEXTCHANGE *pChange) 1.2789 +{ 1.2790 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2791 + ("TSF: 0x%p nsTextStore::InsertEmbeddedAtSelection() called " 1.2792 + "but not supported (E_NOTIMPL)", this)); 1.2793 + 1.2794 + // embedded objects are not supported 1.2795 + return E_NOTIMPL; 1.2796 +} 1.2797 + 1.2798 +HRESULT 1.2799 +nsTextStore::RecordCompositionStartAction(ITfCompositionView* pComposition, 1.2800 + ITfRange* aRange, 1.2801 + bool aPreserveSelection) 1.2802 +{ 1.2803 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2804 + ("TSF: 0x%p nsTextStore::RecordCompositionStartAction(" 1.2805 + "pComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), " 1.2806 + "mComposition.mView=0x%p", 1.2807 + this, pComposition, aRange, GetBoolName(aPreserveSelection), 1.2808 + mComposition.mView.get())); 1.2809 + 1.2810 + LONG start = 0, length = 0; 1.2811 + HRESULT hr = GetRangeExtent(aRange, &start, &length); 1.2812 + if (FAILED(hr)) { 1.2813 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2814 + ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() FAILED " 1.2815 + "due to GetRangeExtent() failure", this)); 1.2816 + return hr; 1.2817 + } 1.2818 + 1.2819 + Content& currentContent = CurrentContent(); 1.2820 + if (!currentContent.IsInitialized()) { 1.2821 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2822 + ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() FAILED " 1.2823 + "due to CurrentContent() failure", this)); 1.2824 + return E_FAIL; 1.2825 + } 1.2826 + 1.2827 + PendingAction* action = mPendingActions.AppendElement(); 1.2828 + action->mType = PendingAction::COMPOSITION_START; 1.2829 + action->mSelectionStart = start; 1.2830 + action->mSelectionLength = length; 1.2831 + 1.2832 + currentContent.StartComposition(pComposition, *action, aPreserveSelection); 1.2833 + 1.2834 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2835 + ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() succeeded: " 1.2836 + "mComposition={ mStart=%ld, mString.Length()=%ld, " 1.2837 + "mSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " 1.2838 + "style.fInterimChar=%s } }", 1.2839 + this, mComposition.mStart, mComposition.mString.Length(), 1.2840 + mSelection.StartOffset(), mSelection.EndOffset(), 1.2841 + GetActiveSelEndName(mSelection.ActiveSelEnd()), 1.2842 + GetBoolName(mSelection.IsInterimChar()))); 1.2843 + return S_OK; 1.2844 +} 1.2845 + 1.2846 +HRESULT 1.2847 +nsTextStore::RecordCompositionEndAction() 1.2848 +{ 1.2849 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.2850 + ("TSF: 0x%p nsTextStore::RecordCompositionEndAction(), " 1.2851 + "mComposition={ mView=0x%p, mString=\"%s\" }", 1.2852 + this, mComposition.mView.get(), 1.2853 + NS_ConvertUTF16toUTF8(mComposition.mString).get())); 1.2854 + 1.2855 + MOZ_ASSERT(mComposition.IsComposing()); 1.2856 + 1.2857 + PendingAction* action = mPendingActions.AppendElement(); 1.2858 + action->mType = PendingAction::COMPOSITION_END; 1.2859 + action->mData = mComposition.mString; 1.2860 + 1.2861 + Content& currentContent = CurrentContent(); 1.2862 + if (!currentContent.IsInitialized()) { 1.2863 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2864 + ("TSF: 0x%p nsTextStore::RecordCompositionEndAction() FAILED due " 1.2865 + "to CurrentContent() failure", this)); 1.2866 + return E_FAIL; 1.2867 + } 1.2868 + currentContent.EndComposition(*action); 1.2869 + 1.2870 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2871 + ("TSF: 0x%p nsTextStore::RecordCompositionEndAction(), succeeded", 1.2872 + this)); 1.2873 + return S_OK; 1.2874 +} 1.2875 + 1.2876 +STDMETHODIMP 1.2877 +nsTextStore::OnStartComposition(ITfCompositionView* pComposition, 1.2878 + BOOL* pfOk) 1.2879 +{ 1.2880 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2881 + ("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, " 1.2882 + "pfOk=0x%p), mComposition.mView=0x%p", 1.2883 + this, pComposition, pfOk, mComposition.mView.get())); 1.2884 + 1.2885 + AutoPendingActionAndContentFlusher flusher(this); 1.2886 + 1.2887 + *pfOk = FALSE; 1.2888 + 1.2889 + // Only one composition at a time 1.2890 + if (mComposition.IsComposing()) { 1.2891 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2892 + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " 1.2893 + "there is another composition already (but returns S_OK)", this)); 1.2894 + return S_OK; 1.2895 + } 1.2896 + 1.2897 + nsRefPtr<ITfRange> range; 1.2898 + HRESULT hr = pComposition->GetRange(getter_AddRefs(range)); 1.2899 + if (FAILED(hr)) { 1.2900 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2901 + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " 1.2902 + "pComposition->GetRange() failure", this)); 1.2903 + return hr; 1.2904 + } 1.2905 + hr = RecordCompositionStartAction(pComposition, range, false); 1.2906 + if (FAILED(hr)) { 1.2907 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2908 + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " 1.2909 + "RecordCompositionStartAction() failure", this)); 1.2910 + return hr; 1.2911 + } 1.2912 + 1.2913 + *pfOk = TRUE; 1.2914 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2915 + ("TSF: 0x%p nsTextStore::OnStartComposition() succeeded", this)); 1.2916 + return S_OK; 1.2917 +} 1.2918 + 1.2919 +STDMETHODIMP 1.2920 +nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, 1.2921 + ITfRange* pRangeNew) 1.2922 +{ 1.2923 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2924 + ("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, " 1.2925 + "pRangeNew=0x%p), mComposition.mView=0x%p", 1.2926 + this, pComposition, pRangeNew, mComposition.mView.get())); 1.2927 + 1.2928 + AutoPendingActionAndContentFlusher flusher(this); 1.2929 + 1.2930 + if (!mDocumentMgr || !mContext) { 1.2931 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2932 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2933 + "not ready for the composition", this)); 1.2934 + return E_UNEXPECTED; 1.2935 + } 1.2936 + if (!mComposition.IsComposing()) { 1.2937 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2938 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2939 + "no active composition", this)); 1.2940 + return E_UNEXPECTED; 1.2941 + } 1.2942 + if (mComposition.mView != pComposition) { 1.2943 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2944 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2945 + "different composition view specified", this)); 1.2946 + return E_UNEXPECTED; 1.2947 + } 1.2948 + 1.2949 + // pRangeNew is null when the update is not complete 1.2950 + if (!pRangeNew) { 1.2951 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2952 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded but " 1.2953 + "not complete", this)); 1.2954 + return S_OK; 1.2955 + } 1.2956 + 1.2957 + HRESULT hr = RestartCompositionIfNecessary(pRangeNew); 1.2958 + if (FAILED(hr)) { 1.2959 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2960 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2961 + "RestartCompositionIfNecessary() failure", this)); 1.2962 + return hr; 1.2963 + } 1.2964 + 1.2965 + hr = RecordCompositionUpdateAction(); 1.2966 + if (FAILED(hr)) { 1.2967 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2968 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2969 + "RecordCompositionUpdateAction() failure", this)); 1.2970 + return hr; 1.2971 + } 1.2972 + 1.2973 +#ifdef PR_LOGGING 1.2974 + if (PR_LOG_TEST(sTextStoreLog, PR_LOG_ALWAYS)) { 1.2975 + Selection& currentSel = CurrentSelection(); 1.2976 + if (currentSel.IsDirty()) { 1.2977 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.2978 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " 1.2979 + "CurrentSelection() failure", this)); 1.2980 + return E_FAIL; 1.2981 + } 1.2982 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2983 + ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded: " 1.2984 + "mComposition={ mStart=%ld, mString=\"%s\" }, " 1.2985 + "CurrentSelection()={ acpStart=%ld, acpEnd=%ld, style.ase=%s }", 1.2986 + this, mComposition.mStart, 1.2987 + NS_ConvertUTF16toUTF8(mComposition.mString).get(), 1.2988 + currentSel.StartOffset(), currentSel.EndOffset(), 1.2989 + GetActiveSelEndName(currentSel.ActiveSelEnd()))); 1.2990 + } 1.2991 +#endif // #ifdef PR_LOGGING 1.2992 + return S_OK; 1.2993 +} 1.2994 + 1.2995 +STDMETHODIMP 1.2996 +nsTextStore::OnEndComposition(ITfCompositionView* pComposition) 1.2997 +{ 1.2998 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.2999 + ("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), " 1.3000 + "mComposition={ mView=0x%p, mString=\"%s\" }", 1.3001 + this, pComposition, mComposition.mView.get(), 1.3002 + NS_ConvertUTF16toUTF8(mComposition.mString).get())); 1.3003 + 1.3004 + AutoPendingActionAndContentFlusher flusher(this); 1.3005 + 1.3006 + if (!mComposition.IsComposing()) { 1.3007 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3008 + ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " 1.3009 + "no active composition", this)); 1.3010 + return E_UNEXPECTED; 1.3011 + } 1.3012 + 1.3013 + if (mComposition.mView != pComposition) { 1.3014 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3015 + ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " 1.3016 + "different composition view specified", this)); 1.3017 + return E_UNEXPECTED; 1.3018 + } 1.3019 + 1.3020 + HRESULT hr = RecordCompositionEndAction(); 1.3021 + if (FAILED(hr)) { 1.3022 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3023 + ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " 1.3024 + "RecordCompositionEndAction() failure", this)); 1.3025 + return hr; 1.3026 + } 1.3027 + 1.3028 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3029 + ("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this)); 1.3030 + return S_OK; 1.3031 +} 1.3032 + 1.3033 +STDMETHODIMP 1.3034 +nsTextStore::OnActivated(REFCLSID clsid, REFGUID guidProfile, 1.3035 + BOOL fActivated) 1.3036 +{ 1.3037 + // NOTE: This is installed only on XP or Server 2003. 1.3038 + if (fActivated) { 1.3039 + // TODO: We should check if the profile's category is keyboard or not. 1.3040 + mOnActivatedCalled = true; 1.3041 + mIsIMM_IME = IsIMM_IME(::GetKeyboardLayout(0)); 1.3042 + 1.3043 + LANGID langID; 1.3044 + HRESULT hr = sInputProcessorProfiles->GetCurrentLanguage(&langID); 1.3045 + if (FAILED(hr)) { 1.3046 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3047 + ("TSF: nsTextStore::OnActivated() FAILED due to " 1.3048 + "GetCurrentLanguage() failure, hr=0x%08X", hr)); 1.3049 + } else if (IsTIPCategoryKeyboard(clsid, langID, guidProfile)) { 1.3050 + GetTIPDescription(clsid, langID, guidProfile, 1.3051 + mActiveTIPKeyboardDescription); 1.3052 + } else if (clsid == CLSID_NULL || guidProfile == GUID_NULL) { 1.3053 + // Perhaps, this case is that keyboard layout without TIP is activated. 1.3054 + mActiveTIPKeyboardDescription.Truncate(); 1.3055 + } 1.3056 + } 1.3057 + 1.3058 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3059 + ("TSF: 0x%p nsTextStore::OnActivated(rclsid=%s, guidProfile=%s, " 1.3060 + "fActivated=%s), mIsIMM_IME=%s, mActiveTIPDescription=\"%s\"", 1.3061 + this, GetCLSIDNameStr(clsid).get(), 1.3062 + GetGUIDNameStr(guidProfile).get(), GetBoolName(fActivated), 1.3063 + GetBoolName(mIsIMM_IME), 1.3064 + NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); 1.3065 + return S_OK; 1.3066 +} 1.3067 + 1.3068 +STDMETHODIMP 1.3069 +nsTextStore::OnActivated(DWORD dwProfileType, 1.3070 + LANGID langid, 1.3071 + REFCLSID rclsid, 1.3072 + REFGUID catid, 1.3073 + REFGUID guidProfile, 1.3074 + HKL hkl, 1.3075 + DWORD dwFlags) 1.3076 +{ 1.3077 + // NOTE: This is installed only on Vista or later. However, this may be 1.3078 + // called by EnsureInitActiveLanguageProfile() even on XP or Server 1.3079 + // 2003. 1.3080 + if ((dwFlags & TF_IPSINK_FLAG_ACTIVE) && 1.3081 + (dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT || 1.3082 + catid == GUID_TFCAT_TIP_KEYBOARD)) { 1.3083 + mOnActivatedCalled = true; 1.3084 + mIsIMM_IME = IsIMM_IME(hkl); 1.3085 + GetTIPDescription(rclsid, langid, guidProfile, 1.3086 + mActiveTIPKeyboardDescription); 1.3087 + } 1.3088 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3089 + ("TSF: 0x%p nsTextStore::OnActivated(dwProfileType=%s (0x%08X), " 1.3090 + "langid=0x%08X, rclsid=%s, catid=%s, guidProfile=%s, hkl=0x%08X, " 1.3091 + "dwFlags=0x%08X (TF_IPSINK_FLAG_ACTIVE: %s)), mIsIMM_IME=%s, " 1.3092 + "mActiveTIPDescription=\"%s\"", 1.3093 + this, dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR ? 1.3094 + "TF_PROFILETYPE_INPUTPROCESSOR" : 1.3095 + dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ? 1.3096 + "TF_PROFILETYPE_KEYBOARDLAYOUT" : "Unknown", dwProfileType, 1.3097 + langid, GetCLSIDNameStr(rclsid).get(), GetGUIDNameStr(catid).get(), 1.3098 + GetGUIDNameStr(guidProfile).get(), hkl, dwFlags, 1.3099 + GetBoolName(dwFlags & TF_IPSINK_FLAG_ACTIVE), 1.3100 + GetBoolName(mIsIMM_IME), 1.3101 + NS_ConvertUTF16toUTF8(mActiveTIPKeyboardDescription).get())); 1.3102 + return S_OK; 1.3103 +} 1.3104 + 1.3105 +// static 1.3106 +nsresult 1.3107 +nsTextStore::OnFocusChange(bool aGotFocus, 1.3108 + nsWindowBase* aFocusedWidget, 1.3109 + IMEState::Enabled aIMEEnabled) 1.3110 +{ 1.3111 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3112 + ("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, " 1.3113 + "aFocusedWidget=0x%p, aIMEEnabled=%s), sTsfThreadMgr=0x%p, " 1.3114 + "sTsfTextStore=0x%p", 1.3115 + GetBoolName(aGotFocus), aFocusedWidget, 1.3116 + GetIMEEnabledName(aIMEEnabled), sTsfThreadMgr, sTsfTextStore)); 1.3117 + 1.3118 + // no change notifications if TSF is disabled 1.3119 + NS_ENSURE_TRUE(sTsfThreadMgr && sTsfTextStore, NS_ERROR_NOT_AVAILABLE); 1.3120 + 1.3121 + nsRefPtr<ITfDocumentMgr> prevFocusedDocumentMgr; 1.3122 + if (aGotFocus && (aIMEEnabled == IMEState::ENABLED || 1.3123 + aIMEEnabled == IMEState::PASSWORD)) { 1.3124 + bool bRet = sTsfTextStore->Create(aFocusedWidget); 1.3125 + NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE); 1.3126 + NS_ENSURE_TRUE(sTsfTextStore->mDocumentMgr, NS_ERROR_FAILURE); 1.3127 + if (aIMEEnabled == IMEState::PASSWORD) { 1.3128 + MarkContextAsKeyboardDisabled(sTsfTextStore->mContext); 1.3129 + nsRefPtr<ITfContext> topContext; 1.3130 + sTsfTextStore->mDocumentMgr->GetTop(getter_AddRefs(topContext)); 1.3131 + if (topContext && topContext != sTsfTextStore->mContext) { 1.3132 + MarkContextAsKeyboardDisabled(topContext); 1.3133 + } 1.3134 + } 1.3135 + HRESULT hr = sTsfThreadMgr->SetFocus(sTsfTextStore->mDocumentMgr); 1.3136 + NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); 1.3137 + // Use AssociateFocus() for ensuring that any native focus event 1.3138 + // never steal focus from our documentMgr. 1.3139 + hr = sTsfThreadMgr->AssociateFocus(aFocusedWidget->GetWindowHandle(), 1.3140 + sTsfTextStore->mDocumentMgr, 1.3141 + getter_AddRefs(prevFocusedDocumentMgr)); 1.3142 + NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); 1.3143 + } else { 1.3144 + if (ThinksHavingFocus()) { 1.3145 + DebugOnly<HRESULT> hr = sTsfThreadMgr->AssociateFocus( 1.3146 + sTsfTextStore->mWidget->GetWindowHandle(), 1.3147 + nullptr, getter_AddRefs(prevFocusedDocumentMgr)); 1.3148 + NS_ASSERTION(SUCCEEDED(hr), "Disassociating focus failed"); 1.3149 + NS_ASSERTION(prevFocusedDocumentMgr == sTsfTextStore->mDocumentMgr, 1.3150 + "different documentMgr has been associated with the window"); 1.3151 + sTsfTextStore->Destroy(); 1.3152 + } 1.3153 + HRESULT hr = sTsfThreadMgr->SetFocus(sTsfDisabledDocumentMgr); 1.3154 + NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); 1.3155 + } 1.3156 + return NS_OK; 1.3157 +} 1.3158 + 1.3159 +// static 1.3160 +nsIMEUpdatePreference 1.3161 +nsTextStore::GetIMEUpdatePreference() 1.3162 +{ 1.3163 + if (sTsfThreadMgr && sTsfTextStore && sTsfTextStore->mDocumentMgr) { 1.3164 + nsRefPtr<ITfDocumentMgr> docMgr; 1.3165 + sTsfThreadMgr->GetFocus(getter_AddRefs(docMgr)); 1.3166 + if (docMgr == sTsfTextStore->mDocumentMgr) { 1.3167 + nsIMEUpdatePreference updatePreference( 1.3168 + nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE | 1.3169 + nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE | 1.3170 + nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE | 1.3171 + nsIMEUpdatePreference::NOTIFY_DURING_DEACTIVE); 1.3172 + // nsTextStore shouldn't notify TSF of selection change and text change 1.3173 + // which are caused by composition. 1.3174 + updatePreference.DontNotifyChangesCausedByComposition(); 1.3175 + return updatePreference; 1.3176 + } 1.3177 + } 1.3178 + return nsIMEUpdatePreference(); 1.3179 +} 1.3180 + 1.3181 +nsresult 1.3182 +nsTextStore::OnTextChangeInternal(const IMENotification& aIMENotification) 1.3183 +{ 1.3184 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3185 + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(aIMENotification={ " 1.3186 + "mMessage=0x%08X, mTextChangeData={ mStartOffset=%lu, " 1.3187 + "mOldEndOffset=%lu, mNewEndOffset=%lu}), mSink=0x%p, mSinkMask=%s, " 1.3188 + "mComposition.IsComposing()=%s", 1.3189 + this, aIMENotification.mMessage, 1.3190 + aIMENotification.mTextChangeData.mStartOffset, 1.3191 + aIMENotification.mTextChangeData.mOldEndOffset, 1.3192 + aIMENotification.mTextChangeData.mNewEndOffset, mSink.get(), 1.3193 + GetSinkMaskNameStr(mSinkMask).get(), 1.3194 + GetBoolName(mComposition.IsComposing()))); 1.3195 + 1.3196 + if (IsReadLocked()) { 1.3197 + return NS_OK; 1.3198 + } 1.3199 + 1.3200 + mSelection.MarkDirty(); 1.3201 + 1.3202 + if (!mSink || !(mSinkMask & TS_AS_TEXT_CHANGE)) { 1.3203 + return NS_OK; 1.3204 + } 1.3205 + 1.3206 + if (!aIMENotification.mTextChangeData.IsInInt32Range()) { 1.3207 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3208 + ("TSF: 0x%p nsTextStore::OnTextChangeInternal() FAILED due to " 1.3209 + "offset is too big for calling mSink->OnTextChange()...", 1.3210 + this)); 1.3211 + return NS_OK; 1.3212 + } 1.3213 + 1.3214 + // Some TIPs are confused by text change notification during composition. 1.3215 + // Especially, some of them stop working for composition in our process. 1.3216 + // For preventing it, let's commit the composition. 1.3217 + if (mComposition.IsComposing()) { 1.3218 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3219 + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(), " 1.3220 + "committing the composition for avoiding making TIP confused...", 1.3221 + this)); 1.3222 + CommitCompositionInternal(false); 1.3223 + return NS_OK; 1.3224 + } 1.3225 + 1.3226 + TS_TEXTCHANGE textChange; 1.3227 + textChange.acpStart = 1.3228 + static_cast<LONG>(aIMENotification.mTextChangeData.mStartOffset); 1.3229 + textChange.acpOldEnd = 1.3230 + static_cast<LONG>(aIMENotification.mTextChangeData.mOldEndOffset); 1.3231 + textChange.acpNewEnd = 1.3232 + static_cast<LONG>(aIMENotification.mTextChangeData.mNewEndOffset); 1.3233 + 1.3234 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3235 + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(), calling " 1.3236 + "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " 1.3237 + "acpNewEnd=%ld })...", this, textChange.acpStart, 1.3238 + textChange.acpOldEnd, textChange.acpNewEnd)); 1.3239 + mSink->OnTextChange(0, &textChange); 1.3240 + 1.3241 + return NS_OK; 1.3242 +} 1.3243 + 1.3244 +nsresult 1.3245 +nsTextStore::OnSelectionChangeInternal(void) 1.3246 +{ 1.3247 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3248 + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), " 1.3249 + "mSink=0x%p, mSinkMask=%s, mIsRecordingActionsWithoutLock=%s, " 1.3250 + "mComposition.IsComposing()=%s", 1.3251 + this, mSink.get(), GetSinkMaskNameStr(mSinkMask).get(), 1.3252 + GetBoolName(mIsRecordingActionsWithoutLock), 1.3253 + GetBoolName(mComposition.IsComposing()))); 1.3254 + 1.3255 + if (IsReadLocked()) { 1.3256 + return NS_OK; 1.3257 + } 1.3258 + 1.3259 + mSelection.MarkDirty(); 1.3260 + 1.3261 + if (!mSink || !(mSinkMask & TS_AS_SEL_CHANGE)) { 1.3262 + return NS_OK; 1.3263 + } 1.3264 + 1.3265 + // Some TIPs are confused by selection change notification during composition. 1.3266 + // Especially, some of them stop working for composition in our process. 1.3267 + // For preventing it, let's commit the composition. 1.3268 + if (mComposition.IsComposing()) { 1.3269 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3270 + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), " 1.3271 + "committing the composition for avoiding making TIP confused...", 1.3272 + this)); 1.3273 + CommitCompositionInternal(false); 1.3274 + return NS_OK; 1.3275 + } 1.3276 + 1.3277 + if (!mIsRecordingActionsWithoutLock) { 1.3278 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3279 + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), calling " 1.3280 + "mSink->OnSelectionChange()...", this)); 1.3281 + mSink->OnSelectionChange(); 1.3282 + } else { 1.3283 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3284 + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), pending " 1.3285 + "a call of mSink->OnSelectionChange()...", this)); 1.3286 + mPendingOnSelectionChange = true; 1.3287 + } 1.3288 + return NS_OK; 1.3289 +} 1.3290 + 1.3291 +nsresult 1.3292 +nsTextStore::OnLayoutChangeInternal() 1.3293 +{ 1.3294 + NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); 1.3295 + NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE); 1.3296 + 1.3297 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3298 + ("TSF: 0x%p nsTextStore::OnLayoutChangeInternal(), calling " 1.3299 + "mSink->OnLayoutChange()...", this)); 1.3300 + HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW); 1.3301 + NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); 1.3302 + 1.3303 + return NS_OK; 1.3304 +} 1.3305 + 1.3306 +void 1.3307 +nsTextStore::CreateNativeCaret() 1.3308 +{ 1.3309 + // This method must work only on desktop application. 1.3310 + if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Desktop) { 1.3311 + return; 1.3312 + } 1.3313 + 1.3314 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3315 + ("TSF: 0x%p nsTextStore::CreateNativeCaret(), " 1.3316 + "mComposition.IsComposing()=%s", 1.3317 + this, GetBoolName(mComposition.IsComposing()))); 1.3318 + 1.3319 + Selection& currentSel = CurrentSelection(); 1.3320 + if (currentSel.IsDirty()) { 1.3321 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3322 + ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " 1.3323 + "CurrentSelection() failure", this)); 1.3324 + return; 1.3325 + } 1.3326 + 1.3327 + // XXX If this is called without composition and the selection isn't 1.3328 + // collapsed, is it OK? 1.3329 + uint32_t caretOffset = currentSel.MaxOffset(); 1.3330 + 1.3331 + WidgetQueryContentEvent queryCaretRect(true, NS_QUERY_CARET_RECT, mWidget); 1.3332 + queryCaretRect.InitForQueryCaretRect(caretOffset); 1.3333 + mWidget->InitEvent(queryCaretRect); 1.3334 + mWidget->DispatchWindowEvent(&queryCaretRect); 1.3335 + if (!queryCaretRect.mSucceeded) { 1.3336 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3337 + ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " 1.3338 + "NS_QUERY_CARET_RECT failure (offset=%d)", this, caretOffset)); 1.3339 + return; 1.3340 + } 1.3341 + 1.3342 + nsIntRect& caretRect = queryCaretRect.mReply.mRect; 1.3343 + mNativeCaretIsCreated = ::CreateCaret(mWidget->GetWindowHandle(), nullptr, 1.3344 + caretRect.width, caretRect.height); 1.3345 + if (!mNativeCaretIsCreated) { 1.3346 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3347 + ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " 1.3348 + "CreateCaret() failure", this)); 1.3349 + return; 1.3350 + } 1.3351 + 1.3352 + nsWindow* window = static_cast<nsWindow*>(mWidget.get()); 1.3353 + nsWindow* toplevelWindow = window->GetTopLevelWindow(false); 1.3354 + if (!toplevelWindow) { 1.3355 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3356 + ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " 1.3357 + "no top level window", this)); 1.3358 + return; 1.3359 + } 1.3360 + 1.3361 + if (toplevelWindow != window) { 1.3362 + caretRect.MoveBy(toplevelWindow->WidgetToScreenOffset()); 1.3363 + caretRect.MoveBy(-window->WidgetToScreenOffset()); 1.3364 + } 1.3365 + 1.3366 + ::SetCaretPos(caretRect.x, caretRect.y); 1.3367 +} 1.3368 + 1.3369 +bool 1.3370 +nsTextStore::EnsureInitActiveTIPKeyboard() 1.3371 +{ 1.3372 + if (mOnActivatedCalled) { 1.3373 + return true; 1.3374 + } 1.3375 + 1.3376 + if (IsVistaOrLater()) { 1.3377 + nsRefPtr<ITfInputProcessorProfileMgr> profileMgr; 1.3378 + HRESULT hr = 1.3379 + sInputProcessorProfiles->QueryInterface(IID_ITfInputProcessorProfileMgr, 1.3380 + getter_AddRefs(profileMgr)); 1.3381 + if (FAILED(hr) || !profileMgr) { 1.3382 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3383 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " 1.3384 + "to get input processor profile manager, hr=0x%08X", this, hr)); 1.3385 + return false; 1.3386 + } 1.3387 + 1.3388 + TF_INPUTPROCESSORPROFILE profile; 1.3389 + hr = profileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile); 1.3390 + if (hr == S_FALSE) { 1.3391 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3392 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " 1.3393 + "to get active keyboard layout profile due to no active profile, " 1.3394 + "hr=0x%08X", this, hr)); 1.3395 + // XXX Should we call OnActivated() with arguments like non-TIP in this 1.3396 + // case? 1.3397 + return false; 1.3398 + } 1.3399 + if (FAILED(hr)) { 1.3400 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3401 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " 1.3402 + "to get active TIP keyboard, hr=0x%08X", this, hr)); 1.3403 + return false; 1.3404 + } 1.3405 + 1.3406 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3407 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " 1.3408 + "calling OnActivated() manually...", this)); 1.3409 + OnActivated(profile.dwProfileType, profile.langid, profile.clsid, 1.3410 + profile.catid, profile.guidProfile, ::GetKeyboardLayout(0), 1.3411 + TF_IPSINK_FLAG_ACTIVE); 1.3412 + return true; 1.3413 + } 1.3414 + 1.3415 + LANGID langID; 1.3416 + HRESULT hr = sInputProcessorProfiles->GetCurrentLanguage(&langID); 1.3417 + if (FAILED(hr)) { 1.3418 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3419 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " 1.3420 + "to get current language ID, hr=0x%08X", this, hr)); 1.3421 + return false; 1.3422 + } 1.3423 + 1.3424 + nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; 1.3425 + hr = sInputProcessorProfiles->EnumLanguageProfiles(langID, 1.3426 + getter_AddRefs(enumLangProfiles)); 1.3427 + if (FAILED(hr) || !enumLangProfiles) { 1.3428 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3429 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), FAILED " 1.3430 + "to get language profiles enumerator, hr=0x%08X", this, hr)); 1.3431 + return false; 1.3432 + } 1.3433 + 1.3434 + TF_LANGUAGEPROFILE profile; 1.3435 + ULONG fetch = 0; 1.3436 + while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { 1.3437 + if (!profile.fActive || profile.catid != GUID_TFCAT_TIP_KEYBOARD) { 1.3438 + continue; 1.3439 + } 1.3440 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3441 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " 1.3442 + "calling OnActivated() manually...", this)); 1.3443 + bool isTIP = profile.guidProfile != GUID_NULL; 1.3444 + OnActivated(isTIP ? TF_PROFILETYPE_INPUTPROCESSOR : 1.3445 + TF_PROFILETYPE_KEYBOARDLAYOUT, 1.3446 + profile.langid, profile.clsid, profile.catid, 1.3447 + profile.guidProfile, ::GetKeyboardLayout(0), 1.3448 + TF_IPSINK_FLAG_ACTIVE); 1.3449 + return true; 1.3450 + } 1.3451 + 1.3452 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3453 + ("TSF: 0x%p nsTextStore::EnsureInitActiveLanguageProfile(), " 1.3454 + "calling OnActivated() without active TIP manually...", this)); 1.3455 + OnActivated(TF_PROFILETYPE_KEYBOARDLAYOUT, 1.3456 + langID, CLSID_NULL, GUID_TFCAT_TIP_KEYBOARD, 1.3457 + GUID_NULL, ::GetKeyboardLayout(0), 1.3458 + TF_IPSINK_FLAG_ACTIVE); 1.3459 + return true; 1.3460 +} 1.3461 + 1.3462 +void 1.3463 +nsTextStore::CommitCompositionInternal(bool aDiscard) 1.3464 +{ 1.3465 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3466 + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), " 1.3467 + "mSink=0x%p, mContext=0x%p, mComposition.mView=0x%p, " 1.3468 + "mComposition.mString=\"%s\"", 1.3469 + this, GetBoolName(aDiscard), mSink.get(), mContext.get(), 1.3470 + mComposition.mView.get(), 1.3471 + NS_ConvertUTF16toUTF8(mComposition.mString).get())); 1.3472 + 1.3473 + if (mComposition.IsComposing() && aDiscard) { 1.3474 + LONG endOffset = mComposition.EndOffset(); 1.3475 + mComposition.mString.Truncate(0); 1.3476 + if (mSink && !mLock) { 1.3477 + TS_TEXTCHANGE textChange; 1.3478 + textChange.acpStart = mComposition.mStart; 1.3479 + textChange.acpOldEnd = endOffset; 1.3480 + textChange.acpNewEnd = mComposition.mStart; 1.3481 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3482 + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), calling" 1.3483 + "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " 1.3484 + "acpNewEnd=%ld })...", this, textChange.acpStart, 1.3485 + textChange.acpOldEnd, textChange.acpNewEnd)); 1.3486 + mSink->OnTextChange(0, &textChange); 1.3487 + } 1.3488 + } 1.3489 + // Terminate two contexts, the base context (mContext) and the top 1.3490 + // if the top context is not the same as the base context 1.3491 + nsRefPtr<ITfContext> context = mContext; 1.3492 + do { 1.3493 + if (context) { 1.3494 + nsRefPtr<ITfContextOwnerCompositionServices> services; 1.3495 + context->QueryInterface(IID_ITfContextOwnerCompositionServices, 1.3496 + getter_AddRefs(services)); 1.3497 + if (services) { 1.3498 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3499 + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), " 1.3500 + "requesting TerminateComposition() for the context 0x%p...", 1.3501 + this, context.get())); 1.3502 + services->TerminateComposition(nullptr); 1.3503 + } 1.3504 + } 1.3505 + if (context != mContext) 1.3506 + break; 1.3507 + if (mDocumentMgr) 1.3508 + mDocumentMgr->GetTop(getter_AddRefs(context)); 1.3509 + } while (context != mContext); 1.3510 +} 1.3511 + 1.3512 +static 1.3513 +bool 1.3514 +GetCompartment(IUnknown* pUnk, 1.3515 + const GUID& aID, 1.3516 + ITfCompartment** aCompartment) 1.3517 +{ 1.3518 + if (!pUnk) return false; 1.3519 + 1.3520 + nsRefPtr<ITfCompartmentMgr> compMgr; 1.3521 + pUnk->QueryInterface(IID_ITfCompartmentMgr, getter_AddRefs(compMgr)); 1.3522 + if (!compMgr) return false; 1.3523 + 1.3524 + return SUCCEEDED(compMgr->GetCompartment(aID, aCompartment)) && 1.3525 + (*aCompartment) != nullptr; 1.3526 +} 1.3527 + 1.3528 +// static 1.3529 +void 1.3530 +nsTextStore::SetIMEOpenState(bool aState) 1.3531 +{ 1.3532 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3533 + ("TSF: nsTextStore::SetIMEOpenState(aState=%s)", GetBoolName(aState))); 1.3534 + 1.3535 + nsRefPtr<ITfCompartment> comp; 1.3536 + if (!GetCompartment(sTsfThreadMgr, 1.3537 + GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, 1.3538 + getter_AddRefs(comp))) { 1.3539 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3540 + ("TSF: nsTextStore::SetIMEOpenState() FAILED due to" 1.3541 + "no compartment available")); 1.3542 + return; 1.3543 + } 1.3544 + 1.3545 + VARIANT variant; 1.3546 + variant.vt = VT_I4; 1.3547 + variant.lVal = aState; 1.3548 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3549 + ("TSF: nsTextStore::SetIMEOpenState(), setting " 1.3550 + "0x%04X to GUID_COMPARTMENT_KEYBOARD_OPENCLOSE...", 1.3551 + variant.lVal)); 1.3552 + comp->SetValue(sTsfClientId, &variant); 1.3553 +} 1.3554 + 1.3555 +// static 1.3556 +bool 1.3557 +nsTextStore::GetIMEOpenState(void) 1.3558 +{ 1.3559 + nsRefPtr<ITfCompartment> comp; 1.3560 + if (!GetCompartment(sTsfThreadMgr, 1.3561 + GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, 1.3562 + getter_AddRefs(comp))) 1.3563 + return false; 1.3564 + 1.3565 + VARIANT variant; 1.3566 + ::VariantInit(&variant); 1.3567 + if (SUCCEEDED(comp->GetValue(&variant)) && variant.vt == VT_I4) 1.3568 + return variant.lVal != 0; 1.3569 + 1.3570 + ::VariantClear(&variant); // clear up in case variant.vt != VT_I4 1.3571 + return false; 1.3572 +} 1.3573 + 1.3574 +// static 1.3575 +void 1.3576 +nsTextStore::SetInputContext(nsWindowBase* aWidget, 1.3577 + const InputContext& aContext, 1.3578 + const InputContextAction& aAction) 1.3579 +{ 1.3580 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3581 + ("TSF: nsTextStore::SetInputContext(aWidget=%p, " 1.3582 + "aContext.mIMEState.mEnabled=%s, aAction.mFocusChange=%s), " 1.3583 + "ThinksHavingFocus()=%s", 1.3584 + aWidget, GetIMEEnabledName(aContext.mIMEState.mEnabled), 1.3585 + GetFocusChangeName(aAction.mFocusChange), 1.3586 + GetBoolName(ThinksHavingFocus()))); 1.3587 + 1.3588 + NS_ENSURE_TRUE_VOID(sTsfTextStore); 1.3589 + sTsfTextStore->SetInputScope(aContext.mHTMLInputType); 1.3590 + 1.3591 + if (aAction.mFocusChange != InputContextAction::FOCUS_NOT_CHANGED) { 1.3592 + return; 1.3593 + } 1.3594 + 1.3595 + // If focus isn't actually changed but the enabled state is changed, 1.3596 + // emulate the focus move. 1.3597 + if (!ThinksHavingFocus() && 1.3598 + aContext.mIMEState.mEnabled == IMEState::ENABLED) { 1.3599 + OnFocusChange(true, aWidget, aContext.mIMEState.mEnabled); 1.3600 + } else if (ThinksHavingFocus() && 1.3601 + aContext.mIMEState.mEnabled != IMEState::ENABLED) { 1.3602 + OnFocusChange(false, aWidget, aContext.mIMEState.mEnabled); 1.3603 + } 1.3604 +} 1.3605 + 1.3606 +// static 1.3607 +void 1.3608 +nsTextStore::MarkContextAsKeyboardDisabled(ITfContext* aContext) 1.3609 +{ 1.3610 + VARIANT variant_int4_value1; 1.3611 + variant_int4_value1.vt = VT_I4; 1.3612 + variant_int4_value1.lVal = 1; 1.3613 + 1.3614 + nsRefPtr<ITfCompartment> comp; 1.3615 + if (!GetCompartment(aContext, 1.3616 + GUID_COMPARTMENT_KEYBOARD_DISABLED, 1.3617 + getter_AddRefs(comp))) { 1.3618 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3619 + ("TSF: nsTextStore::MarkContextAsKeyboardDisabled() failed" 1.3620 + "aContext=0x%p...", aContext)); 1.3621 + return; 1.3622 + } 1.3623 + 1.3624 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3625 + ("TSF: nsTextStore::MarkContextAsKeyboardDisabled(), setting " 1.3626 + "to disable context 0x%p...", 1.3627 + aContext)); 1.3628 + comp->SetValue(sTsfClientId, &variant_int4_value1); 1.3629 +} 1.3630 + 1.3631 +// static 1.3632 +void 1.3633 +nsTextStore::MarkContextAsEmpty(ITfContext* aContext) 1.3634 +{ 1.3635 + VARIANT variant_int4_value1; 1.3636 + variant_int4_value1.vt = VT_I4; 1.3637 + variant_int4_value1.lVal = 1; 1.3638 + 1.3639 + nsRefPtr<ITfCompartment> comp; 1.3640 + if (!GetCompartment(aContext, 1.3641 + GUID_COMPARTMENT_EMPTYCONTEXT, 1.3642 + getter_AddRefs(comp))) { 1.3643 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3644 + ("TSF: nsTextStore::MarkContextAsEmpty() failed" 1.3645 + "aContext=0x%p...", aContext)); 1.3646 + return; 1.3647 + } 1.3648 + 1.3649 + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, 1.3650 + ("TSF: nsTextStore::MarkContextAsEmpty(), setting " 1.3651 + "to mark empty context 0x%p...", aContext)); 1.3652 + comp->SetValue(sTsfClientId, &variant_int4_value1); 1.3653 +} 1.3654 + 1.3655 +// static 1.3656 +bool 1.3657 +nsTextStore::IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, 1.3658 + REFGUID aProfile) 1.3659 +{ 1.3660 + if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { 1.3661 + return false; 1.3662 + } 1.3663 + 1.3664 + nsRefPtr<IEnumTfLanguageProfiles> enumLangProfiles; 1.3665 + HRESULT hr = 1.3666 + sInputProcessorProfiles->EnumLanguageProfiles(aLangID, 1.3667 + getter_AddRefs(enumLangProfiles)); 1.3668 + if (FAILED(hr) || !enumLangProfiles) { 1.3669 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3670 + ("TSF: nsTextStore::IsTIPCategoryKeyboard(), FAILED " 1.3671 + "to get language profiles enumerator, hr=0x%08X", hr)); 1.3672 + return false; 1.3673 + } 1.3674 + 1.3675 + TF_LANGUAGEPROFILE profile; 1.3676 + ULONG fetch = 0; 1.3677 + while (SUCCEEDED(enumLangProfiles->Next(1, &profile, &fetch)) && fetch) { 1.3678 + // XXX We're not sure a profile is registered with two or more categories. 1.3679 + if (profile.clsid == aTextService && 1.3680 + profile.guidProfile == aProfile && 1.3681 + profile.catid == GUID_TFCAT_TIP_KEYBOARD) { 1.3682 + return true; 1.3683 + } 1.3684 + } 1.3685 + return false; 1.3686 +} 1.3687 + 1.3688 +// static 1.3689 +void 1.3690 +nsTextStore::GetTIPDescription(REFCLSID aTextService, LANGID aLangID, 1.3691 + REFGUID aProfile, nsAString& aDescription) 1.3692 +{ 1.3693 + aDescription.Truncate(); 1.3694 + 1.3695 + if (aTextService == CLSID_NULL || aProfile == GUID_NULL) { 1.3696 + return; 1.3697 + } 1.3698 + 1.3699 + BSTR description = nullptr; 1.3700 + HRESULT hr = 1.3701 + sInputProcessorProfiles->GetLanguageProfileDescription(aTextService, 1.3702 + aLangID, 1.3703 + aProfile, 1.3704 + &description); 1.3705 + if (FAILED(hr)) { 1.3706 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3707 + ("TSF: nsTextStore::InitActiveTIPDescription() FAILED due to " 1.3708 + "GetLanguageProfileDescription() failure, hr=0x%08X", hr)); 1.3709 + return; 1.3710 + } 1.3711 + 1.3712 + if (description && description[0]) { 1.3713 + aDescription.Assign(description); 1.3714 + } 1.3715 + ::SysFreeString(description); 1.3716 +} 1.3717 + 1.3718 +// static 1.3719 +void 1.3720 +nsTextStore::Initialize() 1.3721 +{ 1.3722 +#ifdef PR_LOGGING 1.3723 + if (!sTextStoreLog) { 1.3724 + sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets"); 1.3725 + } 1.3726 +#endif 1.3727 + 1.3728 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3729 + ("TSF: nsTextStore::Initialize() is called...")); 1.3730 + 1.3731 + if (sTsfThreadMgr) { 1.3732 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3733 + ("TSF: nsTextStore::Initialize() FAILED due to already initialized")); 1.3734 + return; 1.3735 + } 1.3736 + 1.3737 + bool enableTsf = Preferences::GetBool(kPrefNameTSFEnabled, false); 1.3738 + // Migrate legacy TSF pref to new pref. This should be removed in next 1.3739 + // release cycle or later. 1.3740 + if (!enableTsf && Preferences::GetBool(kLegacyPrefNameTSFEnabled, false)) { 1.3741 + enableTsf = true; 1.3742 + Preferences::SetBool(kPrefNameTSFEnabled, true); 1.3743 + Preferences::ClearUser(kLegacyPrefNameTSFEnabled); 1.3744 + } 1.3745 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3746 + ("TSF: nsTextStore::Initialize(), TSF is %s", 1.3747 + enableTsf ? "enabled" : "disabled")); 1.3748 + if (!enableTsf) { 1.3749 + return; 1.3750 + } 1.3751 + 1.3752 + // XXX MSDN documents that ITfInputProcessorProfiles is available only on 1.3753 + // desktop apps. However, there is no known way to obtain 1.3754 + // ITfInputProcessorProfileMgr instance without ITfInputProcessorProfiles 1.3755 + // instance. 1.3756 + nsRefPtr<ITfInputProcessorProfiles> inputProcessorProfiles; 1.3757 + HRESULT hr = 1.3758 + ::CoCreateInstance(CLSID_TF_InputProcessorProfiles, nullptr, 1.3759 + CLSCTX_INPROC_SERVER, 1.3760 + IID_ITfInputProcessorProfiles, 1.3761 + getter_AddRefs(inputProcessorProfiles)); 1.3762 + if (FAILED(hr) || !inputProcessorProfiles) { 1.3763 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3764 + ("TSF: nsTextStore::Initialize() FAILED to create input processor " 1.3765 + "profiles, hr=0x%08X", hr)); 1.3766 + return; 1.3767 + } 1.3768 + 1.3769 + nsRefPtr<ITfThreadMgr> threadMgr; 1.3770 + hr = ::CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, 1.3771 + CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, 1.3772 + getter_AddRefs(threadMgr)); 1.3773 + if (FAILED(hr) || !threadMgr) { 1.3774 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3775 + ("TSF: nsTextStore::Initialize() FAILED to " 1.3776 + "create the thread manager, hr=0x%08X", hr)); 1.3777 + return; 1.3778 + } 1.3779 + 1.3780 + nsRefPtr<ITfMessagePump> messagePump; 1.3781 + hr = threadMgr->QueryInterface(IID_ITfMessagePump, 1.3782 + getter_AddRefs(messagePump)); 1.3783 + if (FAILED(hr) || !messagePump) { 1.3784 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3785 + ("TSF: nsTextStore::Initialize() FAILED to " 1.3786 + "QI message pump from the thread manager, hr=0x%08X", hr)); 1.3787 + return; 1.3788 + } 1.3789 + 1.3790 + nsRefPtr<ITfKeystrokeMgr> keystrokeMgr; 1.3791 + hr = threadMgr->QueryInterface(IID_ITfKeystrokeMgr, 1.3792 + getter_AddRefs(keystrokeMgr)); 1.3793 + if (FAILED(hr) || !keystrokeMgr) { 1.3794 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3795 + ("TSF: nsTextStore::Initialize() FAILED to " 1.3796 + "QI keystroke manager from the thread manager, hr=0x%08X", hr)); 1.3797 + return; 1.3798 + } 1.3799 + 1.3800 + hr = threadMgr->Activate(&sTsfClientId); 1.3801 + if (FAILED(hr)) { 1.3802 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3803 + ("TSF: nsTextStore::Initialize() FAILED to activate, hr=0x%08X", hr)); 1.3804 + return; 1.3805 + } 1.3806 + 1.3807 + nsRefPtr<ITfDisplayAttributeMgr> displayAttributeMgr; 1.3808 + hr = ::CoCreateInstance(CLSID_TF_DisplayAttributeMgr, nullptr, 1.3809 + CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeMgr, 1.3810 + getter_AddRefs(displayAttributeMgr)); 1.3811 + if (FAILED(hr) || !displayAttributeMgr) { 1.3812 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3813 + ("TSF: nsTextStore::Initialize() FAILED to create " 1.3814 + "a display attribute manager instance, hr=0x%08X", hr)); 1.3815 + return; 1.3816 + } 1.3817 + 1.3818 + nsRefPtr<ITfCategoryMgr> categoryMgr; 1.3819 + hr = ::CoCreateInstance(CLSID_TF_CategoryMgr, nullptr, 1.3820 + CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, 1.3821 + getter_AddRefs(categoryMgr)); 1.3822 + if (FAILED(hr) || !categoryMgr) { 1.3823 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3824 + ("TSF: nsTextStore::Initialize() FAILED to create " 1.3825 + "a category manager instance, hr=0x%08X", hr)); 1.3826 + return; 1.3827 + } 1.3828 + 1.3829 + nsRefPtr<ITfDocumentMgr> disabledDocumentMgr; 1.3830 + hr = threadMgr->CreateDocumentMgr(getter_AddRefs(disabledDocumentMgr)); 1.3831 + if (FAILED(hr) || !disabledDocumentMgr) { 1.3832 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3833 + ("TSF: nsTextStore::Initialize() FAILED to create " 1.3834 + "a document manager for disabled mode, hr=0x%08X", hr)); 1.3835 + return; 1.3836 + } 1.3837 + 1.3838 + nsRefPtr<ITfContext> disabledContext; 1.3839 + DWORD editCookie = 0; 1.3840 + hr = disabledDocumentMgr->CreateContext(sTsfClientId, 0, nullptr, 1.3841 + getter_AddRefs(disabledContext), 1.3842 + &editCookie); 1.3843 + if (FAILED(hr) || !disabledContext) { 1.3844 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3845 + ("TSF: nsTextStore::Initialize() FAILED to create " 1.3846 + "a context for disabled mode, hr=0x%08X", hr)); 1.3847 + return; 1.3848 + } 1.3849 + 1.3850 + MarkContextAsKeyboardDisabled(disabledContext); 1.3851 + MarkContextAsEmpty(disabledContext); 1.3852 + 1.3853 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3854 + ("TSF: nsTextStore::Initialize() is creating " 1.3855 + "an nsTextStore instance...")); 1.3856 + nsRefPtr<nsTextStore> textStore = new nsTextStore(); 1.3857 + if (!textStore->Init(threadMgr)) { 1.3858 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.3859 + ("TSF: nsTextStore::Initialize() FAILED to initialize nsTextStore " 1.3860 + "instance")); 1.3861 + return; 1.3862 + } 1.3863 + 1.3864 + inputProcessorProfiles.swap(sInputProcessorProfiles); 1.3865 + threadMgr.swap(sTsfThreadMgr); 1.3866 + messagePump.swap(sMessagePump); 1.3867 + keystrokeMgr.swap(sKeystrokeMgr); 1.3868 + displayAttributeMgr.swap(sDisplayAttrMgr); 1.3869 + categoryMgr.swap(sCategoryMgr); 1.3870 + disabledDocumentMgr.swap(sTsfDisabledDocumentMgr); 1.3871 + disabledContext.swap(sTsfDisabledContext); 1.3872 + textStore.swap(sTsfTextStore); 1.3873 + 1.3874 + sCreateNativeCaretForATOK = 1.3875 + Preferences::GetBool("intl.tsf.hack.atok.create_native_caret", true); 1.3876 + 1.3877 + MOZ_ASSERT(!sFlushTIPInputMessage); 1.3878 + sFlushTIPInputMessage = ::RegisterWindowMessageW(L"Flush TIP Input Message"); 1.3879 + 1.3880 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 1.3881 + ("TSF: nsTextStore::Initialize(), sTsfThreadMgr=0x%p, " 1.3882 + "sTsfClientId=0x%08X, sTsfTextStore=0x%p, sDisplayAttrMgr=0x%p, " 1.3883 + "sCategoryMgr=0x%p, sTsfDisabledDocumentMgr=0x%p, sTsfDisabledContext=%p, " 1.3884 + "sCreateNativeCaretForATOK=%s", 1.3885 + sTsfThreadMgr, sTsfClientId, sTsfTextStore, sDisplayAttrMgr, sCategoryMgr, 1.3886 + sTsfDisabledDocumentMgr, sTsfDisabledContext, 1.3887 + GetBoolName(sCreateNativeCaretForATOK))); 1.3888 +} 1.3889 + 1.3890 +// static 1.3891 +void 1.3892 +nsTextStore::Terminate(void) 1.3893 +{ 1.3894 + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: nsTextStore::Terminate()")); 1.3895 + 1.3896 + NS_IF_RELEASE(sDisplayAttrMgr); 1.3897 + NS_IF_RELEASE(sCategoryMgr); 1.3898 + NS_IF_RELEASE(sTsfTextStore); 1.3899 + NS_IF_RELEASE(sTsfDisabledDocumentMgr); 1.3900 + NS_IF_RELEASE(sTsfDisabledContext); 1.3901 + NS_IF_RELEASE(sInputProcessorProfiles); 1.3902 + sTsfClientId = 0; 1.3903 + if (sTsfThreadMgr) { 1.3904 + sTsfThreadMgr->Deactivate(); 1.3905 + NS_RELEASE(sTsfThreadMgr); 1.3906 + NS_RELEASE(sMessagePump); 1.3907 + NS_RELEASE(sKeystrokeMgr); 1.3908 + } 1.3909 +} 1.3910 + 1.3911 +// static 1.3912 +bool 1.3913 +nsTextStore::ProcessRawKeyMessage(const MSG& aMsg) 1.3914 +{ 1.3915 + if (!sKeystrokeMgr) { 1.3916 + return false; // not in TSF mode 1.3917 + } 1.3918 + 1.3919 + if (aMsg.message == WM_KEYDOWN) { 1.3920 + BOOL eaten; 1.3921 + HRESULT hr = sKeystrokeMgr->TestKeyDown(aMsg.wParam, aMsg.lParam, &eaten); 1.3922 + if (FAILED(hr) || !eaten) { 1.3923 + return false; 1.3924 + } 1.3925 + hr = sKeystrokeMgr->KeyDown(aMsg.wParam, aMsg.lParam, &eaten); 1.3926 + return SUCCEEDED(hr) && eaten; 1.3927 + } 1.3928 + if (aMsg.message == WM_KEYUP) { 1.3929 + BOOL eaten; 1.3930 + HRESULT hr = sKeystrokeMgr->TestKeyUp(aMsg.wParam, aMsg.lParam, &eaten); 1.3931 + if (FAILED(hr) || !eaten) { 1.3932 + return false; 1.3933 + } 1.3934 + hr = sKeystrokeMgr->KeyUp(aMsg.wParam, aMsg.lParam, &eaten); 1.3935 + return SUCCEEDED(hr) && eaten; 1.3936 + } 1.3937 + return false; 1.3938 +} 1.3939 + 1.3940 +// static 1.3941 +void 1.3942 +nsTextStore::ProcessMessage(nsWindowBase* aWindow, UINT aMessage, 1.3943 + WPARAM& aWParam, LPARAM& aLParam, 1.3944 + MSGResult& aResult) 1.3945 +{ 1.3946 + switch (aMessage) { 1.3947 + case WM_IME_SETCONTEXT: 1.3948 + // If a windowless plugin had focus and IME was handled on it, composition 1.3949 + // window was set the position. After that, even in TSF mode, WinXP keeps 1.3950 + // to use composition window at the position if the active IME is not 1.3951 + // aware TSF. For avoiding this issue, we need to hide the composition 1.3952 + // window here. 1.3953 + if (aWParam) { 1.3954 + aLParam &= ~ISC_SHOWUICOMPOSITIONWINDOW; 1.3955 + } 1.3956 + break; 1.3957 + } 1.3958 +} 1.3959 + 1.3960 +/******************************************************************/ 1.3961 +/* nsTextStore::Composition */ 1.3962 +/******************************************************************/ 1.3963 + 1.3964 +void 1.3965 +nsTextStore::Composition::Start(ITfCompositionView* aCompositionView, 1.3966 + LONG aCompositionStartOffset, 1.3967 + const nsAString& aCompositionString) 1.3968 +{ 1.3969 + mView = aCompositionView; 1.3970 + mString = aCompositionString; 1.3971 + mStart = aCompositionStartOffset; 1.3972 +} 1.3973 + 1.3974 +void 1.3975 +nsTextStore::Composition::End() 1.3976 +{ 1.3977 + mView = nullptr; 1.3978 + mString.Truncate(); 1.3979 +} 1.3980 + 1.3981 +/****************************************************************************** 1.3982 + * nsTextStore::Content 1.3983 + *****************************************************************************/ 1.3984 + 1.3985 +const nsDependentSubstring 1.3986 +nsTextStore::Content::GetSelectedText() const 1.3987 +{ 1.3988 + MOZ_ASSERT(mInitialized); 1.3989 + return GetSubstring(static_cast<uint32_t>(mSelection.StartOffset()), 1.3990 + static_cast<uint32_t>(mSelection.Length())); 1.3991 +} 1.3992 + 1.3993 +const nsDependentSubstring 1.3994 +nsTextStore::Content::GetSubstring(uint32_t aStart, uint32_t aLength) const 1.3995 +{ 1.3996 + MOZ_ASSERT(mInitialized); 1.3997 + return nsDependentSubstring(mText, aStart, aLength); 1.3998 +} 1.3999 + 1.4000 +void 1.4001 +nsTextStore::Content::ReplaceSelectedTextWith(const nsAString& aString) 1.4002 +{ 1.4003 + MOZ_ASSERT(mInitialized); 1.4004 + ReplaceTextWith(mSelection.StartOffset(), mSelection.Length(), aString); 1.4005 +} 1.4006 + 1.4007 +inline uint32_t 1.4008 +FirstDifferentCharOffset(const nsAString& aStr1, const nsAString& aStr2) 1.4009 +{ 1.4010 + MOZ_ASSERT(aStr1 != aStr2); 1.4011 + uint32_t i = 0; 1.4012 + uint32_t minLength = std::min(aStr1.Length(), aStr2.Length()); 1.4013 + for (; i < minLength && aStr1[i] == aStr2[i]; i++) { 1.4014 + /* nothing to do */ 1.4015 + } 1.4016 + return i; 1.4017 +} 1.4018 + 1.4019 +void 1.4020 +nsTextStore::Content::ReplaceTextWith(LONG aStart, LONG aLength, 1.4021 + const nsAString& aReplaceString) 1.4022 +{ 1.4023 + MOZ_ASSERT(mInitialized); 1.4024 + const nsDependentSubstring replacedString = 1.4025 + GetSubstring(static_cast<uint32_t>(aStart), 1.4026 + static_cast<uint32_t>(aLength)); 1.4027 + if (aReplaceString != replacedString) { 1.4028 + uint32_t firstDifferentOffset = 1.4029 + static_cast<uint32_t>(aStart) + FirstDifferentCharOffset(aReplaceString, 1.4030 + replacedString); 1.4031 + mMinTextModifiedOffset = 1.4032 + std::min(mMinTextModifiedOffset, firstDifferentOffset); 1.4033 + if (mComposition.IsComposing()) { 1.4034 + // Emulate text insertion during compositions, because during a 1.4035 + // composition, editor expects the whole composition string to 1.4036 + // be sent in NS_TEXT_TEXT, not just the inserted part. 1.4037 + // The actual NS_TEXT_TEXT will be sent in SetSelection or 1.4038 + // OnUpdateComposition. 1.4039 + MOZ_ASSERT(aStart >= mComposition.mStart); 1.4040 + MOZ_ASSERT(aStart + aLength <= mComposition.EndOffset()); 1.4041 + mComposition.mString.Replace( 1.4042 + static_cast<uint32_t>(aStart - mComposition.mStart), 1.4043 + static_cast<uint32_t>(aLength), aReplaceString); 1.4044 + } 1.4045 + mText.Replace(static_cast<uint32_t>(aStart), 1.4046 + static_cast<uint32_t>(aLength), aReplaceString); 1.4047 + } 1.4048 + // Selection should be collapsed at the end of the inserted string. 1.4049 + mSelection.CollapseAt( 1.4050 + static_cast<uint32_t>(aStart) + aReplaceString.Length()); 1.4051 +} 1.4052 + 1.4053 +void 1.4054 +nsTextStore::Content::StartComposition(ITfCompositionView* aCompositionView, 1.4055 + const PendingAction& aCompStart, 1.4056 + bool aPreserveSelection) 1.4057 +{ 1.4058 + MOZ_ASSERT(mInitialized); 1.4059 + MOZ_ASSERT(aCompositionView); 1.4060 + MOZ_ASSERT(!mComposition.mView); 1.4061 + MOZ_ASSERT(aCompStart.mType == PendingAction::COMPOSITION_START); 1.4062 + 1.4063 + mComposition.Start(aCompositionView, aCompStart.mSelectionStart, 1.4064 + GetSubstring(static_cast<uint32_t>(aCompStart.mSelectionStart), 1.4065 + static_cast<uint32_t>(aCompStart.mSelectionLength))); 1.4066 + if (!aPreserveSelection) { 1.4067 + mSelection.SetSelection(mComposition.mStart, mComposition.mString.Length(), 1.4068 + false); 1.4069 + } 1.4070 +} 1.4071 + 1.4072 +void 1.4073 +nsTextStore::Content::EndComposition(const PendingAction& aCompEnd) 1.4074 +{ 1.4075 + MOZ_ASSERT(mInitialized); 1.4076 + MOZ_ASSERT(mComposition.mView); 1.4077 + MOZ_ASSERT(aCompEnd.mType == PendingAction::COMPOSITION_END); 1.4078 + 1.4079 + mSelection.CollapseAt(mComposition.mStart + aCompEnd.mData.Length()); 1.4080 + mComposition.End(); 1.4081 +} 1.4082 + 1.4083 +#ifdef DEBUG 1.4084 +// static 1.4085 +bool 1.4086 +nsTextStore::CurrentKeyboardLayoutHasIME() 1.4087 +{ 1.4088 + if (!sInputProcessorProfiles) { 1.4089 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.4090 + ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED due to there is " 1.4091 + "no input processor profiles instance")); 1.4092 + return false; 1.4093 + } 1.4094 + nsRefPtr<ITfInputProcessorProfileMgr> profileMgr; 1.4095 + HRESULT hr = 1.4096 + sInputProcessorProfiles->QueryInterface(IID_ITfInputProcessorProfileMgr, 1.4097 + getter_AddRefs(profileMgr)); 1.4098 + if (FAILED(hr) || !profileMgr) { 1.4099 + // On Windows Vista or later, ImmIsIME() API always returns true. 1.4100 + // If we failed to obtain the profile manager, we cannot know if current 1.4101 + // keyboard layout has IME. 1.4102 + if (IsVistaOrLater()) { 1.4103 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.4104 + ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to query " 1.4105 + "ITfInputProcessorProfileMgr")); 1.4106 + return false; 1.4107 + } 1.4108 + // If the profiles instance doesn't have ITfInputProcessorProfileMgr 1.4109 + // interface, that means probably we're running on WinXP or WinServer2003 1.4110 + // (except WinServer2003 R2). Then, we should use ImmIsIME(). 1.4111 + return ::ImmIsIME(::GetKeyboardLayout(0)); 1.4112 + } 1.4113 + 1.4114 + TF_INPUTPROCESSORPROFILE profile; 1.4115 + hr = profileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile); 1.4116 + if (hr == S_FALSE) { 1.4117 + return false; // not found or not active 1.4118 + } 1.4119 + if (FAILED(hr)) { 1.4120 + PR_LOG(sTextStoreLog, PR_LOG_ERROR, 1.4121 + ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive " 1.4122 + "active profile")); 1.4123 + return false; 1.4124 + } 1.4125 + return (profile.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR); 1.4126 +} 1.4127 +#endif // #ifdef DEBUG