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