diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-06 09:48:13 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-06 09:48:13 +0000 |
commit | b9cdd7d3627f24485722552323eb7fd4be8dbd98 (patch) | |
tree | d2ec22930d2fa3d10be53000832a661a58a53b35 /ui | |
parent | a926f64f4b49d5858765b17813326de13c91d0bd (diff) | |
download | chromium_src-b9cdd7d3627f24485722552323eb7fd4be8dbd98.zip chromium_src-b9cdd7d3627f24485722552323eb7fd4be8dbd98.tar.gz chromium_src-b9cdd7d3627f24485722552323eb7fd4be8dbd98.tar.bz2 |
Add support for 1x fallback images on iOS
iOS doesn't use the Skia image path, so 1x images in the 200 resource
bundles with the magic fallback draw at half size.
This adds matching support on iOS, to scaled fallback images up and
optionally add a visual indication of the fallback.
BUG=None
Review URL: https://chromiumcodereview.appspot.com/11896014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180946 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/base/resource/resource_bundle.cc | 97 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle.h | 17 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_ios.mm | 50 |
3 files changed, 113 insertions, 51 deletions
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index 3cb86bb..6ced085 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc @@ -55,54 +55,6 @@ const unsigned char kPngDataChunkType[4] = { 'I', 'D', 'A', 'T' }; ResourceBundle* g_shared_instance_ = NULL; -bool ShouldHighlightMissingScaledResources() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kHighlightMissingScaledResources); -} - -// A wrapper for PNGCodec::Decode that returns information about custom chunks. -// For security reasons we can't alter PNGCodec to return this information. Our -// PNG files are preprocessed by GRIT, and any special chunks should occur -// immediately after the IHDR chunk. -bool DecodePNG(const unsigned char* buf, - size_t size, - SkBitmap* bitmap, - bool* fell_back_to_1x) { - *fell_back_to_1x = false; - - if (size < arraysize(kPngMagic) || - memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) { - // Data invalid or a JPEG. - return false; - } - size_t pos = arraysize(kPngMagic); - - // Scan for custom chunks until we find one, find the IDAT chunk, or run out - // of chunks. - for (;;) { - if (size - pos < kPngChunkMetadataSize) - break; - uint32 length = 0; - net::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length); - if (size - pos - kPngChunkMetadataSize < length) - break; - if (length == 0 && memcmp(buf + pos + sizeof(uint32), kPngScaleChunkType, - arraysize(kPngScaleChunkType)) == 0) { - *fell_back_to_1x = true; - break; - } - if (memcmp(buf + pos + sizeof(uint32), kPngDataChunkType, - arraysize(kPngDataChunkType)) == 0) { - // Stop looking for custom chunks, any custom chunks should be before an - // IDAT chunk. - break; - } - pos += length + kPngChunkMetadataSize; - } - // Pass the data to the PNG decoder. - return gfx::PNGCodec::Decode(buf, size, bitmap); -} - } // namespace // An ImageSkiaSource that loads bitmaps for the requested scale factor from @@ -715,4 +667,53 @@ gfx::Image& ResourceBundle::GetEmptyImage() { return empty_image_; } +// static +bool ResourceBundle::ShouldHighlightMissingScaledResources() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kHighlightMissingScaledResources); +} + +// static +bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf, + size_t size) { + if (size < arraysize(kPngMagic) || + memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) { + // Data invalid or a JPEG. + return false; + } + size_t pos = arraysize(kPngMagic); + + // Scan for custom chunks until we find one, find the IDAT chunk, or run out + // of chunks. + for (;;) { + if (size - pos < kPngChunkMetadataSize) + break; + uint32 length = 0; + net::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length); + if (size - pos - kPngChunkMetadataSize < length) + break; + if (length == 0 && memcmp(buf + pos + sizeof(uint32), kPngScaleChunkType, + arraysize(kPngScaleChunkType)) == 0) { + return true; + } + if (memcmp(buf + pos + sizeof(uint32), kPngDataChunkType, + arraysize(kPngDataChunkType)) == 0) { + // Stop looking for custom chunks, any custom chunks should be before an + // IDAT chunk. + break; + } + pos += length + kPngChunkMetadataSize; + } + return false; +} + +// static +bool ResourceBundle::DecodePNG(const unsigned char* buf, + size_t size, + SkBitmap* bitmap, + bool* fell_back_to_1x) { + *fell_back_to_1x = PNGContainsFallbackMarker(buf, size); + return gfx::PNGCodec::Decode(buf, size, bitmap); +} + } // namespace ui diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h index 4631702..8d42189 100644 --- a/ui/base/resource/resource_bundle.h +++ b/ui/base/resource/resource_bundle.h @@ -319,6 +319,23 @@ class UI_EXPORT ResourceBundle { SkBitmap* bitmap, bool* fell_back_to_1x) const; + // Returns true if missing scaled resources should be visually indicated when + // drawing the fallback (e.g., by tinting the image). + static bool ShouldHighlightMissingScaledResources(); + + // Returns true if the data in |buf| is a PNG that has the special marker + // added by GRIT that indicates that the image is actually 1x data. + static bool PNGContainsFallbackMarker(const unsigned char* buf, size_t size); + + // A wrapper for PNGCodec::Decode that returns information about custom + // chunks. For security reasons we can't alter PNGCodec to return this + // information. Our PNG files are preprocessed by GRIT, and any special chunks + // should occur immediately after the IHDR chunk. + static bool DecodePNG(const unsigned char* buf, + size_t size, + SkBitmap* bitmap, + bool* fell_back_to_1x); + // Returns an empty image for when a resource cannot be loaded. This is a // bright red bitmap. gfx::Image& GetEmptyImage(); diff --git a/ui/base/resource/resource_bundle_ios.mm b/ui/base/resource/resource_bundle_ios.mm index 8ff7347..7140d69a 100644 --- a/ui/base/resource/resource_bundle_ios.mm +++ b/ui/base/resource/resource_bundle_ios.mm @@ -4,6 +4,7 @@ #include "ui/base/resource/resource_bundle.h" +#import <QuartzCore/QuartzCore.h> #import <UIKit/UIKit.h> #include "base/basictypes.h" @@ -112,14 +113,56 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) { scoped_refptr<base::RefCountedStaticMemory> data( LoadDataResourceBytesForScale(resource_id, scale_factor)); + if (!data.get()) { + LOG(WARNING) << "Unable to load image with id " << resource_id; + return GetEmptyImage(); + } + // Create a data object from the raw bytes. scoped_nsobject<NSData> ns_data( [[NSData alloc] initWithBytes:data->front() length:data->size()]); - // Create the image from the data. The gfx::Image will take ownership. + bool is_fallback = PNGContainsFallbackMarker(data->front(), data->size()); + // Create the image from the data. + CGFloat target_scale = ui::GetScaleFactorScale(scale_factor); + CGFloat source_scale = is_fallback ? 1.0 : target_scale; scoped_nsobject<UIImage> ui_image( - [[UIImage alloc] initWithData:ns_data - scale:ui::GetScaleFactorScale(scale_factor)]); + [[UIImage alloc] initWithData:ns_data scale:source_scale]); + + // If the image is a 1x fallback, scale it up to a full-size representation. + if (is_fallback) { + CGSize source_size = [ui_image size]; + CGSize target_size = CGSizeMake(source_size.width * target_scale, + source_size.height * target_scale); + base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space( + CGColorSpaceCreateDeviceRGB()); + base::mac::ScopedCFTypeRef<CGContextRef> context( + CGBitmapContextCreate( + NULL, + target_size.width, target_size.height, + 8, target_size.width * 4, + color_space, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + + CGRect target_rect = CGRectMake(0, 0, + target_size.width, target_size.height); + CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextDrawImage(context, target_rect, [ui_image CGImage]); + + if (ShouldHighlightMissingScaledResources()) { + CGContextSetFillColorSpace(context, color_space); + CGFloat components[4] = { 1.0, 0.0, 0.0, 0.3 }; // Translucent red. + CGContextSetFillColor(context, components); + CGContextSetBlendMode(context, kCGBlendModeNormal); + CGContextFillRect(context, target_rect); + } + + base::mac::ScopedCFTypeRef<CGImageRef> cg_image( + CGBitmapContextCreateImage(context)); + ui_image.reset([[UIImage alloc] initWithCGImage:cg_image + scale:target_scale + orientation:UIImageOrientationUp]); + } if (!ui_image.get()) { LOG(WARNING) << "Unable to load image with id " << resource_id; @@ -127,6 +170,7 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) { return GetEmptyImage(); } + // The gfx::Image takes ownership. image = gfx::Image(ui_image.release()); } |