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

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: . 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 29 matching lines...) Expand all
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698