summaryrefslogtreecommitdiffstats
path: root/skia
diff options
context:
space:
mode:
authorsail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-27 20:50:52 +0000
committersail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-27 20:50:52 +0000
commit7b9cf72a104f1237de9d4ee29b81e03516106084 (patch)
tree1af51fc4d266a2b21c760947d37c8d3498ca2397 /skia
parente6c61281ca34ea34e8408bd4fd01daf4c8e4c5fd (diff)
downloadchromium_src-7b9cf72a104f1237de9d4ee29b81e03516106084.zip
chromium_src-7b9cf72a104f1237de9d4ee29b81e03516106084.tar.gz
chromium_src-7b9cf72a104f1237de9d4ee29b81e03516106084.tar.bz2
Use large icon resource pak
This is part of change r82185 that was reverted due to a performance regression on 10.5. The performance regression was due to a change in skia_utils_mac.mm to draw images using -[NSImageRep drawRect:] instead of -[NSImage drawRect:...]. It turns out that on 10.5 -[NSImage drawRect:...] does caching that imporoves performance for subsequent drawing by as much as 4x. This change is similar to r82185 expect that we now use -[NSImage drawRect:] if available. BUG=75812 TEST=Ran unit tests locally, try jobs pending. Review URL: http://codereview.chromium.org/6905003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83206 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r--skia/ext/skia_utils_mac.h10
-rw-r--r--skia/ext/skia_utils_mac.mm199
-rw-r--r--skia/ext/skia_utils_mac_unittest.mm136
3 files changed, 270 insertions, 75 deletions
diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h
index 0551643..04d4a1d 100644
--- a/skia/ext/skia_utils_mac.h
+++ b/skia/ext/skia_utils_mac.h
@@ -7,6 +7,7 @@
#pragma once
#include <CoreGraphics/CGColor.h>
+#include <vector>
#include "third_party/skia/include/core/SkColor.h"
@@ -23,8 +24,10 @@ typedef struct _NSSize NSSize;
#ifdef __OBJC__
@class NSImage;
+@class NSImageRep;
#else
class NSImage;
+class NSImageRep;
#endif
namespace gfx {
@@ -64,6 +67,9 @@ SkBitmap CGImageToSkBitmap(CGImageRef image);
// Draws an NSImage with a given size into a SkBitmap.
SkBitmap NSImageToSkBitmap(NSImage* image, NSSize size, bool is_opaque);
+// Draws an NSImageRep with a given size into a SkBitmap.
+SkBitmap NSImageRepToSkBitmap(NSImageRep* image, NSSize size, bool is_opaque);
+
// Given an SkBitmap and a color space, return an autoreleased NSImage.
NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& icon,
CGColorSpaceRef colorSpace);
@@ -73,6 +79,10 @@ NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& icon,
// TODO(thakis): Remove this -- http://crbug.com/69432
NSImage* SkBitmapToNSImage(const SkBitmap& icon);
+// Given a vector of SkBitmaps, return an NSImage with each bitmap added
+// as a representation.
+NSImage* SkBitmapsToNSImage(const std::vector<const SkBitmap*>& bitmaps);
+
// Returns |[NSImage imageNamed:@"NSApplicationIcon"]| as SkBitmap.
SkBitmap AppplicationIconAtSize(int size);
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index c78121a..5547c4a 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -8,9 +8,110 @@
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#include "skia/ext/bitmap_platform_device_mac.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+
+// 10.6 API that we use if available.
+#if !defined(MAC_OS_X_VERSION_10_6) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+
+@interface NSImageRep (NSObject)
+
+- (BOOL)drawInRect:(NSRect)dstSpacePortionRect
+ fromRect:(NSRect)srcSpacePortionRect
+ operation:(NSCompositingOperation)op
+ fraction:(CGFloat)requestedAlpha
+ respectFlipped:(BOOL)respectContextIsFlipped
+ hints:(NSDictionary*)hints;
+
+@end
+
+#endif // OSes < Mac OS X 10.6
+
+namespace {
+
+// Draws an NSImage or an NSImageRep with a given size into a SkBitmap.
+SkBitmap NSImageOrNSImageRepToSkBitmap(
+ NSImage* image,
+ NSImageRep* image_rep,
+ NSSize size,
+ bool is_opaque) {
+ // Only image or image_rep should be provided, not both.
+ DCHECK((image != 0) ^ (image_rep != 0));
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width, size.height);
+ if (!bitmap.allocPixels())
+ return bitmap; // Return |bitmap| which should respond true to isNull().
+
+ bitmap.setIsOpaque(is_opaque);
+
+ base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+ void* data = bitmap.getPixels();
+
+ // Allocate a bitmap context with 4 components per pixel (BGRA). Apple
+ // recommends these flags for improved CG performance.
+#define HAS_ARGB_SHIFTS(a, r, g, b) \
+ (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
+ && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
+#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
+ base::mac::ScopedCFTypeRef<CGContextRef> context(
+ CGBitmapContextCreate(data, size.width, size.height, 8, size.width*4,
+ color_space,
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host));
+#else
+#error We require that Skia's and CoreGraphics's recommended \
+ image memory layout match.
+#endif
+#undef HAS_ARGB_SHIFTS
+
+ // Something went really wrong. Best guess is that the bitmap data is invalid.
+ DCHECK(context);
+
+ // Save the current graphics context so that we can restore it later.
+ gfx::ScopedNSGraphicsContextSaveGState scoped_g_state;
+
+ // Dummy context that we will draw into.
+ NSGraphicsContext* context_cocoa =
+ [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO];
+ [NSGraphicsContext setCurrentContext:context_cocoa];
+
+ // This will stretch any images to |size| if it does not fit or is non-square.
+ NSRect drawRect = NSMakeRect(0, 0, size.width, size.height);
+
+ // NSImage does caching such that subsequent drawing is much faster (on my
+ // machine, about 4x faster). Unfortunately on 10.5 NSImageRep doesn't do
+ // caching. For this reason we draw using an NSImage if available. Once
+ // 10.5 is no longer supported we can drop this and always use NSImageRep.
+ if (image) {
+ [image drawInRect:drawRect
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0];
+ } else {
+ // Use NSCompositeCopy if available, it's slightly faster.
+ if ([image_rep respondsToSelector:@selector(
+ drawInRect:fromRect:operation:fraction:respectFlipped:hints:)]) {
+ [image_rep drawInRect:drawRect
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0
+ respectFlipped:NO
+ hints:NO];
+ } else {
+ [image_rep drawInRect:drawRect];
+ }
+ }
+
+ return bitmap;
+}
+
+} // namespace
namespace gfx {
@@ -68,7 +169,7 @@ CGRect SkRectToCGRect(const SkRect& rect) {
// Converts CGColorRef to the ARGB layout Skia expects.
SkColor CGColorRefToSkColor(CGColorRef color) {
DCHECK(CGColorGetNumberOfComponents(color) == 4);
- const CGFloat *components = CGColorGetComponents(color);
+ const CGFloat* components = CGColorGetComponents(color);
return SkColorSetARGB(SkScalarRound(255.0 * components[3]), // alpha
SkScalarRound(255.0 * components[0]), // red
SkScalarRound(255.0 * components[1]), // green
@@ -116,55 +217,11 @@ SkBitmap CGImageToSkBitmap(CGImageRef image) {
}
SkBitmap NSImageToSkBitmap(NSImage* image, NSSize size, bool is_opaque) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width, size.height);
- if (bitmap.allocPixels() != true)
- return bitmap; // Return |bitmap| which should respond true to isNull().
-
- bitmap.setIsOpaque(is_opaque);
-
- base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space(
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
- void* data = bitmap.getPixels();
-
- // Allocate a bitmap context with 4 components per pixel (BGRA). Apple
- // recommends these flags for improved CG performance.
-#define HAS_ARGB_SHIFTS(a, r, g, b) \
- (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
- && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
-#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
- base::mac::ScopedCFTypeRef<CGContextRef> context(
- CGBitmapContextCreate(data, size.width, size.height, 8, size.width*4,
- color_space,
- kCGImageAlphaPremultipliedFirst |
- kCGBitmapByteOrder32Host));
-#else
-#error We require that Skia's and CoreGraphics's recommended \
- image memory layout match.
-#endif
-#undef HAS_ARGB_SHIFTS
-
- // Something went really wrong. Best guess is that the bitmap data is invalid.
- DCHECK(context != NULL);
-
- // Save the current graphics context so that we can restore it later.
- [NSGraphicsContext saveGraphicsState];
-
- // Dummy context that we will draw into.
- NSGraphicsContext* context_cocoa =
- [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO];
- [NSGraphicsContext setCurrentContext:context_cocoa];
-
- // This will stretch any images to |size| if it does not fit or is non-square.
- [image drawInRect:NSMakeRect(0, 0, size.width, size.height)
- fromRect:NSZeroRect
- operation:NSCompositeCopy
- fraction:1.0];
-
- // Done drawing, restore context.
- [NSGraphicsContext restoreGraphicsState];
+ return NSImageOrNSImageRepToSkBitmap(image, nil, size, is_opaque);
+}
- return bitmap;
+SkBitmap NSImageRepToSkBitmap(NSImageRep* image, NSSize size, bool is_opaque) {
+ return NSImageOrNSImageRepToSkBitmap(nil, image, size, is_opaque);
}
NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& skiaBitmap,
@@ -173,17 +230,16 @@ NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& skiaBitmap,
return nil;
// First convert SkBitmap to CGImageRef.
- CGImageRef cgimage =
- SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace);
+ base::mac::ScopedCFTypeRef<CGImageRef> cgimage(
+ SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace));
// Now convert to NSImage.
- NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc]
- initWithCGImage:cgimage] autorelease];
- CFRelease(cgimage);
- NSImage* image = [[[NSImage alloc] init] autorelease];
+ scoped_nsobject<NSBitmapImageRep> bitmap(
+ [[NSBitmapImageRep alloc] initWithCGImage:cgimage]);
+ scoped_nsobject<NSImage> image([[NSImage alloc] init]);
[image addRepresentation:bitmap];
[image setSize:NSMakeSize(skiaBitmap.width(), skiaBitmap.height())];
- return image;
+ return [image.release() autorelease];
}
NSImage* SkBitmapToNSImage(const SkBitmap& skiaBitmap) {
@@ -192,6 +248,37 @@ NSImage* SkBitmapToNSImage(const SkBitmap& skiaBitmap) {
return SkBitmapToNSImageWithColorSpace(skiaBitmap, colorSpace.get());
}
+NSImage* SkBitmapsToNSImage(const std::vector<const SkBitmap*>& bitmaps) {
+ if (bitmaps.empty())
+ return nil;
+
+ base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+ scoped_nsobject<NSImage> image([[NSImage alloc] init]);
+ NSSize min_size = NSZeroSize;
+
+ for (std::vector<const SkBitmap*>::const_iterator it = bitmaps.begin();
+ it != bitmaps.end(); ++it) {
+ const SkBitmap& skiaBitmap = **it;
+ // First convert SkBitmap to CGImageRef.
+ base::mac::ScopedCFTypeRef<CGImageRef> cgimage(
+ SkCreateCGImageRefWithColorspace(skiaBitmap, color_space));
+
+ // Now convert to NSImage.
+ scoped_nsobject<NSBitmapImageRep> bitmap(
+ [[NSBitmapImageRep alloc] initWithCGImage:cgimage]);
+ [image addRepresentation:bitmap];
+
+ if (min_size.width == 0 || min_size.width > skiaBitmap.width()) {
+ min_size.width = skiaBitmap.width();
+ min_size.height = skiaBitmap.height();
+ }
+ }
+
+ [image setSize:min_size];
+ return [image.release() autorelease];
+}
+
SkBitmap AppplicationIconAtSize(int size) {
NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
return NSImageToSkBitmap(image, NSMakeSize(size, size), /* is_opaque=*/true);
diff --git a/skia/ext/skia_utils_mac_unittest.mm b/skia/ext/skia_utils_mac_unittest.mm
index 7401f11..48fa407 100644
--- a/skia/ext/skia_utils_mac_unittest.mm
+++ b/skia/ext/skia_utils_mac_unittest.mm
@@ -9,39 +9,60 @@ namespace {
class SkiaUtilsMacTest : public testing::Test {
public:
+ // Creates a red or blue bitmap.
+ SkBitmap CreateSkBitmap(int width, int height, bool isred, bool tfbit);
+
+ // Creates a red or blue image.
+ NSImage* CreateNSImage(int width, int height, bool isred);
+
+ // Checks that the given bitmap rep is actually red or blue.
+ void TestImageRep(NSBitmapImageRep* imageRep, bool isred);
+
+ // Checks that the given bitmap is actually red or blue.
+ void TestSkBitmap(const SkBitmap& bitmap, bool isred);
+
// If not red, is blue.
// If not tfbit (twenty-four-bit), is 444.
void ShapeHelper(int width, int height, bool isred, bool tfbit);
};
-void SkiaUtilsMacTest::ShapeHelper(int width, int height,
- bool isred, bool tfbit) {
- SkBitmap thing;
+SkBitmap SkiaUtilsMacTest::CreateSkBitmap(int width, int height,
+ bool isred, bool tfbit) {
+ SkBitmap bitmap;
if (tfbit)
- thing.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
else
- thing.setConfig(SkBitmap::kARGB_4444_Config, width, height);
- thing.allocPixels();
+ bitmap.setConfig(SkBitmap::kARGB_4444_Config, width, height);
+ bitmap.allocPixels();
if (isred)
- thing.eraseRGB(0xff, 0, 0);
+ bitmap.eraseRGB(0xff, 0, 0);
else
- thing.eraseRGB(0, 0, 0xff);
+ bitmap.eraseRGB(0, 0, 0xff);
- // Confirm size
- NSImage* image = gfx::SkBitmapToNSImage(thing);
- EXPECT_DOUBLE_EQ([image size].width, (double)width);
- EXPECT_DOUBLE_EQ([image size].height, (double)height);
+ return bitmap;
+}
- // Get the color of a pixel and make sure it looks fine
+NSImage* SkiaUtilsMacTest::CreateNSImage(int width, int height, bool isred) {
+ scoped_nsobject<NSImage> image(
+ [[NSImage alloc] initWithSize:NSMakeSize(width, height)]);
[image lockFocus];
+ if (isred)
+ [[NSColor colorWithDeviceRed:1.0 green:0.0 blue:0.0 alpha:1.0] set];
+ else
+ [[NSColor colorWithDeviceRed:0.0 green:0.0 blue:1.0 alpha:1.0] set];
+ NSRectFill(NSMakeRect(0, 0, width, height));
+ [image unlockFocus];
+ return [image.release() autorelease];
+}
- int x = width > 17 ? 17 : 0;
- int y = height > 17 ? 17 : 0;
- NSColor* color = NSReadPixel(NSMakePoint(x, y));
+void SkiaUtilsMacTest::TestImageRep(NSBitmapImageRep* imageRep, bool isred) {
+ // Get the color of a pixel and make sure it looks fine
+ int x = [imageRep size].width > 17 ? 17 : 0;
+ int y = [imageRep size].height > 17 ? 17 : 0;
+ NSColor* color = [imageRep colorAtX:x y:y];
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
- [image unlockFocus];
// SkBitmapToNSImage returns a bitmap in the calibrated color space (sRGB),
// while NSReadPixel returns a color in the device color space. Convert back
@@ -62,7 +83,40 @@ void SkiaUtilsMacTest::ShapeHelper(int width, int height,
EXPECT_GT(alpha, 0.95);
}
-TEST_F(SkiaUtilsMacTest, FAILS_BitmapToNSImage_RedSquare64x64) {
+void SkiaUtilsMacTest::TestSkBitmap(const SkBitmap& bitmap, bool isred) {
+ int x = bitmap.width() > 17 ? 17 : 0;
+ int y = bitmap.height() > 17 ? 17 : 0;
+ SkColor color = bitmap.getColor(x, y);
+
+ // Be tolerant of lossy color space conversions.
+ // TODO(sail): Fix color space conversion issues, http://crbug.com/79946
+ if (isred) {
+ EXPECT_GT(SkColorGetR(color), 245u);
+ EXPECT_LT(SkColorGetB(color), 10u);
+ } else {
+ EXPECT_LT(SkColorGetR(color), 10u);
+ EXPECT_GT(SkColorGetB(color), 245u);
+ }
+ EXPECT_LT(SkColorGetG(color), 10u);
+ EXPECT_GT(SkColorGetA(color), 245u);
+}
+
+void SkiaUtilsMacTest::ShapeHelper(int width, int height,
+ bool isred, bool tfbit) {
+ SkBitmap thing(CreateSkBitmap(width, height, isred, tfbit));
+
+ // Confirm size
+ NSImage* image = gfx::SkBitmapToNSImage(thing);
+ EXPECT_DOUBLE_EQ([image size].width, (double)width);
+ EXPECT_DOUBLE_EQ([image size].height, (double)height);
+
+ EXPECT_TRUE([[image representations] count] == 1);
+ EXPECT_TRUE([[[image representations] lastObject]
+ isKindOfClass:[NSBitmapImageRep class]]);
+ TestImageRep([[image representations] lastObject], isred);
+}
+
+TEST_F(SkiaUtilsMacTest, BitmapToNSImage_RedSquare64x64) {
ShapeHelper(64, 64, true, true);
}
@@ -70,8 +124,52 @@ TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle199x19) {
ShapeHelper(199, 19, false, true);
}
-TEST_F(SkiaUtilsMacTest, FAILS_BitmapToNSImage_BlueRectangle444) {
+TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle444) {
ShapeHelper(200, 200, false, false);
}
+TEST_F(SkiaUtilsMacTest, MultipleBitmapsToNSImage) {
+ int redWidth = 10;
+ int redHeight = 15;
+ int blueWidth = 20;
+ int blueHeight = 30;
+
+ SkBitmap redBitmap(CreateSkBitmap(redWidth, redHeight, true, true));
+ SkBitmap blueBitmap(CreateSkBitmap(blueWidth, blueHeight, false, true));
+ std::vector<const SkBitmap*> bitmaps;
+ bitmaps.push_back(&redBitmap);
+ bitmaps.push_back(&blueBitmap);
+
+ NSImage* image = gfx::SkBitmapsToNSImage(bitmaps);
+
+ // Image size should be the same as the smallest bitmap.
+ EXPECT_DOUBLE_EQ(redWidth, [image size].width);
+ EXPECT_DOUBLE_EQ(redHeight, [image size].height);
+
+ EXPECT_EQ(2u, [[image representations] count]);
+
+ for (NSBitmapImageRep* imageRep in [image representations]) {
+ bool isred = [imageRep size].width == redWidth;
+ if (isred) {
+ EXPECT_DOUBLE_EQ(redHeight, [imageRep size].height);
+ } else {
+ EXPECT_DOUBLE_EQ(blueWidth, [imageRep size].width);
+ EXPECT_DOUBLE_EQ(blueHeight, [imageRep size].height);
+ }
+ TestImageRep(imageRep, isred);
+ }
+}
+
+TEST_F(SkiaUtilsMacTest, NSImageRepToSkBitmap) {
+ int width = 10;
+ int height = 15;
+ bool isred = true;
+
+ NSImage* image = CreateNSImage(width, height, isred);
+ EXPECT_EQ(1u, [[image representations] count]);
+ NSBitmapImageRep* imageRep = [[image representations] lastObject];
+ SkBitmap bitmap(gfx::NSImageRepToSkBitmap(imageRep, [image size], false));
+ TestSkBitmap(bitmap, isred);
+}
+
} // namespace