1 #include "SkCGUtils.h"
2 #include "SkBitmap.h"
3 #include "SkColorPriv.h"
4
5 extern CGImageRef SkCreateCGImageRef(const SkBitmap&);
6
SkBitmap_ReleaseInfo(void * info,const void * pixelData,size_t size)7 static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
8 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
9 delete bitmap;
10 }
11
12 #define HAS_ARGB_SHIFTS(a, r, g, b) \
13 (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
14 && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
15
prepareForImageRef(const SkBitmap & bm,size_t * bitsPerComponent,CGBitmapInfo * info)16 static SkBitmap* prepareForImageRef(const SkBitmap& bm,
17 size_t* bitsPerComponent,
18 CGBitmapInfo* info) {
19 bool upscaleTo32 = false;
20
21 switch (bm.config()) {
22 case SkBitmap::kRGB_565_Config:
23 upscaleTo32 = true;
24 // fall through
25 case SkBitmap::kARGB_8888_Config:
26 *bitsPerComponent = 8;
27 #if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
28 || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
29 *info = kCGBitmapByteOrder32Big |
30 kCGImageAlphaPremultipliedLast;
31 #elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
32 || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
33 // Matches the CGBitmapInfo that Apple recommends for best
34 // performance, used by google chrome.
35 *info = kCGBitmapByteOrder32Host |
36 kCGImageAlphaPremultipliedFirst;
37 #else
38 // ...add more formats as required...
39 #warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
40 This will probably not work.
41 // Legacy behavior. Perhaps turn this into an error at some
42 // point.
43 *info = kCGBitmapByteOrder32Big |
44 kCGImageAlphaPremultipliedLast;
45 #endif
46 break;
47 #if 0
48 case SkBitmap::kRGB_565_Config:
49 // doesn't see quite right. Are they thinking 1555?
50 *bitsPerComponent = 5;
51 *info = kCGBitmapByteOrder16Little;
52 break;
53 #endif
54 case SkBitmap::kARGB_4444_Config:
55 *bitsPerComponent = 4;
56 *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast;
57 break;
58 default:
59 return NULL;
60 }
61
62 SkBitmap* copy;
63 if (upscaleTo32) {
64 copy = new SkBitmap;
65 // here we make a ceep copy of the pixels, since CG won't take our
66 // 565 directly
67 bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
68 } else {
69 copy = new SkBitmap(bm);
70 }
71 return copy;
72 }
73
74 #undef HAS_ARGB_SHIFTS
75
SkCreateCGImageRef(const SkBitmap & bm)76 CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
77 size_t bitsPerComponent;
78 CGBitmapInfo info;
79
80 SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
81 if (NULL == bitmap) {
82 return NULL;
83 }
84
85 const int w = bitmap->width();
86 const int h = bitmap->height();
87 const size_t s = bitmap->getSize();
88
89 // our provider "owns" the bitmap*, and will take care of deleting it
90 // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
91 // proc, which will in turn unlock the pixels
92 bitmap->lockPixels();
93 CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
94 SkBitmap_ReleaseInfo);
95
96 CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
97 CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
98 bitmap->bytesPerPixel() * 8,
99 bitmap->rowBytes(), space, info, dataRef,
100 NULL, false, kCGRenderingIntentDefault);
101 CGColorSpaceRelease(space);
102 CGDataProviderRelease(dataRef);
103 return ref;
104 }
105
106
107