1 /*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h"
27
28 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
29 #include "third_party/blink/renderer/modules/speech/speech_synthesis.h"
30 #include "third_party/blink/renderer/platform/heap/heap.h"
31 #include "third_party/blink/renderer/platform/heap/persistent.h"
32
33 namespace blink {
34
Create(ExecutionContext * context)35 SpeechSynthesisUtterance* SpeechSynthesisUtterance::Create(
36 ExecutionContext* context) {
37 return MakeGarbageCollected<SpeechSynthesisUtterance>(context, String());
38 }
39
Create(ExecutionContext * context,const String & text)40 SpeechSynthesisUtterance* SpeechSynthesisUtterance::Create(
41 ExecutionContext* context,
42 const String& text) {
43 return MakeGarbageCollected<SpeechSynthesisUtterance>(context, text);
44 }
45
SpeechSynthesisUtterance(ExecutionContext * context,const String & text)46 SpeechSynthesisUtterance::SpeechSynthesisUtterance(ExecutionContext* context,
47 const String& text)
48 : ExecutionContextClient(context),
49 receiver_(this, context),
50 mojom_utterance_(mojom::blink::SpeechSynthesisUtterance::New()) {
51 // Set default values. |voice| intentionally left null.
52 mojom_utterance_->text = text;
53 mojom_utterance_->lang = String("");
54 mojom_utterance_->volume = mojom::blink::kSpeechSynthesisDoublePrefNotSet;
55 mojom_utterance_->rate = mojom::blink::kSpeechSynthesisDoublePrefNotSet;
56 mojom_utterance_->pitch = mojom::blink::kSpeechSynthesisDoublePrefNotSet;
57 }
58
59 SpeechSynthesisUtterance::~SpeechSynthesisUtterance() = default;
60
InterfaceName() const61 const AtomicString& SpeechSynthesisUtterance::InterfaceName() const {
62 return event_target_names::kSpeechSynthesisUtterance;
63 }
64
voice() const65 SpeechSynthesisVoice* SpeechSynthesisUtterance::voice() const {
66 return voice_;
67 }
68
setVoice(SpeechSynthesisVoice * voice)69 void SpeechSynthesisUtterance::setVoice(SpeechSynthesisVoice* voice) {
70 // Cache our own version of the SpeechSynthesisVoice so that we don't have to
71 // do some lookup to go from the platform voice back to the speech synthesis
72 // voice in the read property.
73 voice_ = voice;
74
75 mojom_utterance_->voice = voice_ ? voice_->name() : String();
76 }
77
Trace(Visitor * visitor)78 void SpeechSynthesisUtterance::Trace(Visitor* visitor) {
79 visitor->Trace(receiver_);
80 visitor->Trace(synthesis_);
81 visitor->Trace(voice_);
82 ExecutionContextClient::Trace(visitor);
83 EventTargetWithInlineData::Trace(visitor);
84 }
85
OnStartedSpeaking()86 void SpeechSynthesisUtterance::OnStartedSpeaking() {
87 DCHECK(synthesis_);
88 synthesis_->DidStartSpeaking(this);
89 }
90
OnFinishedSpeaking()91 void SpeechSynthesisUtterance::OnFinishedSpeaking() {
92 DCHECK(synthesis_);
93 finished_ = true;
94 synthesis_->DidFinishSpeaking(this);
95 }
96
OnPausedSpeaking()97 void SpeechSynthesisUtterance::OnPausedSpeaking() {
98 DCHECK(synthesis_);
99 synthesis_->DidPauseSpeaking(this);
100 }
101
OnResumedSpeaking()102 void SpeechSynthesisUtterance::OnResumedSpeaking() {
103 DCHECK(synthesis_);
104 synthesis_->DidResumeSpeaking(this);
105 }
106
OnEncounteredWordBoundary(uint32_t char_index,uint32_t char_length)107 void SpeechSynthesisUtterance::OnEncounteredWordBoundary(uint32_t char_index,
108 uint32_t char_length) {
109 DCHECK(synthesis_);
110 synthesis_->WordBoundaryEventOccurred(this, char_index, char_length);
111 }
112
OnEncounteredSentenceBoundary(uint32_t char_index,uint32_t char_length)113 void SpeechSynthesisUtterance::OnEncounteredSentenceBoundary(
114 uint32_t char_index,
115 uint32_t char_length) {
116 DCHECK(synthesis_);
117 synthesis_->SentenceBoundaryEventOccurred(this, char_index, char_length);
118 }
119
OnEncounteredSpeakingError()120 void SpeechSynthesisUtterance::OnEncounteredSpeakingError() {
121 DCHECK(synthesis_);
122 finished_ = true;
123 synthesis_->SpeakingErrorOccurred(this);
124 }
125
Start(SpeechSynthesis * synthesis)126 void SpeechSynthesisUtterance::Start(SpeechSynthesis* synthesis) {
127 ExecutionContext* context = GetExecutionContext();
128 if (!context)
129 return;
130
131 finished_ = false;
132
133 mojom::blink::SpeechSynthesisUtterancePtr mojom_utterance_to_send =
134 mojom_utterance_->Clone();
135 if (mojom_utterance_to_send->voice.IsNull())
136 mojom_utterance_to_send->voice = String("");
137 if (mojom_utterance_to_send->text.IsNull())
138 mojom_utterance_to_send->text = String("");
139
140 receiver_.reset();
141
142 synthesis_ = synthesis;
143 synthesis_->MojomSynthesis()->Speak(
144 std::move(mojom_utterance_to_send),
145 receiver_.BindNewPipeAndPassRemote(
146 context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
147
148 // Add a disconnect handler so we can cleanup appropriately.
149 receiver_.set_disconnect_handler(WTF::Bind(
150 &SpeechSynthesisUtterance::OnDisconnected, WrapWeakPersistent(this)));
151 }
152
Dispose()153 void SpeechSynthesisUtterance::Dispose() {
154 receiver_.reset();
155 }
156
OnDisconnected()157 void SpeechSynthesisUtterance::OnDisconnected() {
158 // If the remote end disconnects, just simulate that we finished normally.
159 if (!finished_)
160 OnFinishedSpeaking();
161 }
162
163 } // namespace blink
164