Bug 1275914 part.3 TextComposition should use IMEContentObserver or ContentEventHandler directly when it queries the selection r?smaug
TextComposition queries selection start offset a lot of times. Therefore, for reducing the runtime cost, it should use IMEContentObserver if it's available or ContentEventHandler, otherwise.
MozReview-Commit-ID: 61GgQZDX2HP
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -429,16 +429,52 @@ TextComposition::HandleSelectionEvent(ns
sHandlingSelectionEvent = true;
// XXX During setting selection, a selection listener may change selection
// again. In such case, sHandlingSelectionEvent doesn't indicate if
// the selection change is caused by a selection event. However, it
// must be non-realistic scenario.
handler.OnSelectionEvent(aSelectionEvent);
}
+uint32_t
+TextComposition::GetSelectionStartOffset()
+{
+ nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
+ WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget);
+
+ // The editor which has this composition is observed by active
+ // IMEContentObserver, we can use the cache of it.
+ RefPtr<IMEContentObserver> contentObserver =
+ IMEStateManager::GetActiveContentObserver();
+ bool doQuerySelection = true;
+ if (contentObserver) {
+ if (contentObserver->IsManaging(this)) {
+ doQuerySelection = false;
+ contentObserver->HandleQueryContentEvent(&selectedTextEvent);
+ }
+ // If another editor already has focus, we cannot retrieve selection
+ // in the editor which has this composition...
+ else if (NS_WARN_IF(contentObserver->GetPresContext() == mPresContext)) {
+ return 0; // XXX Is this okay?
+ }
+ }
+
+ // Otherwise, using slow path (i.e., compute every time with
+ // ContentEventHandler)
+ if (doQuerySelection) {
+ ContentEventHandler handler(mPresContext);
+ handler.HandleQueryContentEvent(&selectedTextEvent);
+ }
+
+ if (NS_WARN_IF(!selectedTextEvent.mSucceeded)) {
+ return 0; // XXX Is this okay?
+ }
+ return selectedTextEvent.mReply.mOffset;
+}
+
void
TextComposition::OnCompositionEventDispatched(
const WidgetCompositionEvent* aCompositionEvent)
{
MOZ_RELEASE_ASSERT(!mTabParent);
if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
return;
@@ -452,31 +488,18 @@ TextComposition::OnCompositionEventDispa
mWasCompositionStringEmpty,
"mWasCompositionStringEmpty should be true if the dispatched "
"event is eCompositionStart");
if (mWasCompositionStringEmpty &&
!aCompositionEvent->CausesDOMCompositionEndEvent()) {
// If there was no composition string, current selection start may be the
// offset for inserting composition string.
- nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
- WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget);
- nsEventStatus status = nsEventStatus_eIgnore;
- if (mString.IsEmpty()) {
- widget->DispatchEvent(&selectedTextEvent, status);
- } else {
- MOZ_ASSERT(aCompositionEvent->mMessage == eCompositionChange);
- // TODO: Update mCompositionStartOffset with first IME selection
- }
- if (NS_WARN_IF(!selectedTextEvent.mSucceeded)) {
- // XXX Is this okay?
- mCompositionStartOffset = 0;
- } else {
- mCompositionStartOffset = selectedTextEvent.mReply.mOffset;
- }
+ // Update composition start offset with current selection start.
+ mCompositionStartOffset = GetSelectionStartOffset();
mTargetClauseOffsetInComposition = 0;
}
if (aCompositionEvent->CausesDOMTextEvent()) {
mTargetClauseOffsetInComposition = aCompositionEvent->TargetClauseOffset();
}
}
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -390,16 +390,23 @@ private:
* MaybeNotifyIMEOfCompositionEventHandled() notifies IME of composition
* event handled. This should be called after dispatching a composition
* event which came from widget.
*/
void MaybeNotifyIMEOfCompositionEventHandled(
const WidgetCompositionEvent* aCompositionEvent);
/**
+ * GetSelectionStartOffset() returns normal selection start offset in the
+ * editor which has this composition.
+ * If it failed or lost focus, this would return 0.
+ */
+ uint32_t GetSelectionStartOffset();
+
+ /**
* CompositionEventDispatcher dispatches the specified composition (or text)
* event.
*/
class CompositionEventDispatcher : public Runnable
{
public:
CompositionEventDispatcher(TextComposition* aTextComposition,
nsINode* aEventTarget,