diff options
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()); } |