summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/generated_resources.grd4
-rw-r--r--chrome/app/theme/speech_input_processing.pngbin0 -> 1422 bytes
-rw-r--r--chrome/app/theme/speech_input_recording.pngbin0 -> 2592 bytes
-rw-r--r--chrome/app/theme/theme_resources.grd2
-rw-r--r--chrome/browser/speech/speech_input_bubble.h58
-rw-r--r--chrome/browser/views/speech_input_bubble.cc258
-rw-r--r--chrome/chrome_browser.gypi2
7 files changed, 324 insertions, 0 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index b33fb6d..d4f5e05f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9336,6 +9336,10 @@ Keep your key file in a safe place. You will need it to create new versions of y
It looks like you've moved. Would you like to use <ph name="NEW_GOOGLE_URL">$1<ex>google.com</ex></ph>?
</message>
+ <message name="IDS_SPEECH_INPUT_BUBBLE_HEADING" desc="First line in the content area of the speech input bubble. Instructs the user that they can start speaking.">
+ Speak now
+ </message>
+
</messages>
<structures fallback_to_english="true">
diff --git a/chrome/app/theme/speech_input_processing.png b/chrome/app/theme/speech_input_processing.png
new file mode 100644
index 0000000..0529e35
--- /dev/null
+++ b/chrome/app/theme/speech_input_processing.png
Binary files differ
diff --git a/chrome/app/theme/speech_input_recording.png b/chrome/app/theme/speech_input_recording.png
new file mode 100644
index 0000000..3644c2e
--- /dev/null
+++ b/chrome/app/theme/speech_input_recording.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index fa2bab1..997200c 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -414,6 +414,8 @@
<include name="IDR_UPGRADE_DOT_INACTIVE" file="upgrade_dot_inactive.png" type="BINDATA" />
<include name="IDR_INFO" file="info_small.png" type="BINDATA" />
<include name="IDR_WARNING" file="alert_small.png" type="BINDATA" />
+ <include name="IDR_SPEECH_INPUT_RECORDING" file="speech_input_recording.png" type="BINDATA" />
+ <include name="IDR_SPEECH_INPUT_PROCESSING" file="speech_input_processing.png" type="BINDATA" />
<if expr="pp_ifdef('_google_chrome')">
<include name="IDR_WIZARD_ICON" file="google_chrome/wizard_icon.png" type="BINDATA" />
<include name="IDR_WIZARD_ICON_RTL" file="google_chrome/wizard_icon_rtl.png" type="BINDATA" />
diff --git a/chrome/browser/speech/speech_input_bubble.h b/chrome/browser/speech/speech_input_bubble.h
new file mode 100644
index 0000000..4ddab1b
--- /dev/null
+++ b/chrome/browser/speech/speech_input_bubble.h
@@ -0,0 +1,58 @@
+// 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_BUBBLE_H_
+#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_H_
+#pragma once
+
+#include "gfx/rect.h"
+
+class TabContents;
+
+// SpeechInputBubble displays a popup info bubble during speech recognition,
+// points to the html element which requested speech input and shows recognition
+// progress events. The popup is closed by the user clicking anywhere outside
+// the popup window, or by the caller destroying this object.
+class SpeechInputBubble {
+ public:
+ // Informs listeners of user actions in the bubble.
+ class Delegate {
+ public:
+ // Invoked when the user cancels speech recognition by clicking on the
+ // cancel button. The InfoBubble is still active and the caller should close
+ // it if necessary.
+ virtual void RecognitionCancelled() = 0;
+
+ // Invoked when the user clicks outside the InfoBubble causing it to close.
+ // The InfoBubble window is no longer visible on screen and the caller can
+ // free the InfoBubble instance. This callback is not issued if the bubble
+ // got closed because the object was destroyed by the caller.
+ virtual void InfoBubbleClosed() = 0;
+
+ protected:
+ virtual ~Delegate() {
+ }
+ };
+
+ // Factory method to create new instances.
+ // Creates and displays the bubble.
+ // |tab_contents| is the TabContents hosting the page.
+ // |element_rect| is the display bounds of the html element requesting speech
+ // input (in page coordinates).
+ static SpeechInputBubble* Create(TabContents* tab_contents,
+ Delegate* delegate,
+ const gfx::Rect& element_rect);
+ virtual ~SpeechInputBubble() {}
+
+ // Indicates to the user that recognition is in progress.
+ virtual void SetRecognizingMode() = 0;
+};
+
+// This typedef is to workaround the issue with certain versions of
+// Visual Studio where it gets confused between multiple Delegate
+// classes and gives a C2500 error. (I saw this error on the try bots -
+// the workaround was not needed for my machine).
+typedef SpeechInputBubble::Delegate SpeechInputBubbleDelegate;
+
+#endif // CHROME_BROWSER_SPEECH_SPEECH_INPUT_BUBBLE_H_
diff --git a/chrome/browser/views/speech_input_bubble.cc b/chrome/browser/views/speech_input_bubble.cc
new file mode 100644
index 0000000..1722227
--- /dev/null
+++ b/chrome/browser/views/speech_input_bubble.cc
@@ -0,0 +1,258 @@
+// 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_bubble.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/views/info_bubble.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "gfx/canvas.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/controls/link.h"
+#include "views/standard_layout.h"
+#include "views/view.h"
+
+namespace {
+
+// The speech bubble's arrow is so many pixels from the left of html element.
+const int kBubbleTargetOffsetX = 5;
+const int kBubbleHorizMargin = 40;
+const int kBubbleVertMargin = 0;
+
+// This is the content view which is placed inside a SpeechInputBubble.
+class ContentView
+ : public views::View,
+ public views::LinkController {
+ public:
+ explicit ContentView(SpeechInputBubbleDelegate* delegate);
+
+ void SetRecognizingMode();
+
+ // views::LinkController methods.
+ virtual void LinkActivated(views::Link* source, int event_flags);
+
+ // views::View overrides.
+ virtual gfx::Size GetPreferredSize();
+ virtual void Layout();
+
+ private:
+ SpeechInputBubbleDelegate* delegate_;
+ views::ImageView* icon_;
+ views::Label* heading_;
+ views::Link* cancel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentView);
+};
+
+ContentView::ContentView(SpeechInputBubbleDelegate* delegate)
+ : delegate_(delegate) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);
+
+ heading_ = new views::Label(
+ l10n_util::GetString(IDS_SPEECH_INPUT_BUBBLE_HEADING));
+ heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
+ heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
+ AddChildView(heading_);
+
+ icon_ = new views::ImageView();
+ icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_RECORDING));
+ icon_->SetHorizontalAlignment(views::ImageView::CENTER);
+ AddChildView(icon_);
+
+ cancel_ = new views::Link(l10n_util::GetString(IDS_CANCEL));
+ cancel_->SetController(this);
+ cancel_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
+ cancel_->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
+ AddChildView(cancel_);
+}
+
+void ContentView::SetRecognizingMode() {
+ icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_PROCESSING));
+}
+
+void ContentView::LinkActivated(views::Link* source, int event_flags) {
+ if (source == cancel_) {
+ delegate_->RecognitionCancelled();
+ } else {
+ NOTREACHED() << "Unknown view";
+ }
+}
+
+gfx::Size ContentView::GetPreferredSize() {
+ int width = heading_->GetPreferredSize().width();
+ int control_width = cancel_->GetPreferredSize().width();
+ if (control_width > width)
+ width = control_width;
+ control_width = icon_->GetPreferredSize().width();
+ if (control_width > width)
+ width = control_width;
+ width += kBubbleHorizMargin * 2;
+
+ int height = kBubbleVertMargin * 2 +
+ heading_->GetPreferredSize().height() +
+ cancel_->GetPreferredSize().height() +
+ icon_->GetImage().height();
+ return gfx::Size(width, height);
+}
+
+void ContentView::Layout() {
+ int x = kBubbleHorizMargin;
+ int y = kBubbleVertMargin;
+ int control_width = width() - kBubbleHorizMargin * 2;
+
+ int height = heading_->GetPreferredSize().height();
+ heading_->SetBounds(x, y, control_width, height);
+ y += height;
+
+ height = icon_->GetImage().height();
+ icon_->SetBounds(x, y, control_width, height);
+ y += height;
+
+ height = cancel_->GetPreferredSize().height();
+ cancel_->SetBounds(x, y, control_width, height);
+}
+
+// Implementation of SpeechInputBubble.
+class SpeechInputBubbleImpl
+ : public SpeechInputBubble,
+ public InfoBubbleDelegate,
+ public NotificationObserver {
+ public:
+ SpeechInputBubbleImpl(TabContents* tab_contents,
+ Delegate* delegate,
+ const gfx::Rect& element_rect);
+ virtual ~SpeechInputBubbleImpl();
+
+ virtual void SetRecognizingMode();
+
+ // Returns the screen rectangle to use as the info bubble's target.
+ // |element_rect| is the html element's bounds in page coordinates.
+ gfx::Rect GetInfoBubbleTarget(const gfx::Rect& element_rect);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // InfoBubbleDelegate
+ virtual void InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape);
+ virtual bool CloseOnEscape();
+ virtual bool FadeInOnShow();
+
+ private:
+ Delegate* delegate_;
+ InfoBubble* info_bubble_;
+ TabContents* tab_contents_;
+ ContentView* bubble_content_;
+ NotificationRegistrar registrar_;
+
+ // Set to true if the object is being destroyed normally instead of the
+ // user clicking outside the window causing it to close automatically.
+ bool did_invoke_close_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleImpl);
+};
+
+SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents,
+ Delegate* delegate,
+ const gfx::Rect& element_rect)
+ : delegate_(delegate),
+ info_bubble_(NULL),
+ tab_contents_(tab_contents),
+ bubble_content_(NULL),
+ did_invoke_close_(false) {
+ bubble_content_ = new ContentView(delegate_);
+
+ views::Widget* parent = views::Widget::GetWidgetFromNativeWindow(
+ tab_contents_->view()->GetTopLevelNativeWindow());
+ info_bubble_ = InfoBubble::Show(parent,
+ GetInfoBubbleTarget(element_rect),
+ BubbleBorder::TOP_LEFT, bubble_content_,
+ this);
+
+ // We don't want fade outs when closing because it makes speech recognition
+ // appear slower than it is. Also setting it to false allows |Close| to
+ // destroy the bubble immediately instead of waiting for the fade animation
+ // to end so the caller can manage this object's life cycle like a normal
+ // stack based or member variable object.
+ info_bubble_->set_fade_away_on_close(false);
+
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+}
+
+SpeechInputBubbleImpl::~SpeechInputBubbleImpl() {
+ if (info_bubble_) {
+ did_invoke_close_ = true;
+ info_bubble_->Close();
+ }
+}
+
+void SpeechInputBubbleImpl::SetRecognizingMode() {
+ DCHECK(info_bubble_);
+ DCHECK(bubble_content_);
+ bubble_content_->SetRecognizingMode();
+}
+
+gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget(
+ const gfx::Rect& element_rect) {
+ gfx::Rect container_rect;
+ tab_contents_->GetContainerBounds(&container_rect);
+ return gfx::Rect(
+ container_rect.x() + element_rect.x() + kBubbleTargetOffsetX,
+ container_rect.y() + element_rect.y() + element_rect.height(), 1, 1);
+}
+
+void SpeechInputBubbleImpl::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
+ delegate_->RecognitionCancelled();
+ } else {
+ NOTREACHED() << "Unknown notification";
+ }
+}
+
+void SpeechInputBubbleImpl::InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape) {
+ registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+ info_bubble_ = NULL;
+ bubble_content_ = NULL;
+ if (!did_invoke_close_)
+ delegate_->InfoBubbleClosed();
+}
+
+bool SpeechInputBubbleImpl::CloseOnEscape() {
+ return false;
+}
+
+bool SpeechInputBubbleImpl::FadeInOnShow() {
+ return false;
+}
+
+} // namespace
+
+SpeechInputBubble* SpeechInputBubble::Create(
+ TabContents* tab_contents,
+ SpeechInputBubble::Delegate* delegate,
+ const gfx::Rect& element_rect) {
+ return new SpeechInputBubbleImpl(tab_contents, delegate, element_rect);
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index a65339a..f0d254b 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2422,6 +2422,7 @@
'browser/sidebar/sidebar_container.h',
'browser/sidebar/sidebar_manager.cc',
'browser/sidebar/sidebar_manager.h',
+ 'browser/speech/speech_input_bubble.h',
'browser/speech/speech_input_dispatcher_host.cc',
'browser/speech/speech_input_dispatcher_host.h',
'browser/speech/speech_input_manager.cc',
@@ -2928,6 +2929,7 @@
'browser/views/sad_tab_view.h',
'browser/views/select_file_dialog.cc',
'browser/views/shell_dialogs_win.cc',
+ 'browser/views/speech_input_bubble.cc',
'browser/views/ssl_client_certificate_selector_win.cc',
'browser/views/status_bubble_views.cc',
'browser/views/status_bubble_views.h',