| 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 { |
| 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_; |
| 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 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P)); |
| 359 if (!bitmap.get()) { |
| 330 LOG(WARNING) << "Unable to load image with id " << resource_id; | 360 LOG(WARNING) << "Unable to load image with id " << resource_id; |
| 331 NOTREACHED(); // Want to assert in debug mode. | 361 NOTREACHED(); // Want to assert in debug mode. |
| 332 // The load failed to retrieve the image; show a debugging red square. | 362 // The load failed to retrieve the image; show a debugging red square. |
| 333 return GetEmptyImage(); | 363 return GetEmptyImage(); |
| 334 } | 364 } |
| 335 | 365 |
| 336 Create2xResourceIfMissing(image_skia, resource_id); | 366 gfx::Size size_in_dip(bitmap->width(), bitmap->height()); |
| 337 | 367 gfx::ImageSkia image_skia( |
| 368 new ResourceBundleImageSource(resource_id, size_in_dip), |
| 369 size_in_dip); |
| 370 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(), |
| 371 SCALE_FACTOR_100P)); |
| 338 image = gfx::Image(image_skia); | 372 image = gfx::Image(image_skia); |
| 339 } | 373 } |
| 340 | 374 |
| 341 // The load was successful, so cache the image. | 375 // The load was successful, so cache the image. |
| 342 base::AutoLock lock_scope(*images_and_fonts_lock_); | 376 base::AutoLock lock_scope(*images_and_fonts_lock_); |
| 343 | 377 |
| 344 // Another thread raced the load and has already cached the image. | 378 // Another thread raced the load and has already cached the image. |
| 345 if (images_.count(resource_id)) | 379 if (images_.count(resource_id)) |
| 346 return images_[resource_id]; | 380 return images_[resource_id]; |
| 347 | 381 |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 // 99% of our assets are PNGs, however fallback to JPEG. | 584 // 99% of our assets are PNGs, however fallback to JPEG. |
| 551 SkBitmap* allocated_bitmap = | 585 SkBitmap* allocated_bitmap = |
| 552 gfx::JPEGCodec::Decode(memory->front(), memory->size()); | 586 gfx::JPEGCodec::Decode(memory->front(), memory->size()); |
| 553 if (allocated_bitmap) | 587 if (allocated_bitmap) |
| 554 return allocated_bitmap; | 588 return allocated_bitmap; |
| 555 | 589 |
| 556 NOTREACHED() << "Unable to decode theme image resource " << resource_id; | 590 NOTREACHED() << "Unable to decode theme image resource " << resource_id; |
| 557 return NULL; | 591 return NULL; |
| 558 } | 592 } |
| 559 | 593 |
| 594 SkBitmap* ResourceBundle::LoadBitmap(int resource_id, |
| 595 ScaleFactor scale_factor) { |
| 596 for (size_t i = 0; i < data_packs_.size(); i++) { |
| 597 if (data_packs_[i]->GetScaleFactor() == scale_factor) { |
| 598 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id); |
| 599 if (bitmap) |
| 600 return bitmap; |
| 601 } |
| 602 } |
| 603 return NULL; |
| 604 } |
| 605 |
| 560 gfx::Image& ResourceBundle::GetEmptyImage() { | 606 gfx::Image& ResourceBundle::GetEmptyImage() { |
| 561 base::AutoLock lock(*images_and_fonts_lock_); | 607 base::AutoLock lock(*images_and_fonts_lock_); |
| 562 | 608 |
| 563 if (empty_image_.IsEmpty()) { | 609 if (empty_image_.IsEmpty()) { |
| 564 // The placeholder bitmap is bright red so people notice the problem. | 610 // The placeholder bitmap is bright red so people notice the problem. |
| 565 SkBitmap bitmap; | 611 SkBitmap bitmap; |
| 566 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); | 612 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); |
| 567 bitmap.allocPixels(); | 613 bitmap.allocPixels(); |
| 568 bitmap.eraseARGB(255, 255, 0, 0); | 614 bitmap.eraseARGB(255, 255, 0, 0); |
| 569 empty_image_ = gfx::Image(bitmap); | 615 empty_image_ = gfx::Image(bitmap); |
| 570 } | 616 } |
| 571 return empty_image_; | 617 return empty_image_; |
| 572 } | 618 } |
| 573 | 619 |
| 574 } // namespace ui | 620 } // namespace ui |
| OLD | NEW |