Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / utils / mac / SkCreateCGImageRef.cpp
1
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkCGUtils.h"
9 #include "SkBitmap.h"
10 #include "SkColorPriv.h"
11
12 static CGBitmapInfo ComputeCGAlphaInfo_RGBA(SkAlphaType at) {
13     CGBitmapInfo info = kCGBitmapByteOrder32Big;
14     switch (at) {
15         case kOpaque_SkAlphaType:
16         case kIgnore_SkAlphaType:
17             info |= kCGImageAlphaNoneSkipLast;
18             break;
19         case kPremul_SkAlphaType:
20             info |= kCGImageAlphaPremultipliedLast;
21             break;
22         case kUnpremul_SkAlphaType:
23             info |= kCGImageAlphaLast;
24             break;
25     }
26     return info;
27 }
28
29 static CGBitmapInfo ComputeCGAlphaInfo_BGRA(SkAlphaType at) {
30     CGBitmapInfo info = kCGBitmapByteOrder32Little;
31     switch (at) {
32         case kOpaque_SkAlphaType:
33         case kIgnore_SkAlphaType:
34             info |= kCGImageAlphaNoneSkipFirst;
35             break;
36         case kPremul_SkAlphaType:
37             info |= kCGImageAlphaPremultipliedFirst;
38             break;
39         case kUnpremul_SkAlphaType:
40             info |= kCGImageAlphaFirst;
41             break;
42     }
43     return info;
44 }
45
46 static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
47     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
48     delete bitmap;
49 }
50
51 static bool getBitmapInfo(const SkBitmap& bm,
52                           size_t* bitsPerComponent,
53                           CGBitmapInfo* info,
54                           bool* upscaleTo32) {
55     if (upscaleTo32) {
56         *upscaleTo32 = false;
57     }
58
59     switch (bm.colorType()) {
60         case kRGB_565_SkColorType:
61 #if 0
62             // doesn't see quite right. Are they thinking 1555?
63             *bitsPerComponent = 5;
64             *info = kCGBitmapByteOrder16Little | kCGImageAlphaNone;
65 #else
66             if (upscaleTo32) {
67                 *upscaleTo32 = true;
68             }
69             // now treat like RGBA
70             *bitsPerComponent = 8;
71             *info = ComputeCGAlphaInfo_RGBA(kOpaque_SkAlphaType);
72 #endif
73             break;
74         case kRGBA_8888_SkColorType:
75             *bitsPerComponent = 8;
76             *info = ComputeCGAlphaInfo_RGBA(bm.alphaType());
77             break;
78         case kBGRA_8888_SkColorType:
79             *bitsPerComponent = 8;
80             *info = ComputeCGAlphaInfo_BGRA(bm.alphaType());
81             break;
82         case kARGB_4444_SkColorType:
83             *bitsPerComponent = 4;
84             *info = kCGBitmapByteOrder16Little;
85             if (bm.isOpaque()) {
86                 *info |= kCGImageAlphaNoneSkipLast;
87             } else {
88                 *info |= kCGImageAlphaPremultipliedLast;
89             }
90             break;
91         default:
92             return false;
93     }
94     return true;
95 }
96
97 static SkBitmap* prepareForImageRef(const SkBitmap& bm,
98                                     size_t* bitsPerComponent,
99                                     CGBitmapInfo* info) {
100     bool upscaleTo32;
101     if (!getBitmapInfo(bm, bitsPerComponent, info, &upscaleTo32)) {
102         return NULL;
103     }
104
105     SkBitmap* copy;
106     if (upscaleTo32) {
107         copy = new SkBitmap;
108         // here we make a ceep copy of the pixels, since CG won't take our
109         // 565 directly
110         bm.copyTo(copy, kN32_SkColorType);
111     } else {
112         copy = new SkBitmap(bm);
113     }
114     return copy;
115 }
116
117 CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
118                                             CGColorSpaceRef colorSpace) {
119     size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
120     CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;
121
122     SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
123     if (NULL == bitmap) {
124         return NULL;
125     }
126
127     const int w = bitmap->width();
128     const int h = bitmap->height();
129     const size_t s = bitmap->getSize();
130
131     // our provider "owns" the bitmap*, and will take care of deleting it
132     // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
133     // proc, which will in turn unlock the pixels
134     bitmap->lockPixels();
135     CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
136                                                              SkBitmap_ReleaseInfo);
137
138     bool releaseColorSpace = false;
139     if (NULL == colorSpace) {
140         colorSpace = CGColorSpaceCreateDeviceRGB();
141         releaseColorSpace = true;
142     }
143
144     CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
145                                    bitmap->bytesPerPixel() * 8,
146                                    bitmap->rowBytes(), colorSpace, info, dataRef,
147                                    NULL, false, kCGRenderingIntentDefault);
148
149     if (releaseColorSpace) {
150         CGColorSpaceRelease(colorSpace);
151     }
152     CGDataProviderRelease(dataRef);
153     return ref;
154 }
155
156 void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
157     CGImageRef img = SkCreateCGImageRef(bm);
158
159     if (img) {
160         CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
161
162         CGContextSaveGState(cg);
163         CGContextTranslateCTM(cg, x, r.size.height + y);
164         CGContextScaleCTM(cg, 1, -1);
165
166         CGContextDrawImage(cg, r, img);
167
168         CGContextRestoreGState(cg);
169
170         CGImageRelease(img);
171     }
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175
176 #include "SkStream.h"
177
178 class SkAutoPDFRelease {
179 public:
180     SkAutoPDFRelease(CGPDFDocumentRef doc) : fDoc(doc) {}
181     ~SkAutoPDFRelease() {
182         if (fDoc) {
183             CGPDFDocumentRelease(fDoc);
184         }
185     }
186 private:
187     CGPDFDocumentRef fDoc;
188 };
189 #define SkAutoPDFRelease(...) SK_REQUIRE_LOCAL_VAR(SkAutoPDFRelease)
190
191 bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output) {
192     CGDataProviderRef data = SkCreateDataProviderFromStream(stream);
193     if (NULL == data) {
194         return false;
195     }
196
197     CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(data);
198     CGDataProviderRelease(data);
199     if (NULL == pdf) {
200         return false;
201     }
202     SkAutoPDFRelease releaseMe(pdf);
203
204     CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
205     if (NULL == page) {
206         return false;
207     }
208
209     CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
210
211     int w = (int)CGRectGetWidth(bounds);
212     int h = (int)CGRectGetHeight(bounds);
213
214     SkBitmap bitmap;
215     if (!bitmap.tryAllocN32Pixels(w, h)) {
216         return false;
217     }
218     bitmap.eraseColor(SK_ColorWHITE);
219
220     size_t bitsPerComponent;
221     CGBitmapInfo info;
222     getBitmapInfo(bitmap, &bitsPerComponent, &info, NULL);
223
224     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
225     CGContextRef ctx = CGBitmapContextCreate(bitmap.getPixels(), w, h,
226                                              bitsPerComponent, bitmap.rowBytes(),
227                                              cs, info);
228     CGColorSpaceRelease(cs);
229
230     if (ctx) {
231         CGContextDrawPDFPage(ctx, page);
232         CGContextRelease(ctx);
233     }
234
235     output->swap(bitmap);
236     return true;
237 }
238
239 ///////////////////////////////////////////////////////////////////////////////////////////////////
240
241 SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
242                                     CGImageRef image) {
243     CGBitmapInfo cg_bitmap_info = 0;
244     size_t bitsPerComponent = 0;
245     switch (info.colorType()) {
246         case kRGBA_8888_SkColorType:
247             bitsPerComponent = 8;
248             cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType());
249             break;
250         case kBGRA_8888_SkColorType:
251             bitsPerComponent = 8;
252             cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType());
253             break;
254         default:
255             return false;   // no other colortypes are supported (for now)
256     }
257
258     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
259     CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent,
260                                             rowBytes, cs, cg_bitmap_info);
261     CFRelease(cs);
262     if (NULL == cg) {
263         return false;
264     }
265
266     // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
267     // any blending (which could introduce errors and be slower).
268     CGContextSetBlendMode(cg, kCGBlendModeCopy);
269
270     CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image);
271     CGContextRelease(cg);
272     return true;
273 }
274
275 bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleToFit) {
276     const int width = scaleToFit ? scaleToFit->width() : SkToInt(CGImageGetWidth(image));
277     const int height = scaleToFit ? scaleToFit->height() : SkToInt(CGImageGetHeight(image));
278     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
279
280     SkBitmap tmp;
281     if (!tmp.tryAllocPixels(info)) {
282         return false;
283     }
284
285     if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
286         return false;
287     }
288
289     CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
290     switch (cgInfo) {
291         case kCGImageAlphaNone:
292         case kCGImageAlphaNoneSkipLast:
293         case kCGImageAlphaNoneSkipFirst:
294             SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
295             tmp.setAlphaType(kOpaque_SkAlphaType);
296             break;
297         default:
298             // we don't know if we're opaque or not, so compute it.
299             if (SkBitmap::ComputeIsOpaque(tmp)) {
300                 tmp.setAlphaType(kOpaque_SkAlphaType);
301             }
302     }
303
304     *dst = tmp;
305     return true;
306 }