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

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: code adapted from issue 10914092 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 } // namespace 50 } // namespace
51 51
52 // An ImageSkiaSource that loads bitmaps for requested scale factor from 52 // An ImageSkiaSource that loads bitmaps for requested scale factor from
53 // ResourceBundle on demand for given resource_id. It falls back 53 // 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 54 // 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 55 // 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 56 // |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. 57 // 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 58 // When --highlight-missing-scaled-resources flag is specified, it
59 // will show the scaled image blended with red instead. 59 // will show the scaled image blended with red instead.
oshima 2012/10/09 18:28:35 Update the comment
benrg 2012/10/09 21:37:18 Done.
60 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource { 60 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
61 public: 61 public:
62 ResourceBundleImageSource(ResourceBundle* rb, 62 ResourceBundleImageSource(ResourceBundle* rb, int resource_id)
63 int resource_id, 63 : 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() {} 64 virtual ~ResourceBundleImageSource() {}
70 65
71 // gfx::ImageSkiaSource overrides: 66 // gfx::ImageSkiaSource overrides:
72 virtual gfx::ImageSkiaRep GetImageForScale( 67 virtual gfx::ImageSkiaRep GetImageForScale(
73 ui::ScaleFactor scale_factor) OVERRIDE { 68 ui::ScaleFactor scale_factor) OVERRIDE {
74 scoped_ptr<SkBitmap> result(rb_->LoadBitmap(resource_id_, scale_factor)); 69 SkBitmap image;
75 float scale = ui::GetScaleFactorScale(scale_factor); 70 bool scale_fallback = false;
76 gfx::Size size_in_pixel = size_in_dip_.Scale(scale); 71 bool found = rb_->LoadBitmap(resource_id_, scale_factor,
72 &image, &scale_fallback);
77 73
78 if (scale_factor != SCALE_FACTOR_100P && 74 if (!found) {
79 (!result.get() || 75 // Some images (e.g. wallpapers) exist only at 100%. Return the unscaled
80 result->width() != size_in_pixel.width() || 76 // image with the correct scale factor.
81 result->height() != size_in_pixel.height())) { 77 DCHECK_NE(scale_factor, SCALE_FACTOR_100P);
78 if (!rb_->LoadBitmap(resource_id_, SCALE_FACTOR_100P, &image, NULL))
79 return gfx::ImageSkiaRep();
80 return gfx::ImageSkiaRep(image, SCALE_FACTOR_100P);
81 }
82 82
83 // If non 1x resource is missing from |image| or is the incorrect 83 if (scale_fallback) {
84 // size and --highlight-missing-scaled-resources is specified, logs 84 // GRIT fell back to the 100% image, so rescale it to the correct size.
85 // the resource id and creates a version of the resource at the correct 85 float scale = GetScaleFactorScale(scale_factor);
86 // size. Blends the created resource with red to make it 86 image = skia::ImageOperations::Resize(
87 // distinguishable from bitmaps in the resource pak. 87 image,
88 skia::ImageOperations::RESIZE_LANCZOS3,
89 static_cast<int>(image.width() * scale + 0.5f),
90 static_cast<int>(image.height() * scale + 0.5f));
91 // If --highlight-missing-scaled-resources is specified, log the resource
92 // id and blend the created resource with red.
88 if (ShouldHighlightMissingScaledResources()) { 93 if (ShouldHighlightMissingScaledResources()) {
89 if (!result.get()) { 94 LOG(ERROR) << "Missing " << scale << "x scaled resource. id="
90 LOG(ERROR) << "Missing " << scale << "x resource. id=" 95 << 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 96
106 SkBitmap mask; 97 SkBitmap mask;
107 mask.setConfig(SkBitmap::kARGB_8888_Config, 98 mask.setConfig(SkBitmap::kARGB_8888_Config,
108 bitmap_scaled.width(), 99 image.width(), image.height());
109 bitmap_scaled.height());
110 mask.allocPixels(); 100 mask.allocPixels();
111 mask.eraseColor(SK_ColorRED); 101 mask.eraseColor(SK_ColorRED);
112 result.reset(new SkBitmap()); 102 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 } 103 }
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 } 104 }
126 DCHECK(result.get()); 105
127 return gfx::ImageSkiaRep(*result.get(), scale_factor); 106 return gfx::ImageSkiaRep(image, scale_factor);
128 } 107 }
129 108
130 private: 109 private:
131 ResourceBundle* rb_; 110 ResourceBundle* rb_;
132 const int resource_id_; 111 const int resource_id_;
133 const gfx::Size size_in_dip_;
134 112
135 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource); 113 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
136 }; 114 };
137 115
138 // static 116 // static
139 std::string ResourceBundle::InitSharedInstanceWithLocale( 117 std::string ResourceBundle::InitSharedInstanceWithLocale(
140 const std::string& pref_locale, Delegate* delegate) { 118 const std::string& pref_locale, Delegate* delegate) {
141 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; 119 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
142 g_shared_instance_ = new ResourceBundle(delegate); 120 g_shared_instance_ = new ResourceBundle(delegate);
143 121
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 } 315 }
338 316
339 gfx::Image image; 317 gfx::Image image;
340 if (delegate_) 318 if (delegate_)
341 image = delegate_->GetImageNamed(resource_id); 319 image = delegate_->GetImageNamed(resource_id);
342 320
343 if (image.IsEmpty()) { 321 if (image.IsEmpty()) {
344 DCHECK(!delegate_ && !data_packs_.empty()) << 322 DCHECK(!delegate_ && !data_packs_.empty()) <<
345 "Missing call to SetResourcesDataDLL?"; 323 "Missing call to SetResourcesDataDLL?";
346 324
347 // TODO(oshima): Pick the scale factor from currently used scale factors. 325 // TODO(benrg/oshima): GetPrimaryDisplay() crashes at startup.
348 scoped_ptr<SkBitmap> bitmap(LoadBitmap(resource_id, SCALE_FACTOR_100P)); 326 // ScaleFactor primary_scale_factor = GetScaleFactorFromScale(
349 if (!bitmap.get()) { 327 // gfx::Screen::GetPrimaryDisplay().device_scale_factor());
oshima 2012/10/09 18:28:35 can you show me stack trace?
benrg 2012/10/09 21:37:18 (Done)
oshima 2012/10/09 22:10:17 Thanks. Doing any UI related stuff before aura/ash
328 ScaleFactor primary_scale_factor = SCALE_FACTOR_100P;
329 scoped_ptr<ResourceBundleImageSource> image_source(
330 new ResourceBundleImageSource(this, resource_id));
331 gfx::ImageSkiaRep scaled_image =
332 image_source->GetImageForScale(primary_scale_factor);
oshima 2012/10/09 18:28:35 Can't we just do gfx::ImageSkia image_skia(..); if
benrg 2012/10/09 21:37:18 ImageSkia wants size_in_dip at construction time,
oshima 2012/10/09 22:06:07 How about ImageSkia(source, init_scale_factor) ? Y
benrg 2012/10/10 21:03:56 Done.
333 if (scaled_image.is_null()) {
350 LOG(WARNING) << "Unable to load image with id " << resource_id; 334 LOG(WARNING) << "Unable to load image with id " << resource_id;
351 NOTREACHED(); // Want to assert in debug mode. 335 NOTREACHED(); // Want to assert in debug mode.
352 // The load failed to retrieve the image; show a debugging red square. 336 // The load failed to retrieve the image; show a debugging red square.
353 return GetEmptyImage(); 337 return GetEmptyImage();
354 } 338 }
339 gfx::Size size_in_dip(scaled_image.GetWidth(), scaled_image.GetHeight());
355 340
356 // ResourceBundle::GetSharedInstance() is destroyed after the 341 // ResourceBundle::GetSharedInstance() is destroyed after the
357 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be 342 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
358 // destroyed before the resource bundle is destroyed. 343 // destroyed before the resource bundle is destroyed.
359 gfx::Size size_in_dip(bitmap->width(), bitmap->height()); 344 gfx::ImageSkia image_skia(image_source.release(), size_in_dip);
360 gfx::ImageSkia image_skia( 345 image_skia.AddRepresentation(scaled_image);
361 new ResourceBundleImageSource(this, resource_id, size_in_dip),
362 size_in_dip);
363 image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap.get(),
364 SCALE_FACTOR_100P));
365 image_skia.SetReadOnly(); 346 image_skia.SetReadOnly();
366 image = gfx::Image(image_skia); 347 image = gfx::Image(image_skia);
367 } 348 }
368 349
369 // The load was successful, so cache the image. 350 // The load was successful, so cache the image.
370 base::AutoLock lock_scope(*images_and_fonts_lock_); 351 base::AutoLock lock_scope(*images_and_fonts_lock_);
371 352
372 // Another thread raced the load and has already cached the image. 353 // Another thread raced the load and has already cached the image.
373 if (images_.count(resource_id)) 354 if (images_.count(resource_id))
374 return images_[resource_id]; 355 return images_[resource_id];
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 563
583 if (!large_bold_font_.get()) { 564 if (!large_bold_font_.get()) {
584 large_bold_font_.reset(new gfx::Font()); 565 large_bold_font_.reset(new gfx::Font());
585 *large_bold_font_ = 566 *large_bold_font_ =
586 base_font_->DeriveFont(kLargeFontSizeDelta, 567 base_font_->DeriveFont(kLargeFontSizeDelta,
587 base_font_->GetStyle() | gfx::Font::BOLD); 568 base_font_->GetStyle() | gfx::Font::BOLD);
588 } 569 }
589 } 570 }
590 } 571 }
591 572
592 SkBitmap* ResourceBundle::LoadBitmap(const ResourceHandle& data_handle, 573 bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
593 int resource_id) const { 574 int resource_id,
575 SkBitmap* bitmap,
576 bool* scale_fallback) const {
594 scoped_refptr<base::RefCountedMemory> memory( 577 scoped_refptr<base::RefCountedMemory> memory(
595 data_handle.GetStaticMemory(resource_id)); 578 data_handle.GetStaticMemory(resource_id));
596 if (!memory) 579 if (!memory)
597 return NULL; 580 return false;
598 581
599 SkBitmap bitmap; 582 if (gfx::PNGCodec::Decode(memory->front(), memory->size(),
600 if (gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) 583 bitmap, scale_fallback))
601 return new SkBitmap(bitmap); 584 return true;
oshima 2012/10/09 18:28:35 you need {} in this case
benrg 2012/10/09 21:37:18 Done.
602 585
603 // 99% of our assets are PNGs, however fallback to JPEG. 586 // 99% of our assets are PNGs, however fallback to JPEG.
604 SkBitmap* allocated_bitmap = 587 scoped_ptr<SkBitmap> jpeg_bitmap(
605 gfx::JPEGCodec::Decode(memory->front(), memory->size()); 588 gfx::JPEGCodec::Decode(memory->front(), memory->size()));
606 if (allocated_bitmap) 589 if (jpeg_bitmap.get()) {
607 return allocated_bitmap; 590 bitmap->swap(*jpeg_bitmap.get());
591 return true;
592 }
608 593
609 NOTREACHED() << "Unable to decode theme image resource " << resource_id; 594 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
610 return NULL; 595 return false;
611 } 596 }
612 597
613 SkBitmap* ResourceBundle::LoadBitmap(int resource_id, 598 bool ResourceBundle::LoadBitmap(int resource_id,
614 ScaleFactor scale_factor) const { 599 ScaleFactor scale_factor,
600 SkBitmap* bitmap,
601 bool* scale_fallback) const {
615 for (size_t i = 0; i < data_packs_.size(); ++i) { 602 for (size_t i = 0; i < data_packs_.size(); ++i) {
616 if (data_packs_[i]->GetScaleFactor() == scale_factor) { 603 if (data_packs_[i]->GetScaleFactor() == scale_factor) {
617 SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id); 604 if (LoadBitmap(*data_packs_[i], resource_id, bitmap, scale_fallback))
618 if (bitmap) 605 return true;
619 return bitmap;
620 } 606 }
621 } 607 }
622 return NULL; 608 return false;
623 } 609 }
624 610
625 gfx::Image& ResourceBundle::GetEmptyImage() { 611 gfx::Image& ResourceBundle::GetEmptyImage() {
626 base::AutoLock lock(*images_and_fonts_lock_); 612 base::AutoLock lock(*images_and_fonts_lock_);
627 613
628 if (empty_image_.IsEmpty()) { 614 if (empty_image_.IsEmpty()) {
629 // The placeholder bitmap is bright red so people notice the problem. 615 // The placeholder bitmap is bright red so people notice the problem.
630 SkBitmap bitmap; 616 SkBitmap bitmap;
631 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32); 617 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
632 bitmap.allocPixels(); 618 bitmap.allocPixels();
633 bitmap.eraseARGB(255, 255, 0, 0); 619 bitmap.eraseARGB(255, 255, 0, 0);
634 empty_image_ = gfx::Image(bitmap); 620 empty_image_ = gfx::Image(bitmap);
635 } 621 }
636 return empty_image_; 622 return empty_image_;
637 } 623 }
638 624
639 } // namespace ui 625 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698