Bug 790516 part.1 Move composition string data of nsTextStore into a nested class r=emk

This commit is contained in:
Masayuki Nakano
2013-03-13 12:01:29 +09:00
parent da86de1516
commit 1034fa1d93
2 changed files with 248 additions and 199 deletions

View File

@@ -496,10 +496,7 @@ nsTextStore::~nsTextStore()
"mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p", "mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p",
this, mWidget.get(), mDocumentMgr.get(), mContext.get())); this, mWidget.get(), mDocumentMgr.get(), mContext.get()));
if (mCompositionTimer) { mComposition.EnsureLayoutChangeTimerStopped();
mCompositionTimer->Cancel();
mCompositionTimer = nullptr;
}
SaveTextEvent(nullptr); SaveTextEvent(nullptr);
} }
@@ -886,13 +883,13 @@ nsTextStore::GetSelection(ULONG ulIndex,
bool bool
nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP) nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP)
{ {
if (mCompositionView) { if (mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::GetSelectionInternal(), " ("TSF: 0x%p nsTextStore::GetSelectionInternal(), "
"there is no composition view", this)); "there is no composition view", this));
// Emulate selection during compositions // Emulate selection during compositions
aSelectionACP = mCompositionSelection; aSelectionACP = mComposition.mSelection;
} else { } else {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::GetSelectionInternal(), " ("TSF: 0x%p nsTextStore::GetSelectionInternal(), "
@@ -980,7 +977,8 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty,
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::GetDisplayAttribute(): " ("TSF: 0x%p nsTextStore::GetDisplayAttribute(): "
"GetDisplayAttribute range=%ld-%ld (hr=%s)", "GetDisplayAttribute range=%ld-%ld (hr=%s)",
this, start - mCompositionStart, start - mCompositionStart + length, this, start - mComposition.mStart,
start - mComposition.mStart + length,
GetCommonReturnValueName(hr))); GetCommonReturnValueName(hr)));
} }
#endif #endif
@@ -1094,9 +1092,9 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
{ {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::UpdateCompositionExtent(aRangeNew=0x%p), " ("TSF: 0x%p nsTextStore::UpdateCompositionExtent(aRangeNew=0x%p), "
"mCompositionView=0x%p", this, aRangeNew, mCompositionView.get())); "mComposition.mView=0x%p", this, aRangeNew, mComposition.mView.get()));
if (!mCompositionView) { if (!mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::UpdateCompositionExtent() FAILED due to " ("TSF: 0x%p nsTextStore::UpdateCompositionExtent() FAILED due to "
"no composition view", this)); "no composition view", this));
@@ -1104,7 +1102,7 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
} }
HRESULT hr; HRESULT hr;
nsRefPtr<ITfCompositionView> pComposition(mCompositionView); nsRefPtr<ITfCompositionView> pComposition(mComposition.mView);
nsRefPtr<ITfRange> composingRange(aRangeNew); nsRefPtr<ITfRange> composingRange(aRangeNew);
if (!composingRange) { if (!composingRange) {
hr = pComposition->GetRange(getter_AddRefs(composingRange)); hr = pComposition->GetRange(getter_AddRefs(composingRange));
@@ -1128,12 +1126,12 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::UpdateCompositionExtent(), range=%ld-%ld, " ("TSF: 0x%p nsTextStore::UpdateCompositionExtent(), range=%ld-%ld, "
"mCompositionStart=%ld, mCompositionString.Length()=%lu", "mComposition={ mStart=%ld, mString.Length()=%lu }",
this, compStart, compStart + compLength, mCompositionStart, this, compStart, compStart + compLength, mComposition.mStart,
mCompositionString.Length())); mComposition.mString.Length()));
if (mCompositionStart != compStart || if (mComposition.mStart != compStart ||
mCompositionString.Length() != (ULONG)compLength) { mComposition.mString.Length() != (ULONG)compLength) {
// If the queried composition length is different from the length // If the queried composition length is different from the length
// of our composition string, OnUpdateComposition is being called // of our composition string, OnUpdateComposition is being called
// because a part of the original composition was committed. // because a part of the original composition was committed.
@@ -1143,7 +1141,7 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
OnEndComposition(pComposition); OnEndComposition(pComposition);
OnStartCompositionInternal(pComposition, composingRange, true); OnStartCompositionInternal(pComposition, composingRange, true);
} else { } else {
mCompositionLength = compLength; mComposition.mLength = compLength;
} }
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
@@ -1200,11 +1198,11 @@ nsTextStore::SendTextEventForCompositionString()
{ {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString(), " ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString(), "
"mCompositionView=0x%p, mCompositionString=\"%s\"", "mComposition={ mView=0x%p, mString=\"%s\" }",
this, mCompositionView.get(), this, mComposition.mView.get(),
NS_ConvertUTF16toUTF8(mCompositionString).get())); NS_ConvertUTF16toUTF8(mComposition.mString).get()));
if (!mCompositionView) { if (!mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED "
"due to no composition view", this)); "due to no composition view", this));
@@ -1234,11 +1232,11 @@ nsTextStore::SendTextEventForCompositionString()
mWidget->InitEvent(event); mWidget->InitEvent(event);
nsRefPtr<ITfRange> composingRange; nsRefPtr<ITfRange> composingRange;
hr = mCompositionView->GetRange(getter_AddRefs(composingRange)); hr = mComposition.mView->GetRange(getter_AddRefs(composingRange));
if (FAILED(hr)) { if (FAILED(hr)) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED "
"due to mCompositionView->GetRange() failure", this)); "due to mComposition.mView->GetRange() failure", this));
return hr; return hr;
} }
@@ -1257,7 +1255,7 @@ nsTextStore::SendTextEventForCompositionString()
// No matter if we have display attribute info or not, // No matter if we have display attribute info or not,
// we always pass in at least one range to NS_TEXT_TEXT // we always pass in at least one range to NS_TEXT_TEXT
newRange.mStartOffset = 0; newRange.mStartOffset = 0;
newRange.mEndOffset = mCompositionString.Length(); newRange.mEndOffset = mComposition.mString.Length();
newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; newRange.mRangeType = NS_TEXTRANGE_RAWINPUT;
textRanges.AppendElement(newRange); textRanges.AppendElement(newRange);
@@ -1269,10 +1267,10 @@ nsTextStore::SendTextEventForCompositionString()
continue; continue;
nsTextRange newRange; nsTextRange newRange;
newRange.mStartOffset = uint32_t(start - mCompositionStart); newRange.mStartOffset = uint32_t(start - mComposition.mStart);
// The end of the last range in the array is // The end of the last range in the array is
// always kept at the end of composition // always kept at the end of composition
newRange.mEndOffset = mCompositionString.Length(); newRange.mEndOffset = mComposition.mString.Length();
TF_DISPLAYATTRIBUTE attr; TF_DISPLAYATTRIBUTE attr;
hr = GetDisplayAttribute(attrPropetry, range, &attr); hr = GetDisplayAttribute(attrPropetry, range, &attr);
@@ -1313,20 +1311,21 @@ nsTextStore::SendTextEventForCompositionString()
// We need to hack for Korean Input System which is Korean standard TIP. // We need to hack for Korean Input System which is Korean standard TIP.
// It sets no change style to IME selection (the selection is always only // It sets no change style to IME selection (the selection is always only
// one). So, the composition string looks like normal (or committed) string. // one). So, the composition string looks like normal (or committed) string.
// At this time, mCompositionSelection range is same as the composition // At this time, mComposition.mSelection range is same as the
// string range. Other applications set a wide caret which covers the // composition string range. Other applications set a wide caret which covers
// composition string, however, Gecko doesn't support the wide caret drawing // the composition string, however, Gecko doesn't support the wide caret
// now (Gecko doesn't support XOR drawing), unfortunately. For now, we should // drawing now (Gecko doesn't support XOR drawing), unfortunately. For now,
// change the range style to undefined. // we should change the range style to undefined.
if (mCompositionSelection.acpStart != mCompositionSelection.acpEnd && if (mComposition.mSelection.acpStart !=
mComposition.mSelection.acpEnd &&
textRanges.Length() == 1) { textRanges.Length() == 1) {
nsTextRange& range = textRanges[0]; nsTextRange& range = textRanges[0];
LONG start = std::min(mCompositionSelection.acpStart, LONG start = std::min(mComposition.mSelection.acpStart,
mCompositionSelection.acpEnd); mComposition.mSelection.acpEnd);
LONG end = std::max(mCompositionSelection.acpStart, LONG end = std::max(mComposition.mSelection.acpStart,
mCompositionSelection.acpEnd); mComposition.mSelection.acpEnd);
if ((LONG)range.mStartOffset == start - mCompositionStart && if ((LONG)range.mStartOffset == start - mComposition.mStart &&
(LONG)range.mEndOffset == end - mCompositionStart && (LONG)range.mEndOffset == end - mComposition.mStart &&
range.mRangeStyle.IsNoChangeStyle()) { range.mRangeStyle.IsNoChangeStyle()) {
range.mRangeStyle.Clear(); range.mRangeStyle.Clear();
// The looks of selected type is better than others. // The looks of selected type is better than others.
@@ -1335,15 +1334,15 @@ nsTextStore::SendTextEventForCompositionString()
} }
// The caret position has to be collapsed. // The caret position has to be collapsed.
LONG caretPosition = std::max(mCompositionSelection.acpStart, LONG caretPosition = std::max(mComposition.mSelection.acpStart,
mCompositionSelection.acpEnd); mComposition.mSelection.acpEnd);
caretPosition -= mCompositionStart; caretPosition -= mComposition.mStart;
nsTextRange caretRange; nsTextRange caretRange;
caretRange.mStartOffset = caretRange.mEndOffset = uint32_t(caretPosition); caretRange.mStartOffset = caretRange.mEndOffset = uint32_t(caretPosition);
caretRange.mRangeType = NS_TEXTRANGE_CARETPOSITION; caretRange.mRangeType = NS_TEXTRANGE_CARETPOSITION;
textRanges.AppendElement(caretRange); textRanges.AppendElement(caretRange);
event.theText = mCompositionString; event.theText = mComposition.mString;
event.rangeArray = textRanges.Elements(); event.rangeArray = textRanges.Elements();
event.rangeCount = textRanges.Length(); event.rangeCount = textRanges.Length();
@@ -1356,15 +1355,15 @@ nsTextStore::SendTextEventForCompositionString()
return S_OK; return S_OK;
} }
if (mCompositionString != mLastDispatchedCompositionString) { if (mComposition.mString != mComposition.mLastData) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() "
"dispatching compositionupdate event...", this)); "dispatching compositionupdate event...", this));
nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
mWidget); mWidget);
mWidget->InitEvent(compositionUpdate); mWidget->InitEvent(compositionUpdate);
compositionUpdate.data = mCompositionString; compositionUpdate.data = mComposition.mString;
mLastDispatchedCompositionString = mCompositionString; mComposition.mLastData = mComposition.mString;
mWidget->DispatchWindowEvent(&compositionUpdate); mWidget->DispatchWindowEvent(&compositionUpdate);
} }
@@ -1391,10 +1390,10 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection,
"aDispatchTextEvent=%s), %s", "aDispatchTextEvent=%s), %s",
this, pSelection->acpStart, pSelection->acpEnd, this, pSelection->acpStart, pSelection->acpEnd,
GetBoolName(aDispatchTextEvent), GetBoolName(aDispatchTextEvent),
mCompositionView ? "there is composition view" : mComposition.mView ? "there is composition view" :
"there is no composition view")); "there is no composition view"));
if (mCompositionView) { if (mComposition.mView) {
if (aDispatchTextEvent) { if (aDispatchTextEvent) {
HRESULT hr = UpdateCompositionExtent(nullptr); HRESULT hr = UpdateCompositionExtent(nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
@@ -1404,16 +1403,17 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection,
return hr; return hr;
} }
} }
if (pSelection->acpStart < mCompositionStart || if (pSelection->acpStart < mComposition.mStart ||
pSelection->acpEnd > pSelection->acpEnd >
mCompositionStart + static_cast<LONG>(mCompositionString.Length())) { mComposition.mStart +
static_cast<LONG>(mComposition.mString.Length())) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to "
"the selection being out of the composition string", this)); "the selection being out of the composition string", this));
return TS_E_INVALIDPOS; return TS_E_INVALIDPOS;
} }
// Emulate selection during compositions // Emulate selection during compositions
mCompositionSelection = *pSelection; mComposition.mSelection = *pSelection;
if (aDispatchTextEvent) { if (aDispatchTextEvent) {
HRESULT hr = SendTextEventForCompositionString(); HRESULT hr = SendTextEventForCompositionString();
if (FAILED(hr)) { if (FAILED(hr)) {
@@ -1494,14 +1494,14 @@ nsTextStore::GetText(LONG acpStart,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, " ("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, "
"cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, " "cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, "
"pulRunInfoOut=0x%p, pacpNext=0x%p), %s, mCompositionStart=%ld, " "pulRunInfoOut=0x%p, pacpNext=0x%p), %s, mComposition={ mStart=%ld, "
"mCompositionLength=%ld, mCompositionString.Length()=%lu", "mLength=%ld, mString.Length()=%lu }",
this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut, this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut,
prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext, prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext,
mCompositionView ? "there is composition view" : mComposition.mView ? "there is composition view" :
"there is no composition view", "there is no composition view",
mCompositionStart, mCompositionLength, mComposition.mStart, mComposition.mLength,
mCompositionString.Length())); mComposition.mString.Length()));
if (!IsReadLocked()) { if (!IsReadLocked()) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
@@ -1540,20 +1540,22 @@ nsTextStore::GetText(LONG acpStart,
} }
if (length) { if (length) {
LONG compNewStart = 0, compOldEnd = 0, compNewEnd = 0; LONG compNewStart = 0, compOldEnd = 0, compNewEnd = 0;
if (mCompositionView) { if (mComposition.mView) {
// Sometimes GetText gets called between InsertTextAtSelection and // Sometimes GetText gets called between InsertTextAtSelection and
// OnUpdateComposition. In this case the returned text would // OnUpdateComposition. In this case the returned text would
// be out of sync because we haven't sent NS_TEXT_TEXT in // be out of sync because we haven't sent NS_TEXT_TEXT in
// OnUpdateComposition yet. Manually resync here. // OnUpdateComposition yet. Manually resync here.
compOldEnd = std::min(LONG(length) + acpStart, compOldEnd = std::min(LONG(length) + acpStart,
mCompositionLength + mCompositionStart); mComposition.mLength + mComposition.mStart);
compNewEnd = std::min(LONG(length) + acpStart, compNewEnd = std::min(LONG(length) + acpStart,
LONG(mCompositionString.Length()) + mCompositionStart); LONG(mComposition.mString.Length()) +
compNewStart = std::max(acpStart, mCompositionStart); mComposition.mStart);
compNewStart = std::max(acpStart, mComposition.mStart);
// Check if the range is affected // Check if the range is affected
if (compOldEnd > compNewStart || compNewEnd > compNewStart) { if (compOldEnd > compNewStart || compNewEnd > compNewStart) {
NS_ASSERTION(compOldEnd >= mCompositionStart && NS_ASSERTION(compOldEnd >= mComposition.mStart &&
compNewEnd >= mCompositionStart, "Range end is less than start\n"); compNewEnd >= mComposition.mStart,
"Range end is less than start\n");
length = uint32_t(LONG(length) + compOldEnd - compNewEnd); length = uint32_t(LONG(length) + compOldEnd - compNewEnd);
} }
} }
@@ -1571,11 +1573,12 @@ nsTextStore::GetText(LONG acpStart,
if (compOldEnd > compNewStart || compNewEnd > compNewStart) { if (compOldEnd > compNewStart || compNewEnd > compNewStart) {
// Resync composition string // Resync composition string
const PRUnichar* compStrStart = mCompositionString.BeginReading() + const PRUnichar* compStrStart =
std::max<LONG>(compNewStart - mCompositionStart, 0); mComposition.mString.BeginReading() +
std::max<LONG>(compNewStart - mComposition.mStart, 0);
event.mReply.mString.Replace(compNewStart - acpStart, event.mReply.mString.Replace(compNewStart - acpStart,
compOldEnd - mCompositionStart, compStrStart, compOldEnd - mComposition.mStart, compStrStart,
compNewEnd - mCompositionStart); compNewEnd - mComposition.mStart);
length = uint32_t(LONG(length) - compOldEnd + compNewEnd); length = uint32_t(LONG(length) - compOldEnd + compNewEnd);
} }
if (-1 != acpEnd && event.mReply.mString.Length() != length) { if (-1 != acpEnd && event.mReply.mString.Length() != length) {
@@ -1627,7 +1630,7 @@ nsTextStore::SetText(DWORD dwFlags,
pchText && cch ? pchText && cch ?
NS_ConvertUTF16toUTF8(pchText, cch).get() : "", NS_ConvertUTF16toUTF8(pchText, cch).get() : "",
cch, pChange, cch, pChange,
mCompositionView ? "there is composition view" : mComposition.mView ? "there is composition view" :
"there is no composition view")); "there is no composition view"));
// Per SDK documentation, and since we don't have better // Per SDK documentation, and since we don't have better
@@ -2263,7 +2266,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
pchText, pchText,
pchText && cch ? NS_ConvertUTF16toUTF8(pchText, cch).get() : "", pchText && cch ? NS_ConvertUTF16toUTF8(pchText, cch).get() : "",
cch, pacpStart, pacpEnd, pChange, cch, pacpStart, pacpEnd, pChange,
mCompositionView ? "there is composition view" : mComposition.mView ? "there is composition view" :
"there is no composition view")); "there is no composition view"));
if (cch && !pchText) { if (cch && !pchText) {
@@ -2358,34 +2361,35 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal(" ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal("
"aInsertStr=\"%s\", aTextChange=0x%p), %s", "aInsertStr=\"%s\", aTextChange=0x%p), %s",
this, NS_ConvertUTF16toUTF8(aInsertStr).get(), aTextChange, this, NS_ConvertUTF16toUTF8(aInsertStr).get(), aTextChange,
mCompositionView ? "there is composition view" : mComposition.mView ? "there is composition view" :
"there is no composition view")); "there is no composition view"));
TS_SELECTION_ACP oldSelection; TS_SELECTION_ACP oldSelection;
oldSelection.acpStart = 0; oldSelection.acpStart = 0;
oldSelection.acpEnd = 0; oldSelection.acpEnd = 0;
if (mCompositionView) { if (mComposition.mView) {
oldSelection = mCompositionSelection; oldSelection = mComposition.mSelection;
// Emulate text insertion during compositions, because during a // Emulate text insertion during compositions, because during a
// composition, editor expects the whole composition string to // composition, editor expects the whole composition string to
// be sent in NS_TEXT_TEXT, not just the inserted part. // be sent in NS_TEXT_TEXT, not just the inserted part.
// The actual NS_TEXT_TEXT will be sent in SetSelection or // The actual NS_TEXT_TEXT will be sent in SetSelection or
// OnUpdateComposition. // OnUpdateComposition.
mCompositionString.Replace( mComposition.mString.Replace(
static_cast<uint32_t>(oldSelection.acpStart) - mCompositionStart, static_cast<uint32_t>(oldSelection.acpStart) - mComposition.mStart,
static_cast<uint32_t>(oldSelection.acpEnd - oldSelection.acpStart), static_cast<uint32_t>(oldSelection.acpEnd - oldSelection.acpStart),
aInsertStr); aInsertStr);
mCompositionSelection.acpStart += aInsertStr.Length(); mComposition.mSelection.acpStart += aInsertStr.Length();
mCompositionSelection.acpEnd = mCompositionSelection.acpStart; mComposition.mSelection.acpEnd =
mCompositionSelection.style.ase = TS_AE_END; mComposition.mSelection.acpStart;
mComposition.mSelection.style.ase = TS_AE_END;
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() replaced " ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() replaced "
"a part of (%lu-%lu) the composition string, waiting " "a part of (%lu-%lu) the composition string, waiting "
"SetSelection() or OnUpdateComposition()...", this, "SetSelection() or OnUpdateComposition()...", this,
oldSelection.acpStart - mCompositionStart, oldSelection.acpStart - mComposition.mStart,
oldSelection.acpEnd - mCompositionStart)); oldSelection.acpEnd - mComposition.mStart));
} else { } else {
// Use actual selection if it's not composing. // Use actual selection if it's not composing.
if (aTextChange && !GetSelectionInternal(oldSelection)) { if (aTextChange && !GetSelectionInternal(oldSelection)) {
@@ -2508,12 +2512,13 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal(" ("TSF: 0x%p nsTextStore::OnStartCompositionInternal("
"pComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), " "pComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), "
"mCompositionView=0x%p", "mComposition.mView=0x%p",
this, pComposition, aRange, GetBoolName(aPreserveSelection), this, pComposition, aRange, GetBoolName(aPreserveSelection),
mCompositionView.get())); mComposition.mView.get()));
mCompositionView = pComposition; mComposition.mView = pComposition;
HRESULT hr = GetRangeExtent(aRange, &mCompositionStart, &mCompositionLength); HRESULT hr = GetRangeExtent(aRange, &mComposition.mStart,
&mComposition.mLength);
if (FAILED(hr)) { if (FAILED(hr)) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due "
@@ -2523,8 +2528,8 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), "
"mCompositionStart=%ld, mCompositionLength=%ld", "mComposition={ mStart=%ld, mLength=%ld }",
this, mCompositionStart, mCompositionLength)); this, mComposition.mStart, mComposition.mLength));
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), "
@@ -2533,8 +2538,8 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
// Select composition range so the new composition replaces the range // Select composition range so the new composition replaces the range
nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWidget); nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWidget);
mWidget->InitEvent(selEvent); mWidget->InitEvent(selEvent);
selEvent.mOffset = uint32_t(mCompositionStart); selEvent.mOffset = uint32_t(mComposition.mStart);
selEvent.mLength = uint32_t(mCompositionLength); selEvent.mLength = uint32_t(mComposition.mLength);
selEvent.mReversed = false; selEvent.mReversed = false;
mWidget->DispatchWindowEvent(&selEvent); mWidget->DispatchWindowEvent(&selEvent);
if (!selEvent.mSucceeded) { if (!selEvent.mSucceeded) {
@@ -2559,12 +2564,13 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), "
"dispatching compositionstart event...")); "dispatching compositionstart event..."));
mCompositionString = queryEvent.mReply.mString; mComposition.mString = queryEvent.mReply.mString;
if (!aPreserveSelection) { if (!aPreserveSelection) {
mCompositionSelection.acpStart = mCompositionStart; mComposition.mSelection.acpStart = mComposition.mStart;
mCompositionSelection.acpEnd = mCompositionStart + mCompositionLength; mComposition.mSelection.acpEnd =
mCompositionSelection.style.ase = TS_AE_END; mComposition.mStart + mComposition.mLength;
mCompositionSelection.style.fInterimChar = FALSE; mComposition.mSelection.style.ase = TS_AE_END;
mComposition.mSelection.style.fInterimChar = FALSE;
} }
nsCompositionEvent event(true, NS_COMPOSITION_START, mWidget); nsCompositionEvent event(true, NS_COMPOSITION_START, mWidget);
mWidget->InitEvent(event); mWidget->InitEvent(event);
@@ -2572,41 +2578,30 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnStartCompositionInternal() succeeded: " ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() succeeded: "
"mCompositionStart=%ld, mCompositionLength=%ld, " "mComposition={ mStart=%ld, mLength=%ld, "
"mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " "mSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, "
"style.iInterimChar=%s }", "style.iInterimChar=%s } }",
this, mCompositionStart, mCompositionLength, this, mComposition.mStart, mComposition.mLength,
mCompositionSelection.acpStart, mCompositionSelection.acpEnd, mComposition.mSelection.acpStart,
GetActiveSelEndName(mCompositionSelection.style.ase), mComposition.mSelection.acpEnd,
GetBoolName(mCompositionSelection.style.fInterimChar))); GetActiveSelEndName(mComposition.mSelection.style.ase),
GetBoolName(mComposition.mSelection.style.fInterimChar)));
return S_OK; return S_OK;
} }
static uint32_t
GetLayoutChangeIntervalTime()
{
static int32_t sTime = -1;
if (sTime > 0)
return uint32_t(sTime);
sTime = std::max(10,
Preferences::GetInt("intl.tsf.on_layout_change_interval", 100));
return uint32_t(sTime);
}
STDMETHODIMP STDMETHODIMP
nsTextStore::OnStartComposition(ITfCompositionView* pComposition, nsTextStore::OnStartComposition(ITfCompositionView* pComposition,
BOOL* pfOk) BOOL* pfOk)
{ {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, " ("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, "
"pfOk=0x%p), mCompositionView=0x%p", "pfOk=0x%p), mComposition.mView=0x%p",
this, pComposition, pfOk, mCompositionView.get())); this, pComposition, pfOk, mComposition.mView.get()));
*pfOk = FALSE; *pfOk = FALSE;
// Only one composition at a time // Only one composition at a time
if (mCompositionView) { if (mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to "
"there is another composition already (but returns S_OK)", this)); "there is another composition already (but returns S_OK)", this));
@@ -2629,13 +2624,8 @@ nsTextStore::OnStartComposition(ITfCompositionView* pComposition,
return hr; return hr;
} }
NS_ASSERTION(!mCompositionTimer, "The timer is alive!"); mComposition.StartLayoutChangeTimer(this);
mCompositionTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (mCompositionTimer) {
mCompositionTimer->InitWithFuncCallback(CompositionTimerCallbackFunc, this,
GetLayoutChangeIntervalTime(),
nsITimer::TYPE_REPEATING_SLACK);
}
*pfOk = TRUE; *pfOk = TRUE;
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnStartComposition() succeeded", this)); ("TSF: 0x%p nsTextStore::OnStartComposition() succeeded", this));
@@ -2648,8 +2638,8 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition,
{ {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, " ("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, "
"pRangeNew=0x%p), mCompositionView=0x%p", "pRangeNew=0x%p), mComposition.mView=0x%p",
this, pComposition, pRangeNew, mCompositionView.get())); this, pComposition, pRangeNew, mComposition.mView.get()));
if (!mDocumentMgr || !mContext) { if (!mDocumentMgr || !mContext) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
@@ -2657,13 +2647,13 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition,
"not ready for the composition", this)); "not ready for the composition", this));
return E_UNEXPECTED; return E_UNEXPECTED;
} }
if (!mCompositionView) { if (!mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to "
"no active composition", this)); "no active composition", this));
return E_UNEXPECTED; return E_UNEXPECTED;
} }
if (mCompositionView != pComposition) { if (mComposition.mView != pComposition) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to "
"different composition view specified", this)); "different composition view specified", this));
@@ -2696,14 +2686,15 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded: " ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded: "
"mCompositionStart=%ld, mCompositionLength=%ld, " "mComposition={ mStart=%ld, mLength=%ld, "
"mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " "mSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, "
"style.iInterimChar=%s }, mCompositionString=\"%s\"", "style.iInterimChar=%s }, mString=\"%s\" }",
this, mCompositionStart, mCompositionLength, this, mComposition.mStart, mComposition.mLength,
mCompositionSelection.acpStart, mCompositionSelection.acpEnd, mComposition.mSelection.acpStart,
GetActiveSelEndName(mCompositionSelection.style.ase), mComposition.mSelection.acpEnd,
GetBoolName(mCompositionSelection.style.fInterimChar), GetActiveSelEndName(mComposition.mSelection.style.ase),
NS_ConvertUTF16toUTF8(mCompositionString).get())); GetBoolName(mComposition.mSelection.style.fInterimChar),
NS_ConvertUTF16toUTF8(mComposition.mString).get()));
return S_OK; return S_OK;
} }
@@ -2712,18 +2703,18 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
{ {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), " ("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), "
"mCompositionView=0x%p, mCompositionString=\"%s\"", "mComposition={ mView=0x%p, mString=\"%s\" }",
this, pComposition, mCompositionView.get(), this, pComposition, mComposition.mView.get(),
NS_ConvertUTF16toUTF8(mCompositionString).get())); NS_ConvertUTF16toUTF8(mComposition.mString).get()));
if (!mCompositionView) { if (!mComposition.mView) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to "
"no active composition", this)); "no active composition", this));
return E_UNEXPECTED; return E_UNEXPECTED;
} }
if (mCompositionView != pComposition) { if (mComposition.mView != pComposition) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR, PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to "
"different composition view specified", this)); "different composition view specified", this));
@@ -2733,20 +2724,17 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
// Clear the saved text event // Clear the saved text event
SaveTextEvent(nullptr); SaveTextEvent(nullptr);
if (mCompositionTimer) { mComposition.EnsureLayoutChangeTimerStopped();
mCompositionTimer->Cancel();
mCompositionTimer = nullptr;
}
if (mCompositionString != mLastDispatchedCompositionString) { if (mComposition.mString != mComposition.mLastData) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnEndComposition(), " ("TSF: 0x%p nsTextStore::OnEndComposition(), "
"dispatching compositionupdate event...", this)); "dispatching compositionupdate event...", this));
nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
mWidget); mWidget);
mWidget->InitEvent(compositionUpdate); mWidget->InitEvent(compositionUpdate);
compositionUpdate.data = mCompositionString; compositionUpdate.data = mComposition.mString;
mLastDispatchedCompositionString = mCompositionString; mComposition.mLastData = mComposition.mString;
mWidget->DispatchWindowEvent(&compositionUpdate); mWidget->DispatchWindowEvent(&compositionUpdate);
if (!mWidget || mWidget->Destroyed()) { if (!mWidget || mWidget->Destroyed()) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
@@ -2763,7 +2751,7 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
// Use NS_TEXT_TEXT to commit composition string // Use NS_TEXT_TEXT to commit composition string
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget);
mWidget->InitEvent(textEvent); mWidget->InitEvent(textEvent);
textEvent.theText = mCompositionString; textEvent.theText = mComposition.mString;
textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
NS_LITERAL_STRING("\n")); NS_LITERAL_STRING("\n"));
mWidget->DispatchWindowEvent(&textEvent); mWidget->DispatchWindowEvent(&textEvent);
@@ -2780,7 +2768,7 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
"dispatching compositionend event...", this)); "dispatching compositionend event...", this));
nsCompositionEvent event(true, NS_COMPOSITION_END, mWidget); nsCompositionEvent event(true, NS_COMPOSITION_END, mWidget);
event.data = mLastDispatchedCompositionString; event.data = mComposition.mLastData;
mWidget->InitEvent(event); mWidget->InitEvent(event);
mWidget->DispatchWindowEvent(&event); mWidget->DispatchWindowEvent(&event);
@@ -2791,12 +2779,12 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
return S_OK; return S_OK;
} }
mCompositionView = NULL; mComposition.mView = NULL;
mCompositionString.Truncate(0); mComposition.mString.Truncate(0);
mLastDispatchedCompositionString.Truncate(); mComposition.mLastData.Truncate();
// Maintain selection // Maintain selection
SetSelectionInternal(&mCompositionSelection); SetSelectionInternal(&mComposition.mSelection);
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this)); ("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this));
@@ -2910,7 +2898,7 @@ nsTextStore::OnSelectionChangeInternal(void)
} }
nsresult nsresult
nsTextStore::OnCompositionTimer() nsTextStore::OnLayoutChange()
{ {
NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE);
@@ -2920,7 +2908,7 @@ nsTextStore::OnCompositionTimer()
// this only when the composition string screen position is changed by window // this only when the composition string screen position is changed by window
// moving, resizing. And also reflowing and scrolling the contents. // moving, resizing. And also reflowing and scrolling the contents.
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::OnCompositionTimer(), calling " ("TSF: 0x%p nsTextStore::OnLayoutChange(), calling "
"mSink->OnLayoutChange()...", this)); "mSink->OnLayoutChange()...", this));
HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW); HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
@@ -2933,19 +2921,20 @@ nsTextStore::CommitCompositionInternal(bool aDiscard)
{ {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG, PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), " ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), "
"mLock=%s, mSink=0x%p, mContext=0x%p, mCompositionView=0x%p, " "mLock=%s, mSink=0x%p, mContext=0x%p, mComposition.mView=0x%p, "
"mCompositionString=\"%s\"", "mComposition.mString=\"%s\"",
this, GetBoolName(aDiscard), GetLockFlagNameStr(mLock).get(), this, GetBoolName(aDiscard), GetLockFlagNameStr(mLock).get(),
mSink.get(), mContext.get(), mCompositionView.get(), mSink.get(), mContext.get(), mComposition.mView.get(),
NS_ConvertUTF16toUTF8(mCompositionString).get())); NS_ConvertUTF16toUTF8(mComposition.mString).get()));
if (mCompositionView && aDiscard) { if (mComposition.mView && aDiscard) {
mCompositionString.Truncate(0); mComposition.mString.Truncate(0);
if (mSink && !mLock) { if (mSink && !mLock) {
TS_TEXTCHANGE textChange; TS_TEXTCHANGE textChange;
textChange.acpStart = mCompositionStart; textChange.acpStart = mComposition.mStart;
textChange.acpOldEnd = mCompositionStart + mCompositionLength; textChange.acpOldEnd =
textChange.acpNewEnd = mCompositionStart; mComposition.mStart + mComposition.mLength;
textChange.acpNewEnd = mComposition.mStart;
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::CommitCompositionInternal(), calling" ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), calling"
"mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
@@ -3178,6 +3167,51 @@ nsTextStore::Terminate(void)
} }
} }
/******************************************************************/
/* nsTextStore::Composition */
/******************************************************************/
void
nsTextStore::Composition::StartLayoutChangeTimer(nsTextStore* aTextStore)
{
MOZ_ASSERT(!mLayoutChangeTimer);
mLayoutChangeTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
mLayoutChangeTimer->InitWithFuncCallback(TimerCallback, aTextStore,
GetLayoutChangeIntervalTime(), nsITimer::TYPE_REPEATING_SLACK);
}
void
nsTextStore::Composition::EnsureLayoutChangeTimerStopped()
{
if (!mLayoutChangeTimer) {
return;
}
mLayoutChangeTimer->Cancel();
mLayoutChangeTimer = nullptr;
}
// static
void
nsTextStore::Composition::TimerCallback(nsITimer* aTimer, void* aClosure)
{
nsTextStore *ts = static_cast<nsTextStore*>(aClosure);
ts->OnLayoutChange();
}
// static
uint32_t
nsTextStore::Composition::GetLayoutChangeIntervalTime()
{
static int32_t sTime = -1;
if (sTime > 0) {
return static_cast<uint32_t>(sTime);
}
sTime = std::max(10,
Preferences::GetInt("intl.tsf.on_layout_change_interval", 100));
return static_cast<uint32_t>(sTime);
}
#ifdef DEBUG #ifdef DEBUG
// static // static
bool bool

View File

@@ -139,12 +139,6 @@ public:
static nsIMEUpdatePreference GetIMEUpdatePreference(); static nsIMEUpdatePreference GetIMEUpdatePreference();
static void CompositionTimerCallbackFunc(nsITimer *aTimer, void *aClosure)
{
nsTextStore *ts = static_cast<nsTextStore*>(aClosure);
ts->OnCompositionTimer();
}
static bool CanOptimizeKeyAndIMEMessages() static bool CanOptimizeKeyAndIMEMessages()
{ {
// TODO: We need to implement this for ATOK. // TODO: We need to implement this for ATOK.
@@ -185,7 +179,7 @@ public:
static bool IsComposing() static bool IsComposing()
{ {
return (sTsfTextStore && sTsfTextStore->mCompositionView != nullptr); return (sTsfTextStore && sTsfTextStore->mComposition.mView != nullptr);
} }
static bool IsComposingOn(nsWindowBase* aWidget) static bool IsComposingOn(nsWindowBase* aWidget)
@@ -239,7 +233,7 @@ protected:
HRESULT UpdateCompositionExtent(ITfRange* pRangeNew); HRESULT UpdateCompositionExtent(ITfRange* pRangeNew);
HRESULT SendTextEventForCompositionString(); HRESULT SendTextEventForCompositionString();
HRESULT SaveTextEvent(const nsTextEvent* aEvent); HRESULT SaveTextEvent(const nsTextEvent* aEvent);
nsresult OnCompositionTimer(); nsresult OnLayoutChange();
HRESULT ProcessScopeRequest(DWORD dwFlags, HRESULT ProcessScopeRequest(DWORD dwFlags,
ULONG cFilterAttrs, ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs); const TS_ATTRID *paFilterAttrs);
@@ -263,32 +257,53 @@ protected:
DWORD mLockQueued; DWORD mLockQueued;
// Cumulative text change offsets since the last notification // Cumulative text change offsets since the last notification
TS_TEXTCHANGE mTextChange; TS_TEXTCHANGE mTextChange;
class Composition MOZ_FINAL
{
public:
// NULL if no composition is active, otherwise the current composition // NULL if no composition is active, otherwise the current composition
nsRefPtr<ITfCompositionView> mCompositionView; nsRefPtr<ITfCompositionView> mView;
// Current copy of the active composition string. Only mCompositionString is
// Current copy of the active composition string. Only mString is
// changed during a InsertTextAtSelection call if we have a composition. // changed during a InsertTextAtSelection call if we have a composition.
// mCompositionString acts as a buffer until OnUpdateComposition is called // mString acts as a buffer until OnUpdateComposition is called
// and mCompositionString is flushed to editor through NS_TEXT_TEXT. This // and mString is flushed to editor through NS_TEXT_TEXT. This
// way all changes are updated in batches to avoid inconsistencies/artifacts. // way all changes are updated in batches to avoid
nsString mCompositionString; // inconsistencies/artifacts.
nsString mString;
// The latest composition string which was dispatched by composition update
// event.
nsString mLastData;
// "Current selection" during a composition, in ACP offsets. // "Current selection" during a composition, in ACP offsets.
// We use a fake selection during a composition because editor code doesn't // We use a fake selection during a composition because editor code doesn't
// like us accessing the actual selection during a composition. So we leave // like us accessing the actual selection during a composition. So we leave
// the actual selection alone and get/set mCompositionSelection instead // the actual selection alone and get/set mSelection instead
// during GetSelection/SetSelection calls. // during GetSelection/SetSelection calls.
TS_SELECTION_ACP mCompositionSelection; TS_SELECTION_ACP mSelection;
// The start and length of the current active composition, in ACP offsets // The start and length of the current active composition, in ACP offsets
LONG mCompositionStart; LONG mStart;
LONG mCompositionLength; LONG mLength;
void StartLayoutChangeTimer(nsTextStore* aTextStore);
void EnsureLayoutChangeTimerStopped();
private:
// Timer for calling ITextStoreACPSink::OnLayoutChange(). This is only used
// during composing.
nsCOMPtr<nsITimer> mLayoutChangeTimer;
static void TimerCallback(nsITimer* aTimer, void *aClosure);
static uint32_t GetLayoutChangeIntervalTime();
};
// Storing current composition.
Composition mComposition;
// The latest text event which was dispatched for composition string // The latest text event which was dispatched for composition string
// of the current composing transaction. // of the current composing transaction.
nsTextEvent* mLastDispatchedTextEvent; nsTextEvent* mLastDispatchedTextEvent;
// The latest composition string which was dispatched by composition update
// event.
nsString mLastDispatchedCompositionString;
// Timer for calling ITextStoreACPSink::OnLayoutChange. This is only used
// during composing.
nsCOMPtr<nsITimer> mCompositionTimer;
// The input scopes for this context, defaults to IS_DEFAULT. // The input scopes for this context, defaults to IS_DEFAULT.
nsTArray<InputScope> mInputScopes; nsTArray<InputScope> mInputScopes;
bool mInputScopeDetected; bool mInputScopeDetected;