diff options
author | satish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-06 09:46:00 +0000 |
---|---|---|
committer | satish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-06 09:46:00 +0000 |
commit | 423f1cf75160bb3735df618d799c2c53f7020578 (patch) | |
tree | a6cf4a66232903a6347078d62909b195bb26cee2 /chrome/browser/speech | |
parent | 2cd028f67a09efda4047ffb8e3b7ecdc1ee9fae3 (diff) | |
download | chromium_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.cc | 166 |
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()); } |