diff options
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 6 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 8 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_browsertest.cc | 103 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_dispatcher_host.cc | 101 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_dispatcher_host.h | 63 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_manager.cc | 14 | ||||
-rw-r--r-- | chrome/browser/speech/speech_input_manager.h | 44 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | chrome/chrome_renderer.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 31 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 12 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 8 | ||||
-rw-r--r-- | chrome/renderer/speech_input_dispatcher.cc | 61 | ||||
-rw-r--r-- | chrome/renderer/speech_input_dispatcher.h | 46 | ||||
-rw-r--r-- | chrome/test/data/speech/basic_recognition.html | 30 |
16 files changed, 533 insertions, 1 deletions
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index a8253e6..0c5fc51 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -50,6 +50,7 @@ #include "chrome/browser/renderer_host/database_dispatcher_host.h" #include "chrome/browser/renderer_host/render_view_host_notification_task.h" #include "chrome/browser/renderer_host/render_widget_helper.h" +#include "chrome/browser/speech/speech_input_dispatcher_host.h" #include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/browser/task_manager.h" #include "chrome/browser/worker_host/message_port_dispatcher.h" @@ -230,6 +231,8 @@ ResourceMessageFilter::ResourceMessageFilter( off_the_record_(profile->IsOffTheRecord()), next_route_id_callback_(NewCallbackWithReturnValue( render_widget_helper, &RenderWidgetHelper::GetNextRoutingID)), + ALLOW_THIS_IN_INITIALIZER_LIST(speech_input_dispatcher_host_( + new speech_input::SpeechInputDispatcherHost(this->id()))), ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_dispatcher_host_( GeolocationDispatcherHost::New( this->id(), profile->GetGeolocationPermissionContext()))) { @@ -332,7 +335,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { db_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) || mp_dispatcher->OnMessageReceived( msg, this, next_route_id_callback(), &msg_is_ok) || - geolocation_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok); + geolocation_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) || + speech_input_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok); if (!handled) { DCHECK(msg_is_ok); // It should have been marked handled if it wasn't OK. diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index d5cd9d9..317f55e 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -62,6 +62,10 @@ class PrinterQuery; class PrintJobManager; } +namespace speech_input { +class SpeechInputDispatcherHost; +} + namespace webkit_glue { struct WebCookie; } @@ -441,6 +445,10 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // A callback to create a routing id for the associated renderer process. scoped_ptr<CallbackWithReturnValue<int>::Type> next_route_id_callback_; + // Used to handle speech input related messages. + scoped_refptr<speech_input::SpeechInputDispatcherHost> + speech_input_dispatcher_host_; + // Used to handle geolocation-related messages. scoped_refptr<GeolocationDispatcherHost> geolocation_dispatcher_host_; diff --git a/chrome/browser/speech/speech_input_browsertest.cc b/chrome/browser/speech/speech_input_browsertest.cc new file mode 100644 index 0000000..b451934 --- /dev/null +++ b/chrome/browser/speech/speech_input_browsertest.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/file_path.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/speech/speech_input_dispatcher_host.h" +#include "chrome/browser/speech/speech_input_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" + +namespace speech_input { +class FakeSpeechInputManager; +} + +// This class does not need to be refcounted (typically done by PostTask) since +// it will outlive the test and gets released only when the test shuts down. +// Disabling refcounting here saves a bit of unnecessary code and the factory +// method can return a plain pointer below as required by the real code. +DISABLE_RUNNABLE_METHOD_REFCOUNT(speech_input::FakeSpeechInputManager); + +namespace speech_input { + +const char* kTestResult = "Pictures of the moon"; + +class FakeSpeechInputManager : public SpeechInputManager { + public: + explicit FakeSpeechInputManager(Listener* listener) + : render_view_id_(0), + listener_(listener) { + } + + // SpeechInputManager methods. + void StartRecognition(int render_view_id) { + EXPECT_EQ(0, render_view_id_); + render_view_id_ = render_view_id; + // Give the fake result in a short while. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, + &FakeSpeechInputManager::SetFakeRecognitionResult)); + } + void CancelRecognition(int render_view_id) { + EXPECT_EQ(render_view_id_, render_view_id); + render_view_id_ = 0; + } + void StopRecording(int render_view_id) { + EXPECT_EQ(render_view_id_, render_view_id); + // Nothing to do here since we aren't really recording. + } + + private: + void SetFakeRecognitionResult() { + if (render_view_id_) { // Do a check in case we were cancelled.. + listener_->DidCompleteRecording(render_view_id_); + listener_->SetRecognitionResult(render_view_id_, + ASCIIToUTF16(kTestResult)); + listener_->DidCompleteRecognition(render_view_id_); + render_view_id_ = 0; + } + } + + int render_view_id_; + Listener* listener_; +}; + +// Factory method. +SpeechInputManager* fakeManagerFactory(SpeechInputManager::Listener* listener) { + return new FakeSpeechInputManager(listener); +} + +class SpeechInputBrowserTest : public InProcessBrowserTest { + public: + // InProcessBrowserTest methods + virtual void SetUpCommandLine(CommandLine* command_line) { + command_line->AppendSwitch(switches::kEnableSpeechInput); + } + + GURL testUrl(const FilePath::CharType* filename) { + const FilePath kTestDir(FILE_PATH_LITERAL("speech")); + return ui_test_utils::GetTestUrl(kTestDir, FilePath(filename)); + } +}; + +IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, TestBasicRecognition) { + // Inject the fake manager factory so that the test result is returned to the + // web page. + SpeechInputDispatcherHost::set_manager_factory(&fakeManagerFactory); + + // The test page starts speech recognition and waits to receive the above + // defined test string as the result. Once it receives the result it either + // navigates to #pass or #fail depending on the result. + GURL test_url = testUrl(FILE_PATH_LITERAL("basic_recognition.html")); + ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), + test_url, + 2); + + // Check that the page got the result it expected. + EXPECT_EQ("pass", browser()->GetSelectedTabContents()->GetURL().ref()); +} + +} // namespace speech_input diff --git a/chrome/browser/speech/speech_input_dispatcher_host.cc b/chrome/browser/speech/speech_input_dispatcher_host.cc new file mode 100644 index 0000000..8346cbe --- /dev/null +++ b/chrome/browser/speech/speech_input_dispatcher_host.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/speech_input_dispatcher_host.h" + +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/render_view_host_notification_task.h" +#include "chrome/browser/renderer_host/resource_message_filter.h" +#include "chrome/common/render_messages.h" + +namespace speech_input { + +SpeechInputManager::FactoryMethod* + SpeechInputDispatcherHost::manager_factory_ = &SpeechInputManager::Create; + +SpeechInputDispatcherHost::SpeechInputDispatcherHost( + int resource_message_filter_process_id) + : resource_message_filter_process_id_(resource_message_filter_process_id) { + // This is initialized by ResourceMessageFilter. Do not add any non-trivial + // initialization here, instead do it lazily when required (e.g. see the + // method |manager()|) or add an Init() method. +} + +SpeechInputDispatcherHost::~SpeechInputDispatcherHost() { +} + +SpeechInputManager* SpeechInputDispatcherHost::manager() { + if (!manager_.get()) { + manager_.reset((*manager_factory_)(this)); + DCHECK(manager_.get()); + } + return manager_.get(); +} + +bool SpeechInputDispatcherHost::OnMessageReceived( + const IPC::Message& msg, bool* msg_was_ok) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(SpeechInputDispatcherHost, msg, *msg_was_ok) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StartRecognition, + OnStartRecognition) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_CancelRecognition, + OnCancelRecognition) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StopRecording, + OnStopRecording) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void SpeechInputDispatcherHost::OnStartRecognition(int render_view_id) { + LOG(INFO) << "SpeechInputDispatcherHost: start recognition" + << render_view_id; + manager()->StartRecognition(render_view_id); +} + +void SpeechInputDispatcherHost::OnCancelRecognition(int render_view_id) { + LOG(INFO) << "SpeechInputDispatcherHost: cancel recognition" + << render_view_id; + manager()->CancelRecognition(render_view_id); +} + +void SpeechInputDispatcherHost::OnStopRecording(int render_view_id) { + LOG(INFO) << "SpeechInputDispatcherHost: stop recording" + << render_view_id; + manager()->StopRecording(render_view_id); +} + +void SpeechInputDispatcherHost::SendMessageToRenderView(IPC::Message* message, + int render_view_id) { + CallRenderViewHost( + resource_message_filter_process_id_, render_view_id, + &RenderViewHost::Send, message); +} + + +void SpeechInputDispatcherHost::SetRecognitionResult(int render_view_id, + const string16& result) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + SendMessageToRenderView( + new ViewMsg_SpeechInput_SetRecognitionResult(render_view_id, result), + render_view_id); +} + +void SpeechInputDispatcherHost::DidCompleteRecording(int render_view_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + SendMessageToRenderView( + new ViewMsg_SpeechInput_RecordingComplete(render_view_id), + render_view_id); +} + +void SpeechInputDispatcherHost::DidCompleteRecognition(int render_view_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + SendMessageToRenderView( + new ViewMsg_SpeechInput_RecognitionComplete(render_view_id), + render_view_id); +} + +} // namespace speech_input diff --git a/chrome/browser/speech/speech_input_dispatcher_host.h b/chrome/browser/speech/speech_input_dispatcher_host.h new file mode 100644 index 0000000..45f9c98 --- /dev/null +++ b/chrome/browser/speech/speech_input_dispatcher_host.h @@ -0,0 +1,63 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_SPEECH_INPUT_DISPATCHER_HOST_H_ +#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_DISPATCHER_HOST_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "ipc/ipc_message.h" +#include "speech_input_manager.h" + +namespace speech_input { + +// SpeechInputDispatcherHost is a delegate for Speech API messages used by +// ResourceMessageFilter. +// It's the complement of SpeechInputDispatcher (owned by RenderView). +class SpeechInputDispatcherHost + : public base::RefCountedThreadSafe<SpeechInputDispatcherHost>, + public SpeechInputManager::Listener { + public: + explicit SpeechInputDispatcherHost(int resource_message_filter_process_id); + + // SpeechInputManager::Listener methods. + void SetRecognitionResult(int render_view_id, const string16& result); + void DidCompleteRecording(int render_view_id); + void DidCompleteRecognition(int render_view_id); + + // Called to possibly handle the incoming IPC message. Returns true if + // handled. + bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok); + + // Factory setter useful for tests. + static void set_manager_factory(SpeechInputManager::FactoryMethod* factory) { + manager_factory_ = factory; + } + + private: + friend class base::RefCountedThreadSafe<SpeechInputDispatcherHost>; + virtual ~SpeechInputDispatcherHost(); + void SendMessageToRenderView(IPC::Message* message, int render_view_id); + + void OnStartRecognition(int render_view_id); + void OnCancelRecognition(int render_view_id); + void OnStopRecording(int render_view_id); + + // Returns the speech input manager to forward events to, creating one if + // needed. + SpeechInputManager* manager(); + + int resource_message_filter_process_id_; + + scoped_ptr<SpeechInputManager> manager_; + + static SpeechInputManager::FactoryMethod* manager_factory_; + + DISALLOW_COPY_AND_ASSIGN(SpeechInputDispatcherHost); +}; + +} // namespace speech_input + +#endif // CHROME_BROWSER_SPEECH_SPEECH_INPUT_DISPATCHER_HOST_H_ diff --git a/chrome/browser/speech/speech_input_manager.cc b/chrome/browser/speech/speech_input_manager.cc new file mode 100644 index 0000000..f75a839 --- /dev/null +++ b/chrome/browser/speech/speech_input_manager.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/speech_input_manager.h" + +namespace speech_input { + +SpeechInputManager* SpeechInputManager::Create(Listener* listener) { + // TODO(satish): Implement a real speech input manager. + return NULL; +} + +} // namespace speech_input diff --git a/chrome/browser/speech/speech_input_manager.h b/chrome/browser/speech/speech_input_manager.h new file mode 100644 index 0000000..39f0d89 --- /dev/null +++ b/chrome/browser/speech/speech_input_manager.h @@ -0,0 +1,44 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_SPEECH_INPUT_MANAGER_H_ +#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_MANAGER_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "ipc/ipc_message.h" + +namespace speech_input { + +// This is the gatekeeper for speech recognition in the browser process. It +// handles requests received from various render views and makes sure only one +// of them can use speech recognition at a time. It also sends recognition +// results and status events to the render views when required. +class SpeechInputManager { + public: + // Implemented by the dispatcher host to relay events to the render views. + class Listener { + public: + virtual void SetRecognitionResult(int render_view_id, + const string16& value) = 0; + virtual void DidCompleteRecording(int render_view_id) = 0; + virtual void DidCompleteRecognition(int render_view_id) = 0; + }; + + // Factory method to create new instances. + static SpeechInputManager* Create(Listener* listener); + // Factory method definition useful for tests. + typedef SpeechInputManager* (FactoryMethod)(Listener*); + + virtual ~SpeechInputManager() {} + + // Handlers for requests from render views. + virtual void StartRecognition(int render_view_id) = 0; + virtual void CancelRecognition(int render_view_id) = 0; + virtual void StopRecording(int render_view_id) = 0; +}; + +} // namespace speech_input + +#endif // CHROME_BROWSER_SPEECH_SPEECH_INPUT_MANAGER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a96d688..5780bd3 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2316,6 +2316,10 @@ 'browser/shell_integration_mac.mm', 'browser/shell_integration_linux.cc', 'browser/shell_integration_win.cc', + 'browser/speech/speech_input_dispatcher_host.cc', + 'browser/speech/speech_input_dispatcher_host.h', + 'browser/speech/speech_input_manager.cc', + 'browser/speech/speech_input_manager.h', 'browser/spellcheck_host.cc', 'browser/spellcheck_host.h', 'browser/spellchecker_linux.cc', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index cb2b417..a775909 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -172,6 +172,8 @@ 'renderer/safe_browsing/phishing_dom_feature_extractor.h', 'renderer/safe_browsing/phishing_url_feature_extractor.cc', 'renderer/safe_browsing/phishing_url_feature_extractor.h', + 'renderer/speech_input_dispatcher.cc', + 'renderer/speech_input_dispatcher.h', 'renderer/spellchecker/spellcheck.cc', 'renderer/spellchecker/spellcheck.h', 'renderer/spellchecker/spellcheck_worditerator.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index c33e615..a547fac 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1613,6 +1613,7 @@ 'browser/safe_browsing/safe_browsing_browsertest.cc', 'browser/sessions/session_restore_browsertest.cc', 'browser/speech/enable_speech_input_switch_browsertest.cc', + 'browser/speech/speech_input_browsertest.cc', 'browser/ssl/ssl_browser_tests.cc', 'browser/task_manager_browsertest.cc', 'browser/views/browser_actions_container_browsertest.cc', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 76d2585..66ce013 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -976,6 +976,19 @@ IPC_BEGIN_MESSAGES(View) IPC_MESSAGE_ROUTED1(ViewMsg_AccessibilityDoDefaultAction, int /* object id */) + // Relay a speech recognition result, either partial or final. + IPC_MESSAGE_ROUTED1(ViewMsg_SpeechInput_SetRecognitionResult, + string16 /* result */) + + // Indicate that speech recognizer has stopped recording and started + // recognition. + IPC_MESSAGE_ROUTED0(ViewMsg_SpeechInput_RecordingComplete) + + // Indicate that speech recognizer has completed recognition. This will be + // the last message sent in response to a + // ViewHostMsg_SpeechInput_StartRecognition. + IPC_MESSAGE_ROUTED0(ViewMsg_SpeechInput_RecognitionComplete) + IPC_END_MESSAGES(View) @@ -2539,4 +2552,22 @@ IPC_BEGIN_MESSAGES(ViewHost) // This allows the browser to handle things such as zooming differently. IPC_MESSAGE_ROUTED0(ViewHostMsg_SetDisplayingPDFContent) + // Requests the speech input service to start speech recognition on behalf of + // the given |render_view_id|. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SpeechInput_StartRecognition, + int /* render_view_id */) + + // Requests the speech input service to cancel speech recognition on behalf of + // the given |render_view_id|. If speech recognition is not happening nor or + // is happening on behalf of some other render view, this call does nothing. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SpeechInput_CancelRecognition, + int /* render_view_id */) + + // Requests the speech input service to stop audio recording on behalf of + // the given |render_view_id|. Any audio recorded so far will be fed to the + // speech recognizer. If speech recognition is not happening nor or is + // happening on behalf of some other render view, this call does nothing. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SpeechInput_StopRecording, + int /* render_view_id */) + IPC_END_MESSAGES(ViewHost) diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 39c4193..9d97ee2 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -61,6 +61,7 @@ #include "chrome/renderer/render_view_visitor.h" #include "chrome/renderer/renderer_webapplicationcachehost_impl.h" #include "chrome/renderer/renderer_webstoragenamespace_impl.h" +#include "chrome/renderer/speech_input_dispatcher.h" #include "chrome/renderer/spellchecker/spellcheck.h" #include "chrome/renderer/user_script_slave.h" #include "chrome/renderer/visitedlink_slave.h" @@ -628,6 +629,10 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { geolocation_dispatcher_->OnMessageReceived(message)) { return; } + if (speech_input_dispatcher_.get() && + speech_input_dispatcher_->OnMessageReceived(message)) { + return; + } IPC_BEGIN_MESSAGE_MAP(RenderView, message) IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, OnCaptureThumbnail) @@ -5258,6 +5263,13 @@ WebKit::WebGeolocationService* RenderView::geolocationService() { return geolocation_dispatcher_.get(); } +WebKit::WebSpeechInputController* RenderView::speechInputController( + WebKit::WebSpeechInputListener* listener) { + if (!speech_input_dispatcher_.get()) + speech_input_dispatcher_.reset(new SpeechInputDispatcher(this, listener)); + return speech_input_dispatcher_.get(); +} + bool RenderView::IsNonLocalTopLevelNavigation( const GURL& url, WebKit::WebFrame* frame, WebKit::WebNavigationType type) { // Must be a top level frame. diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 3d3cdbd..18f5fe2 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -67,6 +67,7 @@ class PepperDeviceTest; class PrintWebViewHelper; class RenderViewVisitor; class SkBitmap; +class SpeechInputDispatcher; class WebPluginDelegatePepper; class WebPluginDelegateProxy; struct ContextMenuMediaParams; @@ -107,6 +108,8 @@ class WebMediaPlayer; class WebMediaPlayerClient; class WebNode; class WebPlugin; +class WebSpeechInputController; +class WebSpeechInputListener; class WebStorageNamespace; class WebURLRequest; class WebView; @@ -414,6 +417,8 @@ class RenderView : public RenderWidget, virtual void didAcceptAutocompleteSuggestion( const WebKit::WebInputElement& element); virtual WebKit::WebGeolocationService* geolocationService(); + virtual WebKit::WebSpeechInputController* speechInputController( + WebKit::WebSpeechInputListener* listener); // WebKit::WebFrameClient implementation ------------------------------------- @@ -1207,6 +1212,9 @@ class RenderView : public RenderWidget, // maintains the cache and other features of the accessibility tree. scoped_ptr<WebKit::WebAccessibilityCache> accessibility_; + // The speech dispatcher attached to this view, lazily initialized. + scoped_ptr<SpeechInputDispatcher> speech_input_dispatcher_; + // Misc ---------------------------------------------------------------------- // The current and pending file chooser completion objects. If the queue is diff --git a/chrome/renderer/speech_input_dispatcher.cc b/chrome/renderer/speech_input_dispatcher.cc new file mode 100644 index 0000000..70989d6 --- /dev/null +++ b/chrome/renderer/speech_input_dispatcher.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/speech_input_dispatcher.h" + +#include "chrome/renderer/render_view.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputListener.h" + +using WebKit::WebFrame; + +SpeechInputDispatcher::SpeechInputDispatcher( + RenderView* render_view, WebKit::WebSpeechInputListener* listener) + : render_view_(render_view), + listener_(listener) { +} + +bool SpeechInputDispatcher::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(SpeechInputDispatcher, message) + IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_SetRecognitionResult, + OnSpeechRecognitionResult) + IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecordingComplete, + OnSpeechRecordingComplete) + IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecognitionComplete, + OnSpeechRecognitionComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool SpeechInputDispatcher::startRecognition() { + render_view_->Send(new ViewHostMsg_SpeechInput_StartRecognition( + render_view_->routing_id())); + return true; +} + +void SpeechInputDispatcher::cancelRecognition() { + render_view_->Send(new ViewHostMsg_SpeechInput_CancelRecognition( + render_view_->routing_id())); +} + +void SpeechInputDispatcher::stopRecording() { + render_view_->Send(new ViewHostMsg_SpeechInput_StopRecording( + render_view_->routing_id())); +} + +void SpeechInputDispatcher::OnSpeechRecognitionResult( + const string16& result) { + listener_->setRecognitionResult(result); +} + +void SpeechInputDispatcher::OnSpeechRecordingComplete() { + listener_->didCompleteRecording(); +} + +void SpeechInputDispatcher::OnSpeechRecognitionComplete() { + listener_->didCompleteRecognition(); +} diff --git a/chrome/renderer/speech_input_dispatcher.h b/chrome/renderer/speech_input_dispatcher.h new file mode 100644 index 0000000..ccb69a9 --- /dev/null +++ b/chrome/renderer/speech_input_dispatcher.h @@ -0,0 +1,46 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_SPEECH_INPUT_DISPATCHER_H_ +#define CHROME_RENDERER_SPEECH_INPUT_DISPATCHER_H_ + +#include "base/basictypes.h" +#include "ipc/ipc_message.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputController.h" + +class GURL; +class RenderView; + +namespace WebKit { +class WebSpeechInputListener; +} + +// SpeechInputDispatcher is a delegate for speech input messages used by WebKit. +// It's the complement of SpeechInputDispatcherHost (owned by RenderViewHost). +class SpeechInputDispatcher : public WebKit::WebSpeechInputController { + public: + SpeechInputDispatcher(RenderView* render_view, + WebKit::WebSpeechInputListener* listener); + + // Called to possibly handle the incoming IPC message. Returns true if + // handled. Called in render thread. + bool OnMessageReceived(const IPC::Message& msg); + + // WebKit::WebSpeechInputController. + bool startRecognition(); + void cancelRecognition(); + void stopRecording(); + + private: + void OnSpeechRecognitionResult(const string16& result); + void OnSpeechRecordingComplete(); + void OnSpeechRecognitionComplete(); + + RenderView* render_view_; + WebKit::WebSpeechInputListener* listener_; + + DISALLOW_COPY_AND_ASSIGN(SpeechInputDispatcher); +}; + +#endif // CHROME_RENDERER_SPEECH_INPUT_DISPATCHER_H_ diff --git a/chrome/test/data/speech/basic_recognition.html b/chrome/test/data/speech/basic_recognition.html new file mode 100644 index 0000000..ef0ccb1 --- /dev/null +++ b/chrome/test/data/speech/basic_recognition.html @@ -0,0 +1,30 @@ +<html>
+ <head>
+ <title>Speech input test</title>
+ <script type="text/javascript">
+ function onspeechresult(value) {
+ if (value == "Pictures of the moon") {
+ document.getElementById('status').innerHTML = 'PASS';
+ document.location = '#pass';
+ } else {
+ document.location = '#fail';
+ }
+ }
+ function run() {
+ // Send a click to the right corner of the input field where the speech
+ // button is rendered.
+ var inputField = document.getElementById('inputField');
+ var evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, window,
+ 0, 0, 0,
+ inputField.offsetWidth - 4, 4,
+ false, false, false, false, 0, null);
+ inputField.dispatchEvent(evt);
+ }
+ </script>
+ </head>
+ <body onLoad="run()">
+ <input id='inputField' speech onchange="onspeechresult(this.value);"><br>
+ <div id="status">FAIL</div>
+ </body>
+</html>
|