Unfork GraphicsContext::drawNativeImage for iOS
[WebKit-https.git] / Source / WebCore / platform / graphics / cg / GraphicsContext3DCG.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28
29 #if USE(3D_GRAPHICS)
30
31 #include "GraphicsContext3D.h"
32
33 #include "BitmapImage.h"
34 #include "GraphicsContextCG.h"
35 #include "Image.h"
36
37 #if HAVE(ARM_NEON_INTRINSICS)
38 #include "GraphicsContext3DNEON.h"
39 #endif
40
41 #include <CoreGraphics/CGBitmapContext.h>
42 #include <CoreGraphics/CGContext.h>
43 #include <CoreGraphics/CGDataProvider.h>
44 #include <CoreGraphics/CGImage.h>
45
46 #include <wtf/RetainPtr.h>
47 #include <wtf/StdLibExtras.h>
48
49 namespace WebCore {
50
51 enum SourceDataFormatBase {
52     SourceFormatBaseR = 0,
53     SourceFormatBaseA,
54     SourceFormatBaseRA,
55     SourceFormatBaseAR,
56     SourceFormatBaseRGB,
57     SourceFormatBaseRGBA,
58     SourceFormatBaseARGB,
59     SourceFormatBaseNumFormats
60 };
61
62 enum AlphaFormat {
63     AlphaFormatNone = 0,
64     AlphaFormatFirst,
65     AlphaFormatLast,
66     AlphaFormatNumFormats
67 };
68
69 // This returns SourceFormatNumFormats if the combination of input parameters is unsupported.
70 static GraphicsContext3D::DataFormat getSourceDataFormat(unsigned componentsPerPixel, AlphaFormat alphaFormat, bool is16BitFormat, bool bigEndian)
71 {
72     const static SourceDataFormatBase formatTableBase[4][AlphaFormatNumFormats] = { // componentsPerPixel x AlphaFormat
73         // AlphaFormatNone            AlphaFormatFirst            AlphaFormatLast
74         { SourceFormatBaseR,          SourceFormatBaseA,          SourceFormatBaseA          }, // 1 componentsPerPixel
75         { SourceFormatBaseNumFormats, SourceFormatBaseAR,         SourceFormatBaseRA         }, // 2 componentsPerPixel
76         { SourceFormatBaseRGB,        SourceFormatBaseNumFormats, SourceFormatBaseNumFormats }, // 3 componentsPerPixel
77         { SourceFormatBaseNumFormats, SourceFormatBaseARGB,       SourceFormatBaseRGBA        } // 4 componentsPerPixel
78     };
79     const static GraphicsContext3D::DataFormat formatTable[SourceFormatBaseNumFormats][4] = { // SourceDataFormatBase x bitsPerComponent x endian
80         // 8bits, little endian                 8bits, big endian                     16bits, little endian                        16bits, big endian
81         { GraphicsContext3D::DataFormatR8,    GraphicsContext3D::DataFormatR8,    GraphicsContext3D::DataFormatR16Little,    GraphicsContext3D::DataFormatR16Big },
82         { GraphicsContext3D::DataFormatA8,    GraphicsContext3D::DataFormatA8,    GraphicsContext3D::DataFormatA16Little,    GraphicsContext3D::DataFormatA16Big },
83         { GraphicsContext3D::DataFormatAR8,   GraphicsContext3D::DataFormatRA8,   GraphicsContext3D::DataFormatRA16Little,   GraphicsContext3D::DataFormatRA16Big },
84         { GraphicsContext3D::DataFormatRA8,   GraphicsContext3D::DataFormatAR8,   GraphicsContext3D::DataFormatAR16Little,   GraphicsContext3D::DataFormatAR16Big },
85         { GraphicsContext3D::DataFormatBGR8,  GraphicsContext3D::DataFormatRGB8,  GraphicsContext3D::DataFormatRGB16Little,  GraphicsContext3D::DataFormatRGB16Big },
86         { GraphicsContext3D::DataFormatABGR8, GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::DataFormatRGBA16Little, GraphicsContext3D::DataFormatRGBA16Big },
87         { GraphicsContext3D::DataFormatBGRA8, GraphicsContext3D::DataFormatARGB8, GraphicsContext3D::DataFormatARGB16Little, GraphicsContext3D::DataFormatARGB16Big }
88     };
89
90     ASSERT(componentsPerPixel <= 4 && componentsPerPixel > 0);
91     SourceDataFormatBase formatBase = formatTableBase[componentsPerPixel - 1][alphaFormat];
92     if (formatBase == SourceFormatBaseNumFormats)
93         return GraphicsContext3D::DataFormatNumFormats;
94     return formatTable[formatBase][(is16BitFormat ? 2 : 0) + (bigEndian ? 1 : 0)];
95 }
96
97 namespace {
98 uint8_t convertColor16LittleTo8(uint16_t value)
99 {
100     return value >> 8;
101 }
102
103 uint8_t convertColor16BigTo8(uint16_t value)
104 {
105     return static_cast<uint8_t>(value & 0x00FF);
106 }
107
108 template<int format, typename SourceType, typename DstType>
109 ALWAYS_INLINE void convert16BitFormatToRGBA8(const SourceType*, DstType*, unsigned)
110 {
111     ASSERT_NOT_REACHED();
112 }
113
114 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRGBA16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
115 {
116 #if HAVE(ARM_NEON_INTRINSICS)
117     SIMD::unpackOneRowOfRGBA16LittleToRGBA8(source, destination, pixelsPerRow);
118 #endif
119     for (unsigned i = 0; i < pixelsPerRow; ++i) {
120         destination[0] = convertColor16LittleTo8(source[0]);
121         destination[1] = convertColor16LittleTo8(source[1]);
122         destination[2] = convertColor16LittleTo8(source[2]);
123         destination[3] = convertColor16LittleTo8(source[3]);
124         source += 4;
125         destination += 4;
126     }
127 }
128
129 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRGBA16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
130 {
131     for (unsigned i = 0; i < pixelsPerRow; ++i) {
132         destination[0] = convertColor16BigTo8(source[0]);
133         destination[1] = convertColor16BigTo8(source[1]);
134         destination[2] = convertColor16BigTo8(source[2]);
135         destination[3] = convertColor16BigTo8(source[3]);
136         source += 4;
137         destination += 4;
138     }
139 }
140
141 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRGB16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
142 {
143 #if HAVE(ARM_NEON_INTRINSICS)
144     SIMD::unpackOneRowOfRGB16LittleToRGBA8(source, destination, pixelsPerRow);
145 #endif
146     for (unsigned i = 0; i < pixelsPerRow; ++i) {
147         destination[0] = convertColor16LittleTo8(source[0]);
148         destination[1] = convertColor16LittleTo8(source[1]);
149         destination[2] = convertColor16LittleTo8(source[2]);
150         destination[3] = 0xFF;
151         source += 3;
152         destination += 4;
153     }
154 }
155
156 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRGB16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
157 {
158     for (unsigned i = 0; i < pixelsPerRow; ++i) {
159         destination[0] = convertColor16BigTo8(source[0]);
160         destination[1] = convertColor16BigTo8(source[1]);
161         destination[2] = convertColor16BigTo8(source[2]);
162         destination[3] = 0xFF;
163         source += 3;
164         destination += 4;
165     }
166 }
167
168 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatARGB16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
169 {
170 #if HAVE(ARM_NEON_INTRINSICS)
171     SIMD::unpackOneRowOfARGB16LittleToRGBA8(source, destination, pixelsPerRow);
172 #endif
173     for (unsigned i = 0; i < pixelsPerRow; ++i) {
174         destination[0] = convertColor16LittleTo8(source[1]);
175         destination[1] = convertColor16LittleTo8(source[2]);
176         destination[2] = convertColor16LittleTo8(source[3]);
177         destination[3] = convertColor16LittleTo8(source[0]);
178         source += 4;
179         destination += 4;
180     }
181 }
182
183 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatARGB16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
184 {
185     for (unsigned i = 0; i < pixelsPerRow; ++i) {
186         destination[0] = convertColor16BigTo8(source[1]);
187         destination[1] = convertColor16BigTo8(source[2]);
188         destination[2] = convertColor16BigTo8(source[3]);
189         destination[3] = convertColor16BigTo8(source[0]);
190         source += 4;
191         destination += 4;
192     }
193 }
194
195 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatR16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
196 {
197     for (unsigned i = 0; i < pixelsPerRow; ++i) {
198         destination[0] = convertColor16LittleTo8(source[0]);
199         destination[1] = convertColor16LittleTo8(source[0]);
200         destination[2] = convertColor16LittleTo8(source[0]);
201         destination[3] = 0xFF;
202         source += 1;
203         destination += 4;
204     }
205 }
206
207 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatR16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
208 {
209     for (unsigned i = 0; i < pixelsPerRow; ++i) {
210         destination[0] = convertColor16BigTo8(source[0]);
211         destination[1] = convertColor16BigTo8(source[0]);
212         destination[2] = convertColor16BigTo8(source[0]);
213         destination[3] = 0xFF;
214         source += 1;
215         destination += 4;
216     }
217 }
218
219 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRA16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
220 {
221     for (unsigned i = 0; i < pixelsPerRow; ++i) {
222         destination[0] = convertColor16LittleTo8(source[0]);
223         destination[1] = convertColor16LittleTo8(source[0]);
224         destination[2] = convertColor16LittleTo8(source[0]);
225         destination[3] = convertColor16LittleTo8(source[1]);
226         source += 2;
227         destination += 4;
228     }
229 }
230
231 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatRA16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
232 {
233     for (unsigned i = 0; i < pixelsPerRow; ++i) {
234         destination[0] = convertColor16BigTo8(source[0]);
235         destination[1] = convertColor16BigTo8(source[0]);
236         destination[2] = convertColor16BigTo8(source[0]);
237         destination[3] = convertColor16BigTo8(source[1]);
238         source += 2;
239         destination += 4;
240     }
241 }
242
243 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatAR16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
244 {
245     for (unsigned i = 0; i < pixelsPerRow; ++i) {
246         destination[0] = convertColor16LittleTo8(source[1]);
247         destination[1] = convertColor16LittleTo8(source[1]);
248         destination[2] = convertColor16LittleTo8(source[1]);
249         destination[3] = convertColor16LittleTo8(source[0]);
250         source += 2;
251         destination += 4;
252     }
253 }
254
255 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatAR16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
256 {
257     for (unsigned i = 0; i < pixelsPerRow; ++i) {
258         destination[0] = convertColor16BigTo8(source[1]);
259         destination[1] = convertColor16BigTo8(source[1]);
260         destination[2] = convertColor16BigTo8(source[1]);
261         destination[3] = convertColor16BigTo8(source[0]);
262         source += 2;
263         destination += 4;
264     }
265 }
266
267 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatA16Little, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
268 {
269     for (unsigned i = 0; i < pixelsPerRow; ++i) {
270         destination[0] = 0x0;
271         destination[1] = 0x0;
272         destination[2] = 0x0;
273         destination[3] = convertColor16LittleTo8(source[0]);
274         source += 1;
275         destination += 4;
276     }
277 }
278
279 template<> ALWAYS_INLINE void convert16BitFormatToRGBA8<GraphicsContext3D::DataFormatA16Big, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
280 {
281     for (unsigned i = 0; i < pixelsPerRow; ++i) {
282         destination[0] = 0x0;
283         destination[1] = 0x0;
284         destination[2] = 0x0;
285         destination[3] = convertColor16BigTo8(source[0]);
286         source += 1;
287         destination += 4;
288     }
289 }
290
291 void convert16BitFormatToRGBA8(GraphicsContext3D::DataFormat srcFormat, const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
292 {
293 #define CONVERT16BITFORMATTORGBA8(SrcFormat) \
294     case SrcFormat: \
295         return convert16BitFormatToRGBA8<SrcFormat>(source, destination, pixelsPerRow);
296
297     switch (srcFormat) {
298         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatR16Little)
299         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatR16Big)
300         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatA16Little)
301         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatA16Big)
302         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRA16Little)
303         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRA16Big)
304         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatAR16Little)
305         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatAR16Big)
306         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRGB16Little)
307         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRGB16Big)
308         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRGBA16Little)
309         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatRGBA16Big)
310         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatARGB16Little)
311         CONVERT16BITFORMATTORGBA8(GraphicsContext3D::DataFormatARGB16Big)
312     default:
313         ASSERT_NOT_REACHED();
314     }
315 #undef CONVERT16BITFORMATTORGBA8
316 }
317
318 }
319
320 GraphicsContext3D::ImageExtractor::~ImageExtractor()
321 {
322 }
323
324 bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile)
325 {
326     if (!m_image)
327         return false;
328     bool hasAlpha = !m_image->currentFrameKnownToBeOpaque();
329     if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && m_image->data()) {
330         ImageSource decoder(ImageSource::AlphaNotPremultiplied,
331                             ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
332         decoder.setData(m_image->data(), true);
333         if (!decoder.frameCount())
334             return false;
335         m_decodedImage = adoptCF(decoder.createFrameAtIndex(0));
336         m_cgImage = m_decodedImage.get();
337     } else
338         m_cgImage = m_image->nativeImageForCurrentFrame();
339     if (!m_cgImage)
340         return false;
341
342     m_imageWidth = CGImageGetWidth(m_cgImage);
343     m_imageHeight = CGImageGetHeight(m_cgImage);
344     if (!m_imageWidth || !m_imageHeight)
345         return false;
346
347     // See whether the image is using an indexed color space, and if
348     // so, re-render it into an RGB color space. The image re-packing
349     // code requires color data, not color table indices, for the
350     // image data.
351     CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_cgImage);
352     CGColorSpaceModel model = CGColorSpaceGetModel(colorSpace);
353     if (model == kCGColorSpaceModelIndexed) {
354         RetainPtr<CGContextRef> bitmapContext;
355         // FIXME: we should probably manually convert the image by indexing into
356         // the color table, which would allow us to avoid premultiplying the
357         // alpha channel. Creation of a bitmap context with an alpha channel
358         // doesn't seem to work unless it's premultiplied.
359         bitmapContext = adoptCF(CGBitmapContextCreate(0, m_imageWidth, m_imageHeight, 8, m_imageWidth * 4,
360             deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
361         if (!bitmapContext)
362             return false;
363
364         CGContextSetBlendMode(bitmapContext.get(), kCGBlendModeCopy);
365         CGContextSetInterpolationQuality(bitmapContext.get(), kCGInterpolationNone);
366         CGContextDrawImage(bitmapContext.get(), CGRectMake(0, 0, m_imageWidth, m_imageHeight), m_cgImage);
367
368         // Now discard the original CG image and replace it with a copy from the bitmap context.
369         m_decodedImage = adoptCF(CGBitmapContextCreateImage(bitmapContext.get()));
370         m_cgImage = m_decodedImage.get();
371     }
372
373     size_t bitsPerComponent = CGImageGetBitsPerComponent(m_cgImage);
374     size_t bitsPerPixel = CGImageGetBitsPerPixel(m_cgImage);
375     if (bitsPerComponent != 8 && bitsPerComponent != 16)
376         return false;
377     if (bitsPerPixel % bitsPerComponent)
378         return false;
379     size_t componentsPerPixel = bitsPerPixel / bitsPerComponent;
380
381     CGBitmapInfo bitInfo = CGImageGetBitmapInfo(m_cgImage);
382     bool bigEndianSource = false;
383     // These could technically be combined into one large switch
384     // statement, but we prefer not to so that we fail fast if we
385     // encounter an unexpected image configuration.
386     if (bitsPerComponent == 16) {
387         switch (bitInfo & kCGBitmapByteOrderMask) {
388         case kCGBitmapByteOrder16Big:
389             bigEndianSource = true;
390             break;
391         case kCGBitmapByteOrder16Little:
392             bigEndianSource = false;
393             break;
394         case kCGBitmapByteOrderDefault:
395             // This is a bug in earlier version of cg where the default endian
396             // is little whereas the decoded 16-bit png image data is actually
397             // Big. Later version (10.6.4) no longer returns ByteOrderDefault.
398             bigEndianSource = true;
399             break;
400         default:
401             return false;
402         }
403     } else {
404         switch (bitInfo & kCGBitmapByteOrderMask) {
405         case kCGBitmapByteOrder32Big:
406             bigEndianSource = true;
407             break;
408         case kCGBitmapByteOrder32Little:
409             bigEndianSource = false;
410             break;
411         case kCGBitmapByteOrderDefault:
412             // It appears that the default byte order is actually big
413             // endian even on little endian architectures.
414             bigEndianSource = true;
415             break;
416         default:
417             return false;
418         }
419     }
420
421     m_alphaOp = AlphaDoNothing;
422     AlphaFormat alphaFormat = AlphaFormatNone;
423     switch (CGImageGetAlphaInfo(m_cgImage)) {
424     case kCGImageAlphaPremultipliedFirst:
425         if (!premultiplyAlpha)
426             m_alphaOp = AlphaDoUnmultiply;
427         alphaFormat = AlphaFormatFirst;
428         break;
429     case kCGImageAlphaFirst:
430         // This path is only accessible for MacOS earlier than 10.6.4.
431         if (premultiplyAlpha)
432             m_alphaOp = AlphaDoPremultiply;
433         alphaFormat = AlphaFormatFirst;
434         break;
435     case kCGImageAlphaNoneSkipFirst:
436         // This path is only accessible for MacOS earlier than 10.6.4.
437         alphaFormat = AlphaFormatFirst;
438         break;
439     case kCGImageAlphaPremultipliedLast:
440         if (!premultiplyAlpha)
441             m_alphaOp = AlphaDoUnmultiply;
442         alphaFormat = AlphaFormatLast;
443         break;
444     case kCGImageAlphaLast:
445         if (premultiplyAlpha)
446             m_alphaOp = AlphaDoPremultiply;
447         alphaFormat = AlphaFormatLast;
448         break;
449     case kCGImageAlphaNoneSkipLast:
450         alphaFormat = AlphaFormatLast;
451         break;
452     case kCGImageAlphaNone:
453         alphaFormat = AlphaFormatNone;
454         break;
455     default:
456         return false;
457     }
458
459     m_imageSourceFormat = getSourceDataFormat(componentsPerPixel, alphaFormat, bitsPerComponent == 16, bigEndianSource);
460     if (m_imageSourceFormat == DataFormatNumFormats)
461         return false;
462
463     m_pixelData = adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(m_cgImage)));
464     if (!m_pixelData)
465         return false;
466
467     m_imagePixelData = reinterpret_cast<const void*>(CFDataGetBytePtr(m_pixelData.get()));
468
469     unsigned int srcUnpackAlignment = 0;
470     size_t bytesPerRow = CGImageGetBytesPerRow(m_cgImage);
471     unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth;
472     if (padding) {
473         srcUnpackAlignment = padding + 1;
474         while (bytesPerRow % srcUnpackAlignment)
475             ++srcUnpackAlignment;
476     }
477
478     m_imageSourceUnpackAlignment = srcUnpackAlignment;
479     // Using a bitmap context created according to destination format and drawing the CGImage to the bitmap context can also do the format conversion,
480     // but it would premultiply the alpha channel as a side effect.
481     // Prefer to mannually Convert 16bit per-component formats to RGBA8 formats instead.
482     if (bitsPerComponent == 16) {
483         m_formalizedRGBA8Data = std::make_unique<uint8_t[]>(m_imageWidth * m_imageHeight * 4);
484         const uint16_t* source = reinterpret_cast<const uint16_t*>(m_imagePixelData);
485         uint8_t* destination = m_formalizedRGBA8Data.get();
486         const ptrdiff_t srcStrideInElements = bytesPerRow / sizeof(uint16_t);
487         const ptrdiff_t dstStrideInElements = 4 * m_imageWidth;
488         for (unsigned i =0; i < m_imageHeight; i++) {
489             convert16BitFormatToRGBA8(m_imageSourceFormat, source, destination, m_imageWidth);
490             source += srcStrideInElements;
491             destination += dstStrideInElements;
492         }
493         m_imagePixelData = reinterpret_cast<const void*>(m_formalizedRGBA8Data.get());
494         m_imageSourceFormat = DataFormatRGBA8;
495         m_imageSourceUnpackAlignment = 1;
496     }
497     return true;
498 }
499
500 static void releaseImageData(void*, const void* data, size_t)
501 {
502     fastFree(const_cast<void*>(data));
503 }
504
505 void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, GraphicsContext* context)
506 {
507     if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context)
508         return;
509     int rowBytes = imageWidth * 4;
510     RetainPtr<CGDataProviderRef> dataProvider;
511
512     if (context->isAcceleratedContext()) {
513         unsigned char* copiedPixels;
514
515         if (!tryFastCalloc(imageHeight, rowBytes).getValue(copiedPixels))
516             return;
517
518         memcpy(copiedPixels, imagePixels, rowBytes * imageHeight);
519         dataProvider = adoptCF(CGDataProviderCreateWithData(0, copiedPixels, rowBytes * imageHeight, releaseImageData));
520     } else
521         dataProvider = adoptCF(CGDataProviderCreateWithData(0, imagePixels, rowBytes * imageHeight, 0));
522
523     RetainPtr<CGImageRef> cgImage = adoptCF(CGImageCreate(imageWidth, imageHeight, 8, 32, rowBytes, deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
524         dataProvider.get(), 0, false, kCGRenderingIntentDefault));
525
526     // CSS styling may cause the canvas's content to be resized on
527     // the page. Go back to the Canvas to figure out the correct
528     // width and height to draw.
529     FloatRect canvasRect(0, 0, canvasWidth, canvasHeight);
530     FloatSize imageSize(imageWidth, imageHeight);
531     // We want to completely overwrite the previous frame's
532     // rendering results.
533
534     GraphicsContextStateSaver stateSaver(*context);
535     context->scale(FloatSize(1, -1));
536     context->translate(0, -imageHeight);
537     context->setImageInterpolationQuality(InterpolationNone);
538     context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), 1, CompositeCopy);
539 }
540
541 } // namespace WebCore
542
543 #endif // USE(3D_GRAPHICS)