nsresult TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard) { // If this composition is already requested to be committed or canceled, // or has already finished in IME, we don't need to request it again because // request from this instance shouldn't cause committing nor canceling current // composition in IME, and even if the first request failed, new request // won't success, probably. And we shouldn't synthesize events for // committing or canceling composition twice or more times. if (!CanRequsetIMEToCommitOrCancelComposition()) { return NS_OK; } RefPtr<TextComposition> kungFuDeathGrip(this); const nsAutoString lastData(mLastData); { AutoRestore<bool> saveRequestingCancel(mIsRequestingCancel); AutoRestore<bool> saveRequestingCommit(mIsRequestingCommit); if (aDiscard) { mIsRequestingCancel = true; mIsRequestingCommit = false; } else { mIsRequestingCancel = false; mIsRequestingCommit = true; } // FYI: CompositionEvents caused by a call of NotifyIME() may be // discarded by PresShell if it's not safe to dispatch the event. nsresult rv = aWidget->NotifyIME(IMENotification(aDiscard ? REQUEST_TO_CANCEL_COMPOSITION : REQUEST_TO_COMMIT_COMPOSITION)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } mRequestedToCommitOrCancel = true; // If the request is performed synchronously, this must be already destroyed. if (Destroyed()) { return NS_OK; } // Otherwise, synthesize the commit in content. nsAutoString data(aDiscard ? EmptyString() : lastData); if (data == mLastData) { DispatchCompositionEventRunnable(eCompositionCommitAsIs, EmptyString(), true); } else { DispatchCompositionEventRunnable(eCompositionCommit, data, true); } return NS_OK; }
void TextComposition::SynthesizeCommit(bool aDiscard) { nsRefPtr<TextComposition> kungFuDeathGrip(this); nsAutoString data(aDiscard ? EmptyString() : mLastData); if (mLastData != data) { DispatchCompositionEventRunnable(NS_COMPOSITION_UPDATE, data); DispatchCompositionEventRunnable(NS_TEXT_TEXT, data); } DispatchCompositionEventRunnable(NS_COMPOSITION_END, data); }
nsresult TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard) { // If this composition is already requested to be committed or canceled, // we don't need to request it again because even if the first request // failed, new request won't success, probably. And we shouldn't synthesize // events for committing or canceling composition twice or more times. if (mRequestedToCommitOrCancel) { return NS_OK; } nsRefPtr<TextComposition> kungFuDeathGrip(this); const nsAutoString lastData(mLastData); { AutoRestore<bool> saveRequestingCancel(mIsRequestingCancel); AutoRestore<bool> saveRequestingCommit(mIsRequestingCommit); if (aDiscard) { mIsRequestingCancel = true; mIsRequestingCommit = false; } else { mIsRequestingCancel = false; mIsRequestingCommit = true; } if (!mIsSynthesizedForTests) { // FYI: CompositionEvent and TextEvent caused by a call of NotifyIME() // may be discarded by PresShell if it's not safe to dispatch the // event. nsresult rv = aWidget->NotifyIME(IMENotification(aDiscard ? REQUEST_TO_CANCEL_COMPOSITION : REQUEST_TO_COMMIT_COMPOSITION)); if (rv == NS_ERROR_NOT_IMPLEMENTED) { return rv; } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { // Emulates to commit or cancel the composition // FYI: These events may be discarded by PresShell if it's not safe to // dispatch the event. nsCOMPtr<nsIWidget> widget(aWidget); nsAutoString commitData(aDiscard ? EmptyString() : lastData); bool changingData = lastData != commitData; WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget); textEvent.theText = commitData; textEvent.mFlags.mIsSynthesizedForTests = true; MaybeDispatchCompositionUpdate(&textEvent); // If changing the data or committing string isn't empty, we need to // dispatch text event for setting the composition string without // IME selection. if (!Destroyed() && !widget->Destroyed() && (changingData || !commitData.IsEmpty())) { nsEventStatus status = nsEventStatus_eIgnore; widget->DispatchEvent(&textEvent, status); } if (!Destroyed() && !widget->Destroyed()) { nsEventStatus status = nsEventStatus_eIgnore; WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); endEvent.data = commitData; endEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&endEvent, status); } } } mRequestedToCommitOrCancel = true; // If the request is performed synchronously, this must be already destroyed. if (Destroyed()) { return NS_OK; } // Otherwise, synthesize the commit in content. nsAutoString data(aDiscard ? EmptyString() : lastData); bool changingData = lastData != data; if (changingData) { DispatchCompositionEventRunnable(NS_COMPOSITION_UPDATE, data, true); } // If the last composition string and new data are different, we need to // dispatch text event for removing IME selection. However, if the commit // string is empty string and it's not changed from the last data, we don't // need to dispatch text event. if (changingData || !data.IsEmpty()) { DispatchCompositionEventRunnable(NS_TEXT_TEXT, data, true); } DispatchCompositionEventRunnable(NS_COMPOSITION_END, data, true); return NS_OK; }