commit 905d0f6bed2095a68e076ac1d619c35459bde6cb
parent 5a9aae988c77e85395f94537fd06f4be51cf197d
Author: Masayuki Nakano <masayuki@d-toybox.com>
Date: Wed, 12 Nov 2025 22:52:08 +0000
Bug 1824143 - part 2: Make `TSFTextStore::FlushPendingActions()` set `mDeferNotifyingTSFUntilNextUpdate` before dispatching composition events r=m_kato
This fixes a regression of bug 1137561. That made `TSFTextStore` stop
dispatching composition events directly. However, its dispatcher sets
`mDeferNotifyingTSFUntilNextUpdate` to notify TSF of anything until
it receives `NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED` since
`GetTextExt()` etc will return error if the layout has not be updated.
So, we started return `E_FAIL` a lot from various `ITextStoreACP`
methods if TSF/TIP queries something immediately after updating
the composition.
Differential Revision: https://phabricator.services.mozilla.com/D271560
Diffstat:
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp
@@ -353,7 +353,12 @@ void TSFTextStore::FlushPendingActions() {
break;
}
+ const bool hadDeferredNotifyingTSFUnTilNextUpdate =
+ mDeferNotifyingTSFUntilNextUpdate;
if (action.mAdjustSelection) {
+ // Don't notify TSF until we receive
+ // NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
+ mDeferNotifyingTSFUntilNextUpdate = true;
// Select composition range so the new composition replaces the range
WidgetSelectionEvent selectionSet(true, eSetSelection, widget);
widget->InitEvent(selectionSet);
@@ -371,6 +376,8 @@ void TSFTextStore::FlushPendingActions() {
("0x%p TSFTextStore::FlushPendingActions() "
"FAILED due to eSetSelection failure",
this));
+ mDeferNotifyingTSFUntilNextUpdate =
+ hadDeferredNotifyingTSFUnTilNextUpdate;
break;
}
}
@@ -379,6 +386,9 @@ void TSFTextStore::FlushPendingActions() {
// NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED. Therefore, we should
// wait to clear mContentForTSF until it's notified.
mDeferClearingContentForTSF = true;
+ // Don't notify TSF until we receive
+ // NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
+ mDeferNotifyingTSFUntilNextUpdate = true;
MOZ_LOG(gIMELog, LogLevel::Debug,
("0x%p TSFTextStore::FlushPendingActions() "
@@ -394,6 +404,8 @@ void TSFTextStore::FlushPendingActions() {
"FAILED to dispatch compositionstart event, "
"IsHandlingCompositionInContent()=%s",
this, TSFUtils::BoolToChar(IsHandlingCompositionInContent())));
+ mDeferNotifyingTSFUntilNextUpdate =
+ hadDeferredNotifyingTSFUnTilNextUpdate;
// XXX Is this right? If there is a composition in content,
// shouldn't we wait NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED?
mDeferClearingContentForTSF = !IsHandlingCompositionInContent();
@@ -436,6 +448,11 @@ void TSFTextStore::FlushPendingActions() {
this));
WidgetEventTime eventTime = widget->CurrentMessageWidgetEventTime();
nsEventStatus status;
+ // Don't notify TSF until we receive
+ // NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
+ const bool hadDeferredNotifyingTSFUnTilNextUpdate =
+ mDeferNotifyingTSFUntilNextUpdate;
+ mDeferNotifyingTSFUntilNextUpdate = true;
rv = mDispatcher->FlushPendingComposition(status, &eventTime);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(
@@ -444,6 +461,8 @@ void TSFTextStore::FlushPendingActions() {
"FAILED to dispatch compositionchange event, "
"IsHandlingCompositionInContent()=%s",
this, TSFUtils::BoolToChar(IsHandlingCompositionInContent())));
+ mDeferNotifyingTSFUntilNextUpdate =
+ hadDeferredNotifyingTSFUnTilNextUpdate;
// XXX Is this right? If there is a composition in content,
// shouldn't we wait NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED?
mDeferClearingContentForTSF = !IsHandlingCompositionInContent();
@@ -473,6 +492,11 @@ void TSFTextStore::FlushPendingActions() {
this));
WidgetEventTime eventTime = widget->CurrentMessageWidgetEventTime();
nsEventStatus status;
+ // Don't notify TSF until we receive
+ // NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
+ const bool hadDeferredNotifyingTSFUnTilNextUpdate =
+ mDeferNotifyingTSFUntilNextUpdate;
+ mDeferNotifyingTSFUntilNextUpdate = true;
rv = mDispatcher->CommitComposition(status, &action.mData, &eventTime);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(
@@ -481,6 +505,8 @@ void TSFTextStore::FlushPendingActions() {
"FAILED to dispatch compositioncommit event, "
"IsHandlingCompositionInContent()=%s",
this, TSFUtils::BoolToChar(IsHandlingCompositionInContent())));
+ mDeferNotifyingTSFUntilNextUpdate =
+ hadDeferredNotifyingTSFUnTilNextUpdate;
// XXX Is this right? If there is a composition in content,
// shouldn't we wait NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED?
mDeferClearingContentForTSF = !IsHandlingCompositionInContent();
@@ -505,6 +531,12 @@ void TSFTextStore::FlushPendingActions() {
break;
}
+ // Don't notify TSF until we receive
+ // NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
+ const bool hadDeferredNotifyingTSFUnTilNextUpdate =
+ mDeferNotifyingTSFUntilNextUpdate;
+ mDeferNotifyingTSFUntilNextUpdate = true;
+
WidgetSelectionEvent selectionSet(true, eSetSelection, widget);
selectionSet.mOffset = static_cast<uint32_t>(action.mSelectionStart);
selectionSet.mLength = static_cast<uint32_t>(action.mSelectionLength);
@@ -519,6 +551,8 @@ void TSFTextStore::FlushPendingActions() {
("0x%p TSFTextStore::FlushPendingActions() "
"FAILED due to eSetSelection failure",
this));
+ mDeferNotifyingTSFUntilNextUpdate =
+ hadDeferredNotifyingTSFUnTilNextUpdate;
break;
}
break;
diff --git a/widget/windows/TSFTextStoreBase.cpp b/widget/windows/TSFTextStoreBase.cpp
@@ -313,11 +313,6 @@ void TSFTextStoreBase::DispatchEvent(WidgetGUIEvent& aEvent) {
if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
return;
}
- // If the event isn't a query content event, the event may be handled
- // asynchronously. So, we should put off to answer from GetTextExt() etc.
- if (!aEvent.AsQueryContentEvent()) {
- mDeferNotifyingTSFUntilNextUpdate = true;
- }
mWidget->DispatchWindowEvent(aEvent);
}