<html>
  <head>
    <title>Density corrected size: canvas</title>
    <link rel="author" title="Noam Rosenthal" href="noam@webkit.org">
    <meta name="assert" content="Assert that density-corrected size in EXIF is taken into account for images when drawn in canvas">
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
  </head>
  <body>
    <p>You should see green/yellow gradient boxes</p>
    <style>
      canvas {
        width: 120px;
        height: 120px;
        margin: 10px;
      }
    </style>
    <script id="shader-fs" type="x-shader/x-fragment">
        precision mediump float;
        uniform sampler2D u_image;
        varying vec2 v_texCoord;
        uniform float u_frame;

        void main(void) {
            gl_FragColor = texture2D(u_image, v_texCoord);
        }
    </script>
    <script id="shader-vs" type="x-shader/x-vertex">
        precision mediump float;
        attribute vec2 a_vertex;
        attribute vec2 a_tex;
        varying vec2 v_texCoord;

        void main(void) {
            gl_Position = vec4(a_vertex, 0, 1)  ;
            v_texCoord = a_tex;
        }
    </script>

    <script>
      const dim = 3
      function drawImage2d(context, image, srcRect) {
        context.drawImage(image, ...srcRect, 0, 0, dim, dim)
        return context.getImageData(0, 0, dim, dim)
      }
      function drawImage3d(gl, image, srcRect) {
        const vshader = gl.createShader(gl.VERTEX_SHADER)
        const fshader = gl.createShader(gl.FRAGMENT_SHADER)
        gl.shaderSource(vshader, document.querySelector("#shader-vs").textContent)
        gl.shaderSource(fshader, document.querySelector("#shader-fs").textContent)
        gl.compileShader(vshader)
        gl.compileShader(fshader)
        const program = gl.createProgram()
        gl.attachShader(program, vshader)
        gl.attachShader(program, fshader)
        gl.linkProgram(program)
        gl.useProgram(program)
        const a_vertex = gl.getAttribLocation(program, "a_vertex")
        const a_tex = gl.getAttribLocation(program, "a_tex")
        const buf_vertex = gl.createBuffer()
        const buf_tex = gl.createBuffer()
        gl.bindBuffer(gl.ARRAY_BUFFER, buf_tex)
        const [sx, sy, sw, sh] = [srcRect[0] / image.naturalWidth, srcRect[1] / image.naturalHeight, srcRect[2] / image.naturalWidth, srcRect[3] / image.naturalHeight]

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          sx, sy, sx + sw, sy, sx, sy + sh, sx + sw, sy + sh
        ]), gl.STATIC_DRAW)

        gl.bindBuffer(gl.ARRAY_BUFFER, buf_vertex)
        var vertices = [-1, 1, 1, 1, -1, -1, 1, -1]
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
        var texture = gl.createTexture()
        gl.bindTexture(gl.TEXTURE_2D, texture)
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
        gl.viewport(0, 0, dim, dim)
        gl.enableVertexAttribArray(a_vertex)
        gl.enableVertexAttribArray(a_tex)
        gl.uniform1i(gl.getUniformLocation(program, "u_image"), 0)
        gl.bindBuffer(gl.ARRAY_BUFFER, buf_tex)
        gl.vertexAttribPointer(a_tex, 2, gl.FLOAT, false, 0, 0)
        gl.bindBuffer(gl.ARRAY_BUFFER, buf_vertex)
        gl.vertexAttribPointer(a_vertex, 2, gl.FLOAT, false, 0, 0)
        gl.clearColor(1, 1, 1, 1)
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        const pixels = new Uint8ClampedArray(dim * dim * 4)
        gl.readPixels(0, 0, dim, dim, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
        return {data: pixels, width: dim, height: dim}
      }
      function createCanvasWithImage(src, contextType, srcRect) {
        const canvas = document.createElement('canvas')
        canvas.width = canvas.height = dim
        document.body.appendChild(canvas)
        const image = new Image()
        image.src = src
        return new Promise(resolve => {
          image.onload = () => {
            const context = canvas.getContext(contextType)
            if (contextType === '2d')
              resolve(drawImage2d(context, image, srcRect))
            else
              resolve(drawImage3d(context, image, srcRect))
          }
        })
      }

      async function checkCanvasImage(src, contextType, srcRect, reference) {
        const data = await createCanvasWithImage(src, contextType, srcRect)
        assert_array_approx_equals(data.data, reference.data, 32)
      }

      promise_test(async () => {
        const reference = await createCanvasWithImage('resources/exif-resolution-none.jpg', '2d', [40, 5, 20, 5]);
        await checkCanvasImage("resources/exif-resolution-valid-hires.jpg", '2d', [20, 5, 10, 1], reference)
        await checkCanvasImage("resources/exif-resolution-valid-lores.jpg", '2d', [80, 5, 40, 10], reference)
        await checkCanvasImage("resources/exif-resolution-none.jpg", 'webgl', [40, 5, 20, 5], reference)
        await checkCanvasImage("resources/exif-resolution-valid-hires.jpg", 'webgl', [20, 5, 10, 1], reference)
        await checkCanvasImage("resources/exif-resolution-valid-lores.jpg", 'webgl', [80, 5, 40, 1], reference)
      })
    </script>
  </body>
</html>
