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

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: remove unnecessary code 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
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 const int kSmallFontSizeDelta = -2; 39 const int kSmallFontSizeDelta = -2;
39 const int kMediumFontSizeDelta = 3; 40 const int kMediumFontSizeDelta = 3;
40 const int kLargeFontSizeDelta = 8; 41 const int kLargeFontSizeDelta = 8;
41 42
43 ResourceBundle* g_shared_instance_ = NULL;
44
42 // Returns the actual scale factor of |bitmap| given the image representations 45 // Returns the actual scale factor of |bitmap| given the image representations
43 // which have already been added to |image|. 46 // which have already been added to |image|.
44 // TODO(pkotwicz): Remove this once we are no longer loading 1x resources 47 // TODO(pkotwicz): Remove this once we are no longer loading 1x resources
45 // as part of 2x data packs. 48 // as part of 2x data packs.
46 ui::ScaleFactor GetActualScaleFactor(const gfx::ImageSkia& image, 49 ui::ScaleFactor GetActualScaleFactor(const gfx::ImageSkia& image,
47 const SkBitmap& bitmap, 50 const SkBitmap& bitmap,
48 ui::ScaleFactor data_pack_scale_factor) { 51 ui::ScaleFactor data_pack_scale_factor) {
49 if (image.isNull()) 52 if (image.isNull())
50 return data_pack_scale_factor; 53 return data_pack_scale_factor;
51 54
52 return ui::GetScaleFactorFromScale( 55 return ui::GetScaleFactorFromScale(
53 static_cast<float>(bitmap.width()) / image.width()); 56 static_cast<float>(bitmap.width()) / image.width());
54 } 57 }
55 58
56 // If 2x resource is missing from |image| or is the incorrect size, 59 bool ShouldHighlightMissing2xResources() {
57 // logs the resource id and creates a 2x version of the resource. 60 return CommandLine::ForCurrentProcess()->HasSwitch(
58 // Blends the created resource with red to make it distinguishable from 61 switches::kHighlightMissing2xResources);
59 // bitmaps in the resource pak.
60 void Create2xResourceIfMissing(gfx::ImageSkia image, int idr) {
61 CommandLine* command_line = CommandLine::ForCurrentProcess();
62 if (command_line->HasSwitch(
63 switches::kHighlightMissing2xResources) &&
64 !image.HasRepresentation(ui::SCALE_FACTOR_200P)) {
65 gfx::ImageSkiaRep image_rep = image.GetRepresentation(SCALE_FACTOR_200P);
66
67 if (image_rep.scale_factor() == ui::SCALE_FACTOR_100P)
68 LOG(INFO) << "Missing 2x resource with id " << idr;
69 else
70 LOG(INFO) << "Incorrectly sized 2x resource with id " << idr;
71
72 SkBitmap bitmap2x = skia::ImageOperations::Resize(image_rep.sk_bitmap(),
73 skia::ImageOperations::RESIZE_LANCZOS3,
74 image.width() * 2, image.height() * 2);
75
76 SkBitmap mask;
77 mask.setConfig(SkBitmap::kARGB_8888_Config,
78 bitmap2x.width(),
79 bitmap2x.height());
80 mask.allocPixels();
81 mask.eraseColor(SK_ColorRED);
82 SkBitmap result = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask,
83 0.2);
84 image.AddRepresentation(gfx::ImageSkiaRep(result, SCALE_FACTOR_200P));
85 }
86 } 62 }
87 63
88 } // namespace 64 } // namespace
89 65
90 ResourceBundle* ResourceBundle::g_shared_instance_ = NULL; 66 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
sky 2012/08/23 19:44:09 Add a description.
oshima 2012/08/24 16:45:34 Done.
67 public:
68 ResourceBundleImageSource(int resource_id, const gfx::Size& size_in_dip)
69 : resource_id_(resource_id),
70 size_in_dip_(size_in_dip) {
71 }
72 virtual ~ResourceBundleImageSource() {}
73
74 // gfx::ImageSkiaSource overrides:
75 virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) {
76 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
77
78 scoped_ptr<SkBitmap> result(rb.LoadBitmap(resource_id_, scale_factor));
79 gfx::Size size_in_pixel =
80 size_in_dip_.Scale(ui::GetScaleFactorScale(scale_factor));
81
82 if (scale_factor == SCALE_FACTOR_200P &&
83 (!result.get() ||
84 result->width() != size_in_pixel.width() ||
85 result->height() != size_in_pixel.height())) {
86
87 // If 2x resource is missing from |image| or is the incorrect
88 // size and --highlight-missing-2x-resources is specified, logs
89 // the resource id and creates a 2x version of the resource.
90 // Blends the created resource with red to make it
91 // distinguishable from bitmaps in the resource pak.
92 if (ShouldHighlightMissing2xResources()) {
93 if (!result.get())
94 LOG(ERROR) << "Missing 2x resource. id=" << resource_id_;
95 else
96 LOG(ERROR) << "Incorrectly sized 2x resource. id=" << resource_id_;
97
98 SkBitmap bitmap1x = *(rb.LoadBitmap(resource_id_, SCALE_FACTOR_100P));
99 SkBitmap bitmap2x = skia::ImageOperations::Resize(
100 bitmap1x,
101 skia::ImageOperations::RESIZE_LANCZOS3,
102 bitmap1x.width() * 2, bitmap1x.height() * 2);
103
104 SkBitmap mask;
105 mask.setConfig(SkBitmap::kARGB_8888_Config,
106 bitmap2x.width(),
107 bitmap2x.height());
108 mask.allocPixels();
109 mask.eraseColor(SK_ColorRED);
110 result.reset(new SkBitmap());
111 *result.get() = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask,
112 0.2);
113 } else if (!result.get() ||
114 result->width() == size_in_dip_.width()) {
115 // The 2x resource pack may have the 1x image if its grd file
116 // points to 1x image. Fallback to 1x by returning empty image
117 // in this case. This 1x image will be scaled when drawn.
118 return gfx::ImageSkiaRep();
119 }
120 // If the size of 2x image isn't exactly 2x of 1x version,
121 // create ImageSkia as usual. This will end up with
122 // corrupted visual representation as the size of image doesn't
123 // match the expected size.
124 }
125 return gfx::ImageSkiaRep(*result.get(), scale_factor);
126 }
127
128 private:
129 int resource_id_;
sky 2012/08/23 19:44:09 Make these two const.
oshima 2012/08/24 16:45:34 Done.
130 gfx::Size size_in_dip_;
131
132 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
133 };
91 134
92 // static 135 // static
93 std::string ResourceBundle::InitSharedInstanceWithLocale( 136 std::string ResourceBundle::InitSharedInstanceWithLocale(
94 const std::string& pref_locale, Delegate* delegate) { 137 const std::string& pref_locale, Delegate* delegate) {
95 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; 138 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
96 g_shared_instance_ = new ResourceBundle(delegate); 139 g_shared_instance_ = new ResourceBundle(delegate);
97 140
98 g_shared_instance_->LoadCommonResources(); 141 g_shared_instance_->LoadCommonResources();
99 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale); 142 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
100 return result; 143 return result;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 return images_[resource_id]; 347 return images_[resource_id];
305 } 348 }
306 349
307 gfx::Image image; 350 gfx::Image image;
308 if (delegate_) 351 if (delegate_)
309 image = delegate_->GetImageNamed(resource_id); 352 image = delegate_->GetImageNamed(resource_id);
310 353
311 if (image.IsEmpty()) { 354 if (image.IsEmpty()) {
312 DCHECK(!delegate_ && !data_packs_.empty()) << 355 DCHECK(!delegate_ && !data_packs_.empty()) <<
313 "Missing call to SetResourcesDataDLL?"; 356 "Missing call to SetResourcesDataDLL?";
314 gfx::ImageSkia image_skia;
315 for (size_t i = 0; i < data_packs_.size(); ++i) {
316 scoped_ptr<SkBitmap> bitmap(LoadBitmap(*data_packs_[i], resource_id));
317 if (bitmap.get()) {
318 ui::ScaleFactor scale_factor;
319 if (gfx::Screen::IsDIPEnabled()) {
320 scale_factor = GetActualScaleFactor(image_skia, *bitmap,
321 data_packs_[i]->GetScaleFactor());
322 } else {
323 scale_factor = ui::SCALE_FACTOR_100P;
324 }
325 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale_factor));
326 }
327 }
328 357
329 if (image_skia.isNull()) { 358 // TODO(oshima): Pick the scale factor from currently used scale factors.
359 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P));
360 if (!bitmap.get()) {
330 LOG(WARNING) << "Unable to load image with id " << resource_id; 361 LOG(WARNING) << "Unable to load image with id " << resource_id;
331 NOTREACHED(); // Want to assert in debug mode. 362 NOTREACHED(); // Want to assert in debug mode.
332 // The load failed to retrieve the image; show a debugging red square. 363 // The load failed to retrieve the image; show a debugging red square.
333 return GetEmptyImage(); 364 return GetEmptyImage();
334 } 365 }
335 366
336 Create2xResourceIfMissing(image_skia, resource_id); 367 gfx::Size size_in_dip(bitmap->width(), bitmap->height());
337 368 gfx::ImageSkia image_skia(
369 new ResourceBundleImageSource(resource_id, size_in_dip),
370 size_in_dip);
371 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(),
372 SCALE_FACTOR_100P));
338 image = gfx::Image(image_skia); 373 image = gfx::Image(image_skia);
339 } 374 }
340 375
341 // The load was successful, so cache the image. 376 // The load was successful, so cache the image.
342 base::AutoLock lock_scope(*images_and_fonts_lock_); 377 base::AutoLock lock_scope(*images_and_fonts_lock_);
343 378
344 // Another thread raced the load and has already cached the image. 379 // Another thread raced the load and has already cached the image.
345 if (images_.count(resource_id)) 380 if (images_.count(resource_id))
346 return images_[resource_id]; 381 return images_[resource_id];
347 382
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 if (!large_bold_font_.get()) { 565 if (!large_bold_font_.get()) {
531 large_bold_font_.reset(new gfx::Font()); 566 large_bold_font_.reset(new gfx::Font());
532 *large_bold_font_ = 567 *large_bold_font_ =
533 base_font_->DeriveFont(kLargeFontSizeDelta, 568 base_font_->DeriveFont(kLargeFontSizeDelta,
534 base_font_->GetStyle() | gfx::Font::BOLD); 569 base_font_->GetStyle() | gfx::Font::BOLD);
535 } 570 }
536 } 571 }
537 } 572 }
538 573
539 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, 574 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
540 int resource_id) { 575 int resource_id) const {
541 scoped_refptr<base::RefCountedMemory> memory( 576 scoped_refptr<base::RefCountedMemory> memory(
542 data_handle.GetStaticMemory(resource_id)); 577 data_handle.GetStaticMemory(resource_id));
543 if (!memory) 578 if (!memory)
544 return NULL; 579 return NULL;
545 580
546 SkBitmap bitmap; 581 SkBitmap bitmap;
547 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) 582 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap))
548 return new SkBitmap(bitmap); 583 return new SkBitmap(bitmap);
549 584
550 // 99% of our assets are PNGs, however fallback to JPEG. 585 // 99% of our assets are PNGs, however fallback to JPEG.
551 SkBitmap* allocated_bitmap = 586 SkBitmap* allocated_bitmap =
552 gfx::JPEGCodec::Decode(memory->front(), memory->size()); 587 gfx::JPEGCodec::Decode(memory->front(), memory->size());
553 if (allocated_bitmap) 588 if (allocated_bitmap)
554 return allocated_bitmap; 589 return allocated_bitmap;
555 590
556 NOTREACHED() << "Unable to decode theme image resource " << resource_id; 591 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
557 return NULL; 592 return NULL;
558 } 593 }
559 594
595 SkBitmap* ResourceBundle::LoadBitmap(int resource_id,
596 ScaleFactor scale_factor) const {
597 for (size_t i = 0; i < data_packs_.size(); ++i) {
598 if (data_packs_[i]->GetScaleFactor() == scale_factor) {
599 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id);
600 if (bitmap)
601 return bitmap;
602 }
603 }
604 return NULL;
605 }
606
560 gfx::Image& ResourceBundle::GetEmptyImage() { 607 gfx::Image& ResourceBundle::GetEmptyImage() {
561 base::AutoLock lock(*images_and_fonts_lock_); 608 base::AutoLock lock(*images_and_fonts_lock_);
562 609
563 if (empty_image_.IsEmpty()) { 610 if (empty_image_.IsEmpty()) {
564 // The placeholder bitmap is bright red so people notice the problem. 611 // The placeholder bitmap is bright red so people notice the problem.
565 SkBitmap bitmap; 612 SkBitmap bitmap;
566 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); 613 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
567 bitmap.allocPixels(); 614 bitmap.allocPixels();
568 bitmap.eraseARGB(255, 255, 0, 0); 615 bitmap.eraseARGB(255, 255, 0, 0);
569 empty_image_ = gfx::Image(bitmap); 616 empty_image_ = gfx::Image(bitmap);
570 } 617 }
571 return empty_image_; 618 return empty_image_;
572 } 619 }
573 620
574 } // namespace ui 621 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698