1097 lines
36 KiB
C++
1097 lines
36 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#define INPUTSCOPE_INIT_GUID
|
|
#define TEXTATTRS_INIT_GUID
|
|
#include "TSFUtils.h"
|
|
|
|
#include "IMMHandler.h"
|
|
#include "TSFEmptyTextStore.h"
|
|
#include "TSFStaticSink.h"
|
|
#include "TSFTextInputProcessorList.h"
|
|
#include "TSFTextStore.h"
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/Result.h"
|
|
#include "mozilla/StaticPrefs_intl.h"
|
|
#include "mozilla/WindowsVersion.h"
|
|
#include "mozilla/widget/WinRegistry.h"
|
|
#include "nsPrintfCString.h"
|
|
|
|
// For collecting other people's log, tell `MOZ_LOG=IMEHandler:4,sync`
|
|
// rather than `MOZ_LOG=IMEHandler:5,sync` since using `5` may create too
|
|
// big file.
|
|
// Therefore you shouldn't use `LogLevel::Verbose` for logging usual behavior.
|
|
mozilla::LazyLogModule gIMELog("IMEHandler");
|
|
|
|
namespace mozilla::widget {
|
|
|
|
/******************************************************************************
|
|
* Logging helper classes
|
|
******************************************************************************/
|
|
|
|
AutoFindFlagsCString::AutoFindFlagsCString(DWORD aFindFlags) {
|
|
if (!aFindFlags) {
|
|
AssignLiteral("no flags (0)");
|
|
return;
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_BACKWARDS) {
|
|
AppendFlag("TS_ATTR_FIND_BACKWARDS");
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_WANT_OFFSET) {
|
|
AppendFlag("TS_ATTR_FIND_WANT_OFFSET");
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_UPDATESTART) {
|
|
AppendFlag("TS_ATTR_FIND_UPDATESTART");
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_WANT_VALUE) {
|
|
AppendFlag("TS_ATTR_FIND_WANT_VALUE");
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_WANT_END) {
|
|
AppendFlag("TS_ATTR_FIND_WANT_END");
|
|
}
|
|
if (aFindFlags & TS_ATTR_FIND_HIDDEN) {
|
|
AppendFlag("TS_ATTR_FIND_HIDDEN");
|
|
}
|
|
if (IsEmpty()) {
|
|
AppendPrintf("Unknown(%lu)", aFindFlags);
|
|
}
|
|
}
|
|
|
|
AutoACPFromPointFlagsCString::AutoACPFromPointFlagsCString(DWORD aFlags) {
|
|
if (!aFlags) {
|
|
AssignLiteral("no flags (0)");
|
|
return;
|
|
}
|
|
if (aFlags & GXFPF_ROUND_NEAREST) {
|
|
AppendFlag("GXFPF_ROUND_NEAREST");
|
|
aFlags &= ~GXFPF_ROUND_NEAREST;
|
|
}
|
|
if (aFlags & GXFPF_NEAREST) {
|
|
AppendFlag("GXFPF_NEAREST");
|
|
aFlags &= ~GXFPF_NEAREST;
|
|
}
|
|
if (aFlags) {
|
|
AppendFlag(nsPrintfCString("Unknown(%lu)", aFlags));
|
|
}
|
|
}
|
|
|
|
AutoClsidCString::AutoClsidCString(REFCLSID aCLSID) {
|
|
LPOLESTR str = nullptr;
|
|
HRESULT hr = ::StringFromCLSID(aCLSID, &str);
|
|
if (FAILED(hr) || !str || !str[0]) {
|
|
return;
|
|
}
|
|
Assign(NS_ConvertUTF16toUTF8(str));
|
|
::CoTaskMemFree(str);
|
|
}
|
|
|
|
void AutoRawGuidCString::AssignRawGuid(REFGUID aGUID) {
|
|
OLECHAR str[40];
|
|
int len = ::StringFromGUID2(aGUID, str, std::size(str));
|
|
if (!len || !str[0]) {
|
|
return;
|
|
}
|
|
Assign(NS_ConvertUTF16toUTF8(str));
|
|
}
|
|
|
|
AutoGuidCString::AutoGuidCString(REFGUID aGUID) {
|
|
#define ASSIGN_GUID_NAME(aNamedGUID) \
|
|
if (IsEqualGUID(aGUID, aNamedGUID)) { \
|
|
AssignLiteral(#aNamedGUID); \
|
|
return; \
|
|
}
|
|
|
|
ASSIGN_GUID_NAME(GUID_PROP_INPUTSCOPE)
|
|
ASSIGN_GUID_NAME(TSFUtils::sGUID_PROP_URL)
|
|
ASSIGN_GUID_NAME(TSATTRID_OTHERS)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_FaceName)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_SizePts)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Bold)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Italic)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_SmallCaps)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Capitalize)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Uppercase)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Lowercase)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_LasVegasLights)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_BlinkingBackground)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_SparkleText)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_MarchingBlackAnts)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_MarchingRedAnts)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_Shimmer)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_WipeDown)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Animation_WipeRight)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Emboss)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Engrave)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Hidden)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Kerning)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Outlined)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Position)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Protected)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Shadow)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Spacing)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Weight)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Height)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Underline)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Underline_Single)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Underline_Double)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Strikethrough)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Strikethrough_Single)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Strikethrough_Double)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Overline)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Overline_Single)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Overline_Double)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Blink)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Subscript)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Superscript)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_Color)
|
|
ASSIGN_GUID_NAME(TSATTRID_Font_Style_BackgroundColor)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_VerticalWriting)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_RightToLeft)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Orientation)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Language)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_ReadOnly)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_EmbeddedObject)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Alignment)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Alignment_Left)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Alignment_Right)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Alignment_Center)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Alignment_Justify)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Link)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Hyphenation)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_FirstLineIndent)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LeftIndent)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_RightIndent)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_SpaceAfter)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_SpaceBefore)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Single)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_OnePtFive)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Double)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_AtLeast)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Exactly)
|
|
ASSIGN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Multiple)
|
|
ASSIGN_GUID_NAME(TSATTRID_List)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_LevelIndel)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_Bullet)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_Arabic)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_LowerLetter)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_UpperLetter)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_LowerRoman)
|
|
ASSIGN_GUID_NAME(TSATTRID_List_Type_UpperRoman)
|
|
ASSIGN_GUID_NAME(TSATTRID_App)
|
|
ASSIGN_GUID_NAME(TSATTRID_App_IncorrectSpelling)
|
|
ASSIGN_GUID_NAME(TSATTRID_App_IncorrectGrammar)
|
|
|
|
#undef ASSIGN_GUID_NAME
|
|
|
|
AssignRawGuid(aGUID);
|
|
}
|
|
|
|
AutoRiidCString::AutoRiidCString(REFIID aRIID) {
|
|
LPOLESTR str = nullptr;
|
|
HRESULT hr = ::StringFromIID(aRIID, &str);
|
|
if (FAILED(hr) || !str || !str[0]) {
|
|
return;
|
|
}
|
|
|
|
nsAutoString key(L"Interface\\");
|
|
key += str;
|
|
|
|
nsCString result;
|
|
wchar_t buf[256];
|
|
if (WinRegistry::GetString(HKEY_CLASSES_ROOT, key, u""_ns, buf,
|
|
WinRegistry::kLegacyWinUtilsStringFlags)) {
|
|
Assign(NS_ConvertUTF16toUTF8(buf));
|
|
} else {
|
|
Assign(NS_ConvertUTF16toUTF8(str));
|
|
}
|
|
::CoTaskMemFree(str);
|
|
}
|
|
|
|
const char* TSFUtils::CommonHRESULTToChar(HRESULT aResult) {
|
|
switch (aResult) {
|
|
case S_OK:
|
|
return "S_OK";
|
|
case E_ABORT:
|
|
return "E_ABORT";
|
|
case E_ACCESSDENIED:
|
|
return "E_ACCESSDENIED";
|
|
case E_FAIL:
|
|
return "E_FAIL";
|
|
case E_HANDLE:
|
|
return "E_HANDLE";
|
|
case E_INVALIDARG:
|
|
return "E_INVALIDARG";
|
|
case E_NOINTERFACE:
|
|
return "E_NOINTERFACE";
|
|
case E_NOTIMPL:
|
|
return "E_NOTIMPL";
|
|
case E_OUTOFMEMORY:
|
|
return "E_OUTOFMEMORY";
|
|
case E_POINTER:
|
|
return "E_POINTER";
|
|
case E_UNEXPECTED:
|
|
return "E_UNEXPECTED";
|
|
case E_NOT_SET:
|
|
return "E_NOT_SET";
|
|
default:
|
|
return SUCCEEDED(aResult) ? "Succeeded" : "Failed";
|
|
}
|
|
}
|
|
|
|
const char* TSFUtils::HRESULTToChar(HRESULT aResult) {
|
|
switch (aResult) {
|
|
case TS_E_FORMAT:
|
|
return "TS_E_FORMAT";
|
|
case TS_E_INVALIDPOINT:
|
|
return "TS_E_INVALIDPOINT";
|
|
case TS_E_INVALIDPOS:
|
|
return "TS_E_INVALIDPOS";
|
|
case TS_E_NOINTERFACE:
|
|
return "TS_E_NOINTERFACE";
|
|
case TS_E_NOLAYOUT:
|
|
return "TS_E_NOLAYOUT";
|
|
case TS_E_NOLOCK:
|
|
return "TS_E_NOLOCK";
|
|
case TS_E_NOOBJECT:
|
|
return "TS_E_NOOBJECT";
|
|
case TS_E_NOSELECTION:
|
|
return "TS_E_NOSELECTION";
|
|
case TS_E_NOSERVICE:
|
|
return "TS_E_NOSERVICE";
|
|
case TS_E_READONLY:
|
|
return "TS_E_READONLY";
|
|
case TS_E_SYNCHRONOUS:
|
|
return "TS_E_SYNCHRONOUS";
|
|
case TS_S_ASYNC:
|
|
return "TS_S_ASYNC";
|
|
default:
|
|
return TSFUtils::CommonHRESULTToChar(aResult);
|
|
}
|
|
}
|
|
|
|
AutoSinkMasksCString::AutoSinkMasksCString(DWORD aSinkMask) {
|
|
if (aSinkMask & TS_AS_TEXT_CHANGE) {
|
|
AppendFlag("TS_AS_TEXT_CHANGE");
|
|
}
|
|
if (aSinkMask & TS_AS_SEL_CHANGE) {
|
|
AppendFlag("TS_AS_SEL_CHANGE");
|
|
}
|
|
if (aSinkMask & TS_AS_LAYOUT_CHANGE) {
|
|
AppendFlag("TS_AS_LAYOUT_CHANGE");
|
|
}
|
|
if (aSinkMask & TS_AS_ATTR_CHANGE) {
|
|
AppendFlag("TS_AS_ATTR_CHANGE");
|
|
}
|
|
if (aSinkMask & TS_AS_STATUS_CHANGE) {
|
|
AppendFlag("TS_AS_STATUS_CHANGE");
|
|
}
|
|
if (IsEmpty()) {
|
|
AssignLiteral("not-specified");
|
|
}
|
|
}
|
|
|
|
AutoLockFlagsCString::AutoLockFlagsCString(DWORD aLockFlags) {
|
|
if ((aLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) {
|
|
AppendFlag("TS_LF_READWRITE");
|
|
} else if (aLockFlags & TS_LF_READ) {
|
|
AppendFlag("TS_LF_READ");
|
|
}
|
|
if (aLockFlags & TS_LF_SYNC) {
|
|
AppendFlag("TS_LF_SYNC");
|
|
}
|
|
if (IsEmpty()) {
|
|
AssignLiteral("not-specified");
|
|
}
|
|
}
|
|
|
|
const char* TSFUtils::MouseButtonToChar(int16_t aButton) {
|
|
switch (aButton) {
|
|
case MouseButton::ePrimary:
|
|
return "LeftButton";
|
|
case MouseButton::eMiddle:
|
|
return "MiddleButton";
|
|
case MouseButton::eSecondary:
|
|
return "RightButton";
|
|
default:
|
|
return "UnknownButton";
|
|
}
|
|
}
|
|
|
|
AutoMouseButtonsCString::AutoMouseButtonsCString(int16_t aButtons) {
|
|
if (!aButtons) {
|
|
AssignLiteral("no buttons");
|
|
return;
|
|
}
|
|
if (aButtons & MouseButtonsFlag::ePrimaryFlag) {
|
|
AppendFlag("LeftButton");
|
|
}
|
|
if (aButtons & MouseButtonsFlag::eSecondaryFlag) {
|
|
AppendFlag("RightButton");
|
|
}
|
|
if (aButtons & MouseButtonsFlag::eMiddleFlag) {
|
|
AppendFlag("MiddleButton");
|
|
}
|
|
if (aButtons & MouseButtonsFlag::e4thFlag) {
|
|
AppendFlag("4thButton");
|
|
}
|
|
if (aButtons & MouseButtonsFlag::e5thFlag) {
|
|
AppendFlag("5thButton");
|
|
}
|
|
}
|
|
|
|
AutoInputScopesCString::AutoInputScopesCString(
|
|
const nsTArray<InputScope>& aList) {
|
|
for (InputScope inputScope : aList) {
|
|
switch (inputScope) {
|
|
case IS_DEFAULT:
|
|
AppendFlag("IS_DEFAULT");
|
|
break;
|
|
case IS_URL:
|
|
AppendFlag("IS_URL");
|
|
break;
|
|
case IS_FILE_FULLFILEPATH:
|
|
AppendFlag("IS_FILE_FULLFILEPATH");
|
|
break;
|
|
case IS_FILE_FILENAME:
|
|
AppendFlag("IS_FILE_FILENAME");
|
|
break;
|
|
case IS_EMAIL_USERNAME:
|
|
AppendFlag("IS_EMAIL_USERNAME");
|
|
break;
|
|
case IS_EMAIL_SMTPEMAILADDRESS:
|
|
AppendFlag("IS_EMAIL_SMTPEMAILADDRESS");
|
|
break;
|
|
case IS_LOGINNAME:
|
|
AppendFlag("IS_LOGINNAME");
|
|
break;
|
|
case IS_PERSONALNAME_FULLNAME:
|
|
AppendFlag("IS_PERSONALNAME_FULLNAME");
|
|
break;
|
|
case IS_PERSONALNAME_PREFIX:
|
|
AppendFlag("IS_PERSONALNAME_PREFIX");
|
|
break;
|
|
case IS_PERSONALNAME_GIVENNAME:
|
|
AppendFlag("IS_PERSONALNAME_GIVENNAME");
|
|
break;
|
|
case IS_PERSONALNAME_MIDDLENAME:
|
|
AppendFlag("IS_PERSONALNAME_MIDDLENAME");
|
|
break;
|
|
case IS_PERSONALNAME_SURNAME:
|
|
AppendFlag("IS_PERSONALNAME_SURNAME");
|
|
break;
|
|
case IS_PERSONALNAME_SUFFIX:
|
|
AppendFlag("IS_PERSONALNAME_SUFFIX");
|
|
break;
|
|
case IS_ADDRESS_FULLPOSTALADDRESS:
|
|
AppendFlag("IS_ADDRESS_FULLPOSTALADDRESS");
|
|
break;
|
|
case IS_ADDRESS_POSTALCODE:
|
|
AppendFlag("IS_ADDRESS_POSTALCODE");
|
|
break;
|
|
case IS_ADDRESS_STREET:
|
|
AppendFlag("IS_ADDRESS_STREET");
|
|
break;
|
|
case IS_ADDRESS_STATEORPROVINCE:
|
|
AppendFlag("IS_ADDRESS_STATEORPROVINCE");
|
|
break;
|
|
case IS_ADDRESS_CITY:
|
|
AppendFlag("IS_ADDRESS_CITY");
|
|
break;
|
|
case IS_ADDRESS_COUNTRYNAME:
|
|
AppendFlag("IS_ADDRESS_COUNTRYNAME");
|
|
break;
|
|
case IS_ADDRESS_COUNTRYSHORTNAME:
|
|
AppendFlag("IS_ADDRESS_COUNTRYSHORTNAME");
|
|
break;
|
|
case IS_CURRENCY_AMOUNTANDSYMBOL:
|
|
AppendFlag("IS_CURRENCY_AMOUNTANDSYMBOL");
|
|
break;
|
|
case IS_CURRENCY_AMOUNT:
|
|
AppendFlag("IS_CURRENCY_AMOUNT");
|
|
break;
|
|
case IS_DATE_FULLDATE:
|
|
AppendFlag("IS_DATE_FULLDATE");
|
|
break;
|
|
case IS_DATE_MONTH:
|
|
AppendFlag("IS_DATE_MONTH");
|
|
break;
|
|
case IS_DATE_DAY:
|
|
AppendFlag("IS_DATE_DAY");
|
|
break;
|
|
case IS_DATE_YEAR:
|
|
AppendFlag("IS_DATE_YEAR");
|
|
break;
|
|
case IS_DATE_MONTHNAME:
|
|
AppendFlag("IS_DATE_MONTHNAME");
|
|
break;
|
|
case IS_DATE_DAYNAME:
|
|
AppendFlag("IS_DATE_DAYNAME");
|
|
break;
|
|
case IS_DIGITS:
|
|
AppendFlag("IS_DIGITS");
|
|
break;
|
|
case IS_NUMBER:
|
|
AppendFlag("IS_NUMBER");
|
|
break;
|
|
case IS_ONECHAR:
|
|
AppendFlag("IS_ONECHAR");
|
|
break;
|
|
case IS_PASSWORD:
|
|
AppendFlag("IS_PASSWORD");
|
|
break;
|
|
case IS_TELEPHONE_FULLTELEPHONENUMBER:
|
|
AppendFlag("IS_TELEPHONE_FULLTELEPHONENUMBER");
|
|
break;
|
|
case IS_TELEPHONE_COUNTRYCODE:
|
|
AppendFlag("IS_TELEPHONE_COUNTRYCODE");
|
|
break;
|
|
case IS_TELEPHONE_AREACODE:
|
|
AppendFlag("IS_TELEPHONE_AREACODE");
|
|
break;
|
|
case IS_TELEPHONE_LOCALNUMBER:
|
|
AppendFlag("IS_TELEPHONE_LOCALNUMBER");
|
|
break;
|
|
case IS_TIME_FULLTIME:
|
|
AppendFlag("IS_TIME_FULLTIME");
|
|
break;
|
|
case IS_TIME_HOUR:
|
|
AppendFlag("IS_TIME_HOUR");
|
|
break;
|
|
case IS_TIME_MINORSEC:
|
|
AppendFlag("IS_TIME_MINORSEC");
|
|
break;
|
|
case IS_NUMBER_FULLWIDTH:
|
|
AppendFlag("IS_NUMBER_FULLWIDTH");
|
|
break;
|
|
case IS_ALPHANUMERIC_HALFWIDTH:
|
|
AppendFlag("IS_ALPHANUMERIC_HALFWIDTH");
|
|
break;
|
|
case IS_ALPHANUMERIC_FULLWIDTH:
|
|
AppendFlag("IS_ALPHANUMERIC_FULLWIDTH");
|
|
break;
|
|
case IS_CURRENCY_CHINESE:
|
|
AppendFlag("IS_CURRENCY_CHINESE");
|
|
break;
|
|
case IS_BOPOMOFO:
|
|
AppendFlag("IS_BOPOMOFO");
|
|
break;
|
|
case IS_HIRAGANA:
|
|
AppendFlag("IS_HIRAGANA");
|
|
break;
|
|
case IS_KATAKANA_HALFWIDTH:
|
|
AppendFlag("IS_KATAKANA_HALFWIDTH");
|
|
break;
|
|
case IS_KATAKANA_FULLWIDTH:
|
|
AppendFlag("IS_KATAKANA_FULLWIDTH");
|
|
break;
|
|
case IS_HANJA:
|
|
AppendFlag("IS_HANJA");
|
|
break;
|
|
case IS_PHRASELIST:
|
|
AppendFlag("IS_PHRASELIST");
|
|
break;
|
|
case IS_REGULAREXPRESSION:
|
|
AppendFlag("IS_REGULAREXPRESSION");
|
|
break;
|
|
case IS_SRGS:
|
|
AppendFlag("IS_SRGS");
|
|
break;
|
|
case IS_XML:
|
|
AppendFlag("IS_XML");
|
|
break;
|
|
case IS_PRIVATE:
|
|
AppendFlag("IS_PRIVATE");
|
|
break;
|
|
default:
|
|
AppendFlag(nsPrintfCString("Unknown Value(%d)", inputScope));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* mozilla::widget::TSFUtils
|
|
******************************************************************************/
|
|
|
|
StaticRefPtr<ITfThreadMgr> TSFUtils::sThreadMgr;
|
|
StaticRefPtr<ITfMessagePump> TSFUtils::sMessagePump;
|
|
StaticRefPtr<ITfKeystrokeMgr> TSFUtils::sKeystrokeMgr;
|
|
StaticRefPtr<ITfDisplayAttributeMgr> TSFUtils::sDisplayAttrMgr;
|
|
StaticRefPtr<ITfCategoryMgr> TSFUtils::sCategoryMgr;
|
|
StaticRefPtr<ITfCompartment> TSFUtils::sCompartmentForOpenClose;
|
|
StaticRefPtr<ITfInputProcessorProfiles> TSFUtils::sInputProcessorProfiles;
|
|
StaticRefPtr<TSFTextStore> TSFUtils::sActiveTextStore;
|
|
StaticRefPtr<TSFTextStoreBase> TSFUtils::sCurrentTextStore;
|
|
StaticRefPtr<TSFEmptyTextStore> TSFUtils::sEmptyTextStore;
|
|
DWORD TSFUtils::sClientId = 0;
|
|
|
|
template void TSFUtils::ClearStoringTextStoresIf(
|
|
const RefPtr<TSFTextStoreBase>& aTextStore);
|
|
template void TSFUtils::ClearStoringTextStoresIf(
|
|
const RefPtr<TSFTextStore>& aTextStore);
|
|
template void TSFUtils::ClearStoringTextStoresIf(
|
|
const RefPtr<TSFEmptyTextStore>& aTextStore);
|
|
|
|
void TSFUtils::Initialize() {
|
|
MOZ_LOG(gIMELog, LogLevel::Info, ("TSFUtils::Initialize() is called..."));
|
|
|
|
if (sThreadMgr) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::Initialize() FAILED due to already initialized"));
|
|
return;
|
|
}
|
|
|
|
RefPtr<ITfThreadMgr> threadMgr;
|
|
HRESULT hr =
|
|
::CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_ITfThreadMgr, getter_AddRefs(threadMgr));
|
|
if (FAILED(hr) || !threadMgr) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::Initialize() FAILED to "
|
|
"create the thread manager, hr=0x%08lX",
|
|
hr));
|
|
return;
|
|
}
|
|
|
|
hr = threadMgr->Activate(&sClientId);
|
|
if (FAILED(hr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::Initialize() FAILED to activate, hr=0x%08lX", hr));
|
|
return;
|
|
}
|
|
|
|
sThreadMgr = std::move(threadMgr);
|
|
MOZ_LOG(gIMELog, LogLevel::Info,
|
|
(" TSFTextStore::Initialize(), sThreadMgr=0x%p, sClientId=0x%08lX",
|
|
sThreadMgr.get(), sClientId));
|
|
}
|
|
|
|
// static
|
|
void TSFUtils::Shutdown() {
|
|
MOZ_LOG(gIMELog, LogLevel::Info, ("TSFUtils::Shutdown()"));
|
|
|
|
TSFStaticSink::Shutdown();
|
|
|
|
sDisplayAttrMgr = nullptr;
|
|
sCategoryMgr = nullptr;
|
|
if (RefPtr<TSFEmptyTextStore> emptyTextStore = sEmptyTextStore.forget()) {
|
|
emptyTextStore->Destroy();
|
|
MOZ_ASSERT(!sEmptyTextStore);
|
|
}
|
|
sActiveTextStore = nullptr;
|
|
if (RefPtr<TSFTextStoreBase> textStore = sCurrentTextStore.forget()) {
|
|
textStore->Destroy();
|
|
MOZ_ASSERT(!sCurrentTextStore);
|
|
}
|
|
sCompartmentForOpenClose = nullptr;
|
|
sInputProcessorProfiles = nullptr;
|
|
sClientId = 0;
|
|
if (sThreadMgr) {
|
|
sThreadMgr->Deactivate();
|
|
sThreadMgr = nullptr;
|
|
sMessagePump = nullptr;
|
|
sKeystrokeMgr = nullptr;
|
|
}
|
|
}
|
|
|
|
template <typename TSFTextStoreClass>
|
|
void TSFUtils::ClearStoringTextStoresIf(
|
|
const RefPtr<TSFTextStoreClass>& aTextStore) {
|
|
if (sCurrentTextStore.get() ==
|
|
static_cast<TSFTextStoreBase*>(aTextStore.get())) {
|
|
MOZ_ASSERT(sActiveTextStore == sCurrentTextStore);
|
|
sActiveTextStore = nullptr;
|
|
sCurrentTextStore = nullptr;
|
|
return;
|
|
}
|
|
if (static_cast<TSFTextStoreBase*>(sActiveTextStore.get()) ==
|
|
static_cast<TSFTextStoreBase*>(aTextStore.get())) {
|
|
sActiveTextStore = nullptr;
|
|
}
|
|
}
|
|
|
|
IMENotificationRequests TSFUtils::GetIMENotificationRequests() {
|
|
return sCurrentTextStore ? sCurrentTextStore->GetIMENotificationRequests()
|
|
: IMENotificationRequests();
|
|
}
|
|
|
|
inline std::ostream& operator<<(
|
|
std::ostream& aStream,
|
|
const mozilla::widget::TSFUtils::GotFocus& aGotFocus) {
|
|
return aStream << "GotFocus::"
|
|
<< (static_cast<bool>(aGotFocus) ? "Yes" : "No");
|
|
}
|
|
|
|
nsresult TSFUtils::OnFocusChange(GotFocus aGotFocus, nsWindow* aFocusedWindow,
|
|
const InputContext& aContext) {
|
|
MOZ_LOG(gIMELog, LogLevel::Debug,
|
|
(" TSFUtils::OnFocusChange(aGotFocus=%s, "
|
|
"aFocusedWindow=0x%p, aContext=%s), "
|
|
"ThreadMgr=0x%p, EnabledTextStore=0x%p",
|
|
mozilla::ToString(aGotFocus).c_str(), aFocusedWindow,
|
|
mozilla::ToString(aContext).c_str(), TSFUtils::GetThreadMgr(),
|
|
TSFUtils::GetActiveTextStore()));
|
|
|
|
if (!TSFUtils::IsAvailable()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
const RefPtr<TSFTextStoreBase> oldTextStore = sCurrentTextStore.forget();
|
|
sActiveTextStore = nullptr;
|
|
|
|
// If the oldTextStore is editable and still has focus, disassociate document
|
|
// manager from the window handle.
|
|
// NOTE: We never associate the document manager of TSFEmptyTextStore with
|
|
// a window handle. Therefore, we don't need to do this if the oldTextStore
|
|
// is not editable.
|
|
if (oldTextStore && oldTextStore->IsEditable()) {
|
|
if (oldTextStore->MaybeHasFocus()) {
|
|
const RefPtr<ITfThreadMgr> threadMgr(sThreadMgr);
|
|
// If active window is switched, threadMgr has already handled the focus
|
|
// change, then, we'll fail AssociateFocus() and the following assertions
|
|
// will fail. To avoid the latter, we should check whether the focused
|
|
// documentMgr is still what oldTextStore set to.
|
|
RefPtr<ITfDocumentMgr> focusedDocumentMgr;
|
|
threadMgr->GetFocus(getter_AddRefs(focusedDocumentMgr));
|
|
if (focusedDocumentMgr) {
|
|
RefPtr<ITfDocumentMgr> prevFocusedDocumentMgr;
|
|
DebugOnly<HRESULT> hr = threadMgr->AssociateFocus(
|
|
oldTextStore->GetWindow()->GetWindowHandle(), nullptr,
|
|
getter_AddRefs(prevFocusedDocumentMgr));
|
|
NS_WARNING_ASSERTION(SUCCEEDED(hr), "Disassociating focus failed");
|
|
NS_ASSERTION(
|
|
FAILED(hr) ||
|
|
prevFocusedDocumentMgr == oldTextStore->GetDocumentMgr(),
|
|
nsPrintfCString("different documentMgr has been associated "
|
|
"with the window: expected: %p, but got: %p",
|
|
oldTextStore->GetDocumentMgr(),
|
|
prevFocusedDocumentMgr.get())
|
|
.get());
|
|
}
|
|
}
|
|
|
|
// Even if there was an editable focused TextStore, we won't use it with new
|
|
// focused editor. So, release it now.
|
|
oldTextStore->Destroy();
|
|
}
|
|
|
|
if (NS_WARN_IF(!sThreadMgr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::OnFocusChange() FAILED, due to "
|
|
"ThreadMgr being destroyed during calling "
|
|
"ITfThreadMgr::AssociateFocus()"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (NS_WARN_IF(sCurrentTextStore)) {
|
|
MOZ_LOG(
|
|
gIMELog, LogLevel::Error,
|
|
(" TSFUtils::OnFocusChange() FAILED, due to "
|
|
"nested event handling has created another focused TextStore during "
|
|
"calling ITfThreadMgr::AssociateFocus()"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// If this is a notification of blur, move focus to the empty text store.
|
|
if (aGotFocus == GotFocus::No || !aContext.mIMEState.IsEditable()) {
|
|
if (aFocusedWindow->Destroyed()) {
|
|
return NS_OK;
|
|
}
|
|
if (!aContext.mIMEState.IsEditable()) {
|
|
if (RefPtr<TSFEmptyTextStore> emptyTextStore = sEmptyTextStore) {
|
|
nsresult rv =
|
|
emptyTextStore->SetFocusAndUpdateDocumentURLAndBrowsingMode(
|
|
aFocusedWindow, aContext);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
sCurrentTextStore = emptyTextStore.forget();
|
|
return NS_OK;
|
|
}
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::OnFocusChange() FAILED due to the failure of "
|
|
"TSFEmptyTextStore::"
|
|
"SetFocusAndUpdateDocumentURLAndBrowsingMode(), trying to "
|
|
"create new TSFEmptyTextStore..."));
|
|
}
|
|
}
|
|
Result<RefPtr<TSFEmptyTextStore>, nsresult> ret =
|
|
TSFEmptyTextStore::CreateAndSetFocus(aFocusedWindow, aContext);
|
|
if (NS_WARN_IF(ret.isErr())) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::OnFocusChange() FAILED due to failing to "
|
|
"create and set focus to new TSFEmptyTextStore"));
|
|
return ret.unwrapErr();
|
|
}
|
|
if (const RefPtr<TSFEmptyTextStore> oldEmptyTextStore =
|
|
sEmptyTextStore.forget()) {
|
|
oldEmptyTextStore->Destroy();
|
|
}
|
|
sEmptyTextStore = ret.unwrap().forget();
|
|
sCurrentTextStore = sEmptyTextStore;
|
|
return NS_OK;
|
|
}
|
|
|
|
// If an editor is getting focus, create new TextStore and set focus.
|
|
Result<RefPtr<TSFTextStore>, nsresult> ret =
|
|
TSFTextStore::CreateAndSetFocus(aFocusedWindow, aContext);
|
|
if (NS_WARN_IF(ret.isErr())) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
(" TSFUtils::OnFocusChange() FAILED due to failing to create "
|
|
"and set focus to new TSFTextStore failed"));
|
|
return ret.unwrapErr();
|
|
}
|
|
sActiveTextStore = ret.unwrap().forget();
|
|
sCurrentTextStore = sActiveTextStore;
|
|
return NS_OK;
|
|
}
|
|
|
|
void TSFUtils::EnsureMessagePump() {
|
|
if (!sThreadMgr) {
|
|
return;
|
|
}
|
|
static bool sInitialized = false;
|
|
// If it tried to retrieve ITfMessagePump from sThreadMgr but it failed,
|
|
// we shouldn't retry it at every message due to performance reason.
|
|
// Although this shouldn't occur actually.
|
|
if (sInitialized) {
|
|
return;
|
|
}
|
|
sInitialized = true;
|
|
|
|
RefPtr<ITfMessagePump> messagePump;
|
|
HRESULT hr = sThreadMgr->QueryInterface(IID_ITfMessagePump,
|
|
getter_AddRefs(messagePump));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!messagePump)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetMessagePump() FAILED to "
|
|
"QI message pump from the thread manager, hr=0x%08lX",
|
|
hr));
|
|
return;
|
|
}
|
|
sMessagePump = messagePump.forget();
|
|
}
|
|
|
|
void TSFUtils::EnsureKeystrokeMgr() {
|
|
static bool sInitialized = false;
|
|
// If it tried to retrieve ITfKeystrokeMgr from sThreadMgr but it failed,
|
|
// we shouldn't retry it at every keydown nor keyup due to performance
|
|
// reason. Although this shouldn't occur actually.
|
|
if (sInitialized) {
|
|
return;
|
|
}
|
|
RefPtr<ITfKeystrokeMgr> keystrokeMgr;
|
|
HRESULT hr = sThreadMgr->QueryInterface(IID_ITfKeystrokeMgr,
|
|
getter_AddRefs(keystrokeMgr));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!keystrokeMgr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::EnsureKeystrokeMgr() FAILED to "
|
|
"QI keystroke manager from the thread manager, hr=0x%08lX",
|
|
hr));
|
|
return;
|
|
}
|
|
sKeystrokeMgr = keystrokeMgr.forget();
|
|
}
|
|
|
|
ITfInputProcessorProfiles* TSFUtils::GetInputProcessorProfiles() {
|
|
if (sInputProcessorProfiles) {
|
|
return sInputProcessorProfiles;
|
|
}
|
|
// XXX MSDN documents that ITfInputProcessorProfiles is available only on
|
|
// desktop apps. However, there is no known way to obtain
|
|
// ITfInputProcessorProfileMgr instance without ITfInputProcessorProfiles
|
|
// instance.
|
|
RefPtr<ITfInputProcessorProfiles> inputProcessorProfiles;
|
|
HRESULT hr = ::CoCreateInstance(
|
|
CLSID_TF_InputProcessorProfiles, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_ITfInputProcessorProfiles, getter_AddRefs(inputProcessorProfiles));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!inputProcessorProfiles)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetInputProcessorProfiles() FAILED to create input "
|
|
"processor profiles, hr=0x%08lX",
|
|
hr));
|
|
return nullptr;
|
|
}
|
|
sInputProcessorProfiles = inputProcessorProfiles;
|
|
return sInputProcessorProfiles;
|
|
}
|
|
|
|
ITfDisplayAttributeMgr* TSFUtils::GetDisplayAttributeMgr() {
|
|
if (sDisplayAttrMgr) {
|
|
return sDisplayAttrMgr;
|
|
}
|
|
|
|
RefPtr<ITfDisplayAttributeMgr> displayAttributeMgr;
|
|
HRESULT hr = ::CoCreateInstance(
|
|
CLSID_TF_DisplayAttributeMgr, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_ITfDisplayAttributeMgr, getter_AddRefs(displayAttributeMgr));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!displayAttributeMgr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetDisplayAttributeMgr() FAILED to create "
|
|
"a display attribute manager instance, hr=0x%08lX",
|
|
hr));
|
|
return nullptr;
|
|
}
|
|
sDisplayAttrMgr = displayAttributeMgr.forget();
|
|
return sDisplayAttrMgr;
|
|
}
|
|
|
|
ITfCategoryMgr* TSFUtils::GetCategoryMgr() {
|
|
if (sCategoryMgr) {
|
|
return sCategoryMgr;
|
|
}
|
|
RefPtr<ITfCategoryMgr> categoryMgr;
|
|
HRESULT hr =
|
|
::CoCreateInstance(CLSID_TF_CategoryMgr, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_ITfCategoryMgr, getter_AddRefs(categoryMgr));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!categoryMgr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetCategoryMgr() FAILED to create "
|
|
"a category manager instance, hr=0x%08lX",
|
|
hr));
|
|
return nullptr;
|
|
}
|
|
sCategoryMgr = categoryMgr.forget();
|
|
return sCategoryMgr;
|
|
}
|
|
|
|
// static
|
|
ITfCompartment* TSFUtils::GetCompartmentForOpenClose() {
|
|
if (sCompartmentForOpenClose) {
|
|
return sCompartmentForOpenClose;
|
|
}
|
|
|
|
if (!sThreadMgr) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<ITfCompartmentMgr> compartmentMgr;
|
|
HRESULT hr = sThreadMgr->QueryInterface(IID_ITfCompartmentMgr,
|
|
getter_AddRefs(compartmentMgr));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!compartmentMgr)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetCompartmentForOpenClose() FAILED due to"
|
|
"sThreadMgr not having ITfCompartmentMgr, hr=0x%08lX",
|
|
hr));
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<ITfCompartment> compartment;
|
|
hr = compartmentMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,
|
|
getter_AddRefs(compartment));
|
|
if (NS_WARN_IF(FAILED(hr)) || NS_WARN_IF(!compartment)) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::GetCompartmentForOpenClose() FAILED due to"
|
|
"ITfCompartmentMgr::GetCompartment() failuere, hr=0x%08lX",
|
|
hr));
|
|
return nullptr;
|
|
}
|
|
|
|
sCompartmentForOpenClose = compartment;
|
|
return sCompartmentForOpenClose;
|
|
}
|
|
|
|
bool TSFUtils::DoNotReturnErrorFromGetSelection() {
|
|
// There is a crash bug of TSF if we return error from GetSelection().
|
|
// That was introduced in Anniversary Update (build 14393, see bug 1312302)
|
|
// TODO: We should avoid to run this hack on fixed builds. When we get
|
|
// exact build number, we should get back here.
|
|
static bool sTSFMayCrashIfGetSelectionReturnsError =
|
|
IsWin10AnniversaryUpdateOrLater();
|
|
return sTSFMayCrashIfGetSelectionReturnsError;
|
|
}
|
|
|
|
TSFUtils::AutoRangeExtant::AutoRangeExtant(ITfRange* aRange) {
|
|
RefPtr<ITfRangeACP> rangeACP;
|
|
aRange->QueryInterface(IID_ITfRangeACP, getter_AddRefs(rangeACP));
|
|
if (MOZ_UNLIKELY(!rangeACP)) {
|
|
return;
|
|
}
|
|
mHR = rangeACP->GetExtent(&mStart, &mLength);
|
|
}
|
|
|
|
TextRangeType TSFUtils::GetTextRangeType(TF_DISPLAYATTRIBUTE& aDisplayAttr) {
|
|
switch (aDisplayAttr.bAttr) {
|
|
case TF_ATTR_TARGET_CONVERTED:
|
|
return TextRangeType::eSelectedClause;
|
|
case TF_ATTR_CONVERTED:
|
|
return TextRangeType::eConvertedClause;
|
|
case TF_ATTR_TARGET_NOTCONVERTED:
|
|
return TextRangeType::eSelectedRawClause;
|
|
default:
|
|
return TextRangeType::eRawClause;
|
|
}
|
|
}
|
|
|
|
Maybe<nscolor> TSFUtils::GetColor(const TF_DA_COLOR& aTSFColor) {
|
|
switch (aTSFColor.type) {
|
|
case TF_CT_SYSCOLOR: {
|
|
DWORD sysColor = ::GetSysColor(aTSFColor.nIndex);
|
|
return Some(NS_RGB(GetRValue(sysColor), GetGValue(sysColor),
|
|
GetBValue(sysColor)));
|
|
}
|
|
case TF_CT_COLORREF:
|
|
return Some(NS_RGB(GetRValue(aTSFColor.cr), GetGValue(aTSFColor.cr),
|
|
GetBValue(aTSFColor.cr)));
|
|
case TF_CT_NONE:
|
|
default:
|
|
return Nothing();
|
|
}
|
|
}
|
|
|
|
Maybe<TextRangeStyle::LineStyle> TSFUtils::GetLineStyle(
|
|
TF_DA_LINESTYLE aTSFLineStyle) {
|
|
switch (aTSFLineStyle) {
|
|
case TF_LS_NONE:
|
|
return Some(TextRangeStyle::LineStyle::None);
|
|
case TF_LS_SOLID:
|
|
return Some(TextRangeStyle::LineStyle::Solid);
|
|
case TF_LS_DOT:
|
|
return Some(TextRangeStyle::LineStyle::Dotted);
|
|
case TF_LS_DASH:
|
|
return Some(TextRangeStyle::LineStyle::Dashed);
|
|
case TF_LS_SQUIGGLE:
|
|
return Some(TextRangeStyle::LineStyle::Wavy);
|
|
default:
|
|
return Nothing();
|
|
}
|
|
}
|
|
|
|
bool TSFUtils::ShouldSetInputScopeOfURLBarToDefault() {
|
|
// FYI: Google Japanese Input may be an IMM-IME. If it's installed on
|
|
// Win7, it's always IMM-IME. Otherwise, basically, it's a TIP.
|
|
// However, if it's installed on Win7 and has not been updated yet
|
|
// after the OS is upgraded to Win8 or later, it's still an IMM-IME.
|
|
// Therefore, we also need to check with IMMHandler here.
|
|
if (!StaticPrefs::intl_ime_hack_set_input_scope_of_url_bar_to_default()) {
|
|
return false;
|
|
}
|
|
|
|
if (IMMHandler::IsGoogleJapaneseInputActive()) {
|
|
return true;
|
|
}
|
|
|
|
switch (TSFStaticSink::ActiveTIP()) {
|
|
case TextInputProcessorID::MicrosoftIMEForJapanese:
|
|
case TextInputProcessorID::GoogleJapaneseInput:
|
|
case TextInputProcessorID::MicrosoftBopomofo:
|
|
case TextInputProcessorID::MicrosoftChangJie:
|
|
case TextInputProcessorID::MicrosoftPhonetic:
|
|
case TextInputProcessorID::MicrosoftQuick:
|
|
case TextInputProcessorID::MicrosoftNewChangJie:
|
|
case TextInputProcessorID::MicrosoftNewPhonetic:
|
|
case TextInputProcessorID::MicrosoftNewQuick:
|
|
case TextInputProcessorID::MicrosoftPinyin:
|
|
case TextInputProcessorID::MicrosoftPinyinNewExperienceInputStyle:
|
|
case TextInputProcessorID::MicrosoftOldHangul:
|
|
case TextInputProcessorID::MicrosoftWubi:
|
|
case TextInputProcessorID::MicrosoftIMEForKorean:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
TSFUtils::AttrIndex TSFUtils::GetRequestedAttrIndex(const TS_ATTRID& aAttrID) {
|
|
if (IsEqualGUID(aAttrID, GUID_PROP_INPUTSCOPE)) {
|
|
return AttrIndex::InputScope;
|
|
}
|
|
if (IsEqualGUID(aAttrID, sGUID_PROP_URL)) {
|
|
return AttrIndex::DocumentURL;
|
|
}
|
|
if (IsEqualGUID(aAttrID, TSATTRID_Text_VerticalWriting)) {
|
|
return AttrIndex::TextVerticalWriting;
|
|
}
|
|
if (IsEqualGUID(aAttrID, TSATTRID_Text_Orientation)) {
|
|
return AttrIndex::TextOrientation;
|
|
}
|
|
return AttrIndex::NotSupported;
|
|
}
|
|
|
|
TS_ATTRID TSFUtils::GetAttrID(AttrIndex aIndex) {
|
|
switch (aIndex) {
|
|
case AttrIndex::InputScope:
|
|
return GUID_PROP_INPUTSCOPE;
|
|
case AttrIndex::DocumentURL:
|
|
return sGUID_PROP_URL;
|
|
case AttrIndex::TextVerticalWriting:
|
|
return TSATTRID_Text_VerticalWriting;
|
|
case AttrIndex::TextOrientation:
|
|
return TSATTRID_Text_Orientation;
|
|
default:
|
|
MOZ_CRASH("Invalid index? Or not implemented yet?");
|
|
return GUID_NULL;
|
|
}
|
|
}
|
|
|
|
Result<RefPtr<ITfCompartment>, bool> TSFUtils::GetCompartment(IUnknown* pUnk,
|
|
const GUID& aID) {
|
|
if (MOZ_UNLIKELY(!pUnk)) {
|
|
return Err(false);
|
|
}
|
|
|
|
RefPtr<ITfCompartmentMgr> compMgr;
|
|
pUnk->QueryInterface(IID_ITfCompartmentMgr, getter_AddRefs(compMgr));
|
|
if (MOZ_UNLIKELY(!compMgr)) {
|
|
return Err(false);
|
|
}
|
|
|
|
RefPtr<ITfCompartment> compartment;
|
|
HRESULT hr = compMgr->GetCompartment(aID, getter_AddRefs(compartment));
|
|
if (MOZ_UNLIKELY(FAILED(hr) || !compartment)) {
|
|
return Err(false);
|
|
}
|
|
return std::move(compartment);
|
|
}
|
|
|
|
bool TSFUtils::MarkContextAsKeyboardDisabled(ITfContext* aContext) {
|
|
VARIANT variant_int4_value1;
|
|
variant_int4_value1.vt = VT_I4;
|
|
variant_int4_value1.lVal = 1;
|
|
|
|
Result<RefPtr<ITfCompartment>, bool> compartmentOrError =
|
|
TSFUtils::GetCompartment(aContext, GUID_COMPARTMENT_KEYBOARD_DISABLED);
|
|
if (MOZ_UNLIKELY(compartmentOrError.isErr())) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::MarkContextAsKeyboardDisabled(aContext=0x%p) failed",
|
|
aContext));
|
|
return false;
|
|
}
|
|
|
|
MOZ_LOG(gIMELog, LogLevel::Debug,
|
|
("TSFUtils::MarkContextAsKeyboardDisabled(), setting "
|
|
"to disable context 0x%p...",
|
|
aContext));
|
|
return SUCCEEDED(
|
|
compartmentOrError.unwrap()->SetValue(sClientId, &variant_int4_value1));
|
|
}
|
|
|
|
bool TSFUtils::MarkContextAsEmpty(ITfContext* aContext) {
|
|
VARIANT variant_int4_value1;
|
|
variant_int4_value1.vt = VT_I4;
|
|
variant_int4_value1.lVal = 1;
|
|
|
|
Result<RefPtr<ITfCompartment>, bool> compartmentOrError =
|
|
TSFUtils::GetCompartment(aContext, GUID_COMPARTMENT_EMPTYCONTEXT);
|
|
if (MOZ_UNLIKELY(compartmentOrError.isErr())) {
|
|
MOZ_LOG(gIMELog, LogLevel::Error,
|
|
("TSFUtils::MarkContextAsEmpty(aContext=%p) failed", aContext));
|
|
return false;
|
|
}
|
|
|
|
MOZ_LOG(gIMELog, LogLevel::Debug,
|
|
("TSFUtils::MarkContextAsEmpty(aContext=%p), setting to mark as "
|
|
"empty context",
|
|
aContext));
|
|
return SUCCEEDED(
|
|
compartmentOrError.unwrap()->SetValue(sClientId, &variant_int4_value1));
|
|
}
|
|
|
|
} // namespace mozilla::widget
|