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" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 const int kMediumFontSizeDelta = 3; | 40 const int kMediumFontSizeDelta = 3; |
| 41 const int kLargeFontSizeDelta = 8; | 41 const int kLargeFontSizeDelta = 8; |
| 42 | 42 |
| 43 ResourceBundle* g_shared_instance_ = NULL; | 43 ResourceBundle* g_shared_instance_ = NULL; |
| 44 | 44 |
| 45 bool ShouldHighlightMissingScaledResources() { | 45 bool ShouldHighlightMissingScaledResources() { |
| 46 return CommandLine::ForCurrentProcess()->HasSwitch( | 46 return CommandLine::ForCurrentProcess()->HasSwitch( |
| 47 switches::kHighlightMissingScaledResources); | 47 switches::kHighlightMissingScaledResources); |
| 48 } | 48 } |
| 49 | 49 |
| 50 int ScaleDimension(int in, int numerator, int denominator) { | |
| 51 DCHECK(0 < in && in < 65536); | |
| 52 DCHECK(100 <= numerator && numerator <= 200); | |
| 53 DCHECK(100 <= denominator && denominator <= 200); | |
| 54 return (in * numerator + (denominator / 2)) / denominator; | |
| 55 } | |
| 56 | |
| 50 } // namespace | 57 } // namespace |
| 51 | 58 |
| 52 // An ImageSkiaSource that loads bitmaps for requested scale factor from | 59 // An ImageSkiaSource that loads bitmaps for requested scale factor from |
| 53 // ResourceBundle on demand for given resource_id. It falls back | 60 // ResourceBundle on demand for given resource_id. It falls back |
| 54 // to the 1x bitmap if the bitmap for the requested scale factor does not | 61 // to the 1x bitmap if the bitmap for the requested scale factor does not |
| 55 // exist. If the resource for the requested scale factor is not exactly | 62 // exist. If the resource for the requested scale factor is not exactly |
| 56 // |scale_factor| * the size of the 1x resource, it will end up with | 63 // |scale_factor| * the size of the 1x resource, it will end up with |
| 57 // broken UI because it will be drawn as if the bitmap was the correct size. | 64 // broken UI because it will be drawn as if the bitmap was the correct size. |
| 58 // When --highlight-missing-scaled-resources flag is specified, it | 65 // When --highlight-missing-scaled-resources flag is specified, it |
| 59 // will show the scaled image blended with red instead. | 66 // will show the scaled image blended with red instead. |
| 60 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource { | 67 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource { |
| 61 public: | 68 public: |
| 62 ResourceBundleImageSource(ResourceBundle* rb, | 69 ResourceBundleImageSource(ResourceBundle* rb, int resource_id) |
| 63 int resource_id, | 70 : rb_(rb), resource_id_(resource_id) {} |
| 64 const gfx::Size& size_in_dip) | |
| 65 : rb_(rb), | |
| 66 resource_id_(resource_id), | |
| 67 size_in_dip_(size_in_dip) { | |
| 68 } | |
| 69 virtual ~ResourceBundleImageSource() {} | 71 virtual ~ResourceBundleImageSource() {} |
| 70 | 72 |
| 71 // gfx::ImageSkiaSource overrides: | 73 // gfx::ImageSkiaSource overrides: |
| 72 virtual gfx::ImageSkiaRep GetImageForScale( | 74 virtual gfx::ImageSkiaRep GetImageForScale( |
| 73 ui::ScaleFactor scale_factor) OVERRIDE { | 75 ui::ScaleFactor scale_factor) OVERRIDE { |
| 74 scoped_ptr<SkBitmap> result(rb_->LoadBitmap(resource_id_, scale_factor)); | 76 int percent = static_cast<int>( |
| 75 float scale = ui::GetScaleFactorScale(scale_factor); | 77 GetScaleFactorScale(scale_factor) * 100 + 0.5); |
| 76 gfx::Size size_in_pixel = size_in_dip_.Scale(scale); | 78 SkBitmap image; |
| 79 int image_percent; | |
| 80 bool found = rb_->LoadBitmap( | |
| 81 resource_id_, scale_factor, &image, &image_percent); | |
|
oshima
2012/10/05 20:33:11
We need scale info only in the images that fell ba
oshima
2012/10/07 02:42:21
And in that case, all we need is a simple marker i
benrg
2012/10/07 04:36:11
Yes, when we add a csCl chunk the scale is always
oshima
2012/10/08 17:32:15
Since we'll never store scale other than 100, let'
benrg
2012/10/09 00:07:06
Done.
| |
| 77 | 82 |
| 78 if (scale_factor != SCALE_FACTOR_100P && | 83 if (!found) { |
| 79 (!result.get() || | 84 // Some images (e.g. wallpapers) exist only at 100%. Return the unscaled |
| 80 result->width() != size_in_pixel.width() || | 85 // image with the correct scale factor. |
|
oshima
2012/10/08 17:32:15
you can just return empty ImageSkiaReps and it wil
benrg
2012/10/09 00:07:06
I left this as is for now because the new code bel
| |
| 81 result->height() != size_in_pixel.height())) { | 86 DCHECK_NE(scale_factor, SCALE_FACTOR_100P); |
| 87 found = rb_->LoadBitmap( | |
| 88 resource_id_, SCALE_FACTOR_100P, &image, &image_percent); | |
| 89 DCHECK(found); | |
|
oshima
2012/10/08 17:32:15
I don't think this DCHECK is useful.
| |
| 90 return gfx::ImageSkiaRep(image, SCALE_FACTOR_100P); | |
| 91 } | |
| 82 | 92 |
| 83 // If non 1x resource is missing from |image| or is the incorrect | 93 if (image_percent > 0 && percent != image_percent) { |
| 84 // size and --highlight-missing-scaled-resources is specified, logs | 94 // The scale stored in the image (normally 100%) doesn't match the |
| 85 // the resource id and creates a version of the resource at the correct | 95 // requested scale: rescale the image. |
| 86 // size. Blends the created resource with red to make it | 96 image = skia::ImageOperations::Resize( |
| 87 // distinguishable from bitmaps in the resource pak. | 97 image, |
| 98 skia::ImageOperations::RESIZE_LANCZOS3, | |
| 99 ScaleDimension(image.width(), percent, image_percent), | |
| 100 ScaleDimension(image.height(), percent, image_percent)); | |
| 101 // If --highlight-missing-scaled-resources is specified, log the resource | |
| 102 // id and blend the created resource with red. | |
| 88 if (ShouldHighlightMissingScaledResources()) { | 103 if (ShouldHighlightMissingScaledResources()) { |
| 89 if (!result.get()) { | 104 LOG(ERROR) << "Missing " << percent << "% scaled resource. id=" |
| 90 LOG(ERROR) << "Missing " << scale << "x resource. id=" | 105 << resource_id_; |
| 91 << resource_id_; | |
| 92 } else { | |
| 93 LOG(ERROR) << "Incorrectly sized " << scale << "x resource. id=" | |
| 94 << resource_id_; | |
| 95 } | |
| 96 | |
| 97 scoped_ptr<SkBitmap> bitmap1x( | |
| 98 rb_->LoadBitmap(resource_id_, SCALE_FACTOR_100P)); | |
| 99 DCHECK(bitmap1x.get()); | |
| 100 SkBitmap bitmap_scaled = skia::ImageOperations::Resize( | |
| 101 *bitmap1x, | |
| 102 skia::ImageOperations::RESIZE_LANCZOS3, | |
| 103 size_in_pixel.width(), | |
| 104 size_in_pixel.height()); | |
| 105 | 106 |
| 106 SkBitmap mask; | 107 SkBitmap mask; |
| 107 mask.setConfig(SkBitmap::kARGB_8888_Config, | 108 mask.setConfig(SkBitmap::kARGB_8888_Config, |
| 108 bitmap_scaled.width(), | 109 image.width(), image.height()); |
| 109 bitmap_scaled.height()); | |
| 110 mask.allocPixels(); | 110 mask.allocPixels(); |
| 111 mask.eraseColor(SK_ColorRED); | 111 mask.eraseColor(SK_ColorRED); |
| 112 result.reset(new SkBitmap()); | 112 image = SkBitmapOperations::CreateBlendedBitmap(image, mask, 0.2); |
| 113 *result.get() = SkBitmapOperations::CreateBlendedBitmap( | |
| 114 bitmap_scaled, mask, 0.2); | |
| 115 } else if (!result.get() || result->width() == size_in_dip_.width()) { | |
| 116 // The scaled resource pack may have the 1x image if its grd file | |
| 117 // points to 1x image. Fallback to 1x by returning empty image | |
| 118 // in this case. This 1x image will be scaled when drawn. | |
| 119 return gfx::ImageSkiaRep(); | |
| 120 } | 113 } |
| 121 // If the size of scaled image isn't exactly |scale| * 1x version, | |
| 122 // create ImageSkia as usual. This will end up with | |
| 123 // corrupted visual representation as the size of image doesn't | |
| 124 // match the expected size. | |
| 125 } | 114 } |
| 126 DCHECK(result.get()); | 115 |
| 127 return gfx::ImageSkiaRep(*result.get(), scale_factor); | 116 return gfx::ImageSkiaRep(image, scale_factor); |
| 128 } | 117 } |
| 129 | 118 |
| 130 private: | 119 private: |
| 131 ResourceBundle* rb_; | 120 ResourceBundle* rb_; |
| 132 const int resource_id_; | 121 const int resource_id_; |
| 133 const gfx::Size size_in_dip_; | |
| 134 | 122 |
| 135 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource); | 123 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource); |
| 136 }; | 124 }; |
| 137 | 125 |
| 138 // static | 126 // static |
| 139 std::string ResourceBundle::InitSharedInstanceWithLocale( | 127 std::string ResourceBundle::InitSharedInstanceWithLocale( |
| 140 const std::string& pref_locale, Delegate* delegate) { | 128 const std::string& pref_locale, Delegate* delegate) { |
| 141 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; | 129 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; |
| 142 g_shared_instance_ = new ResourceBundle(delegate); | 130 g_shared_instance_ = new ResourceBundle(delegate); |
| 143 | 131 |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 } | 325 } |
| 338 | 326 |
| 339 gfx::Image image; | 327 gfx::Image image; |
| 340 if (delegate_) | 328 if (delegate_) |
| 341 image = delegate_->GetImageNamed(resource_id); | 329 image = delegate_->GetImageNamed(resource_id); |
| 342 | 330 |
| 343 if (image.IsEmpty()) { | 331 if (image.IsEmpty()) { |
| 344 DCHECK(!delegate_ && !data_packs_.empty()) << | 332 DCHECK(!delegate_ && !data_packs_.empty()) << |
| 345 "Missing call to SetResourcesDataDLL?"; | 333 "Missing call to SetResourcesDataDLL?"; |
| 346 | 334 |
| 347 // TODO(oshima): Pick the scale factor from currently used scale factors. | 335 // TODO(benrg): We only need this image for its dimensions. Do something |
| 348 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P)); | 336 // more efficient. |
|
oshima
2012/10/07 02:42:21
I wanted to know if the image has fallen back to 1
benrg
2012/10/07 04:36:11
Are you saying that my changes here are okay as is
oshima
2012/10/08 17:32:15
I want to change so that it will load at the targe
benrg
2012/10/09 00:07:06
I folded some of the code from that CL into this o
oshima
2012/10/09 18:28:35
looks ok. Can you send me stack trace of the crash
| |
| 349 if (!bitmap.get()) { | 337 SkBitmap image1x; |
| 338 int image1x_percent; | |
| 339 bool found_1x = LoadBitmap(resource_id, SCALE_FACTOR_100P, | |
| 340 &image1x, &image1x_percent); | |
| 341 if (!found_1x) { | |
| 350 LOG(WARNING) << "Unable to load image with id " << resource_id; | 342 LOG(WARNING) << "Unable to load image with id " << resource_id; |
| 351 NOTREACHED(); // Want to assert in debug mode. | 343 NOTREACHED(); // Want to assert in debug mode. |
| 352 // The load failed to retrieve the image; show a debugging red square. | 344 // The load failed to retrieve the image; show a debugging red square. |
| 353 return GetEmptyImage(); | 345 return GetEmptyImage(); |
| 354 } | 346 } |
| 347 DCHECK(image1x_percent == -1 || image1x_percent == 100); | |
| 348 gfx::Size size_in_dip(image1x.width(), image1x.height()); | |
| 355 | 349 |
| 356 // ResourceBundle::GetSharedInstance() is destroyed after the | 350 // ResourceBundle::GetSharedInstance() is destroyed after the |
| 357 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be | 351 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be |
| 358 // destroyed before the resource bundle is destroyed. | 352 // destroyed before the resource bundle is destroyed. |
| 359 gfx::Size size_in_dip(bitmap->width(), bitmap->height()); | 353 gfx::ImageSkia image_skia(new ResourceBundleImageSource(this, resource_id), |
| 360 gfx::ImageSkia image_skia( | 354 size_in_dip); |
| 361 new ResourceBundleImageSource(this, resource_id, size_in_dip), | 355 image_skia.AddRepresentation(gfx::ImageSkiaRep(image1x, SCALE_FACTOR_100P)); |
| 362 size_in_dip); | |
| 363 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(), | |
| 364 SCALE_FACTOR_100P)); | |
| 365 image_skia.SetReadOnly(); | 356 image_skia.SetReadOnly(); |
| 366 image = gfx::Image(image_skia); | 357 image = gfx::Image(image_skia); |
| 367 } | 358 } |
| 368 | 359 |
| 369 // The load was successful, so cache the image. | 360 // The load was successful, so cache the image. |
| 370 base::AutoLock lock_scope(*images_and_fonts_lock_); | 361 base::AutoLock lock_scope(*images_and_fonts_lock_); |
| 371 | 362 |
| 372 // Another thread raced the load and has already cached the image. | 363 // Another thread raced the load and has already cached the image. |
| 373 if (images_.count(resource_id)) | 364 if (images_.count(resource_id)) |
| 374 return images_[resource_id]; | 365 return images_[resource_id]; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 582 | 573 |
| 583 if (!large_bold_font_.get()) { | 574 if (!large_bold_font_.get()) { |
| 584 large_bold_font_.reset(new gfx::Font()); | 575 large_bold_font_.reset(new gfx::Font()); |
| 585 *large_bold_font_ = | 576 *large_bold_font_ = |
| 586 base_font_->DeriveFont(kLargeFontSizeDelta, | 577 base_font_->DeriveFont(kLargeFontSizeDelta, |
| 587 base_font_->GetStyle() | gfx::Font::BOLD); | 578 base_font_->GetStyle() | gfx::Font::BOLD); |
| 588 } | 579 } |
| 589 } | 580 } |
| 590 } | 581 } |
| 591 | 582 |
| 592 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, | 583 bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, |
| 593 int resource_id) const { | 584 int resource_id, |
| 585 SkBitmap* bitmap, | |
| 586 int* percent) const { | |
| 594 scoped_refptr<base::RefCountedMemory> memory( | 587 scoped_refptr<base::RefCountedMemory> memory( |
| 595 data_handle.GetStaticMemory(resource_id)); | 588 data_handle.GetStaticMemory(resource_id)); |
| 596 if (!memory) | 589 if (!memory) |
| 597 return NULL; | 590 return false; |
| 598 | 591 |
| 599 SkBitmap bitmap; | 592 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), bitmap, percent)) |
| 600 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) | 593 return true; |
| 601 return new SkBitmap(bitmap); | |
| 602 | 594 |
| 603 // 99% of our assets are PNGs, however fallback to JPEG. | 595 // 99% of our assets are PNGs, however fallback to JPEG. |
| 604 SkBitmap* allocated_bitmap = | 596 scoped_ptr<SkBitmap> jpeg_bitmap( |
| 605 gfx::JPEGCodec::Decode(memory->front(), memory->size()); | 597 gfx::JPEGCodec::Decode(memory->front(), memory->size())); |
| 606 if (allocated_bitmap) | 598 if (jpeg_bitmap.get()) { |
| 607 return allocated_bitmap; | 599 bitmap->swap(*jpeg_bitmap.get()); |
| 600 *percent = -1; | |
| 601 return true; | |
| 602 } | |
| 608 | 603 |
| 609 NOTREACHED() << "Unable to decode theme image resource " << resource_id; | 604 NOTREACHED() << "Unable to decode theme image resource " << resource_id; |
| 610 return NULL; | 605 return false; |
| 611 } | 606 } |
| 612 | 607 |
| 613 SkBitmap* ResourceBundle::LoadBitmap(int resource_id, | 608 bool ResourceBundle::LoadBitmap(int resource_id, |
| 614 ScaleFactor scale_factor) const { | 609 ScaleFactor scale_factor, |
| 610 SkBitmap* bitmap, | |
| 611 int* percent) const { | |
|
oshima
2012/10/05 20:33:11
I think it's better to use ScaleFactor rather than
benrg
2012/10/07 04:36:11
Done.
| |
| 615 for (size_t i = 0; i < data_packs_.size(); ++i) { | 612 for (size_t i = 0; i < data_packs_.size(); ++i) { |
| 616 if (data_packs_[i]->GetScaleFactor() == scale_factor) { | 613 if (data_packs_[i]->GetScaleFactor() == scale_factor) { |
| 617 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id); | 614 if (LoadBitmap(*data_packs_[i], resource_id, bitmap, percent)) |
| 618 if (bitmap) | 615 return true; |
| 619 return bitmap; | |
| 620 } | 616 } |
| 621 } | 617 } |
| 622 return NULL; | 618 return false; |
| 623 } | 619 } |
| 624 | 620 |
| 625 gfx::Image& ResourceBundle::GetEmptyImage() { | 621 gfx::Image& ResourceBundle::GetEmptyImage() { |
| 626 base::AutoLock lock(*images_and_fonts_lock_); | 622 base::AutoLock lock(*images_and_fonts_lock_); |
| 627 | 623 |
| 628 if (empty_image_.IsEmpty()) { | 624 if (empty_image_.IsEmpty()) { |
| 629 // The placeholder bitmap is bright red so people notice the problem. | 625 // The placeholder bitmap is bright red so people notice the problem. |
| 630 SkBitmap bitmap; | 626 SkBitmap bitmap; |
| 631 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); | 627 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); |
| 632 bitmap.allocPixels(); | 628 bitmap.allocPixels(); |
| 633 bitmap.eraseARGB(255, 255, 0, 0); | 629 bitmap.eraseARGB(255, 255, 0, 0); |
| 634 empty_image_ = gfx::Image(bitmap); | 630 empty_image_ = gfx::Image(bitmap); |
| 635 } | 631 } |
| 636 return empty_image_; | 632 return empty_image_; |
| 637 } | 633 } |
| 638 | 634 |
| 639 } // namespace ui | 635 } // namespace ui |
| OLD | NEW |