nsresult
nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
                                   const nsAString& aUri,
                                   const nsAString& aName,
                                   const nsAString& aLang,
                                   bool aLocalService)
{
  bool found = false;
  mUriVoiceMap.GetWeak(aUri, &found);
  NS_ENSURE_FALSE(found, NS_ERROR_INVALID_ARG);

  nsRefPtr<VoiceData> voice = new VoiceData(aService, aUri, aName, aLang,
                                            aLocalService);

  mVoices.AppendElement(voice);
  mUriVoiceMap.Put(aUri, voice);

  nsTArray<SpeechSynthesisParent*> ssplist;
  GetAllSpeechSynthActors(ssplist);

  if (!ssplist.IsEmpty()) {
    mozilla::dom::RemoteVoice ssvoice(nsString(aUri),
                                      nsString(aName),
                                      nsString(aLang),
                                      aLocalService);

    for (uint32_t i = 0; i < ssplist.Length(); ++i) {
      unused << ssplist[i]->SendVoiceAdded(ssvoice);
    }
  }

  return NS_OK;
}
NS_IMETHODIMP
nsSynthVoiceRegistry::SetDefaultVoice(const nsAString& aUri,
                                      bool aIsDefault)
{
  bool found = false;
  VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
  NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);

  mDefaultVoices.RemoveElement(retval);

  LOG(PR_LOG_DEBUG, ("nsSynthVoiceRegistry::SetDefaultVoice %s %s",
                     NS_ConvertUTF16toUTF8(aUri).get(),
                     aIsDefault ? "true" : "false"));

  if (aIsDefault) {
    mDefaultVoices.AppendElement(retval);
  }

  if (XRE_GetProcessType() == GeckoProcessType_Default) {
    nsTArray<SpeechSynthesisParent*> ssplist;
    GetAllSpeechSynthActors(ssplist);

    for (uint32_t i = 0; i < ssplist.Length(); ++i) {
      unused << ssplist[i]->SendSetDefaultVoice(nsString(aUri), aIsDefault);
    }
  }

  return NS_OK;
}
NS_IMETHODIMP
nsSynthVoiceRegistry::SetDefaultVoice(const nsAString& aUri,
                                      bool aIsDefault)
{
  bool found = false;
  VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
  if(NS_WARN_IF(!(found))) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  mDefaultVoices.RemoveElement(retval);

  LOG(LogLevel::Debug, ("nsSynthVoiceRegistry::SetDefaultVoice %s %s",
                     NS_ConvertUTF16toUTF8(aUri).get(),
                     aIsDefault ? "true" : "false"));

  if (aIsDefault) {
    mDefaultVoices.AppendElement(retval);
  }

  if (XRE_IsParentProcess()) {
    nsTArray<SpeechSynthesisParent*> ssplist;
    GetAllSpeechSynthActors(ssplist);

    for (uint32_t i = 0; i < ssplist.Length(); ++i) {
      unused << ssplist[i]->SendSetDefaultVoice(nsString(aUri), aIsDefault);
    }
  }

  return NS_OK;
}
NS_IMETHODIMP
nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
                                  const nsAString& aUri)
{
  LOG(PR_LOG_DEBUG,
      ("nsSynthVoiceRegistry::RemoveVoice uri='%s' (%s)",
       NS_ConvertUTF16toUTF8(aUri).get(),
       (XRE_GetProcessType() == GeckoProcessType_Content) ? "child" : "parent"));

  bool found = false;
  VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);

  NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
  NS_ENSURE_TRUE(aService == retval->mService, NS_ERROR_INVALID_ARG);

  mVoices.RemoveElement(retval);
  mDefaultVoices.RemoveElement(retval);
  mUriVoiceMap.Remove(aUri);

  nsTArray<SpeechSynthesisParent*> ssplist;
  GetAllSpeechSynthActors(ssplist);

  for (uint32_t i = 0; i < ssplist.Length(); ++i)
    unused << ssplist[i]->SendVoiceRemoved(nsString(aUri));

  return NS_OK;
}
NS_IMETHODIMP
nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
                                  const nsAString& aUri)
{
  LOG(LogLevel::Debug,
      ("nsSynthVoiceRegistry::RemoveVoice uri='%s' (%s)",
       NS_ConvertUTF16toUTF8(aUri).get(),
       (XRE_IsContentProcess()) ? "child" : "parent"));

  bool found = false;
  VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);

  if(NS_WARN_IF(!(found))) {
    return NS_ERROR_NOT_AVAILABLE;
  }
  if(NS_WARN_IF(!(aService == retval->mService))) {
    return NS_ERROR_INVALID_ARG;
  }

  mVoices.RemoveElement(retval);
  mDefaultVoices.RemoveElement(retval);
  mUriVoiceMap.Remove(aUri);

  nsTArray<SpeechSynthesisParent*> ssplist;
  GetAllSpeechSynthActors(ssplist);

  for (uint32_t i = 0; i < ssplist.Length(); ++i)
    unused << ssplist[i]->SendVoiceRemoved(nsString(aUri));

  return NS_OK;
}