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:
Masayuki Nakano
2025-04-17 08:30:04 +00:00
parent 11f14aca31
commit 36f67d0eb3
4 changed files with 97 additions and 47 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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;
};