summaryrefslogtreecommitdiffstats
path: root/chrome/browser/speech
diff options
context:
space:
mode:
authorsatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 09:46:00 +0000
committersatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 09:46:00 +0000
commit423f1cf75160bb3735df618d799c2c53f7020578 (patch)
treea6cf4a66232903a6347078d62909b195bb26cee2 /chrome/browser/speech
parent2cd028f67a09efda4047ffb8e3b7ecdc1ee9fae3 (diff)
downloadchromium_src-423f1cf75160bb3735df618d799c2c53f7020578.zip
chromium_src-423f1cf75160bb3735df618d799c2c53f7020578.tar.gz
chromium_src-423f1cf75160bb3735df618d799c2c53f7020578.tar.bz2
Move the spinner & warm up animation frames into file-scoped globals instead of instance variables.
Also corrected naming of the other file-scoped globals in that vicinity. BUG=none TEST=none, no change in functionality. Review URL: http://codereview.chromium.org/6794058 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80596 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/speech')
-rw-r--r--chrome/browser/speech/speech_input_bubble.cc166
1 files changed, 94 insertions, 72 deletions
diff --git a/chrome/browser/speech/speech_input_bubble.cc b/chrome/browser/speech/speech_input_bubble.cc
index 9537476..251c1c3 100644
--- a/chrome/browser/speech/speech_input_bubble.cc
+++ b/chrome/browser/speech/speech_input_bubble.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/lazy_instance.h"
#include "chrome/browser/speech/speech_input_bubble.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "grit/generated_resources.h"
@@ -13,68 +14,53 @@
namespace {
-color_utils::HSL kGrayscaleShift = { -1, 0, 0.6 };
-
-SkBitmap* mic_full_ = NULL; // Mic image with full volume.
-SkBitmap* mic_noise_ = NULL; // Mic image with full noise volume.
-SkBitmap* mic_empty_ = NULL; // Mic image with zero volume.
-SkBitmap* mic_mask_ = NULL; // Gradient mask used by the volume indicator.
-SkBitmap* spinner_ = NULL; // Spinner image for the progress animation.
-
+const color_utils::HSL kGrayscaleShift = { -1, 0, 0.6 };
const int kWarmingUpAnimationStartMs = 500;
const int kWarmingUpAnimationStepMs = 100;
const int kRecognizingAnimationStepMs = 100;
-} // namespace
-
-SpeechInputBubble::FactoryMethod SpeechInputBubble::factory_ = NULL;
-const int SpeechInputBubble::kBubbleTargetOffsetX = 10;
-
-SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents,
- Delegate* delegate,
- const gfx::Rect& element_rect) {
- if (factory_)
- return (*factory_)(tab_contents, delegate, element_rect);
-
- // Has the tab already closed before bubble create request was processed?
- if (!tab_contents)
- return NULL;
-
- return CreateNativeBubble(tab_contents, delegate, element_rect);
-}
-
-SpeechInputBubbleBase::SpeechInputBubbleBase(TabContents* tab_contents)
- : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- display_mode_(DISPLAY_MODE_RECORDING),
- tab_contents_(tab_contents) {
- if (!mic_empty_) { // Static variables.
- mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_MIC_EMPTY);
- mic_noise_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_MIC_NOISE);
- mic_full_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_MIC_FULL);
- mic_mask_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_MIC_MASK);
- spinner_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_SPINNER);
- }
-
- // Instance variables.
- mic_image_.reset(new SkBitmap());
- mic_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
- mic_empty_->height());
- mic_image_->allocPixels();
-
- buffer_image_.reset(new SkBitmap());
- buffer_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
- mic_empty_->height());
- buffer_image_->allocPixels();
+// A lazily initialized singleton to hold all the image used by the speech
+// input bubbles and safely destroy them on exit.
+class SpeechInputBubbleImages {
+ public:
+ const std::vector<SkBitmap>& spinner() { return spinner_; }
+ const std::vector<SkBitmap>& warm_up() { return warm_up_; }
+ SkBitmap* mic_full() { return mic_full_; }
+ SkBitmap* mic_empty() { return mic_empty_; }
+ SkBitmap* mic_noise() { return mic_noise_; }
+ SkBitmap* mic_mask() { return mic_mask_; }
+
+ private:
+ // Private constructor to enforce singleton.
+ friend struct base::DefaultLazyInstanceTraits<SpeechInputBubbleImages>;
+ SpeechInputBubbleImages();
+
+ std::vector<SkBitmap> spinner_; // Frames for the progress spinner.
+ std::vector<SkBitmap> warm_up_; // Frames for the warm up animation.
+
+ // These bitmaps are owned by ResourceBundle and need not be destroyed.
+ SkBitmap* mic_full_; // Mic image with full volume.
+ SkBitmap* mic_noise_; // Mic image with full noise volume.
+ SkBitmap* mic_empty_; // Mic image with zero volume.
+ SkBitmap* mic_mask_; // Gradient mask used by the volume indicator.
+};
+
+SpeechInputBubbleImages::SpeechInputBubbleImages() {
+ mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_MIC_EMPTY);
+ mic_noise_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_MIC_NOISE);
+ mic_full_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_MIC_FULL);
+ mic_mask_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_MIC_MASK);
// The sprite image consists of all the animation frames put together in one
// horizontal/wide image. Each animation frame is square in shape within the
// sprite.
- const int kFrameSize = spinner_->height();
+ SkBitmap* spinner_image = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SPEECH_INPUT_SPINNER);
+ int frame_size = spinner_image->height();
// When recording starts up, it may take a short while (few ms or even a
// couple of seconds) before the audio device starts really capturing data.
@@ -83,19 +69,17 @@ SpeechInputBubbleBase::SpeechInputBubbleBase(TabContents* tab_contents)
// starts coming in within a couple hundred ms, we switch to the recording
// UI and if it takes longer, we show the real warm up animation frames.
// This reduces visual jank for the most part.
- // TODO(satish): Change this to create the frames only once on first use
- // instead of keeping them as instance variables in every bubble.
SkBitmap empty_spinner;
- empty_spinner.setConfig(SkBitmap::kARGB_8888_Config, kFrameSize, kFrameSize);
+ empty_spinner.setConfig(SkBitmap::kARGB_8888_Config, frame_size, frame_size);
empty_spinner.allocPixels();
empty_spinner.eraseRGB(255, 255, 255);
- warming_up_frames_.push_back(empty_spinner);
+ warm_up_.push_back(empty_spinner);
- for (SkIRect src_rect(SkIRect::MakeWH(kFrameSize, kFrameSize));
- src_rect.fLeft < spinner_->width();
- src_rect.offset(kFrameSize, 0)) {
+ for (SkIRect src_rect(SkIRect::MakeWH(frame_size, frame_size));
+ src_rect.fLeft < spinner_image->width();
+ src_rect.offset(frame_size, 0)) {
SkBitmap frame;
- spinner_->extractSubset(&frame, src_rect);
+ spinner_image->extractSubset(&frame, src_rect);
// The bitmap created by extractSubset just points to the same pixels as
// the original and adjusts rowBytes accordingly. However that doesn't
@@ -104,14 +88,51 @@ SpeechInputBubbleBase::SpeechInputBubbleBase(TabContents* tab_contents)
// below as the copied bitmap has the correct rowBytes and renders fine.
SkBitmap frame_copy;
frame.copyTo(&frame_copy, SkBitmap::kARGB_8888_Config);
- animation_frames_.push_back(frame_copy);
+ spinner_.push_back(frame_copy);
// The warm up spinner animation is a gray scale version of the real one.
- warming_up_frames_.push_back(SkBitmapOperations::CreateHSLShiftedBitmap(
+ warm_up_.push_back(SkBitmapOperations::CreateHSLShiftedBitmap(
frame_copy, kGrayscaleShift));
}
}
+base::LazyInstance<SpeechInputBubbleImages> g_images(base::LINKER_INITIALIZED);
+
+} // namespace
+
+SpeechInputBubble::FactoryMethod SpeechInputBubble::factory_ = NULL;
+const int SpeechInputBubble::kBubbleTargetOffsetX = 10;
+
+SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents,
+ Delegate* delegate,
+ const gfx::Rect& element_rect) {
+ if (factory_)
+ return (*factory_)(tab_contents, delegate, element_rect);
+
+ // Has the tab already closed before bubble create request was processed?
+ if (!tab_contents)
+ return NULL;
+
+ return CreateNativeBubble(tab_contents, delegate, element_rect);
+}
+
+SpeechInputBubbleBase::SpeechInputBubbleBase(TabContents* tab_contents)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
+ display_mode_(DISPLAY_MODE_RECORDING),
+ tab_contents_(tab_contents) {
+ mic_image_.reset(new SkBitmap());
+ mic_image_->setConfig(SkBitmap::kARGB_8888_Config,
+ g_images.Get().mic_empty()->width(),
+ g_images.Get().mic_empty()->height());
+ mic_image_->allocPixels();
+
+ buffer_image_.reset(new SkBitmap());
+ buffer_image_->setConfig(SkBitmap::kARGB_8888_Config,
+ g_images.Get().mic_empty()->width(),
+ g_images.Get().mic_empty()->height());
+ buffer_image_->allocPixels();
+}
+
SpeechInputBubbleBase::~SpeechInputBubbleBase() {
// This destructor is added to make sure members such as the scoped_ptr
// get destroyed here and the derived classes don't have to care about such
@@ -127,14 +148,14 @@ void SpeechInputBubbleBase::SetWarmUpMode() {
}
void SpeechInputBubbleBase::DoWarmingUpAnimationStep() {
- SetImage(warming_up_frames_[animation_step_]);
+ SetImage(g_images.Get().warm_up()[animation_step_]);
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
task_factory_.NewRunnableMethod(
&SpeechInputBubbleBase::DoWarmingUpAnimationStep),
animation_step_ == 0 ? kWarmingUpAnimationStartMs
: kWarmingUpAnimationStepMs);
- if (++animation_step_ >= static_cast<int>(animation_frames_.size()))
+ if (++animation_step_ >= static_cast<int>(g_images.Get().warm_up().size()))
animation_step_ = 1; // Frame 0 is skipped during the animation.
}
@@ -153,8 +174,8 @@ void SpeechInputBubbleBase::SetRecognizingMode() {
}
void SpeechInputBubbleBase::DoRecognizingAnimationStep() {
- SetImage(animation_frames_[animation_step_]);
- if (++animation_step_ >= static_cast<int>(animation_frames_.size()))
+ SetImage(g_images.Get().spinner()[animation_step_]);
+ if (++animation_step_ >= static_cast<int>(g_images.Get().spinner().size()))
animation_step_ = 0;
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
@@ -189,7 +210,8 @@ void SpeechInputBubbleBase::DrawVolumeOverlay(SkCanvas* canvas,
buffer_canvas.restore();
SkPaint multiply_paint;
multiply_paint.setXfermode(SkXfermode::Create(SkXfermode::kMultiply_Mode));
- buffer_canvas.drawBitmap(*mic_mask_, -clip_right, 0, &multiply_paint);
+ buffer_canvas.drawBitmap(*g_images.Get().mic_mask(), -clip_right, 0,
+ &multiply_paint);
canvas->drawBitmap(*buffer_image_.get(), 0, 0);
}
@@ -200,9 +222,9 @@ void SpeechInputBubbleBase::SetInputVolume(float volume, float noise_volume) {
// Draw the empty volume image first and the current volume image on top,
// and then the noise volume image on top of both.
- canvas.drawBitmap(*mic_empty_, 0, 0);
- DrawVolumeOverlay(&canvas, *mic_full_, volume);
- DrawVolumeOverlay(&canvas, *mic_noise_, noise_volume);
+ canvas.drawBitmap(*g_images.Get().mic_empty(), 0, 0);
+ DrawVolumeOverlay(&canvas, *g_images.Get().mic_full(), volume);
+ DrawVolumeOverlay(&canvas, *g_images.Get().mic_noise(), noise_volume);
SetImage(*mic_image_.get());
}