diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html new file mode 100644 index 0000000000..1fbf4c6ccb --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-image-with-format-and-type.html @@ -0,0 +1,722 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../../resources/js-test-style.css"/> +<script src="../../../js/js-test-pre.js"></script> +<script src="../../../js/pnglib.js"></script> +<script src="../../../js/webgl-test-utils.js"></script> + +<script> +"use strict"; +var wtu = WebGLTestUtils; +var gl = null; +var textureLoc = null; +var successfullyParsed = false; + +//---------------------------------------------------------------------- +// Harness + +var testCases = []; + +var DataMode = { + IMAGE: 0, + IMAGE_DATA: 1, + + NUM_HTML_MODES: 2, + + RAW_DATA: 2, + + // This must remain the last mode. + NUM_MODES: 3 +}; + +function init() +{ + description('Verify texImage2D and texSubImage2D code paths taking both HTML and user-specified data with all format/type combinations'); + + var canvas = document.getElementById("example"); + gl = wtu.create3DContext(canvas); + gl.disable(gl.DITHER); + var program = wtu.setupTexturedQuad(gl); + + gl.clearColor(0,0,0,1); + gl.clearDepth(1); + gl.disable(gl.BLEND); + + textureLoc = gl.getUniformLocation(program, "tex"); + + initializeTests(); +} + +function initializeTests() +{ + // Verify that uploading to packed pixel formats performs the + // required conversion and associated loss of precision. + for (var dataMode = 0; dataMode < DataMode.NUM_HTML_MODES; ++dataMode) { + for (var useTexSubImage2D = 0; useTexSubImage2D < 2; ++useTexSubImage2D) { + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.RGBA, + type: gl.UNSIGNED_BYTE, + verifier: allChannelsIncreaseByNoMoreThan, + threshold: 1, + numOccurrences: 1, + description: "RGBA/UNSIGNED_BYTE should maintain full precision of data" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.RGBA, + type: gl.UNSIGNED_SHORT_4_4_4_4, + verifier: allChannelsIncreaseByAtLeast, + threshold: 15, + numOccurrences: 10, + description: "RGBA/UNSIGNED_SHORT_4_4_4_4 must drop low four bits of precision" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.RGBA, + type: gl.UNSIGNED_SHORT_5_5_5_1, + verifier: allChannelsIncreaseByAtLeast, + threshold: 7, + numOccurrences: 20, + description: "RGBA/UNSIGNED_SHORT_5_5_5_1 must drop low three bits of precision" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.RGB, + type: gl.UNSIGNED_BYTE, + verifier: allChannelsIncreaseByNoMoreThan, + threshold: 1, + numOccurrences: 1, + description: "RGB/UNSIGNED_BYTE should maintain full precision of data" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.RGB, + type: gl.UNSIGNED_SHORT_5_6_5, + verifier: allChannelsIncreaseByAtLeast, + threshold: 3, + numOccurrences: 20, + description: "RGB/UNSIGNED_SHORT_5_6_5 must drop low two or three bits of precision" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTranslucentGrayscaleRamp, + premultiplyAlpha: false, + format: gl.ALPHA, + type: gl.UNSIGNED_BYTE, + verifier: alphaChannelIncreasesByNoMoreThan, + threshold: 1, + numOccurrences: 1, + description: "ALPHA/UNSIGNED_BYTE should maintain full precision of data" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.LUMINANCE, + type: gl.UNSIGNED_BYTE, + verifier: allChannelsIncreaseByNoMoreThan, + threshold: 1, + numOccurrences: 1, + description: "LUMINANCE/UNSIGNED_BYTE should maintain full precision of data" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateOpaqueGrayscaleRamp, + premultiplyAlpha: false, + format: gl.LUMINANCE_ALPHA, + type: gl.UNSIGNED_BYTE, + verifier: allChannelsIncreaseByNoMoreThan, + threshold: 1, + numOccurrences: 1, + description: "LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data" + }); + } + } + + // Verify that setting the UNPACK_PREMULTIPLY_ALPHA_WEBGL pixel + // store parameter and sending down a zero alpha causes the color + // channels to go to zero. + for (var dataMode = 0; dataMode < DataMode.NUM_MODES; ++dataMode) { + for (var useTexSubImage2D = 0; useTexSubImage2D < 2; ++useTexSubImage2D) { + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.RGBA, + type: gl.UNSIGNED_BYTE, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_BYTE" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.RGBA, + type: gl.UNSIGNED_SHORT_4_4_4_4, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_4_4_4_4" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.RGBA, + type: gl.UNSIGNED_SHORT_5_5_5_1, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_5_5_5_1" + }); + // The following few tests are invalid for the raw data + // mode because there is either no alpha channel or no + // separate alpha channel. + if (dataMode != DataMode.RAW_DATA) { + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.RGB, + type: gl.UNSIGNED_BYTE, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGB/UNSIGNED_BYTE" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.RGB, + type: gl.UNSIGNED_SHORT_5_6_5, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGB/UNSIGNED_SHORT_5_6_5" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.ALPHA, + type: gl.UNSIGNED_BYTE, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with ALPHA/UNSIGNED_BYTE" + }); + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.LUMINANCE, + type: gl.UNSIGNED_BYTE, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with LUMINANCE/UNSIGNED_BYTE" + }); + } + testCases.push({ + dataMode: dataMode, + useTexSubImage2D: !!useTexSubImage2D, + width: 256, + height: 1, + generator: generateTransparentGrayscaleRamp, + premultiplyAlpha: true, + format: gl.LUMINANCE_ALPHA, + type: gl.UNSIGNED_BYTE, + verifier: colorChannelsAreZero, + description: "UNPACK_PREMULTIPLY_ALPHA_WEBGL with LUMINANCE_ALPHA/UNSIGNED_BYTE" + }); + } + } + + // Produce data for all testcases. Because we load images, some of + // these may generate their data asynchronously. + generateTestData(); +} + +function generateTestData() +{ + for (var i = 0; i < testCases.length; i++) { + var testCase = testCases[i]; + var wrapper = null; + switch (testCase.dataMode) { + case DataMode.IMAGE: + wrapper = new ImageWrapper(testCase.width, testCase.height); + break; + case DataMode.IMAGE_DATA: + wrapper = new ImageDataWrapper(testCase.width, testCase.height); + break; + case DataMode.RAW_DATA: + switch (testCase.type) { + case gl.UNSIGNED_BYTE: + switch (testCase.format) { + case gl.RGBA: + wrapper = new RGBA8DataWrapper(testCase.width, testCase.height); + break; + case gl.RGB: + wrapper = new RGB8DataWrapper(testCase.width, testCase.height); + break; + case gl.ALPHA: + wrapper = new A8DataWrapper(testCase.width, testCase.height); + break; + case gl.LUMINANCE: + wrapper = new L8DataWrapper(testCase.width, testCase.height); + break; + case gl.LUMINANCE_ALPHA: + wrapper = new LA8DataWrapper(testCase.width, testCase.height); + break; + } + break; + case gl.UNSIGNED_SHORT_4_4_4_4: + wrapper = new RGBA4444DataWrapper(testCase.width, testCase.height); + break; + case gl.UNSIGNED_SHORT_5_5_5_1: + wrapper = new RGBA5551DataWrapper(testCase.width, testCase.height); + break; + case gl.UNSIGNED_SHORT_5_6_5: + wrapper = new RGB565DataWrapper(testCase.width, testCase.height); + break; + } + } + testCase.wrapper = wrapper; + testCase.generator(wrapper); + testCase.wrapper.generateData(); + } + + // See whether we need to run the tests, in case all of them + // generated their results synchronously. + maybeRunTests(); +} + +var ranTests = false; + +function maybeRunTests() +{ + if (!ranTests) + for (var i = 0; i < testCases.length; ++i) + if (!testCases[i].wrapper || !testCases[i].wrapper.data) + return; + + ranTests = true; + + for (var i = 0; i < testCases.length; ++i) + runOneTest(testCases[i]); + + finishTest(); +} + +function testCaseToString(testCase) +{ + var mode; + switch (testCase.dataMode) { + case DataMode.IMAGE: + mode = "Image"; + break; + case DataMode.IMAGE_DATA: + mode = "ImageData"; + break; + case DataMode.RAW_DATA: + mode = "raw data"; + break; + } + return (testCase.useTexSubImage2D ? "texSubImage2D" : "texImage2D") + + " with " + mode + " at " + testCase.width + "x" + testCase.height; +} + +function runOneTest(testCase) +{ + debug("Testing " + testCaseToString(testCase)); + var data = testCase.wrapper.data; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + var texture = gl.createTexture(); + // Bind the texture to texture unit 0. + gl.bindTexture(gl.TEXTURE_2D, texture); + // Set up texture parameters. + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + // Set up pixel store parameters. + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, testCase.premultiplyAlpha); + // Upload the image into the texture. + if (testCase.useTexSubImage2D) { + // Initialize the texture to black first. + gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.width, testCase.height, 0, + testCase.format, testCase.type, null); + } + switch (testCase.dataMode) { + case DataMode.IMAGE: + case DataMode.IMAGE_DATA: + if (testCase.useTexSubImage2D) + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, testCase.format, testCase.type, data); + else + gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.format, testCase.type, data); + break; + case DataMode.RAW_DATA: + if (testCase.useTexSubImage2D) + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, testCase.width, testCase.height, testCase.format, testCase.type, data); + else + gl.texImage2D(gl.TEXTURE_2D, 0, testCase.format, testCase.width, testCase.height, 0, testCase.format, testCase.type, data); + break; + } + // Point the uniform sampler to texture unit 0. + gl.uniform1i(textureLoc, 0); + // Draw the triangles. + gl.drawArrays(gl.TRIANGLES, 0, 6); + // Clean up the texture. + gl.deleteTexture(texture); + + // Read back the rendering results. + var buf = new Uint8Array(testCase.width * testCase.height * 4); + gl.readPixels(0, 0, testCase.width, testCase.height, gl.RGBA, gl.UNSIGNED_BYTE, buf); + // Run the verification routine. + if (testCase.verifier(buf, testCase.threshold, testCase.numOccurrences)) + testPassed(testCase.description); + else + testFailed(testCase.description); +} + +//---------------------------------------------------------------------- +// Wrappers for programmatic construction of Image, ImageData and raw texture data +// + +function ImageWrapper(width, height) +{ + this.pngBuilder_ = new PNGlib(width, height, 256); +} + +ImageWrapper.prototype.getWidth = function() { + return this.pngBuilder_.width; +}; + +ImageWrapper.prototype.getHeight = function() { + return this.pngBuilder_.height; +}; + +ImageWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + this.pngBuilder_.buffer[this.pngBuilder_.index(x, y)] = this.pngBuilder_.color(r, g, b, a); +}; + +// Generates data into "data" property, possibly asynchronously. +ImageWrapper.prototype.generateData = function() { + var that = this; + var url = "data:image/png;base64," + this.pngBuilder_.getBase64(); + var img = wtu.makeImage(url, function() { + that.data = img; + maybeRunTests(); + }); +}; + +function ImageDataWrapper(width, height) +{ + if (!ImageDataWrapper.tempCanvas) { + ImageDataWrapper.tempCanvas = document.createElement("canvas"); + } + this.imageData_ = ImageDataWrapper.tempCanvas.getContext("2d").createImageData(width, height); +} + +ImageDataWrapper.tempCanvas = null; + +ImageDataWrapper.prototype.getWidth = function() { + return this.imageData_.width; +}; + +ImageDataWrapper.prototype.getHeight = function() { + return this.imageData_.height; +}; + +ImageDataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var index = 4 * (this.imageData_.width * y + x); + this.imageData_.data[index] = r; + this.imageData_.data[index + 1] = g; + this.imageData_.data[index + 2] = b; + this.imageData_.data[index + 3] = a; +}; + +ImageDataWrapper.prototype.generateData = function() { + this.data = this.imageData_; + maybeRunTests(); +}; + +function TextureDataWrapper(width, height) +{ + this.width_ = width; + this.height_ = height; +} + +TextureDataWrapper.prototype.getWidth = function() { + return this.width_; +}; + +TextureDataWrapper.prototype.getHeight = function() { + return this.height_; +}; + +TextureDataWrapper.prototype.generateData = function() { + this.data = this.data_; + maybeRunTests(); +}; + +function RGBA8DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint8Array(4 * width * height); +} + +RGBA8DataWrapper.prototype = new TextureDataWrapper; + +RGBA8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var index = 4 * (this.width_ * y + x); + this.data_[index] = r; + this.data_[index + 1] = g; + this.data_[index + 2] = b; + this.data_[index + 3] = a; +}; + +function RGBA5551DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint16Array(width * height); +} + +RGBA5551DataWrapper.prototype = new TextureDataWrapper; + +RGBA5551DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var value = (((r & 0xF8) << 8) + | ((g & 0xF8) << 3) + | ((b & 0xF8) >> 2) + | (a >> 7)); + this.data_[this.width_ * y + x] = value; +}; + +function RGBA4444DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint16Array(width * height); +} + +RGBA4444DataWrapper.prototype = new TextureDataWrapper; + +RGBA4444DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var value = (((r & 0xF0) << 8) + | ((g & 0xF0) << 4) + | (b & 0xF0) + | (a >> 4)); + this.data_[this.width_ * y + x] = value; +}; + +function RGB8DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint8Array(3 * width * height); +} + +RGB8DataWrapper.prototype = new TextureDataWrapper; + +RGB8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var index = 3 * (this.width_ * y + x); + this.data_[index] = r; + this.data_[index + 1] = g; + this.data_[index + 2] = b; +}; + +function RGB565DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint16Array(width * height); +} + +RGB565DataWrapper.prototype = new TextureDataWrapper; + +RGB565DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var value = (((r & 0xF8) << 8) + | ((g & 0xFC) << 3) + | ((b & 0xF8) >> 3)); + this.data_[this.width_ * y + x] = value; +}; + +function A8DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint8Array(width * height); +} + +A8DataWrapper.prototype = new TextureDataWrapper; + +A8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + this.data_[this.width_ * y + x] = a; +}; + +function L8DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint8Array(width * height); +} + +L8DataWrapper.prototype = new TextureDataWrapper; + +L8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + this.data_[this.width_ * y + x] = r; +}; + +function LA8DataWrapper(width, height) +{ + TextureDataWrapper.call(this, width, height); + this.data_ = new Uint8Array(2 * width * height); +} + +LA8DataWrapper.prototype = new TextureDataWrapper; + +LA8DataWrapper.prototype.setPixel = function(x, y, r, g, b, a) { + var index = 2 * (this.width_ * y + x); + this.data_[index] = r; + this.data_[index + 1] = a; +}; + +//---------------------------------------------------------------------- +// Color ramp generation functions +// + +function generateOpaqueGrayscaleRamp(wrapper) +{ + var width = wrapper.getWidth(); + var height = wrapper.getHeight(); + for (var x = 0; x < width; ++x) { + var value = Math.round(255.0 * x / width); + for (var y = 0; y < height; ++y) + wrapper.setPixel(x, y, value, value, value, 255); + } +} + +function generateTranslucentGrayscaleRamp(wrapper) +{ + var width = wrapper.getWidth(); + var height = wrapper.getHeight(); + for (var x = 0; x < width; ++x) { + var value = Math.round(255.0 * x / width); + for (var y = 0; y < height; ++y) + wrapper.setPixel(x, y, value, value, value, value); + } +} + +function generateTransparentGrayscaleRamp(wrapper) +{ + var width = wrapper.getWidth(); + var height = wrapper.getHeight(); + for (var x = 0; x < width; ++x) { + var value = Math.round(255.0 * x / width); + for (var y = 0; y < height; ++y) + wrapper.setPixel(x, y, value, value, value, 0); + } +} + +//---------------------------------------------------------------------- +// Verification routines +// + +function allChannelsIncreaseByNoMoreThan(array, threshold, numOccurrences) { + var numFound = 0; + for (var i = 4; i < array.length; i += 4) + for (var j = 0; j < 4; j++) + if (array[i + j] - array[i + j - 4] > threshold) + ++numFound; + + return numFound < numOccurrences; +} + +function alphaChannelIncreasesByNoMoreThan(array, threshold, numOccurrences) { + var numFound = 0; + for (var i = 7; i < array.length; i += 4) + if (array[i] - array[i - 4] > threshold) + ++numFound; + + return numFound < numOccurrences; +} + +function allChannelsIncreaseByAtLeast(array, threshold, numOccurrences) { + var numFound = 0; + for (var i = 4; i < array.length; i += 4) + for (var j = 0; j < 4; ++j) + if (array[i + j] - array[i + j - 4] > threshold) + ++numFound; + + return numFound > numOccurrences; +} + +function colorChannelsAreZero(array, threshold, numOccurrences) { + var passed = true; + var numFailures = 0; + + for (var i = 4; i < array.length; i += 4) + for (var j = 0; j < 3; ++j) + if (array[i + j] != 0) { + passed = false; + if (++numFailures <= 5) + debug(" array[" + (i + j) + "] should have been 0, was " + array[i + j]); + } + + return passed; +} + +</script> +</head> +<body onload="init()"> +<canvas id="example" width="256" height="1"></canvas> +<div id="description"></div> +<div id="console"></div> +</body> +</html> |