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