Bug 917322 part.5 Implement TextEventDispatcher::StartComposition() and nsDOMWindowUtils should use it r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 28 Jan 2015 15:27:31 +0900
changeset 253324 c7fac3ab77af8edfcd9a7175f6122e63bb98c055
parent 253323 7b196aeab6de7296dee5896f6557cb85cde0a962
child 253325 80f1425197337ed5807ad32a67fd58ed009e2013
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs917322
milestone38.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 917322 part.5 Implement TextEventDispatcher::StartComposition() and nsDOMWindowUtils should use it r=smaug
dom/base/nsDOMWindowUtils.cpp
dom/base/nsDOMWindowUtils.h
widget/TextEventDispatcher.cpp
widget/TextEventDispatcher.h
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2129,32 +2129,67 @@ static void
 InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPt = nullptr)
 {
   if (aPt) {
     aEvent.refPoint = *aPt;
   }
   aEvent.time = PR_IntervalNow();
 }
 
+nsresult
+nsDOMWindowUtils::GetTextEventDispatcher(TextEventDispatcher** aDispatcher)
+{
+  if (!aDispatcher) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  *aDispatcher = nullptr;
+
+  nsCOMPtr<nsIWidget> widget(GetWidget());
+  if (NS_WARN_IF(!widget)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  TextEventDispatcher* dispatcher = widget->GetTextEventDispatcher();
+  nsresult rv = dispatcher->GetState();
+  if (NS_SUCCEEDED(rv)) {
+    NS_ADDREF(*aDispatcher = dispatcher);
+    return NS_OK;
+  }
+  if (rv == NS_ERROR_NOT_INITIALIZED) {
+    rv = dispatcher->InitForTests();
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  NS_ADDREF(*aDispatcher = dispatcher);
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType,
                                        const nsAString& aData,
                                        const nsAString& aLocale)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   // get the widget to send the event to
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return NS_ERROR_FAILURE;
   }
 
   uint32_t msg;
   if (aType.EqualsLiteral("compositionstart")) {
-    msg = NS_COMPOSITION_START;
+    nsRefPtr<TextEventDispatcher> dispatcher;
+    nsresult rv = GetTextEventDispatcher(getter_AddRefs(dispatcher));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    nsEventStatus status = nsEventStatus_eIgnore;
+    return dispatcher->StartComposition(status);
   } else if (aType.EqualsLiteral("compositionend")) {
     // Now we don't support manually dispatching composition end with this
     // API.  A compositionend is dispatched when this is called with
     // compositioncommitasis or compositioncommit automatically.  For backward
     // compatibility, this shouldn't return error in this case.
     NS_WARNING("Don't call nsIDOMWindowUtils.sendCompositionEvent() for "
                "compositionend.  Instead, use it with compositioncommitasis or "
                "compositioncommit.  Then, compositionend will be automatically "
@@ -2200,21 +2235,19 @@ nsDOMWindowUtils::CreateCompositionStrin
   *aResult = nullptr;
 
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (NS_WARN_IF(!widget)) {
     return NS_ERROR_FAILURE;
   }
-  nsRefPtr<TextEventDispatcher> dispatcher(widget->GetTextEventDispatcher());
-  nsresult rv = dispatcher->GetState();
-  if (rv == NS_ERROR_NOT_INITIALIZED) {
-    dispatcher->InitForTests();
-  } else if (NS_WARN_IF(NS_FAILED(rv))) {
+  nsRefPtr<TextEventDispatcher> dispatcher;
+  nsresult rv = GetTextEventDispatcher(getter_AddRefs(dispatcher));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   NS_ADDREF(*aResult = new CompositionStringSynthesizer(dispatcher));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType,
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -52,16 +52,18 @@ private:
   nsTArray<nsCOMPtr<nsIDOMNode> > mNodes;
   nsTArray<bool> mNodeIsRoot;
   uint32_t mLength;
 };
 
 class nsDOMWindowUtils MOZ_FINAL : public nsIDOMWindowUtils,
                                    public nsSupportsWeakReference
 {
+  typedef mozilla::widget::TextEventDispatcher
+    TextEventDispatcher;
 public:
   explicit nsDOMWindowUtils(nsGlobalWindow *aWindow);
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMWINDOWUTILS
 
 protected:
   ~nsDOMWindowUtils();
 
@@ -73,16 +75,27 @@ protected:
   // widget returned by GetWidget.
   nsIWidget* GetWidget(nsPoint* aOffset = nullptr);
   nsIWidget* GetWidgetForElement(nsIDOMElement* aElement);
 
   nsIPresShell* GetPresShell();
   nsPresContext* GetPresContext();
   nsIDocument* GetDocument();
   mozilla::layers::LayerTransactionChild* GetLayerTransaction();
+  /**
+   * GetTextEventDispatcher() retrieves a TextEventDispatcher
+   * belonging to the widget (result of GetWidget()) and initializes it.
+   *
+   * @param [out] aDispatcher       The TextEventDispatcher belonging to
+   *                                the widget which has already been
+   *                                initialized and addrefed.
+   * @return   The result of TextEventDispatcher::InitForTest().
+   */
+  nsresult GetTextEventDispatcher(
+             TextEventDispatcher** aDispatcher);
 
   nsView* GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell);
 
   NS_IMETHOD SendMouseEventCommon(const nsAString& aType,
                                   float aX,
                                   float aY,
                                   int32_t aButton,
                                   int32_t aClickCount,
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -70,16 +70,38 @@ TextEventDispatcher::GetState() const
 
 void
 TextEventDispatcher::InitEvent(WidgetCompositionEvent& aEvent) const
 {
   aEvent.time = PR_IntervalNow();
   aEvent.mFlags.mIsSynthesizedForTests = mForTests;
 }
 
+nsresult
+TextEventDispatcher::StartComposition(nsEventStatus& aStatus)
+{
+  aStatus = nsEventStatus_eIgnore;
+
+  nsresult rv = GetState();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIWidget> widget(mWidget);
+  WidgetCompositionEvent compositionStartEvent(true, NS_COMPOSITION_START,
+                                               widget);
+  InitEvent(compositionStartEvent);
+  rv = widget->DispatchEvent(&compositionStartEvent, aStatus);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 /******************************************************************************
  * TextEventDispatcher::PendingComposition
  *****************************************************************************/
 
 TextEventDispatcher::PendingComposition::PendingComposition()
 {
   Clear();
 }
--- a/widget/TextEventDispatcher.h
+++ b/widget/TextEventDispatcher.h
@@ -59,16 +59,21 @@ public:
    *                NS_ERROR_NOT_INITIALIZED: Init() or InitForTests() should
    *                                          be called.
    *                NS_ERROR_NOT_AVAILABLE: The widget isn't available for
    *                                        composition.
    */
   nsresult GetState() const;
 
   /**
+   * StartComposition() starts composition explicitly.
+   */
+  nsresult StartComposition(nsEventStatus& aStatus);
+
+  /**
    * SetPendingCompositionString() sets new composition string which will be
    * dispatched with NS_COMPOSITION_CHANGE event by calling Flush().
    *
    * @param aString         New composition string.
    */
   nsresult SetPendingCompositionString(const nsAString& aString)
   {
     return mPendingComposition.SetString(aString);