1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/input_tag_speech_dispatcher.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "content/common/speech_recognition_messages.h"
9#include "content/renderer/render_view_impl.h"
10#include "third_party/WebKit/public/platform/WebSize.h"
11#include "third_party/WebKit/public/platform/WebString.h"
12#include "third_party/WebKit/public/web/WebDocument.h"
13#include "third_party/WebKit/public/web/WebElement.h"
14#include "third_party/WebKit/public/web/WebFrame.h"
15#include "third_party/WebKit/public/web/WebInputElement.h"
16#include "third_party/WebKit/public/web/WebNode.h"
17#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
18#include "third_party/WebKit/public/web/WebSpeechInputListener.h"
19#include "third_party/WebKit/public/web/WebView.h"
20
21using WebKit::WebDocument;
22using WebKit::WebElement;
23using WebKit::WebFrame;
24using WebKit::WebInputElement;
25using WebKit::WebNode;
26using WebKit::WebView;
27
28namespace content {
29
30InputTagSpeechDispatcher::InputTagSpeechDispatcher(
31    RenderViewImpl* render_view,
32    WebKit::WebSpeechInputListener* listener)
33    : RenderViewObserver(render_view),
34      listener_(listener) {
35}
36
37bool InputTagSpeechDispatcher::OnMessageReceived(
38    const IPC::Message& message) {
39  bool handled = true;
40  IPC_BEGIN_MESSAGE_MAP(InputTagSpeechDispatcher, message)
41    IPC_MESSAGE_HANDLER(InputTagSpeechMsg_SetRecognitionResults,
42                        OnSpeechRecognitionResults)
43    IPC_MESSAGE_HANDLER(InputTagSpeechMsg_RecordingComplete,
44                        OnSpeechRecordingComplete)
45    IPC_MESSAGE_HANDLER(InputTagSpeechMsg_RecognitionComplete,
46                        OnSpeechRecognitionComplete)
47    IPC_MESSAGE_HANDLER(InputTagSpeechMsg_ToggleSpeechInput,
48                        OnSpeechRecognitionToggleSpeechInput)
49    IPC_MESSAGE_UNHANDLED(handled = false)
50  IPC_END_MESSAGE_MAP()
51  return handled;
52}
53
54bool InputTagSpeechDispatcher::startRecognition(
55    int request_id,
56    const WebKit::WebRect& element_rect,
57    const WebKit::WebString& language,
58    const WebKit::WebString& grammar,
59    const WebKit::WebSecurityOrigin& origin) {
60  DVLOG(1) << "InputTagSpeechDispatcher::startRecognition enter";
61
62  InputTagSpeechHostMsg_StartRecognition_Params params;
63  params.grammar = UTF16ToUTF8(grammar);
64  params.language = UTF16ToUTF8(language);
65  params.origin_url = UTF16ToUTF8(origin.toString());
66  params.render_view_id = routing_id();
67  params.request_id = request_id;
68  params.element_rect = element_rect;
69
70  Send(new InputTagSpeechHostMsg_StartRecognition(params));
71  DVLOG(1) << "InputTagSpeechDispatcher::startRecognition exit";
72  return true;
73}
74
75void InputTagSpeechDispatcher::cancelRecognition(int request_id) {
76  DVLOG(1) << "InputTagSpeechDispatcher::cancelRecognition enter";
77  Send(new InputTagSpeechHostMsg_CancelRecognition(routing_id(), request_id));
78  DVLOG(1) << "InputTagSpeechDispatcher::cancelRecognition exit";
79}
80
81void InputTagSpeechDispatcher::stopRecording(int request_id) {
82  DVLOG(1) << "InputTagSpeechDispatcher::stopRecording enter";
83  Send(new InputTagSpeechHostMsg_StopRecording(routing_id(),
84                                               request_id));
85  DVLOG(1) << "InputTagSpeechDispatcher::stopRecording exit";
86}
87
88void InputTagSpeechDispatcher::OnSpeechRecognitionResults(
89    int request_id,
90    const SpeechRecognitionResults& results) {
91  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecognitionResults enter";
92  DCHECK_EQ(results.size(), 1U);
93
94  const SpeechRecognitionResult& result = results[0];
95  WebKit::WebSpeechInputResultArray webkit_result(result.hypotheses.size());
96  for (size_t i = 0; i < result.hypotheses.size(); ++i) {
97    webkit_result[i].assign(result.hypotheses[i].utterance,
98        result.hypotheses[i].confidence);
99  }
100  listener_->setRecognitionResult(request_id, webkit_result);
101
102  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecognitionResults exit";
103}
104
105void InputTagSpeechDispatcher::OnSpeechRecordingComplete(int request_id) {
106  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecordingComplete enter";
107  listener_->didCompleteRecording(request_id);
108  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecordingComplete exit";
109}
110
111void InputTagSpeechDispatcher::OnSpeechRecognitionComplete(int request_id) {
112  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecognitionComplete enter";
113  listener_->didCompleteRecognition(request_id);
114  DVLOG(1) << "InputTagSpeechDispatcher::OnSpeechRecognitionComplete exit";
115}
116
117void InputTagSpeechDispatcher::OnSpeechRecognitionToggleSpeechInput() {
118  DVLOG(1) <<"InputTagSpeechDispatcher::OnSpeechRecognitionToggleSpeechInput";
119
120  WebView* web_view = render_view()->GetWebView();
121
122  WebFrame* frame = web_view->mainFrame();
123  if (!frame)
124    return;
125
126  WebDocument document = frame->document();
127  if (document.isNull())
128    return;
129
130  WebNode focused_node = document.focusedNode();
131  if (focused_node.isNull() || !focused_node.isElementNode())
132    return;
133
134  WebKit::WebElement element = focused_node.to<WebKit::WebElement>();
135  WebKit::WebInputElement* input_element = WebKit::toWebInputElement(&element);
136  if (!input_element)
137    return;
138  if (!input_element->isSpeechInputEnabled())
139    return;
140
141  if (input_element->getSpeechInputState() == WebInputElement::Idle) {
142    input_element->startSpeechInput();
143  } else {
144    input_element->stopSpeechInput();
145  }
146}
147
148}  // namespace content
149