OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |