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 239576 c7fac3ab77af8edfcd9a7175f6122e63bb98c055
parent 239575 7b196aeab6de7296dee5896f6557cb85cde0a962
child 239577 80f1425197337ed5807ad32a67fd58ed009e2013
push id500
push userjoshua.m.grant@gmail.com
push dateThu, 29 Jan 2015 01:48:36 +0000
reviewerssmaug
bugs917322
milestone38.0a1
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);