SkCreateCGImageRef.cpp revision a9caa4f932a7646571a52937b03c244f5bca9bdf
1#include "SkCGUtils.h"
2#include "SkBitmap.h"
3#include "SkColorPriv.h"
4
5extern CGImageRef SkCreateCGImageRef(const SkBitmap&);
6
7static 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
16static 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
76CGImageRef 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