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