Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webgl / src / sdk / tests / conformance / textures / tex-image-with-format-and-type.html
1 <!--
2
3 /*
4 ** Copyright (c) 2012 The Khronos Group Inc.
5 **
6 ** Permission is hereby granted, free of charge, to any person obtaining a
7 ** copy of this software and/or associated documentation files (the
8 ** "Materials"), to deal in the Materials without restriction, including
9 ** without limitation the rights to use, copy, modify, merge, publish,
10 ** distribute, sublicense, and/or sell copies of the Materials, and to
11 ** permit persons to whom the Materials are furnished to do so, subject to
12 ** the following conditions:
13 **
14 ** The above copyright notice and this permission notice shall be included
15 ** in all copies or substantial portions of the Materials.
16 **
17 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
24 */
25
26 -->
27
28 <!DOCTYPE html>
29 <html>
30 <head>
31 <meta charset="utf-8">
32 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
33 <script src="../../resources/js-test-pre.js"></script>
34 <script src="../resources/pnglib.js"></script>
35 <script src="../resources/webgl-test-utils.js"></script>
36
37 <script>
38 "use strict";
39 var wtu = WebGLTestUtils;
40 var gl = null;
41 var textureLoc = null;
42 var successfullyParsed = false;
43
44 //----------------------------------------------------------------------
45 // Harness
46
47 var testCases = [];
48
49 var DataMode = {
50     IMAGE: 0,
51     IMAGE_DATA: 1,
52
53     NUM_HTML_MODES: 2,
54
55     RAW_DATA: 2,
56
57     // This must remain the last mode.
58     NUM_MODES: 3
59 };
60
61 function init()
62 {
63     description('Verify texImage2D and texSubImage2D code paths taking both HTML and user-specified data with all format/type combinations');
64
65     var canvas = document.getElementById("example");
66     gl = wtu.create3DContext(canvas);
67     gl.disable(gl.DITHER);
68     var program = wtu.setupTexturedQuad(gl);
69
70     gl.clearColor(0,0,0,1);
71     gl.clearDepth(1);
72     gl.disable(gl.BLEND);
73
74     textureLoc = gl.getUniformLocation(program, "tex");
75
76     initializeTests();
77 }
78
79 function initializeTests()
80 {
81     // Verify that uploading to packed pixel formats performs the
82     // required conversion and associated loss of precision.
83     for (var dataMode = 0; dataMode < DataMode.NUM_HTML_MODES; ++dataMode) {
84         for (var useTexSubImage2D = 0; useTexSubImage2D < 2; ++useTexSubImage2D) {
85             testCases.push({
86                 dataMode: dataMode,
87                 useTexSubImage2D: !!useTexSubImage2D,
88                 width: 256,
89                 height: 1,
90                 generator: generateOpaqueGrayscaleRamp,
91                 premultiplyAlpha: false,
92                 format: gl.RGBA,
93                 type: gl.UNSIGNED_BYTE,
94                 verifier: allChannelsIncreaseByNoMoreThan,
95                 threshold: 1,
96                 numOccurrences: 1,
97                 description: "RGBA/UNSIGNED_BYTE should maintain full precision of data"
98             });
99             testCases.push({
100                 dataMode: dataMode,
101                 useTexSubImage2D: !!useTexSubImage2D,
102                 width: 256,
103                 height: 1,
104                 generator: generateOpaqueGrayscaleRamp,
105                 premultiplyAlpha: false,
106                 format: gl.RGBA,
107                 type: gl.UNSIGNED_SHORT_4_4_4_4,
108                 verifier: allChannelsIncreaseByAtLeast,
109                 threshold: 15,
110                 numOccurrences: 10,
111                 description: "RGBA/UNSIGNED_SHORT_4_4_4_4 must drop low four bits of precision"
112             });
113             testCases.push({
114                 dataMode: dataMode,
115                 useTexSubImage2D: !!useTexSubImage2D,
116                 width: 256,
117                 height: 1,
118                 generator: generateOpaqueGrayscaleRamp,
119                 premultiplyAlpha: false,
120                 format: gl.RGBA,
121                 type: gl.UNSIGNED_SHORT_5_5_5_1,
122                 verifier: allChannelsIncreaseByAtLeast,
123                 threshold: 7,
124                 numOccurrences: 20,
125                 description: "RGBA/UNSIGNED_SHORT_5_5_5_1 must drop low three bits of precision"
126             });
127             testCases.push({
128                 dataMode: dataMode,
129                 useTexSubImage2D: !!useTexSubImage2D,
130                 width: 256,
131                 height: 1,
132                 generator: generateOpaqueGrayscaleRamp,
133                 premultiplyAlpha: false,
134                 format: gl.RGB,
135                 type: gl.UNSIGNED_BYTE,
136                 verifier: allChannelsIncreaseByNoMoreThan,
137                 threshold: 1,
138                 numOccurrences: 1,
139                 description: "RGB/UNSIGNED_BYTE should maintain full precision of data"
140             });
141             testCases.push({
142                 dataMode: dataMode,
143                 useTexSubImage2D: !!useTexSubImage2D,
144                 width: 256,
145                 height: 1,
146                 generator: generateOpaqueGrayscaleRamp,
147                 premultiplyAlpha: false,
148                 format: gl.RGB,
149                 type: gl.UNSIGNED_SHORT_5_6_5,
150                 verifier: allChannelsIncreaseByAtLeast,
151                 threshold: 3,
152                 numOccurrences: 20,
153                 description: "RGB/UNSIGNED_SHORT_5_6_5 must drop low two or three bits of precision"
154             });
155             testCases.push({
156                 dataMode: dataMode,
157                 useTexSubImage2D: !!useTexSubImage2D,
158                 width: 256,
159                 height: 1,
160                 generator: generateTranslucentGrayscaleRamp,
161                 premultiplyAlpha: false,
162                 format: gl.ALPHA,
163                 type: gl.UNSIGNED_BYTE,
164                 verifier: alphaChannelIncreasesByNoMoreThan,
165                 threshold: 1,
166                 numOccurrences: 1,
167                 description: "ALPHA/UNSIGNED_BYTE should maintain full precision of data"
168             });
169             testCases.push({
170                 dataMode: dataMode,
171                 useTexSubImage2D: !!useTexSubImage2D,
172                 width: 256,
173                 height: 1,
174                 generator: generateOpaqueGrayscaleRamp,
175                 premultiplyAlpha: false,
176                 format: gl.LUMINANCE,
177                 type: gl.UNSIGNED_BYTE,
178                 verifier: allChannelsIncreaseByNoMoreThan,
179                 threshold: 1,
180                 numOccurrences: 1,
181                 description: "LUMINANCE/UNSIGNED_BYTE should maintain full precision of data"
182             });
183             testCases.push({
184                 dataMode: dataMode,
185                 useTexSubImage2D: !!useTexSubImage2D,
186                 width: 256,
187                 height: 1,
188                 generator: generateOpaqueGrayscaleRamp,
189                 premultiplyAlpha: false,
190                 format: gl.LUMINANCE_ALPHA,
191                 type: gl.UNSIGNED_BYTE,
192                 verifier: allChannelsIncreaseByNoMoreThan,
193                 threshold: 1,
194                 numOccurrences: 1,
195                 description: "LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data"
196             });
197         }
198     }
199
200     // Verify that setting the UNPACK_PREMULTIPLY_ALPHA_WEBGL pixel
201     // store parameter and sending down a zero alpha causes the color
202     // channels to go to zero.
203     for (var dataMode = 0; dataMode < DataMode.NUM_MODES; ++dataMode) {
204         for (var useTexSubImage2D = 0; useTexSubImage2D < 2; ++useTexSubImage2D) {
205             testCases.push({
206                 dataMode: dataMode,
207                 useTexSubImage2D: !!useTexSubImage2D,
208                 width: 256,
209                 height: 1,
210                 generator: generateTransparentGrayscaleRamp,
211                 premultiplyAlpha: true,
212                 format: gl.RGBA,
213                 type: gl.UNSIGNED_BYTE,
214                 verifier: colorChannelsAreZero,
215                 description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_BYTE"
216             });
217             testCases.push({
218                 dataMode: dataMode,
219                 useTexSubImage2D: !!useTexSubImage2D,
220                 width: 256,
221                 height: 1,
222                 generator: generateTransparentGrayscaleRamp,
223                 premultiplyAlpha: true,
224                 format: gl.RGBA,
225                 type: gl.UNSIGNED_SHORT_4_4_4_4,
226                 verifier: colorChannelsAreZero,
227                 description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_4_4_4_4"
228             });
229             testCases.push({
230                 dataMode: dataMode,
231                 useTexSubImage2D: !!useTexSubImage2D,
232                 width: 256,
233                 height: 1,
234                 generator: generateTransparentGrayscaleRamp,
235                 premultiplyAlpha: true,
236                 format: gl.RGBA,
237                 type: gl.UNSIGNED_SHORT_5_5_5_1,
238                 verifier: colorChannelsAreZero,
239                 description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_5_5_5_1"
240             });
241             // The following few tests are invalid for the raw data
242             // mode because there is either no alpha channel or no
243             // separate alpha channel.
244             if (dataMode != DataMode.RAW_DATA) {
245                 testCases.push({
246                     dataMode: dataMode,
247                     useTexSubImage2D: !!useTexSubImage2D,
248                     width: 256,
249                     height: 1,
250                     generator: generateTransparentGrayscaleRamp,
251                     premultiplyAlpha: true,
252                     format: gl.RGB,
253                     type: gl.UNSIGNED_BYTE,
254                     verifier: colorChannelsAreZero,
255                     description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGB/UNSIGNED_BYTE"
256                 });
257                 testCases.push({
258                     dataMode: dataMode,
259                     useTexSubImage2D: !!useTexSubImage2D,
260                     width: 256,
261                     height: 1,
262                     generator: generateTransparentGrayscaleRamp,
263                     premultiplyAlpha: true,
264                     format: gl.RGB,
265                     type: gl.UNSIGNED_SHORT_5_6_5,
266                     verifier: colorChannelsAreZero,
267                     description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGB/UNSIGNED_SHORT_5_6_5"
268                 });
269                 testCases.push({
270                     dataMode: dataMode,
271                     useTexSubImage2D: !!useTexSubImage2D,
272                     width: 256,
273                     height: 1,
274                     generator: generateTransparentGrayscaleRamp,
275                     premultiplyAlpha: true,
276                     format: gl.ALPHA,
277                     type: gl.UNSIGNED_BYTE,
278                     verifier: colorChannelsAreZero,
279                     description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with ALPHA/UNSIGNED_BYTE"
280                 });
281                 testCases.push({
282                     dataMode: dataMode,
283                     useTexSubImage2D: !!useTexSubImage2D,
284                     width: 256,
285                     height: 1,
286                     generator: generateTransparentGrayscaleRamp,
287                     premultiplyAlpha: true,
288                     format: gl.LUMINANCE,
289                     type: gl.UNSIGNED_BYTE,
290                     verifier: colorChannelsAreZero,
291                     description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with LUMINANCE/UNSIGNED_BYTE"
292                 });
293             }
294             testCases.push({
295                 dataMode: dataMode,
296                 useTexSubImage2D: !!useTexSubImage2D,
297                 width: 256,
298                 height: 1,
299                 generator: generateTransparentGrayscaleRamp,
300                 premultiplyAlpha: true,
301                 format: gl.LUMINANCE_ALPHA,
302                 type: gl.UNSIGNED_BYTE,
303                 verifier: colorChannelsAreZero,
304                 description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with LUMINANCE_ALPHA/UNSIGNED_BYTE"
305             });
306         }
307     }
308
309     // Produce data for all testcases. Because we load images, some of
310     // these may generate their data asynchronously.
311     generateTestData();
312 }
313
314 function generateTestData()
315 {
316     for (var i = 0; i < testCases.length; i++) {
317         var testCase = testCases[i];
318         var wrapper = null;
319         switch (testCase.dataMode) {
320         case DataMode.IMAGE:
321             wrapper = new ImageWrapper(testCase.width, testCase.height);
322             break;
323         case DataMode.IMAGE_DATA:
324             wrapper = new ImageDataWrapper(testCase.width, testCase.height);
325             break;
326         case DataMode.RAW_DATA:
327             switch (testCase.type) {
328             case gl.UNSIGNED_BYTE:
329                 switch (testCase.format) {
330                 case gl.RGBA:
331                     wrapper = new RGBA8DataWrapper(testCase.width, testCase.height);
332                     break;
333                 case gl.RGB:
334                     wrapper = new RGB8DataWrapper(testCase.width, testCase.height);
335                     break;
336                 case gl.ALPHA:
337                     wrapper = new A8DataWrapper(testCase.width, testCase.height);
338                     break;
339                 case gl.LUMINANCE:
340                     wrapper = new L8DataWrapper(testCase.width, testCase.height);
341                     break;
342                 case gl.LUMINANCE_ALPHA:
343                     wrapper = new LA8DataWrapper(testCase.width, testCase.height);
344                     break;
345                 }
346                 break;
347             case gl.UNSIGNED_SHORT_4_4_4_4:
348                 wrapper = new RGBA4444DataWrapper(testCase.width, testCase.height);
349                 break;
350             case gl.UNSIGNED_SHORT_5_5_5_1:
351                 wrapper = new RGBA5551DataWrapper(testCase.width, testCase.height);
352                 break;
353             case gl.UNSIGNED_SHORT_5_6_5:
354                 wrapper = new RGB565DataWrapper(testCase.width, testCase.height);
355                 break;
356             }
357         }
358         testCase.wrapper = wrapper;
359         testCase.generator(wrapper);
360         testCase.wrapper.generateData();
361     }
362
363     // See whether we need to run the tests, in case all of them
364     // generated their results synchronously.
365     maybeRunTests();
366 }
367
368 var ranTests = false;
369
370 function maybeRunTests()
371 {
372     if (!ranTests)
373         for (var i = 0; i < testCases.length; ++i)
374             if (!testCases[i].wrapper || !testCases[i].wrapper.data)
375                 return;
376
377     ranTests = true;
378
379     for (var i = 0; i < testCases.length; ++i)
380         runOneTest(testCases[i]);
381
382     finishTest();
383 }
384
385 function testCaseToString(testCase)
386 {
387     var mode;
388     switch (testCase.dataMode) {
389     case DataMode.IMAGE:
390         mode = "Image";
391         break;
392     case DataMode.IMAGE_DATA:
393         mode = "ImageData";
394         break;
395     case DataMode.RAW_DATA:
396         mode = "raw data";
397         break;
398     }
399     return (testCase.useTexSubImage2D ? "texSubImage2D" : "texImage2D") +
400             " with " + mode +  " at " + testCase.width + "x" + testCase.height;
401 }
402
403 function runOneTest(testCase)
404 {
405     debug("Testing " + testCaseToString(testCase));
406     var data = testCase.wrapper.data;
407     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
408     var texture = gl.createTexture();
409     // Bind the texture to texture unit 0.
410     gl.bindTexture(gl.TEXTURE_2D, texture);
411     // Set up texture parameters.
412     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
413     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
414     // Set up pixel store parameters.
415     gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, testCase.premultiplyAlpha);
416     // Upload the image into the texture.
417     if (testCase.useTexSubImage2D) {
418         // Initialize the texture to black first.
419         gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.width, testCase.height, 0,
420                       testCase.format, testCase.type, null);
421     }
422     switch (testCase.dataMode) {
423     case DataMode.IMAGE:
424     case DataMode.IMAGE_DATA:
425         if (testCase.useTexSubImage2D)
426             gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, testCase.format, testCase.type, data);
427         else
428             gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.format, testCase.type, data);
429         break;
430     case DataMode.RAW_DATA:
431         if (testCase.useTexSubImage2D)
432             gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, testCase.width, testCase.height, testCase.format, testCase.type, data);
433         else
434             gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.width, testCase.height, 0, testCase.format, testCase.type, data);
435         break;
436     }
437     // Point the uniform sampler to texture unit 0.
438     gl.uniform1i(textureLoc, 0);
439     // Draw the triangles.
440     gl.drawArrays(gl.TRIANGLES, 0, 6);
441     // Clean up the texture.
442     gl.deleteTexture(texture);
443
444     // Read back the rendering results.
445     var buf = new Uint8Array(testCase.width * testCase.height * 4);
446     gl.readPixels(0, 0, testCase.width, testCase.height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
447     // Run the verification routine.
448     if (testCase.verifier(buf, testCase.threshold, testCase.numOccurrences))
449         testPassed(testCase.description);
450     else
451         testFailed(testCase.description);
452 }
453
454 //----------------------------------------------------------------------
455 // Wrappers for programmatic construction of Image, ImageData and raw texture data
456 //
457
458 function ImageWrapper(width, height)
459 {
460     this.pngBuilder_ = new PNGlib(width, height, 256);
461 }
462
463 ImageWrapper.prototype.getWidth = function() {
464     return this.pngBuilder_.width;
465 };
466
467 ImageWrapper.prototype.getHeight = function() {
468     return this.pngBuilder_.height;
469 };
470
471 ImageWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
472     this.pngBuilder_.buffer[this.pngBuilder_.index(x, y)] = this.pngBuilder_.color(r, g, b, a);
473 };
474
475 // Generates data into "data" property, possibly asynchronously.
476 ImageWrapper.prototype.generateData = function() {
477     var that = this;
478     var url = "data:image/png;base64," + this.pngBuilder_.getBase64();
479     var img = wtu.makeImage(url, function() {
480       that.data = img;
481       maybeRunTests();
482     });
483 };
484
485 function ImageDataWrapper(width, height)
486 {
487     if (!ImageDataWrapper.tempCanvas) {
488         ImageDataWrapper.tempCanvas = document.createElement("canvas");
489     }
490     this.imageData_ = ImageDataWrapper.tempCanvas.getContext("2d").createImageData(width, height);
491 }
492
493 ImageDataWrapper.tempCanvas = null;
494
495 ImageDataWrapper.prototype.getWidth = function() {
496     return this.imageData_.width;
497 };
498
499 ImageDataWrapper.prototype.getHeight = function() {
500     return this.imageData_.height;
501 };
502
503 ImageDataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
504     var index = 4 * (this.imageData_.width * y + x);
505     this.imageData_.data[index] = r;
506     this.imageData_.data[index + 1] = g;
507     this.imageData_.data[index + 2] = b;
508     this.imageData_.data[index + 3] = a;
509 };
510
511 ImageDataWrapper.prototype.generateData = function() {
512     this.data = this.imageData_;
513     maybeRunTests();
514 };
515
516 function TextureDataWrapper(width, height)
517 {
518     this.width_ = width;
519     this.height_ = height;
520 }
521
522 TextureDataWrapper.prototype.getWidth = function() {
523     return this.width_;
524 };
525
526 TextureDataWrapper.prototype.getHeight = function() {
527     return this.height_;
528 };
529
530 TextureDataWrapper.prototype.generateData = function() {
531     this.data = this.data_;
532     maybeRunTests();
533 };
534
535 function RGBA8DataWrapper(width, height)
536 {
537     TextureDataWrapper.call(this, width, height);
538     this.data_ = new Uint8Array(4 * width * height);
539 }
540
541 RGBA8DataWrapper.prototype = new TextureDataWrapper;
542
543 RGBA8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
544     var index = 4 * (this.width_ * y + x);
545     this.data_[index] = r;
546     this.data_[index + 1] = g;
547     this.data_[index + 2] = b;
548     this.data_[index + 3] = a;
549 };
550
551 function RGBA5551DataWrapper(width, height)
552 {
553     TextureDataWrapper.call(this, width, height);
554     this.data_ = new Uint16Array(width * height);
555 }
556
557 RGBA5551DataWrapper.prototype = new TextureDataWrapper;
558
559 RGBA5551DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
560     var value = (((r & 0xF8) << 8)
561                  | ((g & 0xF8) << 3)
562                  | ((b & 0xF8) >> 2)
563                  | (a >> 7));
564     this.data_[this.width_ * y + x] = value;
565 };
566
567 function RGBA4444DataWrapper(width, height)
568 {
569     TextureDataWrapper.call(this, width, height);
570     this.data_ = new Uint16Array(width * height);
571 }
572
573 RGBA4444DataWrapper.prototype = new TextureDataWrapper;
574
575 RGBA4444DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
576     var value = (((r & 0xF0) << 8)
577                  | ((g & 0xF0) << 4)
578                  | (b & 0xF0)
579                  | (a >> 4));
580     this.data_[this.width_ * y + x] = value;
581 };
582
583 function RGB8DataWrapper(width, height)
584 {
585     TextureDataWrapper.call(this, width, height);
586     this.data_ = new Uint8Array(3 * width * height);
587 }
588
589 RGB8DataWrapper.prototype = new TextureDataWrapper;
590
591 RGB8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
592     var index = 3 * (this.width_ * y + x);
593     this.data_[index] = r;
594     this.data_[index + 1] = g;
595     this.data_[index + 2] = b;
596 };
597
598 function RGB565DataWrapper(width, height)
599 {
600     TextureDataWrapper.call(this, width, height);
601     this.data_ = new Uint16Array(width * height);
602 }
603
604 RGB565DataWrapper.prototype = new TextureDataWrapper;
605
606 RGB565DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
607     var value = (((r & 0xF8) << 8)
608                  | ((g & 0xFC) << 3)
609                  | ((b & 0xF8) >> 3));
610     this.data_[this.width_ * y + x] = value;
611 };
612
613 function A8DataWrapper(width, height)
614 {
615     TextureDataWrapper.call(this, width, height);
616     this.data_ = new Uint8Array(width * height);
617 }
618
619 A8DataWrapper.prototype = new TextureDataWrapper;
620
621 A8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
622     this.data_[this.width_ * y + x] = a;
623 };
624
625 function L8DataWrapper(width, height)
626 {
627     TextureDataWrapper.call(this, width, height);
628     this.data_ = new Uint8Array(width * height);
629 }
630
631 L8DataWrapper.prototype = new TextureDataWrapper;
632
633 L8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
634     this.data_[this.width_ * y + x] = r;
635 };
636
637 function LA8DataWrapper(width, height)
638 {
639     TextureDataWrapper.call(this, width, height);
640     this.data_ = new Uint8Array(2 * width * height);
641 }
642
643 LA8DataWrapper.prototype = new TextureDataWrapper;
644
645 LA8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) {
646     var index = 2 * (this.width_ * y + x);
647     this.data_[index] = r;
648     this.data_[index + 1] = a;
649 };
650
651 //----------------------------------------------------------------------
652 // Color ramp generation functions
653 //
654
655 function generateOpaqueGrayscaleRamp(wrapper)
656 {
657     var width = wrapper.getWidth();
658     var height = wrapper.getHeight();
659     for (var x = 0; x < width; ++x) {
660         var value = Math.round(255.0 * x / width);
661         for (var y = 0; y < height; ++y)
662             wrapper.setPixel(x, y, value, value, value, 255);
663     }
664 }
665
666 function generateTranslucentGrayscaleRamp(wrapper)
667 {
668     var width = wrapper.getWidth();
669     var height = wrapper.getHeight();
670     for (var x = 0; x < width; ++x) {
671         var value = Math.round(255.0 * x / width);
672         for (var y = 0; y < height; ++y)
673             wrapper.setPixel(x, y, value, value, value, value);
674     }
675 }
676
677 function generateTransparentGrayscaleRamp(wrapper)
678 {
679     var width = wrapper.getWidth();
680     var height = wrapper.getHeight();
681     for (var x = 0; x < width; ++x) {
682         var value = Math.round(255.0 * x / width);
683         for (var y = 0; y < height; ++y)
684             wrapper.setPixel(x, y, value, value, value, 0);
685     }
686 }
687
688 //----------------------------------------------------------------------
689 // Verification routines
690 //
691
692 function allChannelsIncreaseByNoMoreThan(array, threshold, numOccurrences) {
693     var numFound = 0;
694     for (var i = 4; i < array.length; i += 4)
695         for (var j = 0; j < 4; j++)
696             if (array[i + j] - array[i + j - 4] > threshold)
697                 ++numFound;
698
699     return numFound < numOccurrences;
700 }
701
702 function alphaChannelIncreasesByNoMoreThan(array, threshold, numOccurrences) {
703     var numFound = 0;
704     for (var i = 7; i < array.length; i += 4)
705         if (array[i] - array[i - 4] > threshold)
706             ++numFound;
707
708     return numFound < numOccurrences;
709 }
710
711 function allChannelsIncreaseByAtLeast(array, threshold, numOccurrences) {
712     var numFound = 0;
713     for (var i = 4; i < array.length; i += 4)
714         for (var j = 0; j < 4; ++j)
715             if (array[i + j] - array[i + j - 4] > threshold)
716                 ++numFound;
717
718     return numFound > numOccurrences;
719 }
720
721 function colorChannelsAreZero(array, threshold, numOccurrences) {
722     var passed = true;
723     var numFailures = 0;
724
725     for (var i = 4; i < array.length; i += 4)
726         for (var j = 0; j < 3; ++j)
727             if (array[i + j] != 0) {
728                 passed = false;
729                 if (++numFailures <= 5)
730                     debug("  array[" + (i + j) + "] should have been 0, was " + array[i + j]);
731             }
732
733     return passed;
734 }
735
736 </script>
737 </head>
738 <body onload="init()">
739 <canvas id="example" width="256" height="1"></canvas>
740 <div id="description"></div>
741 <div id="console"></div>
742 </body>
743 </html>