| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/lazy_instance.h" | 6 #include "base/lazy_instance.h" |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "chrome/browser/speech/speech_recognition_bubble.h" | 8 #include "chrome/browser/speech/speech_recognition_bubble.h" |
| 9 #include "content/public/browser/web_contents.h" | 9 #include "content/public/browser/web_contents.h" |
| 10 #include "grit/generated_resources.h" | 10 #include "grit/generated_resources.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 const int kWarmingUpAnimationStartMs = 500; | 22 const int kWarmingUpAnimationStartMs = 500; |
| 23 const int kWarmingUpAnimationStepMs = 100; | 23 const int kWarmingUpAnimationStepMs = 100; |
| 24 const int kRecognizingAnimationStepMs = 100; | 24 const int kRecognizingAnimationStepMs = 100; |
| 25 | 25 |
| 26 // A lazily initialized singleton to hold all the image used by the speech | 26 // A lazily initialized singleton to hold all the image used by the speech |
| 27 // recognition bubbles and safely destroy them on exit. | 27 // recognition bubbles and safely destroy them on exit. |
| 28 class SpeechRecognitionBubbleImages { | 28 class SpeechRecognitionBubbleImages { |
| 29 public: | 29 public: |
| 30 const std::vector<SkBitmap>& spinner() { return spinner_; } | 30 const std::vector<SkBitmap>& spinner() { return spinner_; } |
| 31 const std::vector<SkBitmap>& warm_up() { return warm_up_; } | 31 const std::vector<SkBitmap>& warm_up() { return warm_up_; } |
| 32 SkBitmap* mic_full() { return mic_full_; } | 32 gfx::ImageSkia* mic_full() { return mic_full_; } |
| 33 SkBitmap* mic_empty() { return mic_empty_; } | 33 gfx::ImageSkia* mic_empty() { return mic_empty_; } |
| 34 SkBitmap* mic_noise() { return mic_noise_; } | 34 gfx::ImageSkia* mic_noise() { return mic_noise_; } |
| 35 SkBitmap* mic_mask() { return mic_mask_; } | 35 gfx::ImageSkia* mic_mask() { return mic_mask_; } |
| 36 | 36 |
| 37 private: | 37 private: |
| 38 // Private constructor to enforce singleton. | 38 // Private constructor to enforce singleton. |
| 39 friend struct base::DefaultLazyInstanceTraits<SpeechRecognitionBubbleImages>; | 39 friend struct base::DefaultLazyInstanceTraits<SpeechRecognitionBubbleImages>; |
| 40 SpeechRecognitionBubbleImages(); | 40 SpeechRecognitionBubbleImages(); |
| 41 | 41 |
| 42 std::vector<SkBitmap> spinner_; // Frames for the progress spinner. | 42 std::vector<SkBitmap> spinner_; // Frames for the progress spinner. |
| 43 std::vector<SkBitmap> warm_up_; // Frames for the warm up animation. | 43 std::vector<SkBitmap> warm_up_; // Frames for the warm up animation. |
| 44 | 44 |
| 45 // These bitmaps are owned by ResourceBundle and need not be destroyed. | 45 // These images are owned by ResourceBundle and need not be destroyed. |
| 46 SkBitmap* mic_full_; // Mic image with full volume. | 46 gfx::ImageSkia* mic_full_; // Mic image with full volume. |
| 47 SkBitmap* mic_noise_; // Mic image with full noise volume. | 47 gfx::ImageSkia* mic_noise_; // Mic image with full noise volume. |
| 48 SkBitmap* mic_empty_; // Mic image with zero volume. | 48 gfx::ImageSkia* mic_empty_; // Mic image with zero volume. |
| 49 SkBitmap* mic_mask_; // Gradient mask used by the volume indicator. | 49 gfx::ImageSkia* mic_mask_; // Gradient mask used by the volume indicator. |
| 50 }; | 50 }; |
| 51 | 51 |
| 52 SpeechRecognitionBubbleImages::SpeechRecognitionBubbleImages() { | 52 SpeechRecognitionBubbleImages::SpeechRecognitionBubbleImages() { |
| 53 mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 53 mic_empty_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| 54 IDR_SPEECH_INPUT_MIC_EMPTY); | 54 IDR_SPEECH_INPUT_MIC_EMPTY); |
| 55 mic_noise_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 55 mic_noise_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| 56 IDR_SPEECH_INPUT_MIC_NOISE); | 56 IDR_SPEECH_INPUT_MIC_NOISE); |
| 57 mic_full_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 57 mic_full_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| 58 IDR_SPEECH_INPUT_MIC_FULL); | 58 IDR_SPEECH_INPUT_MIC_FULL); |
| 59 mic_mask_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 59 mic_mask_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| 60 IDR_SPEECH_INPUT_MIC_MASK); | 60 IDR_SPEECH_INPUT_MIC_MASK); |
| 61 | 61 |
| 62 // The sprite image consists of all the animation frames put together in one | 62 // The sprite image consists of all the animation frames put together in one |
| 63 // horizontal/wide image. Each animation frame is square in shape within the | 63 // horizontal/wide image. Each animation frame is square in shape within the |
| 64 // sprite. | 64 // sprite. |
| 65 SkBitmap* spinner_image = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 65 const SkBitmap* spinner_image = ResourceBundle::GetSharedInstance(). |
| 66 IDR_SPEECH_INPUT_SPINNER); | 66 GetImageSkiaNamed(IDR_SPEECH_INPUT_SPINNER)->bitmap(); |
| 67 int frame_size = spinner_image->height(); | 67 int frame_size = spinner_image->height(); |
| 68 | 68 |
| 69 // When recording starts up, it may take a short while (few ms or even a | 69 // When recording starts up, it may take a short while (few ms or even a |
| 70 // couple of seconds) before the audio device starts really capturing data. | 70 // couple of seconds) before the audio device starts really capturing data. |
| 71 // This is more apparent on first use. To cover such cases we show a warming | 71 // This is more apparent on first use. To cover such cases we show a warming |
| 72 // up state in the bubble starting with a blank spinner image. If audio data | 72 // up state in the bubble starting with a blank spinner image. If audio data |
| 73 // starts coming in within a couple hundred ms, we switch to the recording | 73 // starts coming in within a couple hundred ms, we switch to the recording |
| 74 // UI and if it takes longer, we show the real warm up animation frames. | 74 // UI and if it takes longer, we show the real warm up animation frames. |
| 75 // This reduces visual jank for the most part. | 75 // This reduces visual jank for the most part. |
| 76 SkBitmap empty_spinner; | 76 SkBitmap empty_spinner; |
| 77 empty_spinner.setConfig(SkBitmap::kARGB_8888_Config, frame_size, frame_size); | 77 empty_spinner.setConfig(SkBitmap::kARGB_8888_Config, frame_size, frame_size); |
| 78 empty_spinner.allocPixels(); | 78 empty_spinner.allocPixels(); |
| 79 empty_spinner.eraseRGB(255, 255, 255); | 79 empty_spinner.eraseRGB(255, 255, 255); |
| 80 warm_up_.push_back(empty_spinner); | 80 warm_up_.push_back(empty_spinner); |
| 81 | 81 |
| 82 for (SkIRect src_rect(SkIRect::MakeWH(frame_size, frame_size)); | 82 for (SkIRect src_rect(SkIRect::MakeWH(frame_size, frame_size)); |
| 83 src_rect.fLeft < spinner_image->width(); | 83 src_rect.fLeft < spinner_image->width(); |
| 84 src_rect.offset(frame_size, 0)) { | 84 src_rect.offset(frame_size, 0)) { |
| 85 SkBitmap frame; | 85 SkBitmap frame; |
| 86 spinner_image->extractSubset(&frame, src_rect); | 86 spinner_image->extractSubset(&frame, src_rect); |
| 87 | 87 |
| 88 // The bitmap created by extractSubset just points to the same pixels as | 88 // The image created by extractSubset just points to the same pixels as |
| 89 // the original and adjusts rowBytes accordingly. However that doesn't | 89 // the original and adjusts rowBytes accordingly. However that doesn't |
| 90 // render properly and gets vertically squished in Linux due to a bug in | 90 // render properly and gets vertically squished in Linux due to a bug in |
| 91 // Skia. Until that gets fixed we work around by taking a real copy of it | 91 // Skia. Until that gets fixed we work around by taking a real copy of it |
| 92 // below as the copied bitmap has the correct rowBytes and renders fine. | 92 // below as the copied image has the correct rowBytes and renders fine. |
| 93 SkBitmap frame_copy; | 93 SkBitmap frame_copy; |
| 94 frame.copyTo(&frame_copy, SkBitmap::kARGB_8888_Config); | 94 frame.copyTo(&frame_copy, SkBitmap::kARGB_8888_Config); |
| 95 spinner_.push_back(frame_copy); | 95 spinner_.push_back(frame_copy); |
| 96 | 96 |
| 97 // The warm up spinner animation is a gray scale version of the real one. | 97 // The warm up spinner animation is a gray scale version of the real one. |
| 98 warm_up_.push_back(SkBitmapOperations::CreateHSLShiftedBitmap( | 98 warm_up_.push_back(SkBitmapOperations::CreateHSLShiftedBitmap( |
| 99 frame_copy, kGrayscaleShift)); | 99 frame_copy, kGrayscaleShift)); |
| 100 } | 100 } |
| 101 } | 101 } |
| 102 | 102 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 } | 192 } |
| 193 | 193 |
| 194 void SpeechRecognitionBubbleBase::SetMessage(const string16& text) { | 194 void SpeechRecognitionBubbleBase::SetMessage(const string16& text) { |
| 195 weak_factory_.InvalidateWeakPtrs(); | 195 weak_factory_.InvalidateWeakPtrs(); |
| 196 message_text_ = text; | 196 message_text_ = text; |
| 197 display_mode_ = DISPLAY_MODE_MESSAGE; | 197 display_mode_ = DISPLAY_MODE_MESSAGE; |
| 198 UpdateLayout(); | 198 UpdateLayout(); |
| 199 } | 199 } |
| 200 | 200 |
| 201 void SpeechRecognitionBubbleBase::DrawVolumeOverlay(SkCanvas* canvas, | 201 void SpeechRecognitionBubbleBase::DrawVolumeOverlay(SkCanvas* canvas, |
| 202 const SkBitmap& bitmap, | 202 const gfx::ImageSkia& image, |
| 203 float volume) { | 203 float volume) { |
| 204 buffer_image_->eraseARGB(0, 0, 0, 0); | 204 buffer_image_->eraseARGB(0, 0, 0, 0); |
| 205 | 205 |
| 206 int width = mic_image_->width(); | 206 int width = mic_image_->width(); |
| 207 int height = mic_image_->height(); | 207 int height = mic_image_->height(); |
| 208 SkCanvas buffer_canvas(*buffer_image_); | 208 SkCanvas buffer_canvas(*buffer_image_); |
| 209 | 209 |
| 210 buffer_canvas.save(); | 210 buffer_canvas.save(); |
| 211 const int kVolumeSteps = 12; | 211 const int kVolumeSteps = 12; |
| 212 SkScalar clip_right = | 212 SkScalar clip_right = |
| 213 (((1.0f - volume) * (width * (kVolumeSteps + 1))) - width) / kVolumeSteps; | 213 (((1.0f - volume) * (width * (kVolumeSteps + 1))) - width) / kVolumeSteps; |
| 214 buffer_canvas.clipRect(SkRect::MakeLTRB(0, 0, | 214 buffer_canvas.clipRect(SkRect::MakeLTRB(0, 0, |
| 215 SkIntToScalar(width) - clip_right, SkIntToScalar(height))); | 215 SkIntToScalar(width) - clip_right, SkIntToScalar(height))); |
| 216 buffer_canvas.drawBitmap(bitmap, 0, 0); | 216 buffer_canvas.drawBitmap(image, 0, 0); |
| 217 buffer_canvas.restore(); | 217 buffer_canvas.restore(); |
| 218 SkPaint multiply_paint; | 218 SkPaint multiply_paint; |
| 219 multiply_paint.setXfermode(SkXfermode::Create(SkXfermode::kMultiply_Mode)); | 219 multiply_paint.setXfermode(SkXfermode::Create(SkXfermode::kMultiply_Mode)); |
| 220 buffer_canvas.drawBitmap(*g_images.Get().mic_mask(), -clip_right, 0, | 220 buffer_canvas.drawBitmap(*g_images.Get().mic_mask(), -clip_right, 0, |
| 221 &multiply_paint); | 221 &multiply_paint); |
| 222 | 222 |
| 223 canvas->drawBitmap(*buffer_image_.get(), 0, 0); | 223 canvas->drawBitmap(*buffer_image_.get(), 0, 0); |
| 224 } | 224 } |
| 225 | 225 |
| 226 void SpeechRecognitionBubbleBase::SetInputVolume(float volume, | 226 void SpeechRecognitionBubbleBase::SetInputVolume(float volume, |
| 227 float noise_volume) { | 227 float noise_volume) { |
| 228 mic_image_->eraseARGB(0, 0, 0, 0); | 228 mic_image_->eraseARGB(0, 0, 0, 0); |
| 229 SkCanvas canvas(*mic_image_); | 229 SkCanvas canvas(*mic_image_); |
| 230 | 230 |
| 231 // Draw the empty volume image first and the current volume image on top, | 231 // Draw the empty volume image first and the current volume image on top, |
| 232 // and then the noise volume image on top of both. | 232 // and then the noise volume image on top of both. |
| 233 canvas.drawBitmap(*g_images.Get().mic_empty(), 0, 0); | 233 canvas.drawBitmap(*g_images.Get().mic_empty(), 0, 0); |
| 234 DrawVolumeOverlay(&canvas, *g_images.Get().mic_full(), volume); | 234 DrawVolumeOverlay(&canvas, *g_images.Get().mic_full(), volume); |
| 235 DrawVolumeOverlay(&canvas, *g_images.Get().mic_noise(), noise_volume); | 235 DrawVolumeOverlay(&canvas, *g_images.Get().mic_noise(), noise_volume); |
| 236 | 236 |
| 237 SetImage(*mic_image_.get()); | 237 SetImage(*mic_image_.get()); |
| 238 } | 238 } |
| 239 | 239 |
| 240 WebContents* SpeechRecognitionBubbleBase::GetWebContents() { | 240 WebContents* SpeechRecognitionBubbleBase::GetWebContents() { |
| 241 return web_contents_; | 241 return web_contents_; |
| 242 } | 242 } |
| 243 | 243 |
| 244 void SpeechRecognitionBubbleBase::SetImage(const SkBitmap& image) { | 244 void SpeechRecognitionBubbleBase::SetImage(const gfx::ImageSkia& image) { |
| 245 icon_image_.reset(new SkBitmap(image)); | 245 icon_image_.reset(new gfx::ImageSkia(image)); |
| 246 UpdateImage(); | 246 UpdateImage(); |
| 247 } | 247 } |
| 248 | 248 |
| 249 SkBitmap SpeechRecognitionBubbleBase::icon_image() { | 249 gfx::ImageSkia SpeechRecognitionBubbleBase::icon_image() { |
| 250 return (icon_image_ != NULL) ? *icon_image_ : SkBitmap(); | 250 return (icon_image_ != NULL) ? *icon_image_ : gfx::ImageSkia(); |
| 251 } | 251 } |
| OLD | NEW |