Bug 1178738 - Implement dispatch of SpeechSynthesisErrorEvent. r?smaug draft
authorEitan Isaacson <eitan@monotonous.org>
Wed, 18 May 2016 10:14:45 -0700
changeset 374073 c9d7f153a8234534bae6394701689f40fb08772f
parent 374072 4c028764b8d8403367d650a845a01f4695fa4ee9
child 374074 6b92c5806fb40ed964fe22605cd523bccad684c2
push id19917
push userbmo:eitan@monotonous.org
push dateWed, 01 Jun 2016 19:05:35 +0000
reviewerssmaug
bugs1178738
milestone49.0a1
Bug 1178738 - Implement dispatch of SpeechSynthesisErrorEvent. r?smaug MozReview-Commit-ID: 77epkO1lh5c
dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
dom/media/webspeech/synth/SpeechSynthesisUtterance.h
dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
dom/media/webspeech/synth/nsSpeechTask.cpp
dom/media/webspeech/synth/test/common.js
dom/media/webspeech/synth/test/file_speech_queue.html
--- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsGkAtoms.h"
 
 #include "mozilla/dom/SpeechSynthesisEvent.h"
+#include "mozilla/dom/SpeechSynthesisErrorEvent.h"
 #include "mozilla/dom/SpeechSynthesisUtteranceBinding.h"
 #include "SpeechSynthesisUtterance.h"
 #include "SpeechSynthesisVoice.h"
 
 #include <stdlib.h>
 
 namespace mozilla {
 namespace dom {
@@ -169,10 +170,29 @@ SpeechSynthesisUtterance::DispatchSpeech
   init.mElapsedTime = aElapsedTime;
   init.mName = aName;
 
   RefPtr<SpeechSynthesisEvent> event =
     SpeechSynthesisEvent::Constructor(this, aEventType, init);
   DispatchTrustedEvent(event);
 }
 
+void
+SpeechSynthesisUtterance::DispatchSpeechSynthesisErrorEvent(uint32_t aCharIndex,
+                                                            float aElapsedTime,
+                                                            SpeechSynthesisErrorCode aError)
+{
+  SpeechSynthesisErrorEventInit init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mUtterance = this;
+  init.mCharIndex = aCharIndex;
+  init.mElapsedTime = aElapsedTime;
+  init.mName = NS_LITERAL_STRING("");
+  init.mError = aError;
+
+  RefPtr<SpeechSynthesisErrorEvent> event =
+    SpeechSynthesisErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init);
+  DispatchTrustedEvent(event);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.h
+++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.h
@@ -15,16 +15,17 @@
 #include "nsSpeechTask.h"
 
 namespace mozilla {
 namespace dom {
 
 class SpeechSynthesisVoice;
 class SpeechSynthesis;
 class nsSynthVoiceRegistry;
+enum class SpeechSynthesisErrorCode : uint32_t;
 
 class SpeechSynthesisUtterance final : public DOMEventTargetHelper
 {
   friend class SpeechSynthesis;
   friend class nsSpeechTask;
   friend class nsSynthVoiceRegistry;
 
 public:
@@ -94,16 +95,20 @@ public:
 
 private:
   virtual ~SpeechSynthesisUtterance();
 
   void DispatchSpeechSynthesisEvent(const nsAString& aEventType,
                                     uint32_t aCharIndex,
                                     float aElapsedTime, const nsAString& aName);
 
+  void DispatchSpeechSynthesisErrorEvent(uint32_t aCharIndex,
+                                         float aElapsedTime,
+                                         SpeechSynthesisErrorCode aError);
+
   nsString mText;
 
   nsString mLang;
 
   float mVolume;
 
   float mRate;
 
--- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -24,17 +24,17 @@ async protocol PSpeechSynthesisRequest
   async Cancel();
 
   async ForceEnd();
 
   async SetAudioOutputVolume(float aVolume);
 
  child:
 
-  async OnEnd(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
+  async OnEnd(bool aIsError, float aElapsedTime, uint32_t aCharIndex, uint32_t aError);
 
   async OnStart(nsString aUri);
 
   async OnPause(float aElapsedTime, uint32_t aCharIndex);
 
   async OnResume(float aElapsedTime, uint32_t aCharIndex);
 
   async OnBoundary(nsString aName, float aElapsedTime, uint32_t aCharIndex);
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
@@ -91,23 +91,24 @@ SpeechSynthesisRequestChild::RecvOnStart
 {
   mTask->DispatchStartImpl(aUri);
   return true;
 }
 
 bool
 SpeechSynthesisRequestChild::RecvOnEnd(const bool& aIsError,
                                        const float& aElapsedTime,
-                                       const uint32_t& aCharIndex)
+                                       const uint32_t& aCharIndex,
+                                       const uint32_t& aError)
 {
   SpeechSynthesisRequestChild* actor = mTask->mActor;
   mTask->mActor = nullptr;
 
   if (aIsError) {
-    mTask->DispatchErrorImpl(aElapsedTime, aCharIndex, 0);
+    mTask->DispatchErrorImpl(aElapsedTime, aCharIndex, aError);
   } else {
     mTask->DispatchEndImpl(aElapsedTime, aCharIndex);
   }
 
   actor->Send__delete__(actor);
 
   return true;
 }
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -51,17 +51,18 @@ public:
   explicit SpeechSynthesisRequestChild(SpeechTaskChild* aTask);
   virtual ~SpeechSynthesisRequestChild();
 
 protected:
   bool RecvOnStart(const nsString& aUri) override;
 
   bool RecvOnEnd(const bool& aIsError,
                  const float& aElapsedTime,
-                 const uint32_t& aCharIndex) override;
+                 const uint32_t& aCharIndex,
+                 const uint32_t& aError) override;
 
   bool RecvOnPause(const float& aElapsedTime, const uint32_t& aCharIndex) override;
 
   bool RecvOnResume(const float& aElapsedTime, const uint32_t& aCharIndex) override;
 
   bool RecvOnBoundary(const nsString& aName, const float& aElapsedTime,
                       const uint32_t& aCharIndex) override;
 
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
@@ -161,17 +161,17 @@ SpeechTaskParent::DispatchStartImpl(cons
 nsresult
 SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
 {
   if (!mActor) {
     // Child is already gone.
     return NS_OK;
   }
 
-  if(NS_WARN_IF(!(mActor->SendOnEnd(false, aElapsedTime, aCharIndex)))) {
+  if(NS_WARN_IF(!(mActor->SendOnEnd(false, aElapsedTime, aCharIndex, 0)))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
@@ -194,17 +194,17 @@ SpeechTaskParent::DispatchResumeImpl(flo
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex, uint32_t aError)
 {
   MOZ_ASSERT(mActor);
-  if(NS_WARN_IF(!(mActor->SendOnEnd(true, aElapsedTime, aCharIndex)))) {
+  if(NS_WARN_IF(!(mActor->SendOnEnd(true, aElapsedTime, aCharIndex, aError)))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchBoundaryImpl(const nsAString& aName,
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -528,19 +528,18 @@ nsSpeechTask::DispatchErrorImpl(float aE
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (mSpeechSynthesis) {
     mSpeechSynthesis->OnEnd(this);
   }
 
   mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
-  mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
-                                           aCharIndex, aElapsedTime,
-                                           EmptyString());
+  mUtterance->DispatchSpeechSynthesisErrorEvent(aCharIndex, aElapsedTime,
+                                                SpeechSynthesisErrorCode(aError));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSpeechTask::DispatchBoundary(const nsAString& aName,
                                float aElapsedTime, uint32_t aCharIndex)
 {
   if (!mIndirectAudio) {
--- a/dom/media/webspeech/synth/test/common.js
+++ b/dom/media/webspeech/synth/test/common.js
@@ -34,17 +34,18 @@ function synthTestQueue(aTestArgs, aEndF
       })(aTestArgs[i][1] ? aTestArgs[i][1].uri : null));
 
     u.addEventListener('end', onend_handler);
     u.addEventListener('error', onend_handler);
 
     u.addEventListener('error',
       (function (expectedError) {
         return function onerror_handler(e) {
-          ok(expectedError, "Error in speech utterance '" + e.target.text + "'");
+          ok(e instanceof SpeechSynthesisErrorEvent, "error event is of right type");
+          is(expectedError, e.error, "Matched error type");
         };
       })(aTestArgs[i][1] ? aTestArgs[i][1].err : false));
 
     utterances.push(u);
     win.speechSynthesis.speak(u);
   }
 
   ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
--- a/dom/media/webspeech/synth/test/file_speech_queue.html
+++ b/dom/media/webspeech/synth/test/file_speech_queue.html
@@ -47,17 +47,17 @@ function testFunc(done_cb) {
     [[{text: "Hello, world."},
       { uri: langUriMap['en-JM'] }],
      [{text: "Bonjour tout le monde .",
        args: { lang: "fr", rate: 0.5, pitch: 0.75 }},
       { uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}],
      [{text: "How are you doing?", args: { lang: "en-GB" } },
       { rate: 1, pitch: 1, uri: langUriMap['en-GB']}],
      [{text: "Come stai?", args: { lang: "it-IT-fail" } },
-      { rate: 1, pitch: 1, uri: langUriMap['it-IT-fail'], err: true }],
+      { rate: 1, pitch: 1, uri: langUriMap['it-IT-fail'], err: "synthesis-failed" }],
      [{text: "¡hasta mañana!", args: { lang: "es-MX" } },
       { uri: langUriMap['es-MX'] }]],
     function () {
       var test_data = [];
       var voices = speechSynthesis.getVoices();
       for (var voice of voices) {
         if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) {
           continue;