Bug 1958821 - Make TSFUtils::OnFocusChange reuse TSFEmptyTextStore instance r=m_kato
`TSFEmptyTextStore` needs to create some TSF objects and need to call some their methods. To avoid its cost, we should reuse `TSFEmptyTextStore` as far as possible. Depends on D245348 Differential Revision: https://phabricator.services.mozilla.com/D245349
This commit is contained in:
@@ -440,43 +440,58 @@ TSFEmptyTextStore::CreateAndSetFocus(nsWindow* aFocusedWindow,
|
||||
TSFUtils::ClearStoringTextStoresIf(textStore);
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
const RefPtr<ITfDocumentMgr> newDocMgr = textStore->mDocumentMgr;
|
||||
if (NS_WARN_IF(!newDocMgr)) {
|
||||
MOZ_LOG(gIMELog, LogLevel::Error,
|
||||
(" TSFEmptyTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"invalid TSFEmptyTextStore::mDocumentMgr"));
|
||||
nsresult rv = textStore->SetFocus(aFocusedWindow, aContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
textStore->Destroy();
|
||||
TSFUtils::ClearStoringTextStoresIf(textStore);
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return Err(rv);
|
||||
}
|
||||
return textStore;
|
||||
}
|
||||
|
||||
nsresult TSFEmptyTextStore::SetFocus(nsWindow* aFocusedWindow,
|
||||
const InputContext& aContext) {
|
||||
const RefPtr<ITfDocumentMgr> docMgr = mDocumentMgr;
|
||||
if (NS_WARN_IF(!docMgr)) {
|
||||
MOZ_LOG(gIMELog, LogLevel::Error,
|
||||
(" TSFEmptyTextStore::SetFocus() FAILED due to "
|
||||
"invalid TSFEmptyTextStore::mDocumentMgr"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
const RefPtr<ITfThreadMgr> threadMgr = TSFUtils::GetThreadMgr();
|
||||
if (NS_WARN_IF(FAILED(threadMgr->SetFocus(newDocMgr)))) {
|
||||
if (NS_WARN_IF(FAILED(threadMgr->SetFocus(docMgr)))) {
|
||||
MOZ_LOG(gIMELog, LogLevel::Error,
|
||||
(" TSFEmptyTextStore::CreateAndSetFocus() FAILED due to "
|
||||
(" TSFEmptyTextStore::SetFocus() FAILED due to "
|
||||
"ITfTheadMgr::SetFocus() failure"));
|
||||
textStore->Destroy();
|
||||
TSFUtils::ClearStoringTextStoresIf(textStore);
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (NS_WARN_IF(!TSFUtils::GetThreadMgr())) {
|
||||
MOZ_LOG(gIMELog, LogLevel::Error,
|
||||
(" TSFEmptyTextStore::CreateAndSetFocus() FAILED due to "
|
||||
(" TSFEmptyTextStore::SetFocus() FAILED due to "
|
||||
"sThreadMgr being destroyed during calling "
|
||||
"ITfTheadMgr::SetFocus()"));
|
||||
textStore->Destroy();
|
||||
TSFUtils::ClearStoringTextStoresIf(textStore);
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (NS_WARN_IF(TSFUtils::GetCurrentTextStore())) {
|
||||
MOZ_LOG(gIMELog, LogLevel::Error,
|
||||
(" TSFEmptyTextStore::CreateAndSetFocus() FAILED due to "
|
||||
(" TSFEmptyTextStore::SetFocus() FAILED due to "
|
||||
"creating TextStore has lost focus during calling "
|
||||
"ITfThreadMgr::SetFocus()"));
|
||||
textStore->Destroy();
|
||||
TSFUtils::ClearStoringTextStoresIf(textStore);
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return textStore;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TSFEmptyTextStore::SetFocusAndUpdateDocumentURLAndBrowsingMode(
|
||||
nsWindow* aFocusedWindow, const InputContext& aContext) {
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
UpdateDocumentURLAndBrowsingMode(aFocusedWindow, aContext)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(SetFocus(aFocusedWindow, aContext)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IMENotificationRequests TSFEmptyTextStore::GetIMENotificationRequests() const {
|
||||
|
||||
@@ -67,6 +67,9 @@ class TSFEmptyTextStore final : public TSFTextStoreBase {
|
||||
[[nodiscard]] static Result<RefPtr<TSFEmptyTextStore>, nsresult>
|
||||
CreateAndSetFocus(nsWindow* aFocusedWindow, const InputContext& aContext);
|
||||
|
||||
nsresult SetFocusAndUpdateDocumentURLAndBrowsingMode(
|
||||
nsWindow* aFocusedWindow, const InputContext& aContext);
|
||||
|
||||
protected:
|
||||
TSFEmptyTextStore();
|
||||
virtual ~TSFEmptyTextStore();
|
||||
@@ -74,6 +77,8 @@ class TSFEmptyTextStore final : public TSFTextStoreBase {
|
||||
bool Init(nsWindow* aWidget, const InputContext& aContext);
|
||||
void ReleaseTSFObjects();
|
||||
|
||||
nsresult SetFocus(nsWindow* aFocusedWindow, const InputContext& aContext);
|
||||
|
||||
// This is called immediately after a call of OnLockGranted() of mSink.
|
||||
// Note that mLock isn't cleared yet when this is called.
|
||||
void DidLockGranted() final {
|
||||
|
||||
@@ -532,6 +532,7 @@ 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(
|
||||
@@ -583,6 +584,10 @@ void TSFUtils::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();
|
||||
@@ -649,34 +654,34 @@ nsresult TSFUtils::OnFocusChange(GotFocus aGotFocus, nsWindow* aFocusedWindow,
|
||||
// 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() &&
|
||||
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());
|
||||
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 a focused TextStore, we won't use it with new focused
|
||||
// editor. So, release it now.
|
||||
if (oldTextStore) {
|
||||
// Even if there was an editable focused TextStore, we won't use it with new
|
||||
// focused editor. So, release it now.
|
||||
oldTextStore->Destroy();
|
||||
}
|
||||
|
||||
@@ -701,6 +706,22 @@ nsresult TSFUtils::OnFocusChange(GotFocus aGotFocus, nsWindow* aFocusedWindow,
|
||||
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())) {
|
||||
@@ -709,7 +730,12 @@ nsresult TSFUtils::OnFocusChange(GotFocus aGotFocus, nsWindow* aFocusedWindow,
|
||||
"create and set focus to new TSFEmptyTextStore"));
|
||||
return ret.unwrapErr();
|
||||
}
|
||||
sCurrentTextStore = ret.unwrap().forget();
|
||||
if (const RefPtr<TSFEmptyTextStore> oldEmptyTextStore =
|
||||
sEmptyTextStore.forget()) {
|
||||
oldEmptyTextStore->Destroy();
|
||||
}
|
||||
sEmptyTextStore = ret.unwrap().forget();
|
||||
sCurrentTextStore = sEmptyTextStore;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla::widget {
|
||||
class TSFEmptyTextStore;
|
||||
class TSFTextStore;
|
||||
class TSFTextStoreBase;
|
||||
struct IMENotificationRequests;
|
||||
@@ -280,6 +281,9 @@ class TSFUtils final {
|
||||
// Current text store which may be an empty one for disabled state.
|
||||
static StaticRefPtr<TSFTextStoreBase> sCurrentTextStore;
|
||||
|
||||
// Global instance for non-editable state.
|
||||
static StaticRefPtr<TSFEmptyTextStore> sEmptyTextStore;
|
||||
|
||||
// TSF client ID for the current application
|
||||
static DWORD sClientId;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user