1<!DOCTYPE html>
2<html>
3<head>
4<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
5<script>
6let ctx = null;
7
8// 2x2 red square
9let image = document.createElement("img");
10image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1j/M/AAEQMDEwgAgQAHxcCAmtAm/sAAAAASUVORK5CYII=";
11
12// Invalid video
13let video = document.createElement("video");
14
15// Blank canvas
16let canvas = document.createElement("canvas");
17canvas.width = 2;
18canvas.height = 2;
19
20let linearGradient = null;
21
22let radialGradient = null;
23
24let pattern = null;
25
26let path12 = new Path2D("M 1 2");
27let path34 = new Path2D("M 3 4");
28
29let imageData14 = new ImageData(1, 4);
30let imageData23 = new ImageData(2, 3);
31
32function load() {
33 ctx = canvas.getContext("2d");
34 linearGradient = ctx.createLinearGradient(1, 2, 3, 4);
35 radialGradient = ctx.createRadialGradient(1, 2, 3, 4, 5, 6);
36 pattern = ctx.createPattern(image, "no-repeat");
37
38 document.body.appendChild(canvas);
39
40 runTest();
41}
42
43function e(f){
44 try { f(); } catch(e) { }
45}
46
47let animationFrameID = false;
48
49function cancelActions() {
50 window.cancelAnimationFrame(animationFrameID);
51}
52
53function performActions() {
54 let frames = [
55 () => {
56 e(() => ctx.arc(1, 2, 3, 4, 5));
57 e(() => ctx.arc(6, 7, 8, 9, 10, true));
58 },
59 () => {
60 e(() => ctx.arcTo(1, 2, 3, 4, 5));
61 },
62 () => {
63 ctx.beginPath();
64 },
65 () => {
66 ctx.bezierCurveTo(1, 2, 3, 4, 5, 6);
67 },
68 () => {
69 ctx.canvas;
70 },
71 () => {
72 ctx.clearRect(1, 2, 3, 4);
73 },
74 () => {
75 ctx.clearShadow();
76 },
77 () => {
78 ctx.clip();
79 ctx.clip("evenodd");
80 ctx.clip(path12);
81 ctx.clip(path34, "evenodd");
82 },
83 () => {
84 ctx.closePath();
85 },
86 () => {
87 ctx.commit();
88 },
89 () => {
90 e(() => ctx.createImageData(imageData14));
91 e(() => ctx.createImageData(2, 3));
92 },
93 () => {
94 e(() => ctx.createLinearGradient(1, 2, 3, 4));
95 },
96 () => {
97 e(() => ctx.createPattern(image, "testA"));
98 e(() => ctx.createPattern(video, "testB"));
99 e(() => ctx.createPattern(canvas, "testC"));
100 },
101 () => {
102 e(() => ctx.createRadialGradient(1, 2, 3, 4, 5, 6));
103 },
104 () => {
105 ctx.direction;
106 ctx.direction = "test";
107 },
108 () => {
109 ctx.drawFocusIfNeeded(document.body);
110 ctx.drawFocusIfNeeded(path12, document.body);
111 },
112 () => {
113 e(() => ctx.drawImage(image, 1, 2));
114 e(() => ctx.drawImage(video, 3, 4));
115 e(() => ctx.drawImage(canvas, 5, 6));
116 e(() => ctx.drawImage(image, 7, 8, 9, 10));
117 e(() => ctx.drawImage(video, 11, 12, 13, 14));
118 e(() => ctx.drawImage(canvas, 15, 16, 17, 18));
119 e(() => ctx.drawImage(image, 19, 20, 21, 22, 23, 24, 25, 26));
120 e(() => ctx.drawImage(video, 27, 28, 29, 30, 31, 32, 33, 34));
121 e(() => ctx.drawImage(canvas, 35, 36, 37, 38, 39, 40, 41 ,42));
122 },
123 () => {
124 ctx.drawImageFromRect(image, 1, 2, 3, 4, 5, 6, 7, 8)
125 ctx.drawImageFromRect(image, 9, 10, 11, 12, 13, 14, 15, 16, "test");
126 },
127 () => {
128 e(() => ctx.ellipse(1, 2, 3, 4, 5, 6, 7));
129 e(() => ctx.ellipse(8, 9, 10, 11, 12, 13, 14, true));
130 },
131 () => {
132 ctx.fill();
133 ctx.fill("evenodd");
134 ctx.fill(path12);
135 ctx.fill(path34, "evenodd");
136 },
137 () => {
138 ctx.fillRect(1, 2, 3, 4);
139 },
140 () => {
141 ctx.fillStyle;
142 ctx.fillStyle = "test";
143 ctx.fillStyle = linearGradient;
144 ctx.fillStyle = radialGradient;
145 ctx.fillStyle = pattern;
146 },
147 () => {
148 ctx.fillText("testA", 1, 2);
149 ctx.fillText("testB", 3, 4, 5);
150 },
151 () => {
152 ctx.font;
153 ctx.font = "test";
154 },
155 () => {
156 e(() => ctx.getImageData(1, 2, 3, 4));
157 },
158 () => {
159 ctx.getLineDash();
160 },
161 () => {
162 ctx.getTransform();
163 },
164 () => {
165 ctx.globalAlpha;
166 ctx.globalAlpha = 0;
167 },
168 () => {
169 ctx.globalCompositeOperation;
170 ctx.globalCompositeOperation = "test";
171 },
172 () => {
173 ctx.imageSmoothingEnabled;
174 ctx.imageSmoothingEnabled = true;
175 },
176 () => {
177 ctx.imageSmoothingQuality;
178 ctx.imageSmoothingQuality = "low";
179 },
180 () => {
181 ctx.isPointInPath(path12, 5, 6);
182 ctx.isPointInPath(path34, 7, 8, "evenodd");
183 ctx.isPointInPath(9, 10);
184 ctx.isPointInPath(11, 12, "evenodd");
185 },
186 () => {
187 ctx.isPointInStroke(path12, 3, 4);
188 ctx.isPointInStroke(5, 6);
189 },
190 () => {
191 ctx.lineCap;
192 ctx.lineCap = "test";
193 },
194 () => {
195 ctx.lineDashOffset;
196 ctx.lineDashOffset = 1;
197 },
198 () => {
199 ctx.lineJoin;
200 ctx.lineJoin = "test";
201 },
202 () => {
203 ctx.lineTo(1, 2);
204 },
205 () => {
206 ctx.lineWidth;
207 ctx.lineWidth = 1;
208 },
209 () => {
210 ctx.measureText("test");
211 },
212 () => {
213 ctx.miterLimit;
214 ctx.miterLimit = 1;
215 },
216 () => {
217 ctx.moveTo(1, 2);
218 },
219 () => {
220 ctx.putImageData(imageData14, 5, 6);
221 ctx.putImageData(imageData23, 7, 8, 9, 10, 11, 12);
222 },
223 () => {
224 ctx.quadraticCurveTo(1, 2, 3, 4);
225 },
226 () => {
227 ctx.rect(1, 2, 3, 4);
228 },
229 () => {
230 ctx.resetTransform();
231 },
232 () => {
233 ctx.restore();
234 },
235 () => {
236 ctx.rotate(1);
237 },
238 () => {
239 ctx.save();
240 },
241 () => {
242 ctx.scale(1, 2);
243 },
244 () => {
245 ctx.setAlpha();
246 ctx.setAlpha(1);
247 },
248 () => {
249 ctx.setCompositeOperation();
250 ctx.setCompositeOperation("test");
251 },
252 () => {
253 ctx.setFillColor("testA");
254 ctx.setFillColor("testB", 1);
255 ctx.setFillColor(2);
256 ctx.setFillColor(3, 4);
257 ctx.setFillColor(5, 6, 7, 8);
258 ctx.setFillColor(9, 10, 11, 12, 13);
259 },
260 () => {
261 ctx.setLineCap();
262 ctx.setLineCap("test");
263 },
264 () => {
265 ctx.setLineDash([1, 2]);
266 },
267 () => {
268 ctx.setLineJoin();
269 ctx.setLineJoin("test");
270 },
271 () => {
272 ctx.setLineWidth();
273 ctx.setLineWidth(1);
274 },
275 () => {
276 ctx.setMiterLimit();
277 ctx.setMiterLimit(1);
278 },
279 () => {
280 ctx.setShadow(1, 2, 3);
281 ctx.setShadow(4, 5, 6, "test", 7);
282 ctx.setShadow(8, 9, 10, 11);
283 ctx.setShadow(12, 13, 14, 15, 16);
284 ctx.setShadow(17, 18, 19, 20, 21, 22, 23);
285 ctx.setShadow(24, 25, 26, 27, 28, 29, 30, 31);
286 },
287 () => {
288 ctx.setStrokeColor("testA");
289 ctx.setStrokeColor("testB", 1);
290 ctx.setStrokeColor(2);
291 ctx.setStrokeColor(3, 4);
292 ctx.setStrokeColor(5, 6, 7, 8);
293 ctx.setStrokeColor(9, 10, 11, 12, 13);
294 },
295 () => {
296 ctx.setTransform(1, 2, 3, 4, 5, 6);
297 e(() => ctx.setTransform());
298 e(() => ctx.setTransform(new DOMMatrix([7, 8, 9, 10, 11, 12])));
299 },
300 () => {
301 ctx.shadowBlur;
302 ctx.shadowBlur = 1;
303 },
304 () => {
305 ctx.shadowColor;
306 ctx.shadowColor = "test";
307 },
308 () => {
309 ctx.shadowOffsetX;
310 ctx.shadowOffsetX = 1;
311 },
312 () => {
313 ctx.shadowOffsetY;
314 ctx.shadowOffsetY = 1;
315 },
316 () => {
317 ctx.stroke();
318 ctx.stroke(path12);
319 },
320 () => {
321 ctx.strokeRect(1, 2, 3, 4);
322 },
323 () => {
324 ctx.strokeStyle;
325 ctx.strokeStyle = "test";
326 ctx.strokeStyle = linearGradient;
327 ctx.strokeStyle = radialGradient;
328 ctx.strokeStyle = pattern;
329 },
330 () => {
331 ctx.strokeText("testA", 1, 2);
332 ctx.strokeText("testB", 3, 4, 5);
333 },
334 () => {
335 ctx.textAlign;
336 ctx.textAlign = "test";
337 },
338 () => {
339 ctx.textBaseline;
340 ctx.textBaseline = "test";
341 },
342 () => {
343 ctx.transform(1, 2, 3, 4, 5, 6);
344 },
345 () => {
346 ctx.translate(1, 2);
347 },
348 () => {
349 ctx.webkitBackingStorePixelRatio;
350 },
351 () => {
352 e(() => ctx.webkitGetImageDataHD(1, 2, 3, 4));
353 },
354 () => {
355 ctx.webkitImageSmoothingEnabled;
356 ctx.webkitImageSmoothingEnabled = true;
357 },
358 () => {
359 ctx.webkitLineDash;
360 ctx.webkitLineDash = [1, 2];
361 },
362 () => {
363 ctx.webkitLineDashOffset;
364 ctx.webkitLineDashOffset = 1;
365 },
366 () => {
367 ctx.webkitPutImageDataHD(imageData14, 5, 6);
368 ctx.webkitPutImageDataHD(imageData23, 7, 8, 9, 10, 11, 12);
369 },
370 () => {
371 TestPage.dispatchEventToFrontend("LastFrame");
372 },
373 ];
374 let index = 0;
375 function f() {
376 frames[index++]();
377 if (index < frames.length)
378 animationFrameID = window.requestAnimationFrame(f);
379 };
380 f();
381}
382
383function test() {
384 let suite = InspectorTest.createAsyncSuite("Canvas.recording2D");
385
386 function requestRecording(parameters, resolve, reject) {
387 let canvases = WebInspector.canvasManager.canvases.filter((canvas) => canvas.contextType === WebInspector.Canvas.ContextType.Canvas2D);
388 if (!canvases.length) {
389 reject("Missing 2D canvas.");
390 return;
391 }
392
393 InspectorTest.assert(canvases.length === 1, "There should only be one canvas-2d.");
394
395 WebInspector.canvasManager.awaitEvent(WebInspector.CanvasManager.Event.RecordingFinished)
396 .then((event) => {
397 InspectorTest.evaluateInPage(`cancelActions()`);
398
399 let json = event.data.recording.toJSON();
400 json.data = json.data.map((item) => {
401 if (typeof item !== "string" || !item.includes("/LayoutTests/inspector/canvas/recording-2d.html"))
402 return item;
403
404 // The bots will fail since the path locally is most likely different than the bots.
405 return "/LayoutTests/inspector/canvas/recording-2d.html";
406 })
407 InspectorTest.log(JSON.stringify(json, null, 2));
408 })
409 .then(resolve, reject);
410
411 CanvasAgent.requestRecording(canvases[0].identifier, ...parameters, (error) => {
412 if (error) {
413 reject(error);
414 return;
415 }
416
417 InspectorTest.evaluateInPage(`performActions()`, (error) => {
418 if (error)
419 reject(error);
420 });
421 });
422
423 return canvases[0];
424 }
425
426 suite.addTestCase({
427 name: "Canvas.recording2D.singleFrame",
428 description: "Check that the recording is stopped after a single frame.",
429 test(resolve, reject) {
430 const singleFrame = true;
431 let canvas = requestRecording([singleFrame], resolve, reject);
432 }
433 });
434
435 suite.addTestCase({
436 name: "Canvas.recording2D.multipleFrames",
437 description: "Check that recording data is serialized correctly for multiple frames.",
438 test(resolve, reject) {
439 const singleFrame = false;
440 let canvas = requestRecording([singleFrame], resolve, reject);
441
442 InspectorTest.singleFireEventListener("LastFrame", () => {
443 CanvasAgent.cancelRecording(canvas.identifier, (error) => {
444 if (error) {
445 reject(error);
446 return;
447 }
448 });
449 });
450 }
451 });
452
453 suite.addTestCase({
454 name: "Canvas.recording2D.memoryLimit",
455 description: "Check that the recording is stopped when it reaches the memory limit.",
456 test(resolve, reject) {
457 const singleFrame = false;
458 const memoryLimit = 10;
459 let canvas = requestRecording([singleFrame, memoryLimit], resolve, reject);
460 }
461 });
462
463 // ------
464
465 suite.addTestCase({
466 name: "Canvas.requestRecording.InvalidCanvasId",
467 description: "Invalid canvas identifiers should cause an error.",
468 test(resolve, reject) {
469 const canvasId = "DOES_NOT_EXIST";
470 CanvasAgent.requestRecording(canvasId, (error) => {
471 InspectorTest.expectThat(error, "Should produce an error.");
472 InspectorTest.log("Error: " + error);
473 resolve();
474 });
475 }
476 });
477
478 suite.addTestCase({
479 name: "Canvas.cancelRecording.InvalidCanvasId",
480 description: "Invalid canvas identifiers should cause an error.",
481 test(resolve, reject) {
482 const canvasId = "DOES_NOT_EXIST";
483 CanvasAgent.cancelRecording(canvasId, (error) => {
484 InspectorTest.expectThat(error, "Should produce an error.");
485 InspectorTest.log("Error: " + error);
486 resolve();
487 });
488 }
489 });
490
491 suite.runTestCasesAndFinish();
492}
493</script>
494</head>
495<body onload="load()">
496 <p>Test that CanvasManager is able to record actions made to 2D canvas contexts.</p>
497</body>
498</html>