Bug 961703 Commit or cancel composition when text/selection/focus is changed during composition for avoiding making some TIPs confused r=m_kato

This commit is contained in:
Masayuki Nakano 2014-01-23 18:36:01 +09:00
Родитель f4da7ac2d5
Коммит d50712b914
1 изменённых файлов: 75 добавлений и 34 удалений

Просмотреть файл

@ -678,7 +678,15 @@ bool
nsTextStore::Destroy(void) nsTextStore::Destroy(void)
{ {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, 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(); mContent.Clear();
mSelection.MarkDirty(); mSelection.MarkDirty();
@ -3065,38 +3073,54 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart,
{ {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, " ("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(), this, aStart, aOldEnd, aNewEnd, mSink.get(),
GetSinkMaskNameStr(mSinkMask).get())); GetSinkMaskNameStr(mSinkMask).get(),
GetBoolName(mComposition.IsComposing())));
if (IsReadLocked()) { if (IsReadLocked()) {
return NS_OK; return NS_OK;
} }
NS_ASSERTION(!mComposition.IsComposing(), "text changed during composition");
mSelection.MarkDirty(); mSelection.MarkDirty();
if (mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE)) { if (!mSink || !(mSinkMask & TS_AS_TEXT_CHANGE)) {
if (aStart >= INT32_MAX || aOldEnd >= INT32_MAX || aNewEnd >= INT32_MAX) { return NS_OK;
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<LONG>(aStart);
textChange.acpOldEnd = static_cast<LONG>(aOldEnd);
textChange.acpNewEnd = static_cast<LONG>(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 (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<LONG>(aStart);
textChange.acpOldEnd = static_cast<LONG>(aOldEnd);
textChange.acpNewEnd = static_cast<LONG>(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; return NS_OK;
} }
@ -3105,27 +3129,44 @@ nsTextStore::OnSelectionChangeInternal(void)
{ {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), " ("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(), this, mSink.get(), GetSinkMaskNameStr(mSinkMask).get(),
GetBoolName(mIsRecordingActionsWithoutLock))); GetBoolName(mIsRecordingActionsWithoutLock),
GetBoolName(mComposition.IsComposing())));
if (IsReadLocked()) { if (IsReadLocked()) {
return NS_OK; return NS_OK;
} }
NS_ASSERTION(!mComposition.IsComposing(),
"selection changed during composition");
mSelection.MarkDirty(); 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, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), calling " ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), calling "
"mSink->OnSelectionChange()...", this)); "mSink->OnSelectionChange()...", this));
if (!mIsRecordingActionsWithoutLock) { mSink->OnSelectionChange();
mSink->OnSelectionChange(); } else {
} else { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
mNotifySelectionChange = true; ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), pending "
} "a call of mSink->OnSelectionChange()...", this));
mNotifySelectionChange = true;
} }
return NS_OK; return NS_OK;
} }