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