Bug 1226015 - Have child send __delete__ in speech synth request protocol, fixes race. r=smaug
authorEitan Isaacson <eitan@monotonous.org>
Mon, 30 Nov 2015 18:59:01 -0800
changeset 308957 a9f0334501a97f1026aaa651ecbe760762abcef5
parent 308956 3a5c79d9350404a65860e0663d2036a0708df5f5
child 308958 03c6bd7c9aecc4d1c697a1b731bd32580d1fb057
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1226015
milestone45.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 1226015 - Have child send __delete__ in speech synth request protocol, fixes race. r=smaug
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/ipc/SpeechSynthesisParent.h
dom/media/webspeech/synth/test/file_speech_error.html
dom/media/webspeech/synth/test/mochitest.ini
dom/media/webspeech/synth/test/nsFakeSynthServices.cpp
dom/media/webspeech/synth/test/test_speech_error.html
--- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -10,29 +10,31 @@ namespace mozilla {
 namespace dom {
 
 async protocol PSpeechSynthesisRequest
 {
   manager PSpeechSynthesis;
 
  parent:
 
+  __delete__();
+
   Pause();
 
   Resume();
 
   Cancel();
 
   ForceEnd();
 
   SetAudioOutputVolume(float aVolume);
 
  child:
 
-  __delete__(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
+  OnEnd(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
 
   OnStart(nsString aUri);
 
   OnPause(float aElapsedTime, uint32_t aCharIndex);
 
   OnResume(float aElapsedTime, uint32_t aCharIndex);
 
   OnBoundary(nsString aName, float aElapsedTime, uint32_t aCharIndex);
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
@@ -82,28 +82,31 @@ SpeechSynthesisRequestChild::~SpeechSynt
 bool
 SpeechSynthesisRequestChild::RecvOnStart(const nsString& aUri)
 {
   mTask->DispatchStartImpl(aUri);
   return true;
 }
 
 bool
-SpeechSynthesisRequestChild::Recv__delete__(const bool& aIsError,
-                                            const float& aElapsedTime,
-                                            const uint32_t& aCharIndex)
+SpeechSynthesisRequestChild::RecvOnEnd(const bool& aIsError,
+                                       const float& aElapsedTime,
+                                       const uint32_t& aCharIndex)
 {
+  SpeechSynthesisRequestChild* actor = mTask->mActor;
   mTask->mActor = nullptr;
 
   if (aIsError) {
     mTask->DispatchErrorImpl(aElapsedTime, aCharIndex);
   } else {
     mTask->DispatchEndImpl(aElapsedTime, aCharIndex);
   }
 
+  actor->Send__delete__(actor);
+
   return true;
 }
 
 bool
 SpeechSynthesisRequestChild::RecvOnPause(const float& aElapsedTime,
                                          const uint32_t& aCharIndex)
 {
   mTask->DispatchPauseImpl(aElapsedTime, aCharIndex);
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -47,19 +47,19 @@ class SpeechSynthesisRequestChild : publ
 {
 public:
   explicit SpeechSynthesisRequestChild(SpeechTaskChild* aTask);
   virtual ~SpeechSynthesisRequestChild();
 
 protected:
   virtual bool RecvOnStart(const nsString& aUri) override;
 
-  virtual bool Recv__delete__(const bool& aIsError,
-                              const float& aElapsedTime,
-                              const uint32_t& aCharIndex) override;
+  virtual bool RecvOnEnd(const bool& aIsError,
+                         const float& aElapsedTime,
+                         const uint32_t& aCharIndex) override;
 
   virtual bool RecvOnPause(const float& aElapsedTime, const uint32_t& aCharIndex) override;
 
   virtual bool RecvOnResume(const float& aElapsedTime, const uint32_t& aCharIndex) override;
 
   virtual 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
@@ -77,19 +77,16 @@ SpeechSynthesisRequestParent::SpeechSynt
   : mTask(aTask)
 {
   mTask->mActor = this;
   MOZ_COUNT_CTOR(SpeechSynthesisRequestParent);
 }
 
 SpeechSynthesisRequestParent::~SpeechSynthesisRequestParent()
 {
-  if (mTask && mTask->mActor) {
-    mTask->mActor = nullptr;
-  }
 
   MOZ_COUNT_DTOR(SpeechSynthesisRequestParent);
 }
 
 void
 SpeechSynthesisRequestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Implement me! Bug 1005141
@@ -99,16 +96,25 @@ bool
 SpeechSynthesisRequestParent::RecvPause()
 {
   MOZ_ASSERT(mTask);
   mTask->Pause();
   return true;
 }
 
 bool
+SpeechSynthesisRequestParent::Recv__delete__()
+{
+  MOZ_ASSERT(mTask);
+  mTask->mActor = nullptr;
+  mTask = nullptr;
+  return true;
+}
+
+bool
 SpeechSynthesisRequestParent::RecvResume()
 {
   MOZ_ASSERT(mTask);
   mTask->Resume();
   return true;
 }
 
 bool
@@ -147,19 +153,17 @@ SpeechTaskParent::DispatchStartImpl(cons
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
 {
   MOZ_ASSERT(mActor);
-  SpeechSynthesisRequestParent* actor = mActor;
-  mActor = nullptr;
-  if(NS_WARN_IF(!(actor->Send__delete__(actor, false, aElapsedTime, aCharIndex)))) {
+  if(NS_WARN_IF(!(mActor->SendOnEnd(false, aElapsedTime, aCharIndex)))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
@@ -182,19 +186,17 @@ SpeechTaskParent::DispatchResumeImpl(flo
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
 {
   MOZ_ASSERT(mActor);
-  SpeechSynthesisRequestParent* actor = mActor;
-  mActor = nullptr;
-  if(NS_WARN_IF(!(actor->Send__delete__(actor, true, aElapsedTime, aCharIndex)))) {
+  if(NS_WARN_IF(!(mActor->SendOnEnd(true, aElapsedTime, aCharIndex)))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchBoundaryImpl(const nsAString& aName,
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
@@ -66,16 +66,18 @@ protected:
 
   virtual bool RecvResume() override;
 
   virtual bool RecvCancel() override;
 
   virtual bool RecvForceEnd() override;
 
   virtual bool RecvSetAudioOutputVolume(const float& aVolume) override;
+
+  virtual bool Recv__delete__() override;
 };
 
 class SpeechTaskParent : public nsSpeechTask
 {
   friend class SpeechSynthesisRequestParent;
 public:
   SpeechTaskParent(float aVolume, const nsAString& aUtterance)
     : nsSpeechTask(aVolume, aUtterance) {}
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_speech_error.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1226015
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1226015</title>
+  <script type="application/javascript">
+    window.SimpleTest = parent.SimpleTest;
+    window.info = parent.info;
+    window.is = parent.is;
+    window.isnot = parent.isnot;
+    window.ok = parent.ok;
+  </script>
+  <script type="application/javascript" src="common.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226015">Mozilla Bug 1226015</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1226015 **/
+
+function testFunc(done_cb) {
+  var utterance = new SpeechSynthesisUtterance();
+  utterance.lang = 'it-IT-error';
+
+  speechSynthesis.speak(utterance);
+  speechSynthesis.cancel();
+
+  ok(true, "we didn't crash, that is good.")
+  SimpleTest.finish();
+}
+
+// Run test with no global queue, and then run it with a global queue.
+testFunc();
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webspeech/synth/test/mochitest.ini
+++ b/dom/media/webspeech/synth/test/mochitest.ini
@@ -1,21 +1,23 @@
 [DEFAULT]
 tags=msg
 support-files =
   common.js
   file_setup.html
   file_speech_queue.html
   file_speech_simple.html
   file_speech_cancel.html
+  file_speech_error.html
   file_indirect_service_events.html
   file_global_queue.html
   file_global_queue_cancel.html
   file_global_queue_pause.html
 
 [test_setup.html]
 [test_speech_queue.html]
 [test_speech_simple.html]
 [test_speech_cancel.html]
+[test_speech_error.html]
 [test_indirect_service_events.html]
 [test_global_queue.html]
 [test_global_queue_cancel.html]
 [test_global_queue_pause.html]
--- a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp
+++ b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp
@@ -25,17 +25,18 @@
 namespace mozilla {
 namespace dom {
 
 StaticRefPtr<nsFakeSynthServices> nsFakeSynthServices::sSingleton;
 
 enum VoiceFlags
 {
   eSuppressEvents = 1,
-  eSuppressEnd = 2
+  eSuppressEnd = 2,
+  eFailAtStart = 4
 };
 
 struct VoiceDetails
 {
   const char* uri;
   const char* name;
   const char* lang;
   bool defaultVoice;
@@ -49,16 +50,17 @@ static const VoiceDetails sDirectVoices[
   {"urn:moz-tts:fake-direct:celine", "Celine Dion", "fr-CA", false, 0},
   {"urn:moz-tts:fake-direct:julie", "Julieta Venegas", "es-MX", false, },
 };
 
 static const VoiceDetails sIndirectVoices[] = {
   {"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0},
   {"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd},
   {"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd},
+  {"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-error", false, eFailAtStart},
 };
 
 // FakeSynthCallback
 class FakeSynthCallback : public nsISpeechTaskCallback
 {
 public:
   explicit FakeSynthCallback(nsISpeechTask* aTask) : mTask(aTask) { }
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -238,16 +240,21 @@ FakeIndirectAudioSynth::Speak(const nsAS
 
   uint32_t flags = 0;
   for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) {
     if (aUri.EqualsASCII(sIndirectVoices[i].uri)) {
       flags = sIndirectVoices[i].flags;
     }
   }
 
+  if (flags & eFailAtStart) {
+    aTask->DispatchError(0, 0);
+    return NS_OK;
+  }
+
   RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(
     (flags & eSuppressEvents) ? nullptr : aTask);
 
   aTask->Setup(cb, 0, 0, 0);
 
   nsCOMPtr<nsIRunnable> runnable = new DispatchStart(aTask);
   NS_DispatchToMainThread(runnable);
 
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/test/test_speech_error.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1226015
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1150315: Web Speech API check all classes are present</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226015">Mozilla Bug 1226015</a>
+<p id="display"></p>
+<iframe id="testFrame"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1226015 **/
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+  { set: [['media.webspeech.synth.enabled', true],
+          ['media.webspeech.synth.force_global_queue', false]] },
+  function() { document.getElementById("testFrame").src = "file_speech_error.html"; });
+
+</script>
+</pre>
+</body>
+</html>