Home | History | Annotate | Download | only in mac
      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