Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: ui/base/resource/resource_bundle.cc

Issue 10820049: Load 2x resources on demand (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/base/resource/resource_bundle.h ('k') | ui/gfx/image/image_skia.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "ui/base/resource/resource_bundle.h" 5 #include "ui/base/resource/resource_bundle.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/ref_counted_memory.h" 12 #include "base/memory/ref_counted_memory.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/path_service.h" 14 #include "base/path_service.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/string_piece.h" 16 #include "base/string_piece.h"
17 #include "base/synchronization/lock.h" 17 #include "base/synchronization/lock.h"
18 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
19 #include "build/build_config.h" 19 #include "build/build_config.h"
20 #include "skia/ext/image_operations.h" 20 #include "skia/ext/image_operations.h"
21 #include "third_party/skia/include/core/SkBitmap.h" 21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/base/l10n/l10n_util.h" 22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/layout.h" 23 #include "ui/base/layout.h"
24 #include "ui/base/resource/data_pack.h" 24 #include "ui/base/resource/data_pack.h"
25 #include "ui/base/ui_base_paths.h" 25 #include "ui/base/ui_base_paths.h"
26 #include "ui/base/ui_base_switches.h" 26 #include "ui/base/ui_base_switches.h"
27 #include "ui/gfx/codec/jpeg_codec.h" 27 #include "ui/gfx/codec/jpeg_codec.h"
28 #include "ui/gfx/codec/png_codec.h" 28 #include "ui/gfx/codec/png_codec.h"
29 #include "ui/gfx/image/image_skia.h" 29 #include "ui/gfx/image/image_skia.h"
30 #include "ui/gfx/image/image_skia_source.h"
30 #include "ui/gfx/screen.h" 31 #include "ui/gfx/screen.h"
31 #include "ui/gfx/skbitmap_operations.h" 32 #include "ui/gfx/skbitmap_operations.h"
32 33
33 namespace ui { 34 namespace ui {
34 35
35 namespace { 36 namespace {
36 37
37 // Font sizes relative to base font. 38 // Font sizes relative to base font.
38 #if defined(OS_CHROMEOS) && defined(CROS_FONTS_USING_BCI) 39 #if defined(OS_CHROMEOS) && defined(CROS_FONTS_USING_BCI)
39 const int kSmallFontSizeDelta = -3; 40 const int kSmallFontSizeDelta = -3;
40 const int kMediumFontSizeDelta = 2; 41 const int kMediumFontSizeDelta = 2;
41 const int kLargeFontSizeDelta = 7; 42 const int kLargeFontSizeDelta = 7;
42 #else 43 #else
43 const int kSmallFontSizeDelta = -2; 44 const int kSmallFontSizeDelta = -2;
44 const int kMediumFontSizeDelta = 3; 45 const int kMediumFontSizeDelta = 3;
45 const int kLargeFontSizeDelta = 8; 46 const int kLargeFontSizeDelta = 8;
46 #endif 47 #endif
47 48
49 ResourceBundle* g_shared_instance_ = NULL;
50
48 // Returns the actual scale factor of |bitmap| given the image representations 51 // Returns the actual scale factor of |bitmap| given the image representations
49 // which have already been added to |image|. 52 // which have already been added to |image|.
50 // TODO(pkotwicz): Remove this once we are no longer loading 1x resources 53 // TODO(pkotwicz): Remove this once we are no longer loading 1x resources
51 // as part of 2x data packs. 54 // as part of 2x data packs.
52 ui::ScaleFactor GetActualScaleFactor(const gfx::ImageSkia& image, 55 ui::ScaleFactor GetActualScaleFactor(const gfx::ImageSkia& image,
53 const SkBitmap& bitmap, 56 const SkBitmap& bitmap,
54 ui::ScaleFactor data_pack_scale_factor) { 57 ui::ScaleFactor data_pack_scale_factor) {
55 if (image.empty()) 58 if (image.empty())
56 return data_pack_scale_factor; 59 return data_pack_scale_factor;
57 60
58 return ui::GetScaleFactorFromScale( 61 return ui::GetScaleFactorFromScale(
59 static_cast<float>(bitmap.width()) / image.width()); 62 static_cast<float>(bitmap.width()) / image.width());
60 } 63 }
61 64
62 // If 2x resource is missing from |image| or is the incorrect size, 65 bool ShouldHighlightMissing2xResources() {
63 // logs the resource id and creates a 2x version of the resource. 66 return CommandLine::ForCurrentProcess()->HasSwitch(
64 // Blends the created resource with red to make it distinguishable from 67 switches::kHighlightMissing2xResources);
65 // bitmaps in the resource pak.
66 void Create2xResourceIfMissing(gfx::ImageSkia image, int idr) {
67 CommandLine* command_line = CommandLine::ForCurrentProcess();
68 if (command_line->HasSwitch(
69 switches::kHighlightMissing2xResources) &&
70 command_line->HasSwitch(switches::kLoad2xResources) &&
71 !image.HasRepresentation(ui::SCALE_FACTOR_200P)) {
72 gfx::ImageSkiaRep image_rep = image.GetRepresentation(SCALE_FACTOR_200P);
73
74 if (image_rep.scale_factor() == ui::SCALE_FACTOR_100P)
75 LOG(INFO) << "Missing 2x resource with id " << idr;
76 else
77 LOG(INFO) << "Incorrectly sized 2x resource with id " << idr;
78
79 SkBitmap bitmap2x = skia::ImageOperations::Resize(image_rep.sk_bitmap(),
80 skia::ImageOperations::RESIZE_LANCZOS3,
81 image.width() * 2, image.height() * 2);
82
83 SkBitmap mask;
84 mask.setConfig(SkBitmap::kARGB_8888_Config,
85 bitmap2x.width(),
86 bitmap2x.height());
87 mask.allocPixels();
88 mask.eraseColor(SK_ColorRED);
89 SkBitmap result = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask,
90 0.2);
91 image.AddRepresentation(gfx::ImageSkiaRep(result, SCALE_FACTOR_200P));
92 }
93 } 68 }
94 69
95 } // namespace 70 } // namespace
96 71
97 ResourceBundle* ResourceBundle::g_shared_instance_ = NULL; 72 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
73 public:
74 ResourceBundleImageSource(int resource_id, const gfx::Size size_in_dip)
75 : resource_id_(resource_id),
76 size_in_dip_(size_in_dip) {
77 }
78 virtual ~ResourceBundleImageSource() {}
79
80 // gfx::ImageSkiaSource overrides:
81 virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) {
82 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
83
84 scoped_ptr<SkBitmap> result(rb.LoadBitmap(resource_id_, scale_factor));
85 gfx::Size size_in_pixel =
86 size_in_dip_.Scale(ui::GetScaleFactorScale(scale_factor));
87
88 if (scale_factor == SCALE_FACTOR_200P &&
89 (!result.get() ||
90 result->width() != size_in_pixel.width() ||
91 result->height() != size_in_pixel.height())) {
92
93 // If 2x resource is missing from |image| or is the incorrect
94 // size and --highlight-missing-2x-resources is specified, logs
95 // the resource id and creates a 2x version of the resource.
96 // Blends the created resource with red to make it
97 // distinguishable from bitmaps in the resource pak.
98 if (ShouldHighlightMissing2xResources()) {
99 if (!result.get())
100 LOG(ERROR) << "Missing 2x resource. id=" << resource_id_;
101 else
102 LOG(ERROR) << "Incorrectly sized 2x resource. id=" << resource_id_;
103
104 SkBitmap bitmap1x = *(rb.LoadBitmap(resource_id_, SCALE_FACTOR_100P));
105 SkBitmap bitmap2x = skia::ImageOperations::Resize(
106 bitmap1x,
107 skia::ImageOperations::RESIZE_LANCZOS3,
108 bitmap1x.width() * 2, bitmap1x.height() * 2);
109
110 SkBitmap mask;
111 mask.setConfig(SkBitmap::kARGB_8888_Config,
112 bitmap2x.width(),
113 bitmap2x.height());
114 mask.allocPixels();
115 mask.eraseColor(SK_ColorRED);
116 result.reset(new SkBitmap());
117 *result.get() = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask,
118 0.2);
119 } else if (!result.get() ||
120 result->width() == size_in_dip_.width()) {
121 // The 2x resource pack may have the 1x image if its grd file
122 // points to 1x image. Fallback to 1x by returning empty image
123 // in this case. This 1x image will be scaled when drawn.
124 return gfx::ImageSkiaRep();
125 }
126 // If the size of 2x image isn't exactly 2x of 1x version,
127 // create ImageSkia as usual. This will end up with
128 // corrupted visual representation as the size of image doesn't
129 // match the expected size.
130 }
131 return gfx::ImageSkiaRep(*result.get(), scale_factor);
132 }
133
134 private:
135 int resource_id_;
136 gfx::Size size_in_dip_;
137
138 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
139 };
98 140
99 // static 141 // static
100 std::string ResourceBundle::InitSharedInstanceWithLocale( 142 std::string ResourceBundle::InitSharedInstanceWithLocale(
101 const std::string& pref_locale, Delegate* delegate) { 143 const std::string& pref_locale, Delegate* delegate) {
102 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; 144 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
103 g_shared_instance_ = new ResourceBundle(delegate); 145 g_shared_instance_ = new ResourceBundle(delegate);
104 146
105 g_shared_instance_->LoadCommonResources(); 147 g_shared_instance_->LoadCommonResources();
106 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale); 148 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
107 return result; 149 return result;
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 const SkBitmap* bitmap = GetImageNamed(resource_id).ToSkBitmap(); 339 const SkBitmap* bitmap = GetImageNamed(resource_id).ToSkBitmap();
298 return const_cast<SkBitmap*>(bitmap); 340 return const_cast<SkBitmap*>(bitmap);
299 } 341 }
300 342
301 gfx::ImageSkia* ResourceBundle::GetImageSkiaNamed(int resource_id) { 343 gfx::ImageSkia* ResourceBundle::GetImageSkiaNamed(int resource_id) {
302 const gfx::ImageSkia* image = GetImageNamed(resource_id).ToImageSkia(); 344 const gfx::ImageSkia* image = GetImageNamed(resource_id).ToImageSkia();
303 return const_cast<gfx::ImageSkia*>(image); 345 return const_cast<gfx::ImageSkia*>(image);
304 } 346 }
305 347
306 gfx::Image& ResourceBundle::GetImageNamed(int resource_id) { 348 gfx::Image& ResourceBundle::GetImageNamed(int resource_id) {
307 // Check to see if the image is already in the cache. 349 // Check to see if the image is already in the cache.
sky 2012/08/08 14:41:24 I believe this code can be invoked on any thread,
oshima 2012/08/08 15:12:16 This method is still thread safe. However, returne
bshe 2012/08/08 17:26:12 Not sure if related, for wallpapers, I believe we
308 { 350 {
309 base::AutoLock lock_scope(*images_and_fonts_lock_); 351 base::AutoLock lock_scope(*images_and_fonts_lock_);
310 if (images_.count(resource_id)) 352 if (images_.count(resource_id))
311 return images_[resource_id]; 353 return images_[resource_id];
312 } 354 }
313 355
314 gfx::Image image; 356 gfx::Image image;
315 if (delegate_) 357 if (delegate_)
316 image = delegate_->GetImageNamed(resource_id); 358 image = delegate_->GetImageNamed(resource_id);
317 359
318 if (image.IsEmpty()) { 360 if (image.IsEmpty()) {
319 DCHECK(!delegate_ && !data_packs_.empty()) << 361 DCHECK(!delegate_ && !data_packs_.empty()) <<
320 "Missing call to SetResourcesDataDLL?"; 362 "Missing call to SetResourcesDataDLL?";
321 gfx::ImageSkia image_skia;
322 for (size_t i = 0; i < data_packs_.size(); ++i) {
323 scoped_ptr<SkBitmap> bitmap(LoadBitmap(*data_packs_[i], resource_id));
324 if (bitmap.get()) {
325 ui::ScaleFactor scale_factor;
326 if (gfx::Screen::IsDIPEnabled()) {
327 scale_factor = GetActualScaleFactor(image_skia, *bitmap,
328 data_packs_[i]->GetScaleFactor());
329 } else {
330 scale_factor = ui::SCALE_FACTOR_100P;
331 }
332 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale_factor));
333 }
334 }
335 363
336 if (image_skia.empty()) { 364 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P));
365 if (!bitmap.get()) {
337 LOG(WARNING) << "Unable to load image with id " << resource_id; 366 LOG(WARNING) << "Unable to load image with id " << resource_id;
338 NOTREACHED(); // Want to assert in debug mode. 367 NOTREACHED(); // Want to assert in debug mode.
339 // The load failed to retrieve the image; show a debugging red square.
340 return GetEmptyImage(); 368 return GetEmptyImage();
341 } 369 }
342 370
343 Create2xResourceIfMissing(image_skia, resource_id); 371 gfx::Size size_in_dip(bitmap->width(), bitmap->height());
344 372 gfx::ImageSkia image_skia(
373 new ResourceBundleImageSource(resource_id, size_in_dip),
374 size_in_dip);
375 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(),
376 SCALE_FACTOR_100P));
345 image = gfx::Image(image_skia); 377 image = gfx::Image(image_skia);
346 } 378 }
347 379
348 // The load was successful, so cache the image. 380 // The load was successful, so cache the image.
349 base::AutoLock lock_scope(*images_and_fonts_lock_); 381 base::AutoLock lock_scope(*images_and_fonts_lock_);
350 382
351 // Another thread raced the load and has already cached the image. 383 // Another thread raced the load and has already cached the image.
352 if (images_.count(resource_id)) 384 if (images_.count(resource_id))
353 return images_[resource_id]; 385 return images_[resource_id];
354 386
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 // 99% of our assets are PNGs, however fallback to JPEG. 589 // 99% of our assets are PNGs, however fallback to JPEG.
558 SkBitmap* allocated_bitmap = 590 SkBitmap* allocated_bitmap =
559 gfx::JPEGCodec::Decode(memory->front(), memory->size()); 591 gfx::JPEGCodec::Decode(memory->front(), memory->size());
560 if (allocated_bitmap) 592 if (allocated_bitmap)
561 return allocated_bitmap; 593 return allocated_bitmap;
562 594
563 NOTREACHED() << "Unable to decode theme image resource " << resource_id; 595 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
564 return NULL; 596 return NULL;
565 } 597 }
566 598
599 SkBitmap* ResourceBundle::LoadBitmap(int resource_id,
600 ScaleFactor scale_factor) {
601 for (size_t i = 0; i < data_packs_.size(); i++) {
602 if (data_packs_[i]->GetScaleFactor() == scale_factor) {
603 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id);
604 if (bitmap)
605 return bitmap;
606 }
607 }
608 return NULL;
609 }
610
567 gfx::Image& ResourceBundle::GetEmptyImage() { 611 gfx::Image& ResourceBundle::GetEmptyImage() {
568 base::AutoLock lock(*images_and_fonts_lock_); 612 base::AutoLock lock(*images_and_fonts_lock_);
569 613
570 if (empty_image_.IsEmpty()) { 614 if (empty_image_.IsEmpty()) {
571 // The placeholder bitmap is bright red so people notice the problem. 615 // The placeholder bitmap is bright red so people notice the problem.
572 SkBitmap bitmap; 616 SkBitmap bitmap;
573 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); 617 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
574 bitmap.allocPixels(); 618 bitmap.allocPixels();
575 bitmap.eraseARGB(255, 255, 0, 0); 619 bitmap.eraseARGB(255, 255, 0, 0);
576 empty_image_ = gfx::Image(bitmap); 620 empty_image_ = gfx::Image(bitmap);
577 } 621 }
578 return empty_image_; 622 return empty_image_;
579 } 623 }
580 624
581 } // namespace ui 625 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/resource/resource_bundle.h ('k') | ui/gfx/image/image_skia.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698