summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/test_accelerated_canvas_context_loss.html
blob: 610c8d8fc338e3812f5d8defedced73d99ccb127 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Check for contextlost/restored events after GPU process restart</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="512" height="512"></canvas>

<script type="application/javascript">

function waitRAF() {
  return new Promise((resolve, reject) => {
    window.requestAnimationFrame(resolve);
  });
}

async function restartGPUProcess() {
  return await SpecialPowers.spawnChrome([], async () => {
    const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);

    if (gfxInfo.usingGPUProcess) {
      const { TestUtils } = ChromeUtils.importESModule(
        "resource://testing-common/TestUtils.sys.mjs"
      );
      let promise = TestUtils.topicObserved("compositor-reinitialized");

      const remoteCanvas = gfxInfo.usingRemoteCanvas;
      const acceleratedCanvas = gfxInfo.usingAcceleratedCanvas;
      ok(true, "Restarting GPU process, remote canvas " + remoteCanvas + ", accelerated canvas " + acceleratedCanvas);

      gfxInfo.killGPUProcessForTests();
      await promise;

      return remoteCanvas || acceleratedCanvas;
    }

    ok(true, "Not using GPU process");
    return false;
  });
}

const canvas = document.getElementById("c");
const context = canvas.getContext("2d");

let restoredPromiseResolve;
let restoredPromiseReject;

const restoredPromise = new Promise((resolve, reject) => {
  restoredPromiseResolve = resolve;
  restoredPromiseReject = reject;
});

let countLostEvents = 0;
let countRestoredEvents = 0;

function onContextLost() {
  ok(context.isContextLost(), "Canvas context should be lost during contextlost event");

  try {
    let transform = context.getTransform();
    ok(transform.isIdentity, "Canvas context should return identity transform while context lost");
  } catch (e) {}

  countLostEvents += 1;
}

function onContextRestored() {
  ok(!context.isContextLost(), "Canvas context should not be lost during contextrestored event");
  countRestoredEvents += 1;

  restoredPromiseResolve(true);
}

function waitContextRestored() {
  let timeoutId = window.setTimeout(restoredPromiseReject, 5000);
  return restoredPromise.then(() => {
    window.clearTimeout(timeoutId);
  });
}

async function start() {
  try {
    canvas.addEventListener("contextlost", onContextLost);
    canvas.addEventListener("contextrestored", onContextRestored);

    ok(!context.isContextLost(), "Canvas context should not be lost before initial fill");

    context.fillStyle = 'red';
    context.fill();
    await waitRAF();

    ok(!context.isContextLost(), "Canvas context should not be lost after initial fill");

    let transform = context.getTransform();
    ok(transform.isIdentity, "Canvas context should default to identity transform");
    context.setTransform(2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
    transform = context.getTransform();
    ok(!transform.isIdentity, "Canvas context should have non-identity transform");

    const restarted = await restartGPUProcess();
    const expectedEvents = restarted ? 1 : 0;

    if (expectedEvents) {
      await waitContextRestored();
    }
    await waitRAF();

    is(countLostEvents, expectedEvents, "Should have fired " + expectedEvents + " contextlost events");
    is(countRestoredEvents, expectedEvents, "Should have fired " + expectedEvents + " contextrestored events");
    ok(!context.isContextLost(), "Canvas context should not be lost after restoration");

    context.fillStyle = 'green';
    context.fill();
    await waitRAF();

    ok(!context.isContextLost(), "Canvas context should not be lost at completion");
  } catch (err) {
    ok(false, "Caught exception " + err);
  } finally {
    SimpleTest.finish();
  }
}

SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Wait for failure condition");
start();

</script>
</body>
</html>