chromium/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-tabswitching.html

<!DOCTYPE html>
<body onload="runRepaintTest()">
<script src="../../resources/visibility.js"></script>
<span id="description" style="color: white">
This test is only useful as a pixel test. You should see two rows with 4 canvases in each. The top row of canvases should have a black background, the bottom row should have a dark blue background.
The canvases in the first two rows should have a single triangle. The canvases on the right should have three triangles superimposed on top of each other.
If multisampling is supported, the odd columns should have smooth edges instead of jagged stair-stepping.
</span>
<br>
<style>
canvas {
    outline: 1px solid blue;
}
body {
    background-color: darkblue;
}
</style>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

uniform vec4 u_color;

void main() {
  gl_FragColor = u_color;
}
</script>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;

uniform vec2 u_resolution;

void main() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<script src="resources/webgl-test-utils.js"></script>
<script>

var ctxs = []

document.getElementById("description").style.position = "absolute";
document.getElementById("description").style.top = "-5000px";

for (var i=0; i<8; ++i) {
    var attrs = {
        // The bottom row has 'alpha': true.
        'alpha': (i >= 4),
        // The 3rd and 4th column has 'preserveDrawingBuffer': true.
        'preserveDrawingBuffer': (i % 4) >= 2,
        // The 2nd and 4th column has 'antialias': true.
        'antialias': (i % 2) == 1
    };
    var can = document.createElement('canvas');
    can.width = can.height = 100;
    can.style.position = "absolute";
    can.style.left = 10 + (i % 4) * 120 + "px";
    can.style.top = (i < 4 ? 40 : 150) + "px";
    document.body.appendChild(can);
    if (i == 3)
        document.body.appendChild(document.createElement('br'));
    ctxs[i] = can.getContext("webgl", attrs);
    setup(ctxs[i]);
}

function setup(gl) {
    // setup a GLSL program
    var wtu = WebGLTestUtils;
    var vertexShader = WebGLTestUtils.loadShaderFromScript(gl, "2d-vertex-shader");
    var fragmentShader = WebGLTestUtils.loadShaderFromScript(gl, "2d-fragment-shader");
    var program = gl.createProgram();
    gl.attachShader(program, vertexShader, gl.VERTEX_SHADER);
    gl.attachShader(program, fragmentShader, gl.FRAGMENT_SHADER);
    gl.linkProgram(program);
    gl.useProgram(program);

    // look up where the vertex data needs to go.
    gl.myPositionLocation = gl.getAttribLocation(program, "a_position");

    // set the resolution
    var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    gl.uniform2f(resolutionLocation, 100, 100);

    var colorLocation = gl.getUniformLocation(program, "u_color");
    gl.uniform4f(colorLocation, 0, 1, 0, 1);
}

function draw(gl, offset) {
    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        80 + offset, 20,
        10 + offset, 10,
        10 + offset, 80]), gl.STATIC_DRAW);

    gl.enableVertexAttribArray(gl.myPositionLocation);
    gl.vertexAttribPointer(gl.myPositionLocation, 2, gl.FLOAT, false, 0, 0);

    // draw
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    gl.deleteBuffer(buffer);
}

function drawAll(offset) {
    for (var i=0; i<8; ++i)
        draw(ctxs[i], offset);
}

function repaintOnVisiblePage() {
    // Check if WebGL draws this frame correctly, because WebGL implementation
    // clears temporary cache when page is hidden.
    drawAll(60);

    if (window.testRunner) {
        testRunner.notifyDone();
    }
}

function repaintOnHiddenPage() {
    // Although page is hidden, WebGL must draw this frame.
    drawAll(30);

    setMainWindowHidden(false).then(() => {
        // If we requestAnimationFrame() here and draw, the triangles drawn
        // while hidden end up being preserved even when preserveDrawingBuffer
        // is false. That seems like it may be a bug? If we request a 2nd frame
        // before we draw, then the triangles drawn while hidden are lost.
        requestAnimationFrame(() => requestAnimationFrame(repaintOnVisiblePage));
    });
}

function firstPaintOnVisiblePage() {
    drawAll(0);

    // We can't requestAnimationFrame() here because the window will be hidden
    // so it won't happen. Instead, we draw without that request.
    setMainWindowHidden(true).then(repaintOnHiddenPage);
}

function runRepaintTest() {
    if (window.testRunner) {
        testRunner.waitUntilDone();
    }

  requestAnimationFrame(firstPaintOnVisiblePage);
}
</script>