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