Chromium Code Reviews| 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 |