[iOS] Fix issues drawing subsampled image elements and CSS images
[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 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 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 #if PLATFORM(IOS)
336         float scaleHint = 1;
337         if (m_image->isBitmapImage()) {
338             FloatSize originalSize = toBitmapImage(m_image)->originalSize();
339             if (!originalSize.isEmpty())
340                 scaleHint = std::min<float>(1, std::max(m_image->size().width() / originalSize.width(), m_image->size().width() / originalSize.height()));
341         }
342         m_decodedImage = adoptCF(decoder.createFrameAtIndex(0, &scaleHint));
343 #else
344         m_decodedImage = adoptCF(decoder.createFrameAtIndex(0));
345 #endif
346         m_cgImage = m_decodedImage.get();
347     } else
348         m_cgImage = m_image->nativeImageForCurrentFrame();
349     if (!m_cgImage)
350         return false;
351
352     m_imageWidth = CGImageGetWidth(m_cgImage);
353     m_imageHeight = CGImageGetHeight(m_cgImage);
354     if (!m_imageWidth || !m_imageHeight)
355         return false;
356
357     // See whether the image is using an indexed color space, and if
358     // so, re-render it into an RGB color space. The image re-packing
359     // code requires color data, not color table indices, for the
360     // image data.
361     CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_cgImage);
362     CGColorSpaceModel model = CGColorSpaceGetModel(colorSpace);
363     if (model == kCGColorSpaceModelIndexed) {
364         RetainPtr<CGContextRef> bitmapContext;
365         // FIXME: we should probably manually convert the image by indexing into
366         // the color table, which would allow us to avoid premultiplying the
367         // alpha channel. Creation of a bitmap context with an alpha channel
368         // doesn't seem to work unless it's premultiplied.
369         bitmapContext = adoptCF(CGBitmapContextCreate(0, m_imageWidth, m_imageHeight, 8, m_imageWidth * 4,
370             deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
371         if (!bitmapContext)
372             return false;
373
374         CGContextSetBlendMode(bitmapContext.get(), kCGBlendModeCopy);
375         CGContextSetInterpolationQuality(bitmapContext.get(), kCGInterpolationNone);
376         CGContextDrawImage(bitmapContext.get(), CGRectMake(0, 0, m_imageWidth, m_imageHeight), m_cgImage);
377
378         // Now discard the original CG image and replace it with a copy from the bitmap context.
379         m_decodedImage = adoptCF(CGBitmapContextCreateImage(bitmapContext.get()));
380         m_cgImage = m_decodedImage.get();
381     }
382
383     size_t bitsPerComponent = CGImageGetBitsPerComponent(m_cgImage);
384     size_t bitsPerPixel = CGImageGetBitsPerPixel(m_cgImage);
385     if (bitsPerComponent != 8 && bitsPerComponent != 16)
386         return false;
387     if (bitsPerPixel % bitsPerComponent)
388         return false;
389     size_t componentsPerPixel = bitsPerPixel / bitsPerComponent;
390
391     CGBitmapInfo bitInfo = CGImageGetBitmapInfo(m_cgImage);
392     bool bigEndianSource = false;
393     // These could technically be combined into one large switch
394     // statement, but we prefer not to so that we fail fast if we
395     // encounter an unexpected image configuration.
396     if (bitsPerComponent == 16) {
397         switch (bitInfo & kCGBitmapByteOrderMask) {
398         case kCGBitmapByteOrder16Big:
399             bigEndianSource = true;
400             break;
401         case kCGBitmapByteOrder16Little:
402             bigEndianSource = false;
403             break;
404         case kCGBitmapByteOrderDefault:
405             // This is a bug in earlier version of cg where the default endian
406             // is little whereas the decoded 16-bit png image data is actually
407             // Big. Later version (10.6.4) no longer returns ByteOrderDefault.
408             bigEndianSource = true;
409             break;
410         default:
411             return false;
412         }
413     } else {
414         switch (bitInfo & kCGBitmapByteOrderMask) {
415         case kCGBitmapByteOrder32Big:
416             bigEndianSource = true;
417             break;
418         case kCGBitmapByteOrder32Little:
419             bigEndianSource = false;
420             break;
421         case kCGBitmapByteOrderDefault:
422             // It appears that the default byte order is actually big
423             // endian even on little endian architectures.
424             bigEndianSource = true;
425             break;
426         default:
427             return false;
428         }
429     }
430
431     m_alphaOp = AlphaDoNothing;
432     AlphaFormat alphaFormat = AlphaFormatNone;
433     switch (CGImageGetAlphaInfo(m_cgImage)) {
434     case kCGImageAlphaPremultipliedFirst:
435         if (!premultiplyAlpha)
436             m_alphaOp = AlphaDoUnmultiply;
437         alphaFormat = AlphaFormatFirst;
438         break;
439     case kCGImageAlphaFirst:
440         // This path is only accessible for MacOS earlier than 10.6.4.
441         if (premultiplyAlpha)
442             m_alphaOp = AlphaDoPremultiply;
443         alphaFormat = AlphaFormatFirst;
444         break;
445     case kCGImageAlphaNoneSkipFirst:
446         // This path is only accessible for MacOS earlier than 10.6.4.
447         alphaFormat = AlphaFormatFirst;
448         break;
449     case kCGImageAlphaPremultipliedLast:
450         if (!premultiplyAlpha)
451             m_alphaOp = AlphaDoUnmultiply;
452         alphaFormat = AlphaFormatLast;
453         break;
454     case kCGImageAlphaLast:
455         if (premultiplyAlpha)
456             m_alphaOp = AlphaDoPremultiply;
457         alphaFormat = AlphaFormatLast;
458         break;
459     case kCGImageAlphaNoneSkipLast:
460         alphaFormat = AlphaFormatLast;
461         break;
462     case kCGImageAlphaNone:
463         alphaFormat = AlphaFormatNone;
464         break;
465     default:
466         return false;
467     }
468
469     m_imageSourceFormat = getSourceDataFormat(componentsPerPixel, alphaFormat, bitsPerComponent == 16, bigEndianSource);
470     if (m_imageSourceFormat == DataFormatNumFormats)
471         return false;
472
473     m_pixelData = adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(m_cgImage)));
474     if (!m_pixelData)
475         return false;
476
477     m_imagePixelData = reinterpret_cast<const void*>(CFDataGetBytePtr(m_pixelData.get()));
478
479     unsigned int srcUnpackAlignment = 0;
480     size_t bytesPerRow = CGImageGetBytesPerRow(m_cgImage);
481     unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth;
482     if (padding) {
483         srcUnpackAlignment = padding + 1;
484         while (bytesPerRow % srcUnpackAlignment)
485             ++srcUnpackAlignment;
486     }
487
488     m_imageSourceUnpackAlignment = srcUnpackAlignment;
489     // Using a bitmap context created according to destination format and drawing the CGImage to the bitmap context can also do the format conversion,
490     // but it would premultiply the alpha channel as a side effect.
491     // Prefer to mannually Convert 16bit per-component formats to RGBA8 formats instead.
492     if (bitsPerComponent == 16) {
493         m_formalizedRGBA8Data = std::make_unique<uint8_t[]>(m_imageWidth * m_imageHeight * 4);
494         const uint16_t* source = reinterpret_cast<const uint16_t*>(m_imagePixelData);
495         uint8_t* destination = m_formalizedRGBA8Data.get();
496         const ptrdiff_t srcStrideInElements = bytesPerRow / sizeof(uint16_t);
497         const ptrdiff_t dstStrideInElements = 4 * m_imageWidth;
498         for (unsigned i =0; i < m_imageHeight; i++) {
499             convert16BitFormatToRGBA8(m_imageSourceFormat, source, destination, m_imageWidth);
500             source += srcStrideInElements;
501             destination += dstStrideInElements;
502         }
503         m_imagePixelData = reinterpret_cast<const void*>(m_formalizedRGBA8Data.get());
504         m_imageSourceFormat = DataFormatRGBA8;
505         m_imageSourceUnpackAlignment = 1;
506     }
507     return true;
508 }
509
510 static void releaseImageData(void*, const void* data, size_t)
511 {
512     fastFree(const_cast<void*>(data));
513 }
514
515 void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, GraphicsContext* context)
516 {
517     if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context)
518         return;
519     int rowBytes = imageWidth * 4;
520     RetainPtr<CGDataProviderRef> dataProvider;
521
522     if (context->isAcceleratedContext()) {
523         unsigned char* copiedPixels;
524
525         if (!tryFastCalloc(imageHeight, rowBytes).getValue(copiedPixels))
526             return;
527
528         memcpy(copiedPixels, imagePixels, rowBytes * imageHeight);
529         dataProvider = adoptCF(CGDataProviderCreateWithData(0, copiedPixels, rowBytes * imageHeight, releaseImageData));
530     } else
531         dataProvider = adoptCF(CGDataProviderCreateWithData(0, imagePixels, rowBytes * imageHeight, 0));
532
533     RetainPtr<CGImageRef> cgImage = adoptCF(CGImageCreate(imageWidth, imageHeight, 8, 32, rowBytes, deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
534         dataProvider.get(), 0, false, kCGRenderingIntentDefault));
535
536     // CSS styling may cause the canvas's content to be resized on
537     // the page. Go back to the Canvas to figure out the correct
538     // width and height to draw.
539     FloatRect canvasRect(0, 0, canvasWidth, canvasHeight);
540     FloatSize imageSize(imageWidth, imageHeight);
541     // We want to completely overwrite the previous frame's
542     // rendering results.
543
544     GraphicsContextStateSaver stateSaver(*context);
545     context->scale(FloatSize(1, -1));
546     context->translate(0, -imageHeight);
547     context->setImageInterpolationQuality(InterpolationNone);
548     context->drawNativeImage(cgImage.get(), imageSize, ColorSpaceDeviceRGB, canvasRect, FloatRect(FloatPoint(), imageSize), 1, CompositeCopy);
549 }
550
551 } // namespace WebCore
552
553 #endif // USE(3D_GRAPHICS)