Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: ui/base/resource/resource_bundle.cc

Issue 11028064: Resize images for hi-dpi based on a custom PNG chunk added by GRIT r78, and roll GRIT r78 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 10 matching lines...) Expand all
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/image/image_skia_source.h"
31 #include "ui/gfx/safe_floor_ceil.h"
31 #include "ui/gfx/screen.h" 32 #include "ui/gfx/screen.h"
32 #include "ui/gfx/size_conversions.h" 33 #include "ui/gfx/size_conversions.h"
33 #include "ui/gfx/skbitmap_operations.h" 34 #include "ui/gfx/skbitmap_operations.h"
34 35
35 namespace ui { 36 namespace ui {
36 37
37 namespace { 38 namespace {
38 39
39 // Font sizes relative to base font. 40 // Font sizes relative to base font.
40 const int kSmallFontSizeDelta = -2; 41 const int kSmallFontSizeDelta = -2;
41 const int kMediumFontSizeDelta = 3; 42 const int kMediumFontSizeDelta = 3;
42 const int kLargeFontSizeDelta = 8; 43 const int kLargeFontSizeDelta = 8;
43 44
44 ResourceBundle* g_shared_instance_ = NULL; 45 ResourceBundle* g_shared_instance_ = NULL;
45 46
46 bool ShouldHighlightMissingScaledResources() { 47 bool ShouldHighlightMissingScaledResources() {
47 return CommandLine::ForCurrentProcess()->HasSwitch( 48 return CommandLine::ForCurrentProcess()->HasSwitch(
48 switches::kHighlightMissingScaledResources); 49 switches::kHighlightMissingScaledResources);
49 } 50 }
50 51
51 } // namespace 52 } // namespace
52 53
53 // An ImageSkiaSource that loads bitmaps for requested scale factor from 54 // An ImageSkiaSource that loads bitmaps for the requested scale factor from
54 // ResourceBundle on demand for given resource_id. It falls back 55 // ResourceBundle on demand for a given |resource_id|. If the bitmap for the
55 // to the 1x bitmap if the bitmap for the requested scale factor does not 56 // requested scale factor does not exist, it will return the 1x bitmap scaled
56 // exist. If the resource for the requested scale factor is not exactly 57 // by the scale factor. This may lead to broken UI if the correct size of the
57 // |scale_factor| * the size of the 1x resource, it will end up with 58 // scaled image is not exactly |scale_factor| * the size of the 1x resource.
58 // broken UI because it will be drawn as if the bitmap was the correct size. 59 // When --highlight-missing-scaled-resources flag is specified, scaled 1x images
59 // When --highlight-missing-scaled-resources flag is specified, it 60 // are higlighted by blending them with red.
60 // will show the scaled image blended with red instead.
61 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource { 61 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
62 public: 62 public:
63 ResourceBundleImageSource(ResourceBundle* rb, 63 ResourceBundleImageSource(ResourceBundle* rb, int resource_id)
64 int resource_id, 64 : rb_(rb), resource_id_(resource_id) {}
65 const gfx::Size& size_in_dip)
66 : rb_(rb),
67 resource_id_(resource_id),
68 size_in_dip_(size_in_dip) {
69 }
70 virtual ~ResourceBundleImageSource() {} 65 virtual ~ResourceBundleImageSource() {}
71 66
72 // gfx::ImageSkiaSource overrides: 67 // gfx::ImageSkiaSource overrides:
73 virtual gfx::ImageSkiaRep GetImageForScale( 68 virtual gfx::ImageSkiaRep GetImageForScale(
74 ui::ScaleFactor scale_factor) OVERRIDE { 69 ui::ScaleFactor scale_factor) OVERRIDE {
75 scoped_ptr<SkBitmap> result(rb_->LoadBitmap(resource_id_, scale_factor)); 70 SkBitmap image;
76 float scale = ui::GetScaleFactorScale(scale_factor); 71 bool fell_back_to_1x = false;
77 gfx::Size size_in_pixel = gfx::ToFlooredSize(size_in_dip_.Scale(scale)); 72 bool found = rb_->LoadBitmap(resource_id_, scale_factor,
73 &image, &fell_back_to_1x);
78 74
79 if (scale_factor != SCALE_FACTOR_100P && 75 if (!found) {
80 (!result.get() || 76 // Some images (e.g. wallpapers) exist only at 100%. Return the unscaled
81 result->width() != size_in_pixel.width() || 77 // image with the correct scale factor.
82 result->height() != size_in_pixel.height())) { 78 if (scale_factor != SCALE_FACTOR_100P)
79 found = rb_->LoadBitmap(resource_id_, SCALE_FACTOR_100P, &image, NULL);
80 if (!found)
oshima 2012/10/11 01:31:54 and you should be able to return just ImageSkiaRep
benrg 2012/10/15 21:58:54 Done.
81 return gfx::ImageSkiaRep();
82 return gfx::ImageSkiaRep(image, SCALE_FACTOR_100P);
83 }
83 84
84 // If non 1x resource is missing from |image| or is the incorrect 85 if (fell_back_to_1x) {
85 // size and --highlight-missing-scaled-resources is specified, logs 86 // GRIT fell back to the 100% image, so rescale it to the correct size.
86 // the resource id and creates a version of the resource at the correct 87 float scale = GetScaleFactorScale(scale_factor);
87 // size. Blends the created resource with red to make it 88 image = skia::ImageOperations::Resize(
88 // distinguishable from bitmaps in the resource pak. 89 image,
90 skia::ImageOperations::RESIZE_LANCZOS3,
91 gfx::ToFlooredInt(image.width() * scale),
92 gfx::ToFlooredInt(image.height() * scale));
93 // If --highlight-missing-scaled-resources is specified, log the resource
94 // id and blend the created resource with red.
89 if (ShouldHighlightMissingScaledResources()) { 95 if (ShouldHighlightMissingScaledResources()) {
90 if (!result.get()) { 96 LOG(ERROR) << "Missing " << scale << "x scaled resource. id="
91 LOG(ERROR) << "Missing " << scale << "x resource. id=" 97 << resource_id_;
92 << resource_id_;
93 } else {
94 LOG(ERROR) << "Incorrectly sized " << scale << "x resource. id="
95 << resource_id_;
96 }
97
98 scoped_ptr<SkBitmap> bitmap1x(
99 rb_->LoadBitmap(resource_id_, SCALE_FACTOR_100P));
100 DCHECK(bitmap1x.get());
101 SkBitmap bitmap_scaled = skia::ImageOperations::Resize(
102 *bitmap1x,
103 skia::ImageOperations::RESIZE_LANCZOS3,
104 size_in_pixel.width(),
105 size_in_pixel.height());
106 98
107 SkBitmap mask; 99 SkBitmap mask;
108 mask.setConfig(SkBitmap::kARGB_8888_Config, 100 mask.setConfig(SkBitmap::kARGB_8888_Config,
109 bitmap_scaled.width(), 101 image.width(), image.height());
110 bitmap_scaled.height());
111 mask.allocPixels(); 102 mask.allocPixels();
112 mask.eraseColor(SK_ColorRED); 103 mask.eraseColor(SK_ColorRED);
113 result.reset(new SkBitmap()); 104 image = SkBitmapOperations::CreateBlendedBitmap(image, mask, 0.2);
114 *result.get() = SkBitmapOperations::CreateBlendedBitmap(
115 bitmap_scaled, mask, 0.2);
116 } else if (!result.get() || result->width() == size_in_dip_.width()) {
117 // The scaled resource pack may have the 1x image if its grd file
118 // points to 1x image. Fallback to 1x by returning empty image
119 // in this case. This 1x image will be scaled when drawn.
120 return gfx::ImageSkiaRep();
121 } 105 }
122 // If the size of scaled image isn't exactly |scale| * 1x version,
123 // create ImageSkia as usual. This will end up with
124 // corrupted visual representation as the size of image doesn't
125 // match the expected size.
126 } 106 }
127 DCHECK(result.get()); 107
128 return gfx::ImageSkiaRep(*result.get(), scale_factor); 108 return gfx::ImageSkiaRep(image, scale_factor);
129 } 109 }
130 110
131 private: 111 private:
132 ResourceBundle* rb_; 112 ResourceBundle* rb_;
133 const int resource_id_; 113 const int resource_id_;
134 const gfx::Size size_in_dip_;
135 114
136 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource); 115 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
137 }; 116 };
138 117
139 // static 118 // static
140 std::string ResourceBundle::InitSharedInstanceWithLocale( 119 std::string ResourceBundle::InitSharedInstanceWithLocale(
141 const std::string& pref_locale, Delegate* delegate) { 120 const std::string& pref_locale, Delegate* delegate) {
142 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; 121 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
143 g_shared_instance_ = new ResourceBundle(delegate); 122 g_shared_instance_ = new ResourceBundle(delegate);
144 123
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 } 312 }
334 313
335 gfx::Image image; 314 gfx::Image image;
336 if (delegate_) 315 if (delegate_)
337 image = delegate_->GetImageNamed(resource_id); 316 image = delegate_->GetImageNamed(resource_id);
338 317
339 if (image.IsEmpty()) { 318 if (image.IsEmpty()) {
340 DCHECK(!delegate_ && !data_packs_.empty()) << 319 DCHECK(!delegate_ && !data_packs_.empty()) <<
341 "Missing call to SetResourcesDataDLL?"; 320 "Missing call to SetResourcesDataDLL?";
342 321
343 // TODO(oshima): Pick the scale factor from currently used scale factors. 322 // TODO(oshima): This should be GetPrimaryDisplay().device_scale_factor(),
344 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P)); 323 // but GetPrimaryDisplay() crashes at startup.
345 if (!bitmap.get()) { 324 ScaleFactor primary_scale_factor = SCALE_FACTOR_100P;
325 // ResourceBundle::GetSharedInstance() is destroyed after the
326 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
327 // destroyed before the resource bundle is destroyed.
328 gfx::ImageSkia image_skia(new ResourceBundleImageSource(this, resource_id),
329 primary_scale_factor);
330 if (image_skia.isNull()) {
346 LOG(WARNING) << "Unable to load image with id " << resource_id; 331 LOG(WARNING) << "Unable to load image with id " << resource_id;
347 NOTREACHED(); // Want to assert in debug mode. 332 NOTREACHED(); // Want to assert in debug mode.
348 // The load failed to retrieve the image; show a debugging red square. 333 // The load failed to retrieve the image; show a debugging red square.
349 return GetEmptyImage(); 334 return GetEmptyImage();
350 } 335 }
351
352 // ResourceBundle::GetSharedInstance() is destroyed after the
353 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
354 // destroyed before the resource bundle is destroyed.
355 gfx::Size size_in_dip(bitmap->width(), bitmap->height());
356 gfx::ImageSkia image_skia(
357 new ResourceBundleImageSource(this, resource_id, size_in_dip),
358 size_in_dip);
359 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(),
360 SCALE_FACTOR_100P));
361 image_skia.SetReadOnly(); 336 image_skia.SetReadOnly();
362 image = gfx::Image(image_skia); 337 image = gfx::Image(image_skia);
363 } 338 }
364 339
365 // The load was successful, so cache the image. 340 // The load was successful, so cache the image.
366 base::AutoLock lock_scope(*images_and_fonts_lock_); 341 base::AutoLock lock_scope(*images_and_fonts_lock_);
367 342
368 // Another thread raced the load and has already cached the image. 343 // Another thread raced the load and has already cached the image.
369 if (images_.count(resource_id)) 344 if (images_.count(resource_id))
370 return images_[resource_id]; 345 return images_[resource_id];
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 553
579 if (!large_bold_font_.get()) { 554 if (!large_bold_font_.get()) {
580 large_bold_font_.reset(new gfx::Font()); 555 large_bold_font_.reset(new gfx::Font());
581 *large_bold_font_ = 556 *large_bold_font_ =
582 base_font_->DeriveFont(kLargeFontSizeDelta, 557 base_font_->DeriveFont(kLargeFontSizeDelta,
583 base_font_->GetStyle() | gfx::Font::BOLD); 558 base_font_->GetStyle() | gfx::Font::BOLD);
584 } 559 }
585 } 560 }
586 } 561 }
587 562
588 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, 563 bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
589 int resource_id) const { 564 int resource_id,
565 SkBitmap* bitmap,
566 bool* fell_back_to_1x) const {
590 scoped_refptr<base::RefCountedMemory> memory( 567 scoped_refptr<base::RefCountedMemory> memory(
591 data_handle.GetStaticMemory(resource_id)); 568 data_handle.GetStaticMemory(resource_id));
592 if (!memory) 569 if (!memory)
593 return NULL; 570 return false;
594 571
595 SkBitmap bitmap; 572 if (gfx::PNGCodec::Decode(memory->front(), memory->size(),
596 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) 573 bitmap, fell_back_to_1x)) {
597 return new SkBitmap(bitmap); 574 return true;
575 }
598 576
599 #if !defined(OS_IOS) 577 #if !defined(OS_IOS)
600 // iOS does not compile or use the JPEG codec. On other platforms, 578 // iOS does not compile or use the JPEG codec. On other platforms,
601 // 99% of our assets are PNGs, however fallback to JPEG. 579 // 99% of our assets are PNGs, however fallback to JPEG.
602 SkBitmap* allocated_bitmap = 580 scoped_ptr<SkBitmap> jpeg_bitmap(
603 gfx::JPEGCodec::Decode(memory->front(), memory->size()); 581 gfx::JPEGCodec::Decode(memory->front(), memory->size()));
604 if (allocated_bitmap) 582 if (jpeg_bitmap.get()) {
605 return allocated_bitmap; 583 bitmap->swap(*jpeg_bitmap.get());
584 return true;
585 }
606 #endif 586 #endif
607 587
608 NOTREACHED() << "Unable to decode theme image resource " << resource_id; 588 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
609 return NULL; 589 return false;
610 } 590 }
611 591
612 SkBitmap* ResourceBundle::LoadBitmap(int resource_id, 592 bool ResourceBundle::LoadBitmap(int resource_id,
613 ScaleFactor scale_factor) const { 593 ScaleFactor scale_factor,
594 SkBitmap* bitmap,
595 bool* fell_back_to_1x) const {
614 for (size_t i = 0; i < data_packs_.size(); ++i) { 596 for (size_t i = 0; i < data_packs_.size(); ++i) {
615 if (data_packs_[i]->GetScaleFactor() == scale_factor) { 597 if (data_packs_[i]->GetScaleFactor() == scale_factor) {
616 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id); 598 if (LoadBitmap(*data_packs_[i], resource_id, bitmap, fell_back_to_1x))
617 if (bitmap) 599 return true;
618 return bitmap;
619 } 600 }
620 } 601 }
621 return NULL; 602 return false;
622 } 603 }
623 604
624 gfx::Image& ResourceBundle::GetEmptyImage() { 605 gfx::Image& ResourceBundle::GetEmptyImage() {
625 base::AutoLock lock(*images_and_fonts_lock_); 606 base::AutoLock lock(*images_and_fonts_lock_);
626 607
627 if (empty_image_.IsEmpty()) { 608 if (empty_image_.IsEmpty()) {
628 // The placeholder bitmap is bright red so people notice the problem. 609 // The placeholder bitmap is bright red so people notice the problem.
629 SkBitmap bitmap; 610 SkBitmap bitmap;
630 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); 611 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
631 bitmap.allocPixels(); 612 bitmap.allocPixels();
632 bitmap.eraseARGB(255, 255, 0, 0); 613 bitmap.eraseARGB(255, 255, 0, 0);
633 empty_image_ = gfx::Image(bitmap); 614 empty_image_ = gfx::Image(bitmap);
634 } 615 }
635 return empty_image_; 616 return empty_image_;
636 } 617 }
637 618
638 } // namespace ui 619 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698