1/*
2 * Copyright (C) 2012 Google 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 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 "config.h"
27
28#include "modules/speech/SpeechRecognition.h"
29
30#include "bindings/core/v8/ExceptionState.h"
31#include "core/dom/Document.h"
32#include "core/dom/ExceptionCode.h"
33#include "core/page/Page.h"
34#include "modules/speech/SpeechRecognitionController.h"
35#include "modules/speech/SpeechRecognitionError.h"
36#include "modules/speech/SpeechRecognitionEvent.h"
37
38namespace blink {
39
40SpeechRecognition* SpeechRecognition::create(ExecutionContext* context)
41{
42    SpeechRecognition* speechRecognition = adoptRefCountedGarbageCollectedWillBeNoop(new SpeechRecognition(context));
43    speechRecognition->suspendIfNeeded();
44    return speechRecognition;
45}
46
47void SpeechRecognition::start(ExceptionState& exceptionState)
48{
49    ASSERT(m_controller);
50    if (m_started) {
51        exceptionState.throwDOMException(InvalidStateError, "recognition has already started.");
52        return;
53    }
54
55    m_finalResults.clear();
56    m_controller->start(this, m_grammars.get(), m_lang, m_continuous, m_interimResults, m_maxAlternatives);
57    m_started = true;
58}
59
60void SpeechRecognition::stopFunction()
61{
62    ASSERT(m_controller);
63    if (m_started && !m_stopping) {
64        m_stopping = true;
65        m_controller->stop(this);
66    }
67}
68
69void SpeechRecognition::abort()
70{
71    ASSERT(m_controller);
72    if (m_started && !m_stopping) {
73        m_stopping = true;
74        m_controller->abort(this);
75    }
76}
77
78void SpeechRecognition::didStartAudio()
79{
80    dispatchEvent(Event::create(EventTypeNames::audiostart));
81}
82
83void SpeechRecognition::didStartSound()
84{
85    dispatchEvent(Event::create(EventTypeNames::soundstart));
86}
87
88void SpeechRecognition::didStartSpeech()
89{
90    dispatchEvent(Event::create(EventTypeNames::speechstart));
91}
92
93void SpeechRecognition::didEndSpeech()
94{
95    dispatchEvent(Event::create(EventTypeNames::speechend));
96}
97
98void SpeechRecognition::didEndSound()
99{
100    dispatchEvent(Event::create(EventTypeNames::soundend));
101}
102
103void SpeechRecognition::didEndAudio()
104{
105    dispatchEvent(Event::create(EventTypeNames::audioend));
106}
107
108void SpeechRecognition::didReceiveResults(const HeapVector<Member<SpeechRecognitionResult> >& newFinalResults, const HeapVector<Member<SpeechRecognitionResult> >& currentInterimResults)
109{
110    unsigned long resultIndex = m_finalResults.size();
111
112    for (size_t i = 0; i < newFinalResults.size(); ++i)
113        m_finalResults.append(newFinalResults[i]);
114
115    HeapVector<Member<SpeechRecognitionResult> > results = m_finalResults;
116    for (size_t i = 0; i < currentInterimResults.size(); ++i)
117        results.append(currentInterimResults[i]);
118
119    dispatchEvent(SpeechRecognitionEvent::createResult(resultIndex, results));
120}
121
122void SpeechRecognition::didReceiveNoMatch(SpeechRecognitionResult* result)
123{
124    dispatchEvent(SpeechRecognitionEvent::createNoMatch(result));
125}
126
127void SpeechRecognition::didReceiveError(PassRefPtrWillBeRawPtr<SpeechRecognitionError> error)
128{
129    dispatchEvent(error);
130    m_started = false;
131}
132
133void SpeechRecognition::didStart()
134{
135    dispatchEvent(Event::create(EventTypeNames::start));
136}
137
138void SpeechRecognition::didEnd()
139{
140    m_started = false;
141    m_stopping = false;
142    if (!m_stoppedByActiveDOMObject)
143        dispatchEvent(Event::create(EventTypeNames::end));
144}
145
146const AtomicString& SpeechRecognition::interfaceName() const
147{
148    return EventTargetNames::SpeechRecognition;
149}
150
151ExecutionContext* SpeechRecognition::executionContext() const
152{
153    return ActiveDOMObject::executionContext();
154}
155
156void SpeechRecognition::stop()
157{
158    m_stoppedByActiveDOMObject = true;
159    if (hasPendingActivity())
160        abort();
161}
162
163bool SpeechRecognition::hasPendingActivity() const
164{
165    return m_started;
166}
167
168SpeechRecognition::SpeechRecognition(ExecutionContext* context)
169    : ActiveDOMObject(context)
170    , m_grammars(SpeechGrammarList::create()) // FIXME: The spec is not clear on the default value for the grammars attribute.
171    , m_continuous(false)
172    , m_interimResults(false)
173    , m_maxAlternatives(1)
174    , m_controller(nullptr)
175    , m_stoppedByActiveDOMObject(false)
176    , m_started(false)
177    , m_stopping(false)
178{
179    Document* document = toDocument(executionContext());
180
181    Page* page = document->page();
182    ASSERT(page);
183
184    m_controller = SpeechRecognitionController::from(page);
185    ASSERT(m_controller);
186
187    // FIXME: Need to hook up with Page to get notified when the visibility changes.
188}
189
190SpeechRecognition::~SpeechRecognition()
191{
192}
193
194void SpeechRecognition::trace(Visitor* visitor)
195{
196    visitor->trace(m_grammars);
197#if ENABLE(OILPAN)
198    visitor->trace(m_controller);
199#endif
200    visitor->trace(m_finalResults);
201    EventTargetWithInlineData::trace(visitor);
202}
203
204} // namespace blink
205