summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/base/resource/resource_bundle.cc97
-rw-r--r--ui/base/resource/resource_bundle.h17
-rw-r--r--ui/base/resource/resource_bundle_ios.mm50
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());
}