diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/nsTextStore.cpp index de06a6cbc178..9d61e296400b 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -678,7 +678,15 @@ bool nsTextStore::Destroy(void) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::Destroy()", this)); + ("TSF: 0x%p nsTextStore::Destroy(), mComposition.IsComposing()=%s", + this, GetBoolName(mComposition.IsComposing()))); + + // If there is composition, TSF keeps the composition even after the text + // store destroyed. So, we should clear the composition here. + if (mComposition.IsComposing()) { + NS_WARNING("Composition is still alive at destroying the text store"); + CommitCompositionInternal(false); + } mContent.Clear(); mSelection.MarkDirty(); @@ -3065,38 +3073,54 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart, { PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, " - "aOldEnd=%lu, aNewEnd=%lu), mSink=0x%p, mSinkMask=%s", + "aOldEnd=%lu, aNewEnd=%lu), mSink=0x%p, mSinkMask=%s, " + "mComposition.IsComposing()=%s", this, aStart, aOldEnd, aNewEnd, mSink.get(), - GetSinkMaskNameStr(mSinkMask).get())); + GetSinkMaskNameStr(mSinkMask).get(), + GetBoolName(mComposition.IsComposing()))); if (IsReadLocked()) { return NS_OK; } - NS_ASSERTION(!mComposition.IsComposing(), "text changed during composition"); mSelection.MarkDirty(); - if (mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE)) { - if (aStart >= INT32_MAX || aOldEnd >= INT32_MAX || aNewEnd >= INT32_MAX) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::OnTextChangeInternal() FAILED due to " - "offset is too big for calling mSink->OnTextChange()...", - this)); - return NS_OK; - } - - TS_TEXTCHANGE textChange; - textChange.acpStart = static_cast(aStart); - textChange.acpOldEnd = static_cast(aOldEnd); - textChange.acpNewEnd = static_cast(aNewEnd); - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::OnTextChangeInternal(), calling" - "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " - "acpNewEnd=%ld })...", this, textChange.acpStart, - textChange.acpOldEnd, textChange.acpNewEnd)); - mSink->OnTextChange(0, &textChange); + if (!mSink || !(mSinkMask & TS_AS_TEXT_CHANGE)) { + return NS_OK; } + + if (aStart >= INT32_MAX || aOldEnd >= INT32_MAX || aNewEnd >= INT32_MAX) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnTextChangeInternal() FAILED due to " + "offset is too big for calling mSink->OnTextChange()...", + this)); + return NS_OK; + } + + // Some TIPs are confused by text change notification during composition. + // Especially, some of them stop working for composition in our process. + // For preventing it, let's commit the composition. + if (mComposition.IsComposing()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(), " + "committing the composition for avoiding making TIP confused...", + this)); + CommitCompositionInternal(false); + return NS_OK; + } + + TS_TEXTCHANGE textChange; + textChange.acpStart = static_cast(aStart); + textChange.acpOldEnd = static_cast(aOldEnd); + textChange.acpNewEnd = static_cast(aNewEnd); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(), calling" + "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " + "acpNewEnd=%ld })...", this, textChange.acpStart, + textChange.acpOldEnd, textChange.acpNewEnd)); + mSink->OnTextChange(0, &textChange); + return NS_OK; } @@ -3105,27 +3129,44 @@ nsTextStore::OnSelectionChangeInternal(void) { PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), " - "mSink=0x%p, mSinkMask=%s, mIsRecordingActionsWithoutLock=%s", + "mSink=0x%p, mSinkMask=%s, mIsRecordingActionsWithoutLock=%s, " + "mComposition.IsComposing()=%s", this, mSink.get(), GetSinkMaskNameStr(mSinkMask).get(), - GetBoolName(mIsRecordingActionsWithoutLock))); + GetBoolName(mIsRecordingActionsWithoutLock), + GetBoolName(mComposition.IsComposing()))); if (IsReadLocked()) { return NS_OK; } - NS_ASSERTION(!mComposition.IsComposing(), - "selection changed during composition"); mSelection.MarkDirty(); - if (mSink && 0 != (mSinkMask & TS_AS_SEL_CHANGE)) { + if (!mSink || !(mSinkMask & TS_AS_SEL_CHANGE)) { + return NS_OK; + } + + // Some TIPs are confused by selection change notification during composition. + // Especially, some of them stop working for composition in our process. + // For preventing it, let's commit the composition. + if (mComposition.IsComposing()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), " + "committing the composition for avoiding making TIP confused...", + this)); + CommitCompositionInternal(false); + return NS_OK; + } + + if (!mIsRecordingActionsWithoutLock) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), calling " "mSink->OnSelectionChange()...", this)); - if (!mIsRecordingActionsWithoutLock) { - mSink->OnSelectionChange(); - } else { - mNotifySelectionChange = true; - } + mSink->OnSelectionChange(); + } else { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), pending " + "a call of mSink->OnSelectionChange()...", this)); + mNotifySelectionChange = true; } return NS_OK; }