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

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: updated comment Created 8 years, 3 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 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 // An ImageSkiaSource that loads bitmaps for given scale factor from
67 // ResourceBundle on demand for given resource_id. It falls back
68 // to 100P image if corresponding 200P image doesn't exist.
69 // If 200P image does not have 2x size of 100P images, it will end up
70 // with broken UI because it will be drawn as if it has 2x size.
71 // When --highlight-missing-2x-resources flag is specified, it
72 // will show the scaled image blended with red instead.
73 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
74 public:
75 ResourceBundleImageSource(int resource_id, const gfx::Size& size_in_dip)
76 : resource_id_(resource_id),
77 size_in_dip_(size_in_dip) {
78 }
79 virtual ~ResourceBundleImageSource() {}
80
81 // gfx::ImageSkiaSource overrides:
82 virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) {
83 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
84
85 scoped_ptr<SkBitmap> result(rb.LoadBitmap(resource_id_, scale_factor));
86 gfx::Size size_in_pixel =
87 size_in_dip_.Scale(ui::GetScaleFactorScale(scale_factor));
88
89 if (scale_factor == SCALE_FACTOR_200P &&
90 (!result.get() ||
91 result->width() != size_in_pixel.width() ||
92 result->height() != size_in_pixel.height())) {
93
94 // If 2x resource is missing from |image| or is the incorrect
95 // size and --highlight-missing-2x-resources is specified, logs
96 // the resource id and creates a 2x version of the resource.
97 // Blends the created resource with red to make it
98 // distinguishable from bitmaps in the resource pak.
99 if (ShouldHighlightMissing2xResources()) {
100 if (!result.get())
101 LOG(ERROR) << "Missing 2x resource. id=" << resource_id_;
102 else
103 LOG(ERROR) << "Incorrectly sized 2x resource. id=" << resource_id_;
104
105 SkBitmap bitmap1x = *(rb.LoadBitmap(resource_id_, SCALE_FACTOR_100P));
106 SkBitmap bitmap2x = skia::ImageOperations::Resize(
107 bitmap1x,
108 skia::ImageOperations::RESIZE_LANCZOS3,
109 bitmap1x.width() * 2, bitmap1x.height() * 2);
110
111 SkBitmap mask;
112 mask.setConfig(SkBitmap::kARGB_8888_Config,
113 bitmap2x.width(),
114 bitmap2x.height());
115 mask.allocPixels();
116 mask.eraseColor(SK_ColorRED);
117 result.reset(new SkBitmap());
118 *result.get() = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask,
119 0.2);
120 } else if (!result.get() ||
121 result->width() == size_in_dip_.width()) {
122 // The 2x resource pack may have the 1x image if its grd file
123 // points to 1x image. Fallback to 1x by returning empty image
124 // in this case. This 1x image will be scaled when drawn.
125 return gfx::ImageSkiaRep();
126 }
127 // If the size of 2x image isn't exactly 2x of 1x version,
128 // create ImageSkia as usual. This will end up with
129 // corrupted visual representation as the size of image doesn't
130 // match the expected size.
131 }
132 return gfx::ImageSkiaRep(*result.get(), scale_factor);
133 }
134
135 private:
136 const int resource_id_;
137 const gfx::Size size_in_dip_;
138
139 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
140 };
91 141
92 // static 142 // static
93 std::string ResourceBundle::InitSharedInstanceWithLocale( 143 std::string ResourceBundle::InitSharedInstanceWithLocale(
94 const std::string& pref_locale, Delegate* delegate) { 144 const std::string& pref_locale, Delegate* delegate) {
95 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; 145 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
96 g_shared_instance_ = new ResourceBundle(delegate); 146 g_shared_instance_ = new ResourceBundle(delegate);
97 147
98 g_shared_instance_->LoadCommonResources(); 148 g_shared_instance_->LoadCommonResources();
99 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale); 149 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
100 return result; 150 return result;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 return images_[resource_id]; 354 return images_[resource_id];
305 } 355 }
306 356
307 gfx::Image image; 357 gfx::Image image;
308 if (delegate_) 358 if (delegate_)
309 image = delegate_->GetImageNamed(resource_id); 359 image = delegate_->GetImageNamed(resource_id);
310 360
311 if (image.IsEmpty()) { 361 if (image.IsEmpty()) {
312 DCHECK(!delegate_ && !data_packs_.empty()) << 362 DCHECK(!delegate_ && !data_packs_.empty()) <<
313 "Missing call to SetResourcesDataDLL?"; 363 "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 364
329 if (image_skia.isNull()) { 365 // TODO(oshima): Pick the scale factor from currently used scale factors.
366 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P));
367 if (!bitmap.get()) {
330 LOG(WARNING) << "Unable to load image with id " << resource_id; 368 LOG(WARNING) << "Unable to load image with id " << resource_id;
331 NOTREACHED(); // Want to assert in debug mode. 369 NOTREACHED(); // Want to assert in debug mode.
332 // The load failed to retrieve the image; show a debugging red square. 370 // The load failed to retrieve the image; show a debugging red square.
333 return GetEmptyImage(); 371 return GetEmptyImage();
334 } 372 }
335 373
336 Create2xResourceIfMissing(image_skia, resource_id); 374 gfx::Size size_in_dip(bitmap->width(), bitmap->height());
337 375 gfx::ImageSkia image_skia(
376 new ResourceBundleImageSource(resource_id, size_in_dip),
377 size_in_dip);
378 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(),
379 SCALE_FACTOR_100P));
380 image_skia.SetReadOnly();
338 image = gfx::Image(image_skia); 381 image = gfx::Image(image_skia);
339 } 382 }
340 383
341 // The load was successful, so cache the image. 384 // The load was successful, so cache the image.
342 base::AutoLock lock_scope(*images_and_fonts_lock_); 385 base::AutoLock lock_scope(*images_and_fonts_lock_);
343 386
344 // Another thread raced the load and has already cached the image. 387 // Another thread raced the load and has already cached the image.
345 if (images_.count(resource_id)) 388 if (images_.count(resource_id))
346 return images_[resource_id]; 389 return images_[resource_id];
347 390
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 if (!large_bold_font_.get()) { 573 if (!large_bold_font_.get()) {
531 large_bold_font_.reset(new gfx::Font()); 574 large_bold_font_.reset(new gfx::Font());
532 *large_bold_font_ = 575 *large_bold_font_ =
533 base_font_->DeriveFont(kLargeFontSizeDelta, 576 base_font_->DeriveFont(kLargeFontSizeDelta,
534 base_font_->GetStyle() | gfx::Font::BOLD); 577 base_font_->GetStyle() | gfx::Font::BOLD);
535 } 578 }
536 } 579 }
537 } 580 }
538 581
539 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, 582 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
540 int resource_id) { 583 int resource_id) const {
541 scoped_refptr<base::RefCountedMemory> memory( 584 scoped_refptr<base::RefCountedMemory> memory(
542 data_handle.GetStaticMemory(resource_id)); 585 data_handle.GetStaticMemory(resource_id));
543 if (!memory) 586 if (!memory)
544 return NULL; 587 return NULL;
545 588
546 SkBitmap bitmap; 589 SkBitmap bitmap;
547 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) 590 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap))
548 return new SkBitmap(bitmap); 591 return new SkBitmap(bitmap);
549 592
550 // 99% of our assets are PNGs, however fallback to JPEG. 593 // 99% of our assets are PNGs, however fallback to JPEG.
551 SkBitmap* allocated_bitmap = 594 SkBitmap* allocated_bitmap =
552 gfx::JPEGCodec::Decode(memory->front(), memory->size()); 595 gfx::JPEGCodec::Decode(memory->front(), memory->size());
553 if (allocated_bitmap) 596 if (allocated_bitmap)
554 return allocated_bitmap; 597 return allocated_bitmap;
555 598
556 NOTREACHED() << "Unable to decode theme image resource " << resource_id; 599 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
557 return NULL; 600 return NULL;
558 } 601 }
559 602
603 SkBitmap* ResourceBundle::LoadBitmap(int resource_id,
604 ScaleFactor scale_factor) const {
605 for (size_t i = 0; i < data_packs_.size(); ++i) {
606 if (data_packs_[i]->GetScaleFactor() == scale_factor) {
607 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id);
608 if (bitmap)
609 return bitmap;
610 }
611 }
612 return NULL;
613 }
614
560 gfx::Image& ResourceBundle::GetEmptyImage() { 615 gfx::Image& ResourceBundle::GetEmptyImage() {
561 base::AutoLock lock(*images_and_fonts_lock_); 616 base::AutoLock lock(*images_and_fonts_lock_);
562 617
563 if (empty_image_.IsEmpty()) { 618 if (empty_image_.IsEmpty()) {
564 // The placeholder bitmap is bright red so people notice the problem. 619 // The placeholder bitmap is bright red so people notice the problem.
565 SkBitmap bitmap; 620 SkBitmap bitmap;
566 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); 621 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
567 bitmap.allocPixels(); 622 bitmap.allocPixels();
568 bitmap.eraseARGB(255, 255, 0, 0); 623 bitmap.eraseARGB(255, 255, 0, 0);
569 empty_image_ = gfx::Image(bitmap); 624 empty_image_ = gfx::Image(bitmap);
570 } 625 }
571 return empty_image_; 626 return empty_image_;
572 } 627 }
573 628
574 } // namespace ui 629 } // 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