зеркало из https://github.com/mozilla/gecko-dev.git
Bug 790561 Separate InsertTextAtSelection() r=jimm
This commit is contained in:
Родитель
bf5f911805
Коммит
4dfed85b87
|
@ -1511,10 +1511,20 @@ nsTextStore::SetText(DWORD dwFlags,
|
|||
return hr;
|
||||
}
|
||||
// Replace just selected text
|
||||
// XXX We should make something like InserTextAtSelectionInternal() for
|
||||
// making the log clearer if InsertTextAtSelection() is called internally.
|
||||
return InsertTextAtSelection(TS_IAS_NOQUERY, pchText, cch,
|
||||
NULL, NULL, pChange);
|
||||
if (!InsertTextAtSelectionInternal(nsDependentString(pchText, cch),
|
||||
pChange)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::SetText() FAILED due to "
|
||||
"InsertTextAtSelectionInternal() failure", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::SetText() succeeded: pChange={ "
|
||||
"acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }",
|
||||
this, pChange ? pChange->acpStart : 0,
|
||||
pChange ? pChange->acpOldEnd : 0, pChange ? pChange->acpNewEnd : 0));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
|
@ -1999,15 +2009,6 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
|
|||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Get selection first
|
||||
TS_SELECTION_ACP sel;
|
||||
if (!GetSelectionInternal(sel)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to "
|
||||
"GetSelectionInternal() failure", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (TS_IAS_QUERYONLY == dwFlags) {
|
||||
if (!IsReadLocked()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
|
@ -2022,6 +2023,16 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
|
|||
"null argument", this));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Get selection first
|
||||
TS_SELECTION_ACP sel;
|
||||
if (!GetSelectionInternal(sel)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to "
|
||||
"GetSelectionInternal() failure", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Simulate text insertion
|
||||
*pacpStart = sel.acpStart;
|
||||
*pacpEnd = sel.acpEnd;
|
||||
|
@ -2044,6 +2055,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
|
|||
"null pChange", this));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (TS_IAS_NOQUERY != dwFlags && (!pacpStart || !pacpEnd)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to "
|
||||
|
@ -2051,69 +2063,14 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
|
|||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (mCompositionView) {
|
||||
// Emulate text insertion during compositions, because during a
|
||||
// composition, editor expects the whole composition string to
|
||||
// be sent in NS_TEXT_TEXT, not just the inserted part.
|
||||
// The actual NS_TEXT_TEXT will be sent in SetSelection or
|
||||
// OnUpdateComposition.
|
||||
mCompositionString.Replace(uint32_t(sel.acpStart - mCompositionStart),
|
||||
sel.acpEnd - sel.acpStart, pchText, cch);
|
||||
|
||||
mCompositionSelection.acpStart += cch;
|
||||
mCompositionSelection.acpEnd = mCompositionSelection.acpStart;
|
||||
mCompositionSelection.style.ase = TS_AE_END;
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() replaced a "
|
||||
"part of (%lu-%lu) the composition string, waiting "
|
||||
"SetSelection() or OnUpdateComposition()...", this,
|
||||
sel.acpStart - mCompositionStart,
|
||||
sel.acpEnd - mCompositionStart));
|
||||
} else {
|
||||
// Use a temporary composition to contain the text
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() dispatching "
|
||||
"a compositionstart event...", this));
|
||||
nsCompositionEvent compEvent(true, NS_COMPOSITION_START, mWindow);
|
||||
mWindow->InitEvent(compEvent);
|
||||
mWindow->DispatchWindowEvent(&compEvent);
|
||||
if (mWindow && !mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() dispatching "
|
||||
"a compositionupdate event...", this));
|
||||
compEvent.message = NS_COMPOSITION_UPDATE;
|
||||
compEvent.data.Assign(pchText, cch);
|
||||
mWindow->DispatchWindowEvent(&compEvent);
|
||||
if (mWindow && !mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() "
|
||||
"dispatching a text event...", this));
|
||||
nsTextEvent event(true, NS_TEXT_TEXT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
event.theText.Assign(pchText, cch);
|
||||
event.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
|
||||
NS_LITERAL_STRING("\n"));
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
if (mWindow && !mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() "
|
||||
"dispatching a compositionend event...", this));
|
||||
compEvent.message = NS_COMPOSITION_END;
|
||||
mWindow->DispatchWindowEvent(&compEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pChange->acpStart = sel.acpStart;
|
||||
pChange->acpOldEnd = sel.acpEnd;
|
||||
// Get new selection
|
||||
if (!GetSelectionInternal(sel)) {
|
||||
if (!InsertTextAtSelectionInternal(nsDependentString(pchText, cch),
|
||||
pChange)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to "
|
||||
"GetSelectionInternal() failure after inserted the text", this));
|
||||
"InsertTextAtSelectionInternal() failure", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
pChange->acpNewEnd = sel.acpEnd;
|
||||
|
||||
if (TS_IAS_NOQUERY != dwFlags) {
|
||||
*pacpStart = pChange->acpStart;
|
||||
*pacpEnd = pChange->acpNewEnd;
|
||||
|
@ -2129,6 +2086,138 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
TS_TEXTCHANGE* aTextChange)
|
||||
{
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal("
|
||||
"aInsertStr=\"%s\", aTextChange=0x%p), %s",
|
||||
this, NS_ConvertUTF16toUTF8(aInsertStr).get(), aTextChange,
|
||||
mCompositionView ? "there is composition view" :
|
||||
"there is no composition view"));
|
||||
|
||||
TS_SELECTION_ACP oldSelection;
|
||||
oldSelection.acpStart = 0;
|
||||
oldSelection.acpEnd = 0;
|
||||
|
||||
if (mCompositionView) {
|
||||
oldSelection = mCompositionSelection;
|
||||
// Emulate text insertion during compositions, because during a
|
||||
// composition, editor expects the whole composition string to
|
||||
// be sent in NS_TEXT_TEXT, not just the inserted part.
|
||||
// The actual NS_TEXT_TEXT will be sent in SetSelection or
|
||||
// OnUpdateComposition.
|
||||
mCompositionString.Replace(
|
||||
static_cast<uint32_t>(oldSelection.acpStart) - mCompositionStart,
|
||||
static_cast<uint32_t>(oldSelection.acpEnd - oldSelection.acpStart),
|
||||
aInsertStr);
|
||||
|
||||
mCompositionSelection.acpStart += aInsertStr.Length();
|
||||
mCompositionSelection.acpEnd = mCompositionSelection.acpStart;
|
||||
mCompositionSelection.style.ase = TS_AE_END;
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() replaced "
|
||||
"a part of (%lu-%lu) the composition string, waiting "
|
||||
"SetSelection() or OnUpdateComposition()...", this,
|
||||
oldSelection.acpStart - mCompositionStart,
|
||||
oldSelection.acpEnd - mCompositionStart));
|
||||
} else {
|
||||
// Use actual selection if it's not composing.
|
||||
if (aTextChange && !GetSelectionInternal(oldSelection)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to GetSelectionInternal() failure", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use a temporary composition to contain the text
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionstart event...", this));
|
||||
nsCompositionEvent compStartEvent(true, NS_COMPOSITION_START, mWindow);
|
||||
mWindow->InitEvent(compStartEvent);
|
||||
mWindow->DispatchWindowEvent(&compStartEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by compositionstart event", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aInsertStr.IsEmpty()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionupdate event...", this));
|
||||
nsCompositionEvent compUpdateEvent(true, NS_COMPOSITION_UPDATE, mWindow);
|
||||
compUpdateEvent.data = aInsertStr;
|
||||
mWindow->DispatchWindowEvent(&compUpdateEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"FAILED due to the widget destroyed by compositionupdate event",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a text event...", this));
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow);
|
||||
mWindow->InitEvent(textEvent);
|
||||
textEvent.theText = aInsertStr;
|
||||
textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
|
||||
NS_LITERAL_STRING("\n"));
|
||||
mWindow->DispatchWindowEvent(&textEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by text event", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionend event...", this));
|
||||
nsCompositionEvent compEndEvent(true, NS_COMPOSITION_END, mWindow);
|
||||
compEndEvent.data = aInsertStr;
|
||||
mWindow->DispatchWindowEvent(&compEndEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by compositionend event", this));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTextChange) {
|
||||
aTextChange->acpStart = oldSelection.acpStart;
|
||||
aTextChange->acpOldEnd = oldSelection.acpEnd;
|
||||
|
||||
// Get new selection
|
||||
TS_SELECTION_ACP newSelection;
|
||||
if (!GetSelectionInternal(newSelection)) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to GetSelectionInternal() failure after inserted the text",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
aTextChange->acpNewEnd = newSelection.acpEnd;
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: "
|
||||
"mWindow=0x%p, mWindow->Destroyed()=%s, aTextChange={ acpStart=%ld, "
|
||||
"acpOldEnd=%ld, acpNewEnd=%ld }",
|
||||
this, mWindow, GetBoolName(mWindow ? mWindow->Destroyed() : true),
|
||||
aTextChange ? aTextChange->acpStart : 0,
|
||||
aTextChange ? aTextChange->acpOldEnd : 0,
|
||||
aTextChange ? aTextChange->acpNewEnd : 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags,
|
||||
IDataObject *pDataObject,
|
||||
|
|
|
@ -174,6 +174,8 @@ protected:
|
|||
// event should not be sent from here.
|
||||
HRESULT SetSelectionInternal(const TS_SELECTION_ACP*,
|
||||
bool aDispatchTextEvent = false);
|
||||
bool InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
TS_TEXTCHANGE* aTextChange);
|
||||
HRESULT OnStartCompositionInternal(ITfCompositionView*, ITfRange*, bool);
|
||||
void CommitCompositionInternal(bool);
|
||||
void SetInputContextInternal(IMEState::Enabled aState);
|
||||
|
|
Загрузка…
Ссылка в новой задаче