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(); |
} |