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