Chromium Code Reviews| Index: chrome/browser/themes/browser_theme_pack.cc |
| diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc |
| index 3a8fb68df6d7987446647d55572ff96063c37d1f..ff1c56ba77ef7f89155f439c643a4763349f0c46 100644 |
| --- a/chrome/browser/themes/browser_theme_pack.cc |
| +++ b/chrome/browser/themes/browser_theme_pack.cc |
| @@ -480,6 +480,127 @@ class ThemeImageSource: public gfx::ImageSkiaSource { |
| DISALLOW_COPY_AND_ASSIGN(ThemeImageSource); |
| }; |
| +// An ImageSkiaSouce that delays decoding PNG data into bitmaps until needed |
| +// and, if necessary, generates bitmaps for scale factors for which no PNG was |
| +// provided. The first PNG will be used to compute the DIP size and will |
| +// therefore be decoded when added. Once a PNG is decoded the resulting bitmap |
| +// is stored for later use. |
| +class ThemeImagePngSource : public gfx::ImageSkiaSource { |
| + public: |
| + ThemeImagePngSource() {} |
|
pkotwicz
2013/06/14 18:23:05
Ideally we should not even cache the PNG data for
|
| + |
| + void AddPng(scoped_refptr<base::RefCountedMemory> png_memory, |
| + ui::ScaleFactor scale_factor) { |
| + png_map_[scale_factor] = png_memory; |
| + if (bitmap_map_.empty()) |
| + init(png_memory, scale_factor); |
| + } |
| + |
| + gfx::Size size() const { return dip_size_; } |
| + |
| + private: |
| + void init(scoped_refptr<base::RefCountedMemory> png_memory, |
| + ui::ScaleFactor scale_factor) { |
| + SkBitmap bitmap; |
| + if (!gfx::PNGCodec::Decode(png_memory->front(), |
| + png_memory->size(), |
| + &bitmap)) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + bitmap_map_[scale_factor] = bitmap; |
| + dip_size_ = gfx::Size( |
| + static_cast<int>(bitmap.width() / |
| + ui::GetScaleFactorScale(scale_factor)), |
| + static_cast<int>(bitmap.height() / |
| + ui::GetScaleFactorScale(scale_factor))); |
| + } |
| + |
| + virtual gfx::ImageSkiaRep GetImageForScale( |
| + ui::ScaleFactor scale_factor) OVERRIDE { |
| + // Look up the scale factor in the bitmap map. If found, use the bitmap and |
| + // return it. |
| + BitmapMap::const_iterator exact_bitmap = bitmap_map_.find(scale_factor); |
| + if (exact_bitmap != bitmap_map_.end()) { |
| + return gfx::ImageSkiaRep(exact_bitmap->second, scale_factor); |
| + } |
| + |
| + // Look up the scale factor in the png map. If found, decode it, |
| + // store the result in the bitmap map and return it. |
| + PngMap::const_iterator exact_png = png_map_.find(scale_factor); |
| + if (exact_png != png_map_.end()) { |
| + SkBitmap bitmap; |
| + if (!gfx::PNGCodec::Decode(exact_png->second->front(), |
| + exact_png->second->size(), |
| + &bitmap)) { |
| + NOTREACHED(); |
| + return gfx::ImageSkiaRep(SkBitmap(), scale_factor); |
| + } |
| + bitmap_map_[scale_factor] = bitmap; |
| + return gfx::ImageSkiaRep(bitmap, scale_factor); |
| + } |
| + |
| + // No exact match was found, find the scale factor with highest scale. |
| + PngMap::const_iterator available_png = png_map_.end(); |
| + for (PngMap::const_iterator it = png_map_.begin(); it != png_map_.end(); |
| + ++it) { |
| + if (available_png == png_map_.end() || |
| + (ui::GetScaleFactorScale(it->first) > |
| + ui::GetScaleFactorScale(available_png->first))) { |
| + available_png = it; |
| + } |
| + } |
| + if (available_png == png_map_.end()) { |
| + NOTREACHED(); |
| + return gfx::ImageSkiaRep(SkBitmap(), scale_factor); |
| + } |
| + |
| + // Look up the found scale factor in the bitmap map. If not found, decode |
| + // the corresponding png and store the result in bitmap map. |
| + BitmapMap::const_iterator available_bitmap = |
| + bitmap_map_.find(available_png->first); |
| + if (available_bitmap == bitmap_map_.end()) { |
| + SkBitmap bitmap; |
| + if (!gfx::PNGCodec::Decode(available_png->second->front(), |
| + available_png->second->size(), |
| + &bitmap)) { |
| + NOTREACHED(); |
| + return gfx::ImageSkiaRep(SkBitmap(), scale_factor); |
| + } |
| + bitmap_map_[available_png->first] = bitmap; |
| + available_bitmap = bitmap_map_.find(available_png->first); |
| + } |
| + |
| + // Use available bitmap to create bitmap for desired scale factor by |
| + // scaling, store the result in the bitmap map and return it. |
| + gfx::Size scaled_size = gfx::ToCeiledSize( |
| + gfx::ScaleSize(gfx::Size(available_bitmap->second.width(), |
| + available_bitmap->second.height()), |
| + ui::GetScaleFactorScale(scale_factor) / |
| + ui::GetScaleFactorScale(available_bitmap->first))); |
| + SkBitmap scaled_bitmap; |
| + scaled_bitmap.setConfig(SkBitmap::kARGB_8888_Config, |
| + scaled_size.width(), |
| + scaled_size.height()); |
| + if (!scaled_bitmap.allocPixels()) |
| + SK_CRASH(); |
| + scaled_bitmap.eraseARGB(0, 0, 0, 0); |
| + SkCanvas canvas(scaled_bitmap); |
| + SkRect scaled_bounds = RectToSkRect(gfx::Rect(scaled_size)); |
| + canvas.drawBitmapRect(available_bitmap->second, NULL, scaled_bounds); |
| + bitmap_map_[scale_factor] = scaled_bitmap; |
| + return gfx::ImageSkiaRep(scaled_bitmap, scale_factor); |
| + } |
| + |
| + private: |
| + typedef std::map<ui::ScaleFactor, |
| + scoped_refptr<base::RefCountedMemory> > PngMap; |
| + typedef std::map<ui::ScaleFactor, SkBitmap> BitmapMap; |
| + PngMap png_map_; |
| + BitmapMap bitmap_map_; |
| + gfx::Size dip_size_; |
| +}; |
| + |
| class TabBackgroundImageSource: public gfx::CanvasImageSource { |
| public: |
| TabBackgroundImageSource(const gfx::ImageSkia& image_to_tint, |
| @@ -749,34 +870,34 @@ gfx::Image BrowserThemePack::GetImageNamed(int idr_id) { |
| if (image_iter != images_on_ui_thread_.end()) |
| return image_iter->second; |
| - // TODO(pkotwicz): Do something better than loading the bitmaps |
| - // for all the scale factors associated with |idr_id|. |
| - // See crbug.com/243831. |
| - gfx::ImageSkia source_image_skia; |
| - for (size_t i = 0; i < scale_factors_.size(); ++i) { |
| - scoped_refptr<base::RefCountedMemory> memory = |
| - GetRawData(idr_id, scale_factors_[i]); |
| - if (memory.get()) { |
| - // Decode the PNG. |
| - SkBitmap bitmap; |
| - if (!gfx::PNGCodec::Decode(memory->front(), memory->size(), |
| - &bitmap)) { |
| - NOTREACHED() << "Unable to decode theme image resource " << idr_id |
| - << " from saved DataPack."; |
| + ThemeImagePngSource* png_source = NULL; |
| + for (int pass = 0; pass < 2; ++pass) { |
| + // Two passes: In the first pass, we process only scale factor 100%, if |
| + // available, and in the second pass all other scale factors. The reason is |
| + // that the first png added, determines the DIP size. |
| + for (size_t i = 0; i < scale_factors_.size(); ++i) { |
| + if ((pass == 0 && scale_factors_[i] != ui::SCALE_FACTOR_100P) || |
| + (pass == 1 && scale_factors_[i] == ui::SCALE_FACTOR_100P)) { |
| continue; |
| } |
| - source_image_skia.AddRepresentation( |
| - gfx::ImageSkiaRep(bitmap, scale_factors_[i])); |
| + scoped_refptr<base::RefCountedMemory> memory = |
| + GetRawData(idr_id, scale_factors_[i]); |
| + if (memory.get()) { |
| + if (!png_source) |
| + png_source = new ThemeImagePngSource; |
| + png_source->AddPng(memory, scale_factors_[i]); |
| + } |
| } |
| } |
| - if (!source_image_skia.isNull()) { |
| - ThemeImageSource* source = new ThemeImageSource(source_image_skia); |
| - gfx::ImageSkia image_skia(source, source_image_skia.size()); |
| + if (png_source) { |
| + // |image_skia| owns png_source. |
| + gfx::ImageSkia image_skia(png_source, png_source->size()); |
| gfx::Image ret = gfx::Image(image_skia); |
| images_on_ui_thread_[prs_id] = ret; |
| return ret; |
| } |
| + |
| return gfx::Image(); |
| } |