1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "platform/graphics/gpu/WebGLImageConversion.h"
7
8#include "platform/CheckedInt.h"
9#include "platform/graphics/ImageObserver.h"
10#include "platform/graphics/cpu/arm/WebGLImageConversionNEON.h"
11#include "platform/image-decoders/ImageDecoder.h"
12#include "wtf/OwnPtr.h"
13#include "wtf/PassOwnPtr.h"
14
15namespace blink {
16
17namespace {
18
19WebGLImageConversion::DataFormat getDataFormat(GLenum destinationFormat, GLenum destinationType)
20{
21    WebGLImageConversion::DataFormat dstFormat = WebGLImageConversion::DataFormatRGBA8;
22    switch (destinationType) {
23    case GL_UNSIGNED_BYTE:
24        switch (destinationFormat) {
25        case GL_RGB:
26            dstFormat = WebGLImageConversion::DataFormatRGB8;
27            break;
28        case GL_RGBA:
29            dstFormat = WebGLImageConversion::DataFormatRGBA8;
30            break;
31        case GL_ALPHA:
32            dstFormat = WebGLImageConversion::DataFormatA8;
33            break;
34        case GL_LUMINANCE:
35            dstFormat = WebGLImageConversion::DataFormatR8;
36            break;
37        case GL_LUMINANCE_ALPHA:
38            dstFormat = WebGLImageConversion::DataFormatRA8;
39            break;
40        default:
41            ASSERT_NOT_REACHED();
42        }
43        break;
44    case GL_UNSIGNED_SHORT_4_4_4_4:
45        dstFormat = WebGLImageConversion::DataFormatRGBA4444;
46        break;
47    case GL_UNSIGNED_SHORT_5_5_5_1:
48        dstFormat = WebGLImageConversion::DataFormatRGBA5551;
49        break;
50    case GL_UNSIGNED_SHORT_5_6_5:
51        dstFormat = WebGLImageConversion::DataFormatRGB565;
52        break;
53    case GL_HALF_FLOAT_OES: // OES_texture_half_float
54        switch (destinationFormat) {
55        case GL_RGB:
56            dstFormat = WebGLImageConversion::DataFormatRGB16F;
57            break;
58        case GL_RGBA:
59            dstFormat = WebGLImageConversion::DataFormatRGBA16F;
60            break;
61        case GL_ALPHA:
62            dstFormat = WebGLImageConversion::DataFormatA16F;
63            break;
64        case GL_LUMINANCE:
65            dstFormat = WebGLImageConversion::DataFormatR16F;
66            break;
67        case GL_LUMINANCE_ALPHA:
68            dstFormat = WebGLImageConversion::DataFormatRA16F;
69            break;
70        default:
71            ASSERT_NOT_REACHED();
72        }
73        break;
74    case GL_FLOAT: // OES_texture_float
75        switch (destinationFormat) {
76        case GL_RGB:
77            dstFormat = WebGLImageConversion::DataFormatRGB32F;
78            break;
79        case GL_RGBA:
80            dstFormat = WebGLImageConversion::DataFormatRGBA32F;
81            break;
82        case GL_ALPHA:
83            dstFormat = WebGLImageConversion::DataFormatA32F;
84            break;
85        case GL_LUMINANCE:
86            dstFormat = WebGLImageConversion::DataFormatR32F;
87            break;
88        case GL_LUMINANCE_ALPHA:
89            dstFormat = WebGLImageConversion::DataFormatRA32F;
90            break;
91        default:
92            ASSERT_NOT_REACHED();
93        }
94        break;
95    default:
96        ASSERT_NOT_REACHED();
97    }
98    return dstFormat;
99}
100
101// Following Float to Half-Float converion code is from the implementation of ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf,
102// "Fast Half Float Conversions" by Jeroen van der Zijp, November 2008 (Revised September 2010).
103// Specially, the basetable[512] and shifttable[512] are generated as follows:
104/*
105unsigned short basetable[512];
106unsigned char shifttable[512];
107
108void generatetables(){
109    unsigned int i;
110    int e;
111    for (i = 0; i < 256; ++i){
112        e = i - 127;
113        if (e < -24){ // Very small numbers map to zero
114            basetable[i | 0x000] = 0x0000;
115            basetable[i | 0x100] = 0x8000;
116            shifttable[i | 0x000] = 24;
117            shifttable[i | 0x100] = 24;
118        }
119        else if (e < -14) { // Small numbers map to denorms
120            basetable[i | 0x000] = (0x0400>>(-e-14));
121            basetable[i | 0x100] = (0x0400>>(-e-14)) | 0x8000;
122            shifttable[i | 0x000] = -e-1;
123            shifttable[i | 0x100] = -e-1;
124        }
125        else if (e <= 15){ // Normal numbers just lose precision
126            basetable[i | 0x000] = ((e+15)<<10);
127            basetable[i| 0x100] = ((e+15)<<10) | 0x8000;
128            shifttable[i|0x000] = 13;
129            shifttable[i|0x100] = 13;
130        }
131        else if (e<128){ // Large numbers map to Infinity
132            basetable[i|0x000] = 0x7C00;
133            basetable[i|0x100] = 0xFC00;
134            shifttable[i|0x000] = 24;
135            shifttable[i|0x100] = 24;
136        }
137        else { // Infinity and NaN's stay Infinity and NaN's
138            basetable[i|0x000] = 0x7C00;
139            basetable[i|0x100] = 0xFC00;
140            shifttable[i|0x000] = 13;
141            shifttable[i|0x100] = 13;
142       }
143    }
144}
145*/
146
147unsigned short baseTable[512] = {
1480,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1490,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1500,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1510,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1520,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1530,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1540,      0,      0,      0,      0,      0,      0,      1,      2,      4,      8,      16,     32,     64,     128,    256,
155512,    1024,   2048,   3072,   4096,   5120,   6144,   7168,   8192,   9216,   10240,  11264,  12288,  13312,  14336,  15360,
15616384,  17408,  18432,  19456,  20480,  21504,  22528,  23552,  24576,  25600,  26624,  27648,  28672,  29696,  30720,  31744,
15731744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
15831744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
15931744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
16031744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
16131744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
16231744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
16331744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
16432768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
16532768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
16632768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
16732768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
16832768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
16932768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
17032768,  32768,  32768,  32768,  32768,  32768,  32768,  32769,  32770,  32772,  32776,  32784,  32800,  32832,  32896,  33024,
17133280,  33792,  34816,  35840,  36864,  37888,  38912,  39936,  40960,  41984,  43008,  44032,  45056,  46080,  47104,  48128,
17249152,  50176,  51200,  52224,  53248,  54272,  55296,  56320,  57344,  58368,  59392,  60416,  61440,  62464,  63488,  64512,
17364512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17464512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17564512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17664512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17764512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17864512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
17964512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512
180};
181
182unsigned char shiftTable[512] = {
18324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18524,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18624,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18724,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18824,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
18924,     24,     24,     24,     24,     24,     24,     23,     22,     21,     20,     19,     18,     17,     16,     15,
19014,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,
19113,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     24,
19224,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19524,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19624,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19724,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
19824,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     13,
19924,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20224,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20524,     24,     24,     24,     24,     24,     24,     23,     22,     21,     20,     19,     18,     17,     16,     15,
20614,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,
20713,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     24,
20824,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
20924,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
21024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
21124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
21224,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
21324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
21424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     13
215};
216
217unsigned short convertFloatToHalfFloat(float f)
218{
219    unsigned temp = *(reinterpret_cast<unsigned *>(&f));
220    unsigned signexp = (temp >> 23) & 0x1ff;
221    return baseTable[signexp] + ((temp & 0x007fffff) >> shiftTable[signexp]);
222}
223
224/* BEGIN CODE SHARED WITH MOZILLA FIREFOX */
225
226// The following packing and unpacking routines are expressed in terms of function templates and inline functions to achieve generality and speedup.
227// Explicit template specializations correspond to the cases that would occur.
228// Some code are merged back from Mozilla code in http://mxr.mozilla.org/mozilla-central/source/content/canvas/src/WebGLTexelConversions.h
229
230//----------------------------------------------------------------------
231// Pixel unpacking routines.
232template<int format, typename SourceType, typename DstType>
233void unpack(const SourceType*, DstType*, unsigned)
234{
235    ASSERT_NOT_REACHED();
236}
237
238template<> void unpack<WebGLImageConversion::DataFormatRGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
239{
240    for (unsigned i = 0; i < pixelsPerRow; ++i) {
241        destination[0] = source[0];
242        destination[1] = source[1];
243        destination[2] = source[2];
244        destination[3] = 0xFF;
245        source += 3;
246        destination += 4;
247    }
248}
249
250template<> void unpack<WebGLImageConversion::DataFormatBGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
251{
252    for (unsigned i = 0; i < pixelsPerRow; ++i) {
253        destination[0] = source[2];
254        destination[1] = source[1];
255        destination[2] = source[0];
256        destination[3] = 0xFF;
257        source += 3;
258        destination += 4;
259    }
260}
261
262template<> void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
263{
264    for (unsigned i = 0; i < pixelsPerRow; ++i) {
265        destination[0] = source[1];
266        destination[1] = source[2];
267        destination[2] = source[3];
268        destination[3] = source[0];
269        source += 4;
270        destination += 4;
271    }
272}
273
274template<> void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
275{
276    for (unsigned i = 0; i < pixelsPerRow; ++i) {
277        destination[0] = source[3];
278        destination[1] = source[2];
279        destination[2] = source[1];
280        destination[3] = source[0];
281        source += 4;
282        destination += 4;
283    }
284}
285
286template<> void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
287{
288    const uint32_t* source32 = reinterpret_cast_ptr<const uint32_t*>(source);
289    uint32_t* destination32 = reinterpret_cast_ptr<uint32_t*>(destination);
290    for (unsigned i = 0; i < pixelsPerRow; ++i) {
291        uint32_t bgra = source32[i];
292#if CPU(BIG_ENDIAN)
293        uint32_t brMask = 0xff00ff00;
294        uint32_t gaMask = 0x00ff00ff;
295#else
296        uint32_t brMask = 0x00ff00ff;
297        uint32_t gaMask = 0xff00ff00;
298#endif
299        uint32_t rgba = (((bgra >> 16) | (bgra << 16)) & brMask) | (bgra & gaMask);
300        destination32[i] = rgba;
301    }
302}
303
304template<> void unpack<WebGLImageConversion::DataFormatRGBA5551, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
305{
306#if HAVE(ARM_NEON_INTRINSICS)
307    SIMD::unpackOneRowOfRGBA5551ToRGBA8(source, destination, pixelsPerRow);
308#endif
309    for (unsigned i = 0; i < pixelsPerRow; ++i) {
310        uint16_t packedValue = source[0];
311        uint8_t r = packedValue >> 11;
312        uint8_t g = (packedValue >> 6) & 0x1F;
313        uint8_t b = (packedValue >> 1) & 0x1F;
314        destination[0] = (r << 3) | (r & 0x7);
315        destination[1] = (g << 3) | (g & 0x7);
316        destination[2] = (b << 3) | (b & 0x7);
317        destination[3] = (packedValue & 0x1) ? 0xFF : 0x0;
318        source += 1;
319        destination += 4;
320    }
321}
322
323template<> void unpack<WebGLImageConversion::DataFormatRGBA4444, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
324{
325#if HAVE(ARM_NEON_INTRINSICS)
326    SIMD::unpackOneRowOfRGBA4444ToRGBA8(source, destination, pixelsPerRow);
327#endif
328    for (unsigned i = 0; i < pixelsPerRow; ++i) {
329        uint16_t packedValue = source[0];
330        uint8_t r = packedValue >> 12;
331        uint8_t g = (packedValue >> 8) & 0x0F;
332        uint8_t b = (packedValue >> 4) & 0x0F;
333        uint8_t a = packedValue & 0x0F;
334        destination[0] = r << 4 | r;
335        destination[1] = g << 4 | g;
336        destination[2] = b << 4 | b;
337        destination[3] = a << 4 | a;
338        source += 1;
339        destination += 4;
340    }
341}
342
343template<> void unpack<WebGLImageConversion::DataFormatRGB565, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
344{
345#if HAVE(ARM_NEON_INTRINSICS)
346    SIMD::unpackOneRowOfRGB565ToRGBA8(source, destination, pixelsPerRow);
347#endif
348    for (unsigned i = 0; i < pixelsPerRow; ++i) {
349        uint16_t packedValue = source[0];
350        uint8_t r = packedValue >> 11;
351        uint8_t g = (packedValue >> 5) & 0x3F;
352        uint8_t b = packedValue & 0x1F;
353        destination[0] = (r << 3) | (r & 0x7);
354        destination[1] = (g << 2) | (g & 0x3);
355        destination[2] = (b << 3) | (b & 0x7);
356        destination[3] = 0xFF;
357        source += 1;
358        destination += 4;
359    }
360}
361
362template<> void unpack<WebGLImageConversion::DataFormatR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
363{
364    for (unsigned i = 0; i < pixelsPerRow; ++i) {
365        destination[0] = source[0];
366        destination[1] = source[0];
367        destination[2] = source[0];
368        destination[3] = 0xFF;
369        source += 1;
370        destination += 4;
371    }
372}
373
374template<> void unpack<WebGLImageConversion::DataFormatRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
375{
376    for (unsigned i = 0; i < pixelsPerRow; ++i) {
377        destination[0] = source[0];
378        destination[1] = source[0];
379        destination[2] = source[0];
380        destination[3] = source[1];
381        source += 2;
382        destination += 4;
383    }
384}
385
386template<> void unpack<WebGLImageConversion::DataFormatAR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
387{
388    for (unsigned i = 0; i < pixelsPerRow; ++i) {
389        destination[0] = source[1];
390        destination[1] = source[1];
391        destination[2] = source[1];
392        destination[3] = source[0];
393        source += 2;
394        destination += 4;
395    }
396}
397
398template<> void unpack<WebGLImageConversion::DataFormatA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
399{
400    for (unsigned i = 0; i < pixelsPerRow; ++i) {
401        destination[0] = 0x0;
402        destination[1] = 0x0;
403        destination[2] = 0x0;
404        destination[3] = source[0];
405        source += 1;
406        destination += 4;
407    }
408}
409
410template<> void unpack<WebGLImageConversion::DataFormatRGBA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
411{
412    const float scaleFactor = 1.0f / 255.0f;
413    for (unsigned i = 0; i < pixelsPerRow; ++i) {
414        destination[0] = source[0] * scaleFactor;
415        destination[1] = source[1] * scaleFactor;
416        destination[2] = source[2] * scaleFactor;
417        destination[3] = source[3] * scaleFactor;
418        source += 4;
419        destination += 4;
420    }
421}
422
423template<> void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
424{
425    const float scaleFactor = 1.0f / 255.0f;
426    for (unsigned i = 0; i < pixelsPerRow; ++i) {
427        destination[0] = source[2] * scaleFactor;
428        destination[1] = source[1] * scaleFactor;
429        destination[2] = source[0] * scaleFactor;
430        destination[3] = source[3] * scaleFactor;
431        source += 4;
432        destination += 4;
433    }
434}
435
436template<> void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
437{
438    const float scaleFactor = 1.0f / 255.0f;
439    for (unsigned i = 0; i < pixelsPerRow; ++i) {
440        destination[0] = source[3] * scaleFactor;
441        destination[1] = source[2] * scaleFactor;
442        destination[2] = source[1] * scaleFactor;
443        destination[3] = source[0] * scaleFactor;
444        source += 4;
445        destination += 4;
446    }
447}
448
449template<> void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
450{
451    const float scaleFactor = 1.0f / 255.0f;
452    for (unsigned i = 0; i < pixelsPerRow; ++i) {
453        destination[0] = source[1] * scaleFactor;
454        destination[1] = source[2] * scaleFactor;
455        destination[2] = source[3] * scaleFactor;
456        destination[3] = source[0] * scaleFactor;
457        source += 4;
458        destination += 4;
459    }
460}
461
462template<> void unpack<WebGLImageConversion::DataFormatRGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
463{
464    const float scaleFactor = 1.0f / 255.0f;
465    for (unsigned i = 0; i < pixelsPerRow; ++i) {
466        destination[0] = source[0] * scaleFactor;
467        destination[1] = source[1] * scaleFactor;
468        destination[2] = source[2] * scaleFactor;
469        destination[3] = 1;
470        source += 3;
471        destination += 4;
472    }
473}
474
475template<> void unpack<WebGLImageConversion::DataFormatBGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
476{
477    const float scaleFactor = 1.0f / 255.0f;
478    for (unsigned i = 0; i < pixelsPerRow; ++i) {
479        destination[0] = source[2] * scaleFactor;
480        destination[1] = source[1] * scaleFactor;
481        destination[2] = source[0] * scaleFactor;
482        destination[3] = 1;
483        source += 3;
484        destination += 4;
485    }
486}
487
488template<> void unpack<WebGLImageConversion::DataFormatRGB32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
489{
490    for (unsigned i = 0; i < pixelsPerRow; ++i) {
491        destination[0] = source[0];
492        destination[1] = source[1];
493        destination[2] = source[2];
494        destination[3] = 1;
495        source += 3;
496        destination += 4;
497    }
498}
499
500template<> void unpack<WebGLImageConversion::DataFormatR32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
501{
502    for (unsigned i = 0; i < pixelsPerRow; ++i) {
503        destination[0] = source[0];
504        destination[1] = source[0];
505        destination[2] = source[0];
506        destination[3] = 1;
507        source += 1;
508        destination += 4;
509    }
510}
511
512template<> void unpack<WebGLImageConversion::DataFormatRA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
513{
514    for (unsigned i = 0; i < pixelsPerRow; ++i) {
515        destination[0] = source[0];
516        destination[1] = source[0];
517        destination[2] = source[0];
518        destination[3] = source[1];
519        source += 2;
520        destination += 4;
521    }
522}
523
524template<> void unpack<WebGLImageConversion::DataFormatA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
525{
526    for (unsigned i = 0; i < pixelsPerRow; ++i) {
527        destination[0] = 0;
528        destination[1] = 0;
529        destination[2] = 0;
530        destination[3] = source[0];
531        source += 1;
532        destination += 4;
533    }
534}
535
536//----------------------------------------------------------------------
537// Pixel packing routines.
538//
539
540template<int format, int alphaOp, typename SourceType, typename DstType>
541void pack(const SourceType*, DstType*, unsigned)
542{
543    ASSERT_NOT_REACHED();
544}
545
546template<> void pack<WebGLImageConversion::DataFormatA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
547{
548    for (unsigned i = 0; i < pixelsPerRow; ++i) {
549        destination[0] = source[3];
550        source += 4;
551        destination += 1;
552    }
553}
554
555template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
556{
557    for (unsigned i = 0; i < pixelsPerRow; ++i) {
558        destination[0] = source[0];
559        source += 4;
560        destination += 1;
561    }
562}
563
564template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
565{
566    for (unsigned i = 0; i < pixelsPerRow; ++i) {
567        float scaleFactor = source[3] / 255.0f;
568        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
569        destination[0] = sourceR;
570        source += 4;
571        destination += 1;
572    }
573}
574
575// FIXME: this routine is lossy and must be removed.
576template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
577{
578    for (unsigned i = 0; i < pixelsPerRow; ++i) {
579        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
580        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
581        destination[0] = sourceR;
582        source += 4;
583        destination += 1;
584    }
585}
586
587template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
588{
589    for (unsigned i = 0; i < pixelsPerRow; ++i) {
590        destination[0] = source[0];
591        destination[1] = source[3];
592        source += 4;
593        destination += 2;
594    }
595}
596
597template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
598{
599    for (unsigned i = 0; i < pixelsPerRow; ++i) {
600        float scaleFactor = source[3] / 255.0f;
601        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
602        destination[0] = sourceR;
603        destination[1] = source[3];
604        source += 4;
605        destination += 2;
606    }
607}
608
609// FIXME: this routine is lossy and must be removed.
610template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
611{
612    for (unsigned i = 0; i < pixelsPerRow; ++i) {
613        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
614        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
615        destination[0] = sourceR;
616        destination[1] = source[3];
617        source += 4;
618        destination += 2;
619    }
620}
621
622template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
623{
624    for (unsigned i = 0; i < pixelsPerRow; ++i) {
625        destination[0] = source[0];
626        destination[1] = source[1];
627        destination[2] = source[2];
628        source += 4;
629        destination += 3;
630    }
631}
632
633template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
634{
635    for (unsigned i = 0; i < pixelsPerRow; ++i) {
636        float scaleFactor = source[3] / 255.0f;
637        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
638        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
639        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
640        destination[0] = sourceR;
641        destination[1] = sourceG;
642        destination[2] = sourceB;
643        source += 4;
644        destination += 3;
645    }
646}
647
648// FIXME: this routine is lossy and must be removed.
649template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
650{
651    for (unsigned i = 0; i < pixelsPerRow; ++i) {
652        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
653        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
654        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
655        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
656        destination[0] = sourceR;
657        destination[1] = sourceG;
658        destination[2] = sourceB;
659        source += 4;
660        destination += 3;
661    }
662}
663
664
665template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
666{
667    memcpy(destination, source, pixelsPerRow * 4);
668}
669
670template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
671{
672    for (unsigned i = 0; i < pixelsPerRow; ++i) {
673        float scaleFactor = source[3] / 255.0f;
674        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
675        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
676        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
677        destination[0] = sourceR;
678        destination[1] = sourceG;
679        destination[2] = sourceB;
680        destination[3] = source[3];
681        source += 4;
682        destination += 4;
683    }
684}
685
686// FIXME: this routine is lossy and must be removed.
687template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
688{
689    for (unsigned i = 0; i < pixelsPerRow; ++i) {
690        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
691        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
692        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
693        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
694        destination[0] = sourceR;
695        destination[1] = sourceG;
696        destination[2] = sourceB;
697        destination[3] = source[3];
698        source += 4;
699        destination += 4;
700    }
701}
702
703template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
704{
705#if HAVE(ARM_NEON_INTRINSICS)
706    SIMD::packOneRowOfRGBA8ToUnsignedShort4444(source, destination, pixelsPerRow);
707#endif
708    for (unsigned i = 0; i < pixelsPerRow; ++i) {
709        *destination = (((source[0] & 0xF0) << 8)
710                        | ((source[1] & 0xF0) << 4)
711                        | (source[2] & 0xF0)
712                        | (source[3] >> 4));
713        source += 4;
714        destination += 1;
715    }
716}
717
718template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
719{
720    for (unsigned i = 0; i < pixelsPerRow; ++i) {
721        float scaleFactor = source[3] / 255.0f;
722        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
723        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
724        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
725        *destination = (((sourceR & 0xF0) << 8)
726                        | ((sourceG & 0xF0) << 4)
727                        | (sourceB & 0xF0)
728                        | (source[3] >> 4));
729        source += 4;
730        destination += 1;
731    }
732}
733
734// FIXME: this routine is lossy and must be removed.
735template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
736{
737    for (unsigned i = 0; i < pixelsPerRow; ++i) {
738        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
739        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
740        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
741        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
742        *destination = (((sourceR & 0xF0) << 8)
743                        | ((sourceG & 0xF0) << 4)
744                        | (sourceB & 0xF0)
745                        | (source[3] >> 4));
746        source += 4;
747        destination += 1;
748    }
749}
750
751template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
752{
753#if HAVE(ARM_NEON_INTRINSICS)
754    SIMD::packOneRowOfRGBA8ToUnsignedShort5551(source, destination, pixelsPerRow);
755#endif
756    for (unsigned i = 0; i < pixelsPerRow; ++i) {
757        *destination = (((source[0] & 0xF8) << 8)
758                        | ((source[1] & 0xF8) << 3)
759                        | ((source[2] & 0xF8) >> 2)
760                        | (source[3] >> 7));
761        source += 4;
762        destination += 1;
763    }
764}
765
766template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
767{
768    for (unsigned i = 0; i < pixelsPerRow; ++i) {
769        float scaleFactor = source[3] / 255.0f;
770        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
771        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
772        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
773        *destination = (((sourceR & 0xF8) << 8)
774                        | ((sourceG & 0xF8) << 3)
775                        | ((sourceB & 0xF8) >> 2)
776                        | (source[3] >> 7));
777        source += 4;
778        destination += 1;
779    }
780}
781
782// FIXME: this routine is lossy and must be removed.
783template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
784{
785    for (unsigned i = 0; i < pixelsPerRow; ++i) {
786        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
787        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
788        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
789        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
790        *destination = (((sourceR & 0xF8) << 8)
791                        | ((sourceG & 0xF8) << 3)
792                        | ((sourceB & 0xF8) >> 2)
793                        | (source[3] >> 7));
794        source += 4;
795        destination += 1;
796    }
797}
798
799template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
800{
801#if HAVE(ARM_NEON_INTRINSICS)
802    SIMD::packOneRowOfRGBA8ToUnsignedShort565(source, destination, pixelsPerRow);
803#endif
804    for (unsigned i = 0; i < pixelsPerRow; ++i) {
805        *destination = (((source[0] & 0xF8) << 8)
806                        | ((source[1] & 0xFC) << 3)
807                        | ((source[2] & 0xF8) >> 3));
808        source += 4;
809        destination += 1;
810    }
811}
812
813template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
814{
815    for (unsigned i = 0; i < pixelsPerRow; ++i) {
816        float scaleFactor = source[3] / 255.0f;
817        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
818        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
819        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
820        *destination = (((sourceR & 0xF8) << 8)
821                        | ((sourceG & 0xFC) << 3)
822                        | ((sourceB & 0xF8) >> 3));
823        source += 4;
824        destination += 1;
825    }
826}
827
828// FIXME: this routine is lossy and must be removed.
829template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
830{
831    for (unsigned i = 0; i < pixelsPerRow; ++i) {
832        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
833        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
834        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
835        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
836        *destination = (((sourceR & 0xF8) << 8)
837                        | ((sourceG & 0xFC) << 3)
838                        | ((sourceB & 0xF8) >> 3));
839        source += 4;
840        destination += 1;
841    }
842}
843
844template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
845{
846    for (unsigned i = 0; i < pixelsPerRow; ++i) {
847        destination[0] = source[0];
848        destination[1] = source[1];
849        destination[2] = source[2];
850        source += 4;
851        destination += 3;
852    }
853}
854
855template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
856{
857    for (unsigned i = 0; i < pixelsPerRow; ++i) {
858        float scaleFactor = source[3];
859        destination[0] = source[0] * scaleFactor;
860        destination[1] = source[1] * scaleFactor;
861        destination[2] = source[2] * scaleFactor;
862        source += 4;
863        destination += 3;
864    }
865}
866
867template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
868{
869    for (unsigned i = 0; i < pixelsPerRow; ++i) {
870        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
871        destination[0] = source[0] * scaleFactor;
872        destination[1] = source[1] * scaleFactor;
873        destination[2] = source[2] * scaleFactor;
874        source += 4;
875        destination += 3;
876    }
877}
878
879// Used only during RGBA8 or BGRA8 -> floating-point uploads.
880template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
881{
882    memcpy(destination, source, pixelsPerRow * 4 * sizeof(float));
883}
884
885template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
886{
887    for (unsigned i = 0; i < pixelsPerRow; ++i) {
888        float scaleFactor = source[3];
889        destination[0] = source[0] * scaleFactor;
890        destination[1] = source[1] * scaleFactor;
891        destination[2] = source[2] * scaleFactor;
892        destination[3] = source[3];
893        source += 4;
894        destination += 4;
895    }
896}
897
898template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
899{
900    for (unsigned i = 0; i < pixelsPerRow; ++i) {
901        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
902        destination[0] = source[0] * scaleFactor;
903        destination[1] = source[1] * scaleFactor;
904        destination[2] = source[2] * scaleFactor;
905        destination[3] = source[3];
906        source += 4;
907        destination += 4;
908    }
909}
910
911template<> void pack<WebGLImageConversion::DataFormatA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
912{
913    for (unsigned i = 0; i < pixelsPerRow; ++i) {
914        destination[0] = source[3];
915        source += 4;
916        destination += 1;
917    }
918}
919
920template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
921{
922    for (unsigned i = 0; i < pixelsPerRow; ++i) {
923        destination[0] = source[0];
924        source += 4;
925        destination += 1;
926    }
927}
928
929template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
930{
931    for (unsigned i = 0; i < pixelsPerRow; ++i) {
932        float scaleFactor = source[3];
933        destination[0] = source[0] * scaleFactor;
934        source += 4;
935        destination += 1;
936    }
937}
938
939template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
940{
941    for (unsigned i = 0; i < pixelsPerRow; ++i) {
942        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
943        destination[0] = source[0] * scaleFactor;
944        source += 4;
945        destination += 1;
946    }
947}
948
949template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
950{
951    for (unsigned i = 0; i < pixelsPerRow; ++i) {
952        destination[0] = source[0];
953        destination[1] = source[3];
954        source += 4;
955        destination += 2;
956    }
957}
958
959template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
960{
961    for (unsigned i = 0; i < pixelsPerRow; ++i) {
962        float scaleFactor = source[3];
963        destination[0] = source[0] * scaleFactor;
964        destination[1] = source[3];
965        source += 4;
966        destination += 2;
967    }
968}
969
970template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
971{
972    for (unsigned i = 0; i < pixelsPerRow; ++i) {
973        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
974        destination[0] = source[0] * scaleFactor;
975        destination[1] = source[3];
976        source += 4;
977        destination += 2;
978    }
979}
980
981template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
982{
983    for (unsigned i = 0; i < pixelsPerRow; ++i) {
984        destination[0] = convertFloatToHalfFloat(source[0]);
985        destination[1] = convertFloatToHalfFloat(source[1]);
986        destination[2] = convertFloatToHalfFloat(source[2]);
987        destination[3] = convertFloatToHalfFloat(source[3]);
988        source += 4;
989        destination += 4;
990    }
991}
992
993template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
994{
995    for (unsigned i = 0; i < pixelsPerRow; ++i) {
996        float scaleFactor = source[3];
997        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
998        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
999        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
1000        destination[3] = convertFloatToHalfFloat(source[3]);
1001        source += 4;
1002        destination += 4;
1003    }
1004}
1005
1006template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1007{
1008    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1009        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1010        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1011        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
1012        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
1013        destination[3] = convertFloatToHalfFloat(source[3]);
1014        source += 4;
1015        destination += 4;
1016    }
1017}
1018
1019template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1020{
1021    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1022        destination[0] = convertFloatToHalfFloat(source[0]);
1023        destination[1] = convertFloatToHalfFloat(source[1]);
1024        destination[2] = convertFloatToHalfFloat(source[2]);
1025        source += 4;
1026        destination += 3;
1027    }
1028}
1029
1030template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1031{
1032    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1033        float scaleFactor = source[3];
1034        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1035        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
1036        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
1037        source += 4;
1038        destination += 3;
1039    }
1040}
1041
1042template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1043{
1044    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1045        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1046        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1047        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
1048        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
1049        source += 4;
1050        destination += 3;
1051    }
1052}
1053
1054template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1055{
1056    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1057        destination[0] = convertFloatToHalfFloat(source[0]);
1058        destination[1] = convertFloatToHalfFloat(source[3]);
1059        source += 4;
1060        destination += 2;
1061    }
1062}
1063
1064template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1065{
1066    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1067        float scaleFactor = source[3];
1068        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1069        destination[1] = convertFloatToHalfFloat(source[3]);
1070        source += 4;
1071        destination += 2;
1072    }
1073}
1074
1075template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1076{
1077    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1078        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1079        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1080        destination[1] = convertFloatToHalfFloat(source[3]);
1081        source += 4;
1082        destination += 2;
1083    }
1084}
1085
1086template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1087{
1088    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1089        destination[0] = convertFloatToHalfFloat(source[0]);
1090        source += 4;
1091        destination += 1;
1092    }
1093}
1094
1095template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1096{
1097    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1098        float scaleFactor = source[3];
1099        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1100        source += 4;
1101        destination += 1;
1102    }
1103}
1104
1105template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1106{
1107    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1108        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1109        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1110        source += 4;
1111        destination += 1;
1112    }
1113}
1114
1115template<> void pack<WebGLImageConversion::DataFormatA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1116{
1117    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1118        destination[0] = convertFloatToHalfFloat(source[3]);
1119        source += 4;
1120        destination += 1;
1121    }
1122}
1123
1124bool HasAlpha(int format)
1125{
1126    return format == WebGLImageConversion::DataFormatA8
1127        || format == WebGLImageConversion::DataFormatA16F
1128        || format == WebGLImageConversion::DataFormatA32F
1129        || format == WebGLImageConversion::DataFormatRA8
1130        || format == WebGLImageConversion::DataFormatAR8
1131        || format == WebGLImageConversion::DataFormatRA16F
1132        || format == WebGLImageConversion::DataFormatRA32F
1133        || format == WebGLImageConversion::DataFormatRGBA8
1134        || format == WebGLImageConversion::DataFormatBGRA8
1135        || format == WebGLImageConversion::DataFormatARGB8
1136        || format == WebGLImageConversion::DataFormatABGR8
1137        || format == WebGLImageConversion::DataFormatRGBA16F
1138        || format == WebGLImageConversion::DataFormatRGBA32F
1139        || format == WebGLImageConversion::DataFormatRGBA4444
1140        || format == WebGLImageConversion::DataFormatRGBA5551;
1141}
1142
1143bool HasColor(int format)
1144{
1145    return format == WebGLImageConversion::DataFormatRGBA8
1146        || format == WebGLImageConversion::DataFormatRGBA16F
1147        || format == WebGLImageConversion::DataFormatRGBA32F
1148        || format == WebGLImageConversion::DataFormatRGB8
1149        || format == WebGLImageConversion::DataFormatRGB16F
1150        || format == WebGLImageConversion::DataFormatRGB32F
1151        || format == WebGLImageConversion::DataFormatBGR8
1152        || format == WebGLImageConversion::DataFormatBGRA8
1153        || format == WebGLImageConversion::DataFormatARGB8
1154        || format == WebGLImageConversion::DataFormatABGR8
1155        || format == WebGLImageConversion::DataFormatRGBA5551
1156        || format == WebGLImageConversion::DataFormatRGBA4444
1157        || format == WebGLImageConversion::DataFormatRGB565
1158        || format == WebGLImageConversion::DataFormatR8
1159        || format == WebGLImageConversion::DataFormatR16F
1160        || format == WebGLImageConversion::DataFormatR32F
1161        || format == WebGLImageConversion::DataFormatRA8
1162        || format == WebGLImageConversion::DataFormatRA16F
1163        || format == WebGLImageConversion::DataFormatRA32F
1164        || format == WebGLImageConversion::DataFormatAR8;
1165}
1166
1167template<int Format>
1168struct IsFloatFormat {
1169    static const bool Value =
1170        Format == WebGLImageConversion::DataFormatRGBA32F
1171        || Format == WebGLImageConversion::DataFormatRGB32F
1172        || Format == WebGLImageConversion::DataFormatRA32F
1173        || Format == WebGLImageConversion::DataFormatR32F
1174        || Format == WebGLImageConversion::DataFormatA32F;
1175};
1176
1177template<int Format>
1178struct IsHalfFloatFormat {
1179    static const bool Value =
1180        Format == WebGLImageConversion::DataFormatRGBA16F
1181        || Format == WebGLImageConversion::DataFormatRGB16F
1182        || Format == WebGLImageConversion::DataFormatRA16F
1183        || Format == WebGLImageConversion::DataFormatR16F
1184        || Format == WebGLImageConversion::DataFormatA16F;
1185};
1186
1187template<int Format>
1188struct Is16bppFormat {
1189    static const bool Value =
1190        Format == WebGLImageConversion::DataFormatRGBA5551
1191        || Format == WebGLImageConversion::DataFormatRGBA4444
1192        || Format == WebGLImageConversion::DataFormatRGB565;
1193};
1194
1195template<int Format, bool IsFloat = IsFloatFormat<Format>::Value, bool IsHalfFloat = IsHalfFloatFormat<Format>::Value, bool Is16bpp = Is16bppFormat<Format>::Value>
1196struct DataTypeForFormat {
1197    typedef uint8_t Type;
1198};
1199
1200template<int Format>
1201struct DataTypeForFormat<Format, true, false, false> {
1202    typedef float Type;
1203};
1204
1205template<int Format>
1206struct DataTypeForFormat<Format, false, true, false> {
1207    typedef uint16_t Type;
1208};
1209
1210template<int Format>
1211struct DataTypeForFormat<Format, false, false, true> {
1212    typedef uint16_t Type;
1213};
1214
1215template<int Format>
1216struct IntermediateFormat {
1217    static const int Value = (IsFloatFormat<Format>::Value || IsHalfFloatFormat<Format>::Value) ? WebGLImageConversion::DataFormatRGBA32F : WebGLImageConversion::DataFormatRGBA8;
1218};
1219
1220unsigned TexelBytesForFormat(WebGLImageConversion::DataFormat format)
1221{
1222    switch (format) {
1223    case WebGLImageConversion::DataFormatR8:
1224    case WebGLImageConversion::DataFormatA8:
1225        return 1;
1226    case WebGLImageConversion::DataFormatRA8:
1227    case WebGLImageConversion::DataFormatAR8:
1228    case WebGLImageConversion::DataFormatRGBA5551:
1229    case WebGLImageConversion::DataFormatRGBA4444:
1230    case WebGLImageConversion::DataFormatRGB565:
1231    case WebGLImageConversion::DataFormatA16F:
1232    case WebGLImageConversion::DataFormatR16F:
1233        return 2;
1234    case WebGLImageConversion::DataFormatRGB8:
1235    case WebGLImageConversion::DataFormatBGR8:
1236        return 3;
1237    case WebGLImageConversion::DataFormatRGBA8:
1238    case WebGLImageConversion::DataFormatARGB8:
1239    case WebGLImageConversion::DataFormatABGR8:
1240    case WebGLImageConversion::DataFormatBGRA8:
1241    case WebGLImageConversion::DataFormatR32F:
1242    case WebGLImageConversion::DataFormatA32F:
1243    case WebGLImageConversion::DataFormatRA16F:
1244        return 4;
1245    case WebGLImageConversion::DataFormatRGB16F:
1246        return 6;
1247    case WebGLImageConversion::DataFormatRA32F:
1248    case WebGLImageConversion::DataFormatRGBA16F:
1249        return 8;
1250    case WebGLImageConversion::DataFormatRGB32F:
1251        return 12;
1252    case WebGLImageConversion::DataFormatRGBA32F:
1253        return 16;
1254    default:
1255        return 0;
1256    }
1257}
1258
1259/* END CODE SHARED WITH MOZILLA FIREFOX */
1260
1261class FormatConverter {
1262public:
1263    FormatConverter(unsigned width, unsigned height,
1264        const void* srcStart, void* dstStart, int srcStride, int dstStride)
1265        : m_width(width), m_height(height), m_srcStart(srcStart), m_dstStart(dstStart), m_srcStride(srcStride), m_dstStride(dstStride), m_success(false)
1266    {
1267        const unsigned MaxNumberOfComponents = 4;
1268        const unsigned MaxBytesPerComponent  = 4;
1269        m_unpackedIntermediateSrcData = adoptArrayPtr(new uint8_t[m_width * MaxNumberOfComponents *MaxBytesPerComponent]);
1270        ASSERT(m_unpackedIntermediateSrcData.get());
1271    }
1272
1273    void convert(WebGLImageConversion::DataFormat srcFormat, WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp);
1274    bool Success() const { return m_success; }
1275
1276private:
1277    template<WebGLImageConversion::DataFormat SrcFormat>
1278    void convert(WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp);
1279
1280    template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat>
1281    void convert(WebGLImageConversion::AlphaOp);
1282
1283    template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat, WebGLImageConversion::AlphaOp alphaOp>
1284    void convert();
1285
1286    const unsigned m_width, m_height;
1287    const void* const m_srcStart;
1288    void* const m_dstStart;
1289    const int m_srcStride, m_dstStride;
1290    bool m_success;
1291    OwnPtr<uint8_t[]> m_unpackedIntermediateSrcData;
1292};
1293
1294void FormatConverter::convert(WebGLImageConversion::DataFormat srcFormat, WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp alphaOp)
1295{
1296#define FORMATCONVERTER_CASE_SRCFORMAT(SrcFormat) \
1297    case SrcFormat: \
1298        return convert<SrcFormat>(dstFormat, alphaOp);
1299
1300        switch (srcFormat) {
1301            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatR8)
1302            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatA8)
1303            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatR32F)
1304            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatA32F)
1305            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA8)
1306            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA32F)
1307            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB8)
1308            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatBGR8)
1309            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB565)
1310            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB32F)
1311            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA8)
1312            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatARGB8)
1313            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatABGR8)
1314            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatAR8)
1315            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatBGRA8)
1316            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA5551)
1317            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA4444)
1318            FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA32F)
1319        default:
1320            ASSERT_NOT_REACHED();
1321        }
1322#undef FORMATCONVERTER_CASE_SRCFORMAT
1323}
1324
1325template<WebGLImageConversion::DataFormat SrcFormat>
1326void FormatConverter::convert(WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp alphaOp)
1327{
1328#define FORMATCONVERTER_CASE_DSTFORMAT(DstFormat) \
1329    case DstFormat: \
1330        return convert<SrcFormat, DstFormat>(alphaOp);
1331
1332        switch (dstFormat) {
1333            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR8)
1334            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR16F)
1335            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR32F)
1336            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA8)
1337            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA16F)
1338            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA32F)
1339            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA8)
1340            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA16F)
1341            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA32F)
1342            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB8)
1343            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB565)
1344            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB16F)
1345            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB32F)
1346            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA8)
1347            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA5551)
1348            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA4444)
1349            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA16F)
1350            FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA32F)
1351        default:
1352            ASSERT_NOT_REACHED();
1353        }
1354
1355#undef FORMATCONVERTER_CASE_DSTFORMAT
1356}
1357
1358template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat>
1359void FormatConverter::convert(WebGLImageConversion::AlphaOp alphaOp)
1360{
1361#define FORMATCONVERTER_CASE_ALPHAOP(alphaOp) \
1362    case alphaOp: \
1363        return convert<SrcFormat, DstFormat, alphaOp>();
1364
1365        switch (alphaOp) {
1366            FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoNothing)
1367            FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoPremultiply)
1368            FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoUnmultiply)
1369        default:
1370            ASSERT_NOT_REACHED();
1371        }
1372#undef FORMATCONVERTER_CASE_ALPHAOP
1373}
1374
1375template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat, WebGLImageConversion::AlphaOp alphaOp>
1376void FormatConverter::convert()
1377{
1378    // Many instantiations of this template function will never be entered, so we try
1379    // to return immediately in these cases to avoid the compiler to generate useless code.
1380    if (SrcFormat == DstFormat && alphaOp == WebGLImageConversion::AlphaDoNothing) {
1381        ASSERT_NOT_REACHED();
1382        return;
1383    }
1384    if (!IsFloatFormat<DstFormat>::Value && IsFloatFormat<SrcFormat>::Value) {
1385        ASSERT_NOT_REACHED();
1386        return;
1387    }
1388
1389    // Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat.
1390    const bool srcFormatComesFromDOMElementOrImageData = WebGLImageConversion::srcFormatComeFromDOMElementOrImageData(SrcFormat);
1391    if (!srcFormatComesFromDOMElementOrImageData && SrcFormat != DstFormat) {
1392        ASSERT_NOT_REACHED();
1393        return;
1394    }
1395    // Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied.
1396    if (!srcFormatComesFromDOMElementOrImageData && alphaOp == WebGLImageConversion::AlphaDoUnmultiply) {
1397        ASSERT_NOT_REACHED();
1398        return;
1399    }
1400    if ((!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) && alphaOp != WebGLImageConversion::AlphaDoNothing) {
1401        ASSERT_NOT_REACHED();
1402        return;
1403    }
1404
1405    typedef typename DataTypeForFormat<SrcFormat>::Type SrcType;
1406    typedef typename DataTypeForFormat<DstFormat>::Type DstType;
1407    const int IntermediateSrcFormat = IntermediateFormat<DstFormat>::Value;
1408    typedef typename DataTypeForFormat<IntermediateSrcFormat>::Type IntermediateSrcType;
1409    const ptrdiff_t srcStrideInElements = m_srcStride / sizeof(SrcType);
1410    const ptrdiff_t dstStrideInElements = m_dstStride / sizeof(DstType);
1411    const bool trivialUnpack = (SrcFormat == WebGLImageConversion::DataFormatRGBA8 && !IsFloatFormat<DstFormat>::Value && !IsHalfFloatFormat<DstFormat>::Value) || SrcFormat == WebGLImageConversion::DataFormatRGBA32F;
1412    const bool trivialPack = (DstFormat == WebGLImageConversion::DataFormatRGBA8 || DstFormat == WebGLImageConversion::DataFormatRGBA32F) && alphaOp == WebGLImageConversion::AlphaDoNothing && m_dstStride > 0;
1413    ASSERT(!trivialUnpack || !trivialPack);
1414
1415    const SrcType *srcRowStart = static_cast<const SrcType*>(m_srcStart);
1416    DstType* dstRowStart = static_cast<DstType*>(m_dstStart);
1417    if (!trivialUnpack && trivialPack) {
1418        for (size_t i = 0; i < m_height; ++i) {
1419            unpack<SrcFormat>(srcRowStart, dstRowStart, m_width);
1420            srcRowStart += srcStrideInElements;
1421            dstRowStart += dstStrideInElements;
1422        }
1423    } else if (!trivialUnpack && !trivialPack) {
1424        for (size_t i = 0; i < m_height; ++i) {
1425            unpack<SrcFormat>(srcRowStart, reinterpret_cast<IntermediateSrcType*>(m_unpackedIntermediateSrcData.get()), m_width);
1426            pack<DstFormat, alphaOp>(reinterpret_cast<IntermediateSrcType*>(m_unpackedIntermediateSrcData.get()), dstRowStart, m_width);
1427            srcRowStart += srcStrideInElements;
1428            dstRowStart += dstStrideInElements;
1429        }
1430    } else {
1431        for (size_t i = 0; i < m_height; ++i) {
1432            pack<DstFormat, alphaOp>(srcRowStart, dstRowStart, m_width);
1433            srcRowStart += srcStrideInElements;
1434            dstRowStart += dstStrideInElements;
1435        }
1436    }
1437    m_success = true;
1438    return;
1439}
1440
1441} // anonymous namespace
1442
1443bool WebGLImageConversion::computeFormatAndTypeParameters(GLenum format, GLenum type, unsigned* componentsPerPixel, unsigned* bytesPerComponent)
1444{
1445    switch (format) {
1446    case GL_ALPHA:
1447    case GL_LUMINANCE:
1448    case GL_DEPTH_COMPONENT:
1449    case GL_DEPTH_STENCIL_OES:
1450        *componentsPerPixel = 1;
1451        break;
1452    case GL_LUMINANCE_ALPHA:
1453        *componentsPerPixel = 2;
1454        break;
1455    case GL_RGB:
1456        *componentsPerPixel = 3;
1457        break;
1458    case GL_RGBA:
1459    case GL_BGRA_EXT: // GL_EXT_texture_format_BGRA8888
1460        *componentsPerPixel = 4;
1461        break;
1462    default:
1463        return false;
1464    }
1465    switch (type) {
1466    case GL_UNSIGNED_BYTE:
1467        *bytesPerComponent = sizeof(GLubyte);
1468        break;
1469    case GL_UNSIGNED_SHORT:
1470        *bytesPerComponent = sizeof(GLushort);
1471        break;
1472    case GL_UNSIGNED_SHORT_5_6_5:
1473    case GL_UNSIGNED_SHORT_4_4_4_4:
1474    case GL_UNSIGNED_SHORT_5_5_5_1:
1475        *componentsPerPixel = 1;
1476        *bytesPerComponent = sizeof(GLushort);
1477        break;
1478    case GL_UNSIGNED_INT_24_8_OES:
1479    case GL_UNSIGNED_INT:
1480        *bytesPerComponent = sizeof(GLuint);
1481        break;
1482    case GL_FLOAT: // OES_texture_float
1483        *bytesPerComponent = sizeof(GLfloat);
1484        break;
1485    case GL_HALF_FLOAT_OES: // OES_texture_half_float
1486        *bytesPerComponent = sizeof(GLushort);
1487        break;
1488    default:
1489        return false;
1490    }
1491    return true;
1492}
1493
1494GLenum WebGLImageConversion::computeImageSizeInBytes(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, unsigned* imageSizeInBytes, unsigned* paddingInBytes)
1495{
1496    ASSERT(imageSizeInBytes);
1497    ASSERT(alignment == 1 || alignment == 2 || alignment == 4 || alignment == 8);
1498    if (width < 0 || height < 0)
1499        return GL_INVALID_VALUE;
1500    unsigned bytesPerComponent, componentsPerPixel;
1501    if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent, &componentsPerPixel))
1502        return GL_INVALID_ENUM;
1503    if (!width || !height) {
1504        *imageSizeInBytes = 0;
1505        if (paddingInBytes)
1506            *paddingInBytes = 0;
1507        return GL_NO_ERROR;
1508    }
1509    CheckedInt<uint32_t> checkedValue(bytesPerComponent * componentsPerPixel);
1510    checkedValue *=  width;
1511    if (!checkedValue.isValid())
1512        return GL_INVALID_VALUE;
1513    unsigned validRowSize = checkedValue.value();
1514    unsigned padding = 0;
1515    unsigned residual = validRowSize % alignment;
1516    if (residual) {
1517        padding = alignment - residual;
1518        checkedValue += padding;
1519    }
1520    // Last row needs no padding.
1521    checkedValue *= (height - 1);
1522    checkedValue += validRowSize;
1523    if (!checkedValue.isValid())
1524        return GL_INVALID_VALUE;
1525    *imageSizeInBytes = checkedValue.value();
1526    if (paddingInBytes)
1527        *paddingInBytes = padding;
1528    return GL_NO_ERROR;
1529}
1530
1531WebGLImageConversion::ImageExtractor::ImageExtractor(Image* image, ImageHtmlDomSource imageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile)
1532{
1533    m_image = image;
1534    m_imageHtmlDomSource = imageHtmlDomSource;
1535    m_extractSucceeded = extractImage(premultiplyAlpha, ignoreGammaAndColorProfile);
1536}
1537
1538WebGLImageConversion::ImageExtractor::~ImageExtractor()
1539{
1540    if (m_skiaImage)
1541        m_skiaImage->bitmap().unlockPixels();
1542}
1543
1544bool WebGLImageConversion::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile)
1545{
1546    if (!m_image)
1547        return false;
1548    m_skiaImage = m_image->nativeImageForCurrentFrame();
1549    m_alphaOp = AlphaDoNothing;
1550    bool hasAlpha = m_skiaImage ? !m_skiaImage->bitmap().isOpaque() : true;
1551    if ((!m_skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && m_image->data()) {
1552        // Attempt to get raw unpremultiplied image data.
1553        OwnPtr<ImageDecoder> decoder(ImageDecoder::create(
1554            *(m_image->data()), ImageSource::AlphaNotPremultiplied,
1555            ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied));
1556        if (!decoder)
1557            return false;
1558        decoder->setData(m_image->data(), true);
1559        if (!decoder->frameCount())
1560            return false;
1561        ImageFrame* frame = decoder->frameBufferAtIndex(0);
1562        if (!frame || frame->status() != ImageFrame::FrameComplete)
1563            return false;
1564        hasAlpha = frame->hasAlpha();
1565        m_nativeImage = frame->asNewNativeImage();
1566        if (!m_nativeImage.get() || !m_nativeImage->isDataComplete() || !m_nativeImage->bitmap().width() || !m_nativeImage->bitmap().height())
1567            return false;
1568        if (m_nativeImage->bitmap().colorType() != kN32_SkColorType)
1569            return false;
1570        m_skiaImage = m_nativeImage.get();
1571        if (hasAlpha && premultiplyAlpha)
1572            m_alphaOp = AlphaDoPremultiply;
1573    } else if (!premultiplyAlpha && hasAlpha) {
1574        // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value for each pixel is 0xFF
1575        // which is true at present and may be changed in the future and needs adjustment accordingly.
1576        // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port,
1577        // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false.
1578        if (m_imageHtmlDomSource != HtmlDomVideo)
1579            m_alphaOp = AlphaDoUnmultiply;
1580    }
1581    if (!m_skiaImage)
1582        return false;
1583
1584    m_imageSourceFormat = SK_B32_SHIFT ? DataFormatRGBA8 : DataFormatBGRA8;
1585    m_imageWidth = m_skiaImage->bitmap().width();
1586    m_imageHeight = m_skiaImage->bitmap().height();
1587    if (!m_imageWidth || !m_imageHeight) {
1588        m_skiaImage.clear();
1589        return false;
1590    }
1591    // Fail if the image was downsampled because of memory limits.
1592    if (m_imageWidth != (unsigned)m_image->size().width() || m_imageHeight != (unsigned)m_image->size().height()) {
1593        m_skiaImage.clear();
1594        return false;
1595    }
1596    m_imageSourceUnpackAlignment = 0;
1597    m_skiaImage->bitmap().lockPixels();
1598    m_imagePixelData = m_skiaImage->bitmap().getPixels();
1599    return true;
1600}
1601
1602unsigned WebGLImageConversion::getClearBitsByFormat(GLenum format)
1603{
1604    switch (format) {
1605    case GL_ALPHA:
1606    case GL_LUMINANCE:
1607    case GL_LUMINANCE_ALPHA:
1608    case GL_RGB:
1609    case GL_RGB565:
1610    case GL_RGBA:
1611    case GL_RGBA4:
1612    case GL_RGB5_A1:
1613        return GL_COLOR_BUFFER_BIT;
1614    case GL_DEPTH_COMPONENT16:
1615    case GL_DEPTH_COMPONENT:
1616        return GL_DEPTH_BUFFER_BIT;
1617    case GL_STENCIL_INDEX8:
1618        return GL_STENCIL_BUFFER_BIT;
1619    case GL_DEPTH_STENCIL_OES:
1620        return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
1621    default:
1622        return 0;
1623    }
1624}
1625
1626unsigned WebGLImageConversion::getChannelBitsByFormat(GLenum format)
1627{
1628    switch (format) {
1629    case GL_ALPHA:
1630        return ChannelAlpha;
1631    case GL_LUMINANCE:
1632        return ChannelRGB;
1633    case GL_LUMINANCE_ALPHA:
1634        return ChannelRGBA;
1635    case GL_RGB:
1636    case GL_RGB565:
1637        return ChannelRGB;
1638    case GL_RGBA:
1639    case GL_RGBA4:
1640    case GL_RGB5_A1:
1641        return ChannelRGBA;
1642    case GL_DEPTH_COMPONENT16:
1643    case GL_DEPTH_COMPONENT:
1644        return ChannelDepth;
1645    case GL_STENCIL_INDEX8:
1646        return ChannelStencil;
1647    case GL_DEPTH_STENCIL_OES:
1648        return ChannelDepth | ChannelStencil;
1649    default:
1650        return 0;
1651    }
1652}
1653
1654bool WebGLImageConversion::packImageData(
1655    Image* image,
1656    const void* pixels,
1657    GLenum format,
1658    GLenum type,
1659    bool flipY,
1660    AlphaOp alphaOp,
1661    DataFormat sourceFormat,
1662    unsigned width,
1663    unsigned height,
1664    unsigned sourceUnpackAlignment,
1665    Vector<uint8_t>& data)
1666{
1667    if (!pixels)
1668        return false;
1669
1670    unsigned packedSize;
1671    // Output data is tightly packed (alignment == 1).
1672    if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GL_NO_ERROR)
1673        return false;
1674    data.resize(packedSize);
1675
1676    if (!packPixels(reinterpret_cast<const uint8_t*>(pixels), sourceFormat, width, height, sourceUnpackAlignment, format, type, alphaOp, data.data(), flipY))
1677        return false;
1678    if (ImageObserver *observer = image->imageObserver())
1679        observer->didDraw(image);
1680    return true;
1681}
1682
1683bool WebGLImageConversion::extractImageData(
1684    const uint8_t* imageData,
1685    const IntSize& imageDataSize,
1686    GLenum format,
1687    GLenum type,
1688    bool flipY,
1689    bool premultiplyAlpha,
1690    Vector<uint8_t>& data)
1691{
1692    if (!imageData)
1693        return false;
1694    int width = imageDataSize.width();
1695    int height = imageDataSize.height();
1696
1697    unsigned packedSize;
1698    // Output data is tightly packed (alignment == 1).
1699    if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GL_NO_ERROR)
1700        return false;
1701    data.resize(packedSize);
1702
1703    if (!packPixels(imageData, DataFormatRGBA8, width, height, 0, format, type, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing, data.data(), flipY))
1704        return false;
1705
1706    return true;
1707}
1708
1709bool WebGLImageConversion::extractTextureData(
1710    unsigned width,
1711    unsigned height,
1712    GLenum format, GLenum type,
1713    unsigned unpackAlignment,
1714    bool flipY, bool premultiplyAlpha,
1715    const void* pixels,
1716    Vector<uint8_t>& data)
1717{
1718    // Assumes format, type, etc. have already been validated.
1719    DataFormat sourceDataFormat = getDataFormat(format, type);
1720
1721    // Resize the output buffer.
1722    unsigned int componentsPerPixel, bytesPerComponent;
1723    if (!computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent))
1724        return false;
1725    unsigned bytesPerPixel = componentsPerPixel * bytesPerComponent;
1726    data.resize(width * height * bytesPerPixel);
1727
1728    if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width, height, unpackAlignment, format, type, (premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing), data.data(), flipY))
1729        return false;
1730
1731    return true;
1732}
1733
1734bool WebGLImageConversion::packPixels(
1735    const uint8_t* sourceData,
1736    DataFormat sourceDataFormat,
1737    unsigned width,
1738    unsigned height,
1739    unsigned sourceUnpackAlignment,
1740    unsigned destinationFormat,
1741    unsigned destinationType,
1742    AlphaOp alphaOp,
1743    void* destinationData,
1744    bool flipY)
1745{
1746    int validSrc = width * TexelBytesForFormat(sourceDataFormat);
1747    int remainder = sourceUnpackAlignment ? (validSrc % sourceUnpackAlignment) : 0;
1748    int srcStride = remainder ? (validSrc + sourceUnpackAlignment - remainder) : validSrc;
1749
1750    DataFormat dstDataFormat = getDataFormat(destinationFormat, destinationType);
1751    int dstStride = width * TexelBytesForFormat(dstDataFormat);
1752    if (flipY) {
1753        destinationData = static_cast<uint8_t*>(destinationData) + dstStride*(height - 1);
1754        dstStride = -dstStride;
1755    }
1756    if (!HasAlpha(sourceDataFormat) || !HasColor(sourceDataFormat) || !HasColor(dstDataFormat))
1757        alphaOp = AlphaDoNothing;
1758
1759    if (sourceDataFormat == dstDataFormat && alphaOp == AlphaDoNothing) {
1760        const uint8_t* ptr = sourceData;
1761        const uint8_t* ptrEnd = sourceData + srcStride * height;
1762        unsigned rowSize = (dstStride > 0) ? dstStride: -dstStride;
1763        uint8_t* dst = static_cast<uint8_t*>(destinationData);
1764        while (ptr < ptrEnd) {
1765            memcpy(dst, ptr, rowSize);
1766            ptr += srcStride;
1767            dst += dstStride;
1768        }
1769        return true;
1770    }
1771
1772    FormatConverter converter(width, height, sourceData, destinationData, srcStride, dstStride);
1773    converter.convert(sourceDataFormat, dstDataFormat, alphaOp);
1774    if (!converter.Success())
1775        return false;
1776    return true;
1777}
1778
1779} // namespace blink
1780