Bug 790561 Separate InsertTextAtSelection() r=jimm
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 14 Sep 2012 13:51:00 +0900
changeset 107091 440f587c464a401c2c6dd56636ddfb5ef8b04a16
parent 107090 2a5c6e070367ac13ad9572039ea12198f07ef175
child 107092 9e68f92a96b62613704a095cebf75c77549c50f5
push id23470
push userryanvm@gmail.com
push dateSat, 15 Sep 2012 01:09:09 +0000
treeherdermozilla-central@9fff2012b66c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs790561
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 790561 Separate InsertTextAtSelection() r=jimm
widget/windows/nsTextStore.cpp
widget/windows/nsTextStore.h
--- a/widget/windows/nsTextStore.cpp
+++ b/widget/windows/nsTextStore.cpp
@@ -1506,20 +1506,30 @@ nsTextStore::SetText(DWORD dwFlags,
   HRESULT hr = SetSelectionInternal(&selection);
   if (FAILED(hr)) {
     PR_LOG(sTextStoreLog, PR_LOG_ERROR,
            ("TSF: 0x%p   nsTextStore::SetText() FAILED due to "
             "SetSelectionInternal() failure", this));
     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
 nsTextStore::GetFormattedText(LONG acpStart,
                               LONG acpEnd,
                               IDataObject **ppDataObject)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
@@ -1994,39 +2004,40 @@ nsTextStore::InsertTextAtSelection(DWORD
 
   if (cch && !pchText) {
     PR_LOG(sTextStoreLog, PR_LOG_ERROR,
            ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
             "null pchText", 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;
-  }
-
   if (TS_IAS_QUERYONLY == dwFlags) {
     if (!IsReadLocked()) {
       PR_LOG(sTextStoreLog, PR_LOG_ERROR,
              ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
               "not locked (read)", this));
       return TS_E_NOLOCK;
     }
 
     if (!pacpStart || !pacpEnd) {
       PR_LOG(sTextStoreLog, PR_LOG_ERROR,
              ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
               "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;
     if (pChange) {
       pChange->acpStart = sel.acpStart;
       pChange->acpOldEnd = sel.acpEnd;
       pChange->acpNewEnd = sel.acpStart + cch;
     }
@@ -2039,101 +2050,179 @@ nsTextStore::InsertTextAtSelection(DWORD
     }
 
     if (!pChange) {
       PR_LOG(sTextStoreLog, PR_LOG_ERROR,
              ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
               "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 "
               "null argument", this));
       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;
     }
   }
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
          ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() succeeded: "
           "*pacpStart=%ld, *pacpEnd=%ld, "
           "*pChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld })",
           this, pacpStart ? *pacpStart : 0, pacpEnd ? *pacpEnd : 0,
           pChange ? pChange->acpStart: 0, pChange ? pChange->acpOldEnd : 0,
           pChange ? pChange->acpNewEnd : 0));
   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,
                                        LONG *pacpStart,
                                        LONG *pacpEnd,
                                        TS_TEXTCHANGE *pChange)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -169,16 +169,18 @@ protected:
   bool     GetScreenExtInternal(RECT &aScreenExt);
   bool     GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP);
   // If aDispatchTextEvent is true, this method will dispatch text event if
   // this is called during IME composing.  aDispatchTextEvent should be true
   // only when this is called from SetSelection.  Because otherwise, the text
   // 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);
   nsresult OnTextChangeInternal(uint32_t, uint32_t, uint32_t);
   void     OnTextChangeMsgInternal(void);
   nsresult OnSelectionChangeInternal(void);
   HRESULT  GetDisplayAttribute(ITfProperty* aProperty,
                                ITfRange* aRange,