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