1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 9cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 12cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 13cb93a386Sopenharmony_ci#include "include/private/SkMacros.h" 14cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 15cb93a386Sopenharmony_ci#include "include/utils/mac/SkCGUtils.h" 16cb93a386Sopenharmony_ci#include "src/utils/mac/SkUniqueCFRef.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci#include <climits> 19cb93a386Sopenharmony_ci#include <memory> 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cistatic CGBitmapInfo compute_cgalpha_info_rgba(SkAlphaType at) { 22cb93a386Sopenharmony_ci CGBitmapInfo info = kCGBitmapByteOrder32Big; 23cb93a386Sopenharmony_ci switch (at) { 24cb93a386Sopenharmony_ci case kUnknown_SkAlphaType: break; 25cb93a386Sopenharmony_ci case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break; 26cb93a386Sopenharmony_ci case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedLast; break; 27cb93a386Sopenharmony_ci case kUnpremul_SkAlphaType: info |= kCGImageAlphaLast; break; 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci return info; 30cb93a386Sopenharmony_ci} 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cistatic CGBitmapInfo compute_cgalpha_info_bgra(SkAlphaType at) { 33cb93a386Sopenharmony_ci CGBitmapInfo info = kCGBitmapByteOrder32Little; 34cb93a386Sopenharmony_ci switch (at) { 35cb93a386Sopenharmony_ci case kUnknown_SkAlphaType: break; 36cb93a386Sopenharmony_ci case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipFirst; break; 37cb93a386Sopenharmony_ci case kPremul_SkAlphaType: info |= kCGImageAlphaPremultipliedFirst; break; 38cb93a386Sopenharmony_ci case kUnpremul_SkAlphaType: info |= kCGImageAlphaFirst; break; 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci return info; 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_cistatic CGBitmapInfo compute_cgalpha_info_4444(SkAlphaType at) { 43cb93a386Sopenharmony_ci CGBitmapInfo info = kCGBitmapByteOrder16Little; 44cb93a386Sopenharmony_ci switch (at) { 45cb93a386Sopenharmony_ci case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast; break; 46cb93a386Sopenharmony_ci default: info |= kCGImageAlphaPremultipliedLast; break; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci return info; 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_cistatic bool get_bitmap_info(SkColorType skColorType, 52cb93a386Sopenharmony_ci SkAlphaType skAlphaType, 53cb93a386Sopenharmony_ci size_t* bitsPerComponent, 54cb93a386Sopenharmony_ci CGBitmapInfo* info, 55cb93a386Sopenharmony_ci bool* upscaleTo32) { 56cb93a386Sopenharmony_ci if (upscaleTo32) { 57cb93a386Sopenharmony_ci *upscaleTo32 = false; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci switch (skColorType) { 60cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 61cb93a386Sopenharmony_ci if (upscaleTo32) { 62cb93a386Sopenharmony_ci *upscaleTo32 = true; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci // now treat like RGBA 65cb93a386Sopenharmony_ci *bitsPerComponent = 8; 66cb93a386Sopenharmony_ci *info = compute_cgalpha_info_rgba(kOpaque_SkAlphaType); 67cb93a386Sopenharmony_ci break; 68cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 69cb93a386Sopenharmony_ci *bitsPerComponent = 8; 70cb93a386Sopenharmony_ci *info = compute_cgalpha_info_rgba(skAlphaType); 71cb93a386Sopenharmony_ci break; 72cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 73cb93a386Sopenharmony_ci *bitsPerComponent = 8; 74cb93a386Sopenharmony_ci *info = compute_cgalpha_info_bgra(skAlphaType); 75cb93a386Sopenharmony_ci break; 76cb93a386Sopenharmony_ci case kARGB_4444_SkColorType: 77cb93a386Sopenharmony_ci *bitsPerComponent = 4; 78cb93a386Sopenharmony_ci *info = compute_cgalpha_info_4444(skAlphaType); 79cb93a386Sopenharmony_ci break; 80cb93a386Sopenharmony_ci default: 81cb93a386Sopenharmony_ci return false; 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci return true; 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_cistatic std::unique_ptr<SkBitmap> prepare_for_image_ref(const SkBitmap& bm, 87cb93a386Sopenharmony_ci size_t* bitsPerComponent, 88cb93a386Sopenharmony_ci CGBitmapInfo* info) { 89cb93a386Sopenharmony_ci bool upscaleTo32; 90cb93a386Sopenharmony_ci if (!get_bitmap_info(bm.colorType(), bm.alphaType(), bitsPerComponent, info, &upscaleTo32)) { 91cb93a386Sopenharmony_ci return nullptr; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci if (upscaleTo32) { 94cb93a386Sopenharmony_ci std::unique_ptr<SkBitmap> copy(new SkBitmap); 95cb93a386Sopenharmony_ci // here we make a deep copy of the pixels, since CG won't take our 96cb93a386Sopenharmony_ci // 565 directly, so we always go to RGBA 97cb93a386Sopenharmony_ci copy->allocPixels(bm.info().makeColorType(kRGBA_8888_SkColorType)); 98cb93a386Sopenharmony_ci bm.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0); 99cb93a386Sopenharmony_ci return copy; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci return std::make_unique<SkBitmap>(bm); 102cb93a386Sopenharmony_ci} 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ciCGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, 105cb93a386Sopenharmony_ci CGColorSpaceRef colorSpace) { 106cb93a386Sopenharmony_ci if (bm.drawsNothing()) { 107cb93a386Sopenharmony_ci return nullptr; 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING; 110cb93a386Sopenharmony_ci CGBitmapInfo info SK_INIT_TO_AVOID_WARNING; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci std::unique_ptr<SkBitmap> bitmap = prepare_for_image_ref(bm, &bitsPerComponent, &info); 113cb93a386Sopenharmony_ci if (nullptr == bitmap) { 114cb93a386Sopenharmony_ci return nullptr; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci SkPixmap pm = bitmap->pixmap(); // Copy bitmap info before releasing it. 118cb93a386Sopenharmony_ci const size_t s = bitmap->computeByteSize(); 119cb93a386Sopenharmony_ci void* pixels = bitmap->getPixels(); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // our provider "owns" the bitmap*, and will take care of deleting it 122cb93a386Sopenharmony_ci SkUniqueCFRef<CGDataProviderRef> dataRef(CGDataProviderCreateWithData( 123cb93a386Sopenharmony_ci bitmap.release(), pixels, s, 124cb93a386Sopenharmony_ci [](void* p, const void*, size_t) { delete reinterpret_cast<SkBitmap*>(p); })); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci SkUniqueCFRef<CGColorSpaceRef> rgb; 127cb93a386Sopenharmony_ci if (nullptr == colorSpace) { 128cb93a386Sopenharmony_ci rgb.reset(CGColorSpaceCreateDeviceRGB()); 129cb93a386Sopenharmony_ci colorSpace = rgb.get(); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci return CGImageCreate(pm.width(), pm.height(), bitsPerComponent, 132cb93a386Sopenharmony_ci pm.info().bytesPerPixel() * CHAR_BIT, pm.rowBytes(), colorSpace, 133cb93a386Sopenharmony_ci info, dataRef.get(), nullptr, false, kCGRenderingIntentDefault); 134cb93a386Sopenharmony_ci} 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_civoid SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) { 137cb93a386Sopenharmony_ci SkUniqueCFRef<CGImageRef> img(SkCreateCGImageRef(bm)); 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (img) { 140cb93a386Sopenharmony_ci CGRect r = CGRectMake(0, 0, bm.width(), bm.height()); 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci CGContextSaveGState(cg); 143cb93a386Sopenharmony_ci CGContextTranslateCTM(cg, x, r.size.height + y); 144cb93a386Sopenharmony_ci CGContextScaleCTM(cg, 1, -1); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci CGContextDrawImage(cg, r, img.get()); 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci CGContextRestoreGState(cg); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ciCGContextRef SkCreateCGContext(const SkPixmap& pmap) { 155cb93a386Sopenharmony_ci CGBitmapInfo cg_bitmap_info = 0; 156cb93a386Sopenharmony_ci size_t bitsPerComponent = 0; 157cb93a386Sopenharmony_ci switch (pmap.colorType()) { 158cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 159cb93a386Sopenharmony_ci bitsPerComponent = 8; 160cb93a386Sopenharmony_ci cg_bitmap_info = compute_cgalpha_info_rgba(pmap.alphaType()); 161cb93a386Sopenharmony_ci break; 162cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 163cb93a386Sopenharmony_ci bitsPerComponent = 8; 164cb93a386Sopenharmony_ci cg_bitmap_info = compute_cgalpha_info_bgra(pmap.alphaType()); 165cb93a386Sopenharmony_ci break; 166cb93a386Sopenharmony_ci default: 167cb93a386Sopenharmony_ci return nullptr; // no other colortypes are supported (for now) 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci size_t rb = pmap.addr() ? pmap.rowBytes() : 0; 171cb93a386Sopenharmony_ci SkUniqueCFRef<CGColorSpaceRef> cs(CGColorSpaceCreateDeviceRGB()); 172cb93a386Sopenharmony_ci CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(), 173cb93a386Sopenharmony_ci bitsPerComponent, rb, cs.get(), cg_bitmap_info); 174cb93a386Sopenharmony_ci return cg; 175cb93a386Sopenharmony_ci} 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_cibool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels, 178cb93a386Sopenharmony_ci CGImageRef image) { 179cb93a386Sopenharmony_ci CGBitmapInfo cg_bitmap_info = 0; 180cb93a386Sopenharmony_ci size_t bitsPerComponent = 0; 181cb93a386Sopenharmony_ci switch (info.colorType()) { 182cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 183cb93a386Sopenharmony_ci bitsPerComponent = 8; 184cb93a386Sopenharmony_ci cg_bitmap_info = compute_cgalpha_info_rgba(info.alphaType()); 185cb93a386Sopenharmony_ci break; 186cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 187cb93a386Sopenharmony_ci bitsPerComponent = 8; 188cb93a386Sopenharmony_ci cg_bitmap_info = compute_cgalpha_info_bgra(info.alphaType()); 189cb93a386Sopenharmony_ci break; 190cb93a386Sopenharmony_ci default: 191cb93a386Sopenharmony_ci return false; // no other colortypes are supported (for now) 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci SkUniqueCFRef<CGColorSpaceRef> cs(CGColorSpaceCreateDeviceRGB()); 195cb93a386Sopenharmony_ci SkUniqueCFRef<CGContextRef> cg(CGBitmapContextCreate( 196cb93a386Sopenharmony_ci pixels, info.width(), info.height(), bitsPerComponent, 197cb93a386Sopenharmony_ci rowBytes, cs.get(), cg_bitmap_info)); 198cb93a386Sopenharmony_ci if (!cg) { 199cb93a386Sopenharmony_ci return false; 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing 203cb93a386Sopenharmony_ci // any blending (which could introduce errors and be slower). 204cb93a386Sopenharmony_ci CGContextSetBlendMode(cg.get(), kCGBlendModeCopy); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci CGContextDrawImage(cg.get(), CGRectMake(0, 0, info.width(), info.height()), image); 207cb93a386Sopenharmony_ci return true; 208cb93a386Sopenharmony_ci} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_cibool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) { 211cb93a386Sopenharmony_ci const int width = SkToInt(CGImageGetWidth(image)); 212cb93a386Sopenharmony_ci const int height = SkToInt(CGImageGetHeight(image)); 213cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci SkBitmap tmp; 216cb93a386Sopenharmony_ci if (!tmp.tryAllocPixels(info)) { 217cb93a386Sopenharmony_ci return false; 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) { 221cb93a386Sopenharmony_ci return false; 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci 224cb93a386Sopenharmony_ci CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image); 225cb93a386Sopenharmony_ci switch (cgInfo) { 226cb93a386Sopenharmony_ci case kCGImageAlphaNone: 227cb93a386Sopenharmony_ci case kCGImageAlphaNoneSkipLast: 228cb93a386Sopenharmony_ci case kCGImageAlphaNoneSkipFirst: 229cb93a386Sopenharmony_ci SkASSERT(SkBitmap::ComputeIsOpaque(tmp)); 230cb93a386Sopenharmony_ci tmp.setAlphaType(kOpaque_SkAlphaType); 231cb93a386Sopenharmony_ci break; 232cb93a386Sopenharmony_ci default: 233cb93a386Sopenharmony_ci // we don't know if we're opaque or not, so compute it. 234cb93a386Sopenharmony_ci if (SkBitmap::ComputeIsOpaque(tmp)) { 235cb93a386Sopenharmony_ci tmp.setAlphaType(kOpaque_SkAlphaType); 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci *dst = tmp; 240cb93a386Sopenharmony_ci return true; 241cb93a386Sopenharmony_ci} 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_cisk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) { 244cb93a386Sopenharmony_ci SkBitmap bm; 245cb93a386Sopenharmony_ci if (!SkCreateBitmapFromCGImage(&bm, src)) { 246cb93a386Sopenharmony_ci return nullptr; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci bm.setImmutable(); 250cb93a386Sopenharmony_ci return bm.asImage(); 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 254