chromium/third_party/blink/web_tests/fast/canvas/canvas-clip-stack-persistence.html

<!DOCTYPE html>
<html>
  <head>
    <title>Test that the clip state persists across frame boundaries.</title>
  </head>
  <body>
    <canvas id='canvas1' width='100' height='100'></canvas>
    <canvas id='canvas2' width='100' height='100'></canvas>
    <canvas id='canvas3' width='100' height='100'></canvas>
    <canvas id='canvas4' width='100' height='100'></canvas>
    <canvas id='canvas5' width='100' height='100'></canvas>
    <script>
      var canvas1 = document.getElementById('canvas1');
      var canvas2 = document.getElementById('canvas2');
      var canvas3 = document.getElementById('canvas3');
      var canvas4 = document.getElementById('canvas4');
      var canvas5 = document.getElementById('canvas5');
      var ctx1 = canvas1.getContext('2d');
      var ctx2 = canvas2.getContext('2d');
      var ctx3 = canvas3.getContext('2d');
      var ctx4 = canvas4.getContext('2d');
      var ctx5 = canvas5.getContext('2d');
      if (window.testRunner) {
        testRunner.waitUntilDone();
      }
      window.requestAnimationFrame(setupClips);

      function setupClips() {
        // ctx1 covers clipPath and unrealized save on the stack
        ctx1.fillStyle = 'green';
        ctx1.fillRect(0, 0, 100, 100);
        ctx1.save();
        ctx1.beginPath();
        ctx1.moveTo(10, 10);
        ctx1.lineTo(90, 50);
        ctx1.lineTo(10, 90);
        ctx1.clip();
        ctx1.save();

        // ctx2 covers accumulation of path and rect in separate layers
        ctx2.fillStyle = 'green';
        ctx2.fillRect(0, 0, 100, 100);
        ctx2.save();
        ctx2.beginPath();
        ctx2.moveTo(10, 10);
        ctx2.lineTo(90, 50);
        ctx2.lineTo(10, 90);
        ctx2.clip();
        ctx2.save();
        ctx2.beginPath();
        ctx2.rect(50, 0, 50, 100);
        ctx2.clip();

        // ctx3 identical to ctx2, but will call restore before drawing
        ctx3.fillStyle = 'green';
        ctx3.fillRect(0, 0, 100, 100);
        ctx3.save();
        ctx3.beginPath();
        ctx3.moveTo(10, 10);
        ctx3.lineTo(90, 50);
        ctx3.lineTo(10, 90);
        ctx3.clip();
        ctx3.save();
        ctx3.beginPath();
        ctx3.rect(50, 0, 50, 100);
        ctx3.clip();

        // ctx4 transformed clip
        ctx4.fillStyle = 'green';
        ctx4.fillRect(0, 0, 100, 100);
        ctx4.save();
        ctx4.translate(10, 0)
        ctx4.beginPath();
        ctx4.moveTo(10, 10);
        ctx4.lineTo(90, 50);
        ctx4.lineTo(10, 90);
        ctx4.clip();

        // ctx5 nested transformed clips
        ctx5.fillStyle = 'green';
        ctx5.fillRect(0, 0, 100, 100);
        ctx5.save();
        ctx5.translate(10, 0)
        ctx5.beginPath();
        ctx5.moveTo(0, 10);
        ctx5.translate(0, 5);
        ctx5.lineTo(80, 45);
        ctx5.lineTo(0, 85);
        ctx5.clip();
        ctx5.translate(5, 0);

        ctx5.save();
        ctx5.beginPath();
        ctx5.translate(3, 0);
        ctx5.moveTo(72, 5);
        ctx5.translate(0, 3);
        ctx5.lineTo(72, 82);
        ctx5.lineTo(-8, 42);
        ctx5.clip();

        window.requestAnimationFrame(drawPass)
      }

      function drawPass() {
        ctx1.fillStyle = 'yellow';
        ctx1.fillRect(0, 0, 100, 100);

        ctx2.fillStyle = 'yellow';
        ctx2.fillRect(0, 0, 100, 100);

        ctx3.restore();
        ctx3.fillStyle = 'yellow';
        ctx3.fillRect(0, 0, 100, 100);

        ctx4.fillStyle = 'yellow';
        ctx4.fillRect(-10, 0, 100, 100);

        ctx5.fillStyle = 'purple';
        ctx5.fillRect(-18, -8, 100, 100);
        ctx5.restore();
        ctx5.fillStyle = 'yellow';
        ctx5.globalAlpha = 0.5;
        ctx5.fillRect(-15, -5, 100, 100);


        if (window.testRunner) {
          testRunner.notifyDone();
        }
      }
    </script>
  </body>
</html>