xbintsc 0.5.38 → 0.5.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.js +23 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/html.js +9 -2
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/tests/codegen/closures.test.js +7 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
- package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
- package/dist/tests/e2e/gui-data-url.test.d.ts +10 -0
- package/dist/tests/e2e/gui-data-url.test.js +127 -0
- package/dist/tests/e2e/gui-data-url.test.js.map +1 -0
- package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
- package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
- package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.js +96 -0
- package/dist/tests/e2e/gui-effects.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +77 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
- package/dist/tests/e2e/gui-perf.test.js +283 -0
- package/dist/tests/e2e/gui-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +9 -1
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.js +4 -4
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +23 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/api.md +28 -2
- package/doc/gui/canvas.md +114 -27
- package/doc/gui/known-issues.md +47 -19
- package/doc/gui/media.md +11 -2
- package/doc/gui/rendering.md +120 -18
- package/doc/gui/runtime.md +18 -3
- package/doc/gui/webgl.md +38 -19
- package/doc/gui.md +38 -5
- package/doc/zh-CN/gui/api.md +25 -2
- package/doc/zh-CN/gui/canvas.md +97 -26
- package/doc/zh-CN/gui/known-issues.md +32 -12
- package/doc/zh-CN/gui/media.md +9 -2
- package/doc/zh-CN/gui/rendering.md +89 -11
- package/doc/zh-CN/gui/runtime.md +13 -3
- package/doc/zh-CN/gui/webgl.md +27 -5
- package/doc/zh-CN/gui.md +25 -2
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +3 -1
- package/runtime/ext_gui/canvas.cpp +135 -89
- package/runtime/ext_gui/canvas.h +116 -0
- package/runtime/ext_gui/canvas_clip.cpp +143 -0
- package/runtime/ext_gui/canvas_composite.cpp +241 -0
- package/runtime/ext_gui/canvas_coverage.cpp +241 -0
- package/runtime/ext_gui/canvas_gradient.cpp +41 -4
- package/runtime/ext_gui/canvas_image_data.cpp +4 -0
- package/runtime/ext_gui/canvas_internal.h +34 -9
- package/runtime/ext_gui/canvas_raster.cpp +207 -178
- package/runtime/ext_gui/canvas_shadow.cpp +161 -0
- package/runtime/ext_gui/canvas_stroke.cpp +37 -9
- package/runtime/ext_gui/canvas_style.cpp +59 -0
- package/runtime/ext_gui/canvas_text.cpp +140 -0
- package/runtime/ext_gui/css.h +7 -0
- package/runtime/ext_gui/css_sheet.cpp +22 -0
- package/runtime/ext_gui/document.cpp +25 -1
- package/runtime/ext_gui/document.h +8 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +48 -15
- package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
- package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
- package/runtime/ext_gui/dom_api_internal.h +36 -37
- package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
- package/runtime/ext_gui/dom_api_proto.cpp +18 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +19 -9
- package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
- package/runtime/ext_gui/gradient_values.cpp +56 -49
- package/runtime/ext_gui/gui.cpp +5 -0
- package/runtime/ext_gui/gui_canvas.cpp +4 -0
- package/runtime/ext_gui/gui_engine.h +30 -0
- package/runtime/ext_gui/gui_events.cpp +185 -58
- package/runtime/ext_gui/gui_media.cpp +3 -0
- package/runtime/ext_gui/image.cpp +225 -1
- package/runtime/ext_gui/image.h +6 -4
- package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
- package/runtime/ext_gui/layout.cpp +4 -0
- package/runtime/ext_gui/paint.cpp +72 -3
- package/runtime/ext_gui/paint.h +11 -1
- package/runtime/ext_gui/paint_background.cpp +110 -12
- package/runtime/ext_gui/paint_effects.cpp +2 -1
- package/runtime/ext_gui/paint_internal.h +5 -1
- package/runtime/ext_gui/perf.cpp +171 -0
- package/runtime/ext_gui/perf.h +127 -0
- package/runtime/ext_gui/renderer.cpp +190 -54
- package/runtime/ext_gui/renderer.h +52 -14
- package/runtime/ext_gui/renderer_image.cpp +135 -65
- package/runtime/ext_gui/renderer_internal.h +41 -3
- package/runtime/ext_gui/renderer_layer.cpp +552 -0
- package/runtime/ext_gui/renderer_text.cpp +24 -12
- package/runtime/ext_gui/style.cpp +101 -30
- package/runtime/ext_gui/style.h +35 -4
- package/runtime/ext_gui/style_print.cpp +15 -1
- package/runtime/ext_gui/style_values.cpp +10 -0
- package/runtime/ext_gui/text.cpp +23 -4
- package/runtime/ext_gui/text.h +29 -0
- package/runtime/ext_gui/text_cache.cpp +118 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
- package/runtime/ext_gui/webgl.h +48 -146
- package/runtime/ext_gui/webgl_blit.cpp +12 -1
- package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
- package/runtime/ext_gui/webgl_buffer.cpp +59 -1
- package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
- package/runtime/ext_gui/webgl_clear.cpp +3 -0
- package/runtime/ext_gui/webgl_context.cpp +29 -3
- package/runtime/ext_gui/webgl_draw.cpp +75 -270
- package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
- package/runtime/ext_gui/webgl_draw_state.h +130 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
- package/runtime/ext_gui/webgl_objects.h +148 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
- package/runtime/ext_gui/webgl_program_internal.h +35 -0
- package/runtime/ext_gui/webgl_shader.cpp +22 -30
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/src/codegen/generator/module.ts +22 -7
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +9 -2
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the Canvas2D features added after the first canvas
|
|
3
|
+
* slice: clipping, compositing, shadows, hit testing, smoothing, data-URL
|
|
4
|
+
* backgrounds and `OffscreenCanvas`.
|
|
5
|
+
*
|
|
6
|
+
* They run the real rasteriser and read pixels back with `getImageData`, so a
|
|
7
|
+
* regression in coverage/alpha math shows up as a concrete colour.
|
|
8
|
+
*/
|
|
9
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
10
|
+
import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
|
|
11
|
+
const harness = createGuiHarness();
|
|
12
|
+
const PAGE = `
|
|
13
|
+
<html><head><style>body { margin: 0; }</style></head><body>
|
|
14
|
+
<canvas id="c" width="120" height="120"></canvas>
|
|
15
|
+
<canvas id="src" width="20" height="20"></canvas>
|
|
16
|
+
<canvas id="transferred" width="20" height="20"></canvas>
|
|
17
|
+
<div id="bg" style="width:40px;height:40px"></div>
|
|
18
|
+
</body></html>`;
|
|
19
|
+
describe.skipIf(!guiAvailable)("gui extension — canvas state, clip and offscreen", () => {
|
|
20
|
+
beforeAll(() => harness.setup());
|
|
21
|
+
afterAll(() => harness.cleanup());
|
|
22
|
+
it("clips drawing and composites with the Porter-Duff operators", () => {
|
|
23
|
+
const { value } = harness.compileAndRun("canvas-clip-composite", `
|
|
24
|
+
import { createWindow, run } from "gui";
|
|
25
|
+
|
|
26
|
+
const win = createWindow({ title: "clip", width: 400, height: 300 });
|
|
27
|
+
win.on("ready", () => {
|
|
28
|
+
const canvas: any = document.getElementById("c");
|
|
29
|
+
const ctx: any = canvas.getContext("2d");
|
|
30
|
+
const px = (x: number, y: number): string => {
|
|
31
|
+
const d = ctx.getImageData(x, y, 1, 1).data;
|
|
32
|
+
return d[0] + "," + d[1] + "," + d[2] + "," + d[3];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
ctx.fillStyle = "#ffffff";
|
|
36
|
+
ctx.fillRect(0, 0, 120, 120);
|
|
37
|
+
|
|
38
|
+
// A rectangular clip keeps a red fill inside (0,0)-(50,50).
|
|
39
|
+
ctx.save();
|
|
40
|
+
ctx.beginPath();
|
|
41
|
+
ctx.rect(0, 0, 50, 50);
|
|
42
|
+
ctx.clip();
|
|
43
|
+
ctx.fillStyle = "#ff0000";
|
|
44
|
+
ctx.fillRect(0, 0, 120, 120);
|
|
45
|
+
ctx.restore();
|
|
46
|
+
console.log("clip-in=" + px(25, 25));
|
|
47
|
+
console.log("clip-out=" + px(75, 25));
|
|
48
|
+
// restore() brings the unclipped region back.
|
|
49
|
+
ctx.fillStyle = "#00ff00";
|
|
50
|
+
ctx.fillRect(75, 75, 20, 20);
|
|
51
|
+
console.log("after-restore=" + px(80, 80));
|
|
52
|
+
|
|
53
|
+
// A Path2D clip.
|
|
54
|
+
const path: any = new Path2D();
|
|
55
|
+
path.rect(60, 0, 20, 20);
|
|
56
|
+
ctx.save();
|
|
57
|
+
ctx.clip(path);
|
|
58
|
+
ctx.fillStyle = "#0000ff";
|
|
59
|
+
ctx.fillRect(60, 0, 20, 20);
|
|
60
|
+
ctx.restore();
|
|
61
|
+
console.log("path-clip=" + px(65, 5));
|
|
62
|
+
|
|
63
|
+
// destination-out clears the covered pixels to transparent.
|
|
64
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
65
|
+
ctx.fillStyle = "#000000";
|
|
66
|
+
ctx.fillRect(0, 0, 20, 20);
|
|
67
|
+
console.log("composite=" + ctx.globalCompositeOperation);
|
|
68
|
+
console.log("dest-out=" + px(10, 10));
|
|
69
|
+
ctx.globalCompositeOperation = "source-over";
|
|
70
|
+
|
|
71
|
+
// isPointInPath / isPointInStroke use the current path and transform.
|
|
72
|
+
ctx.beginPath();
|
|
73
|
+
ctx.rect(10, 10, 20, 20);
|
|
74
|
+
console.log("point-in=" + ctx.isPointInPath(15, 15));
|
|
75
|
+
console.log("point-out=" + ctx.isPointInPath(50, 50));
|
|
76
|
+
ctx.lineWidth = 6;
|
|
77
|
+
ctx.beginPath();
|
|
78
|
+
ctx.moveTo(80, 80);
|
|
79
|
+
ctx.lineTo(110, 80);
|
|
80
|
+
console.log("stroke-in=" + ctx.isPointInStroke(95, 81));
|
|
81
|
+
console.log("stroke-out=" + ctx.isPointInStroke(95, 95));
|
|
82
|
+
win.close();
|
|
83
|
+
});
|
|
84
|
+
win.loadHTML(\`${PAGE}\`);
|
|
85
|
+
run();
|
|
86
|
+
`);
|
|
87
|
+
expect(value("clip-in")).toBe("255,0,0,255");
|
|
88
|
+
expect(value("clip-out")).toBe("255,255,255,255");
|
|
89
|
+
expect(value("after-restore")).toBe("0,255,0,255");
|
|
90
|
+
expect(value("path-clip")).toBe("0,0,255,255");
|
|
91
|
+
expect(value("composite")).toBe("destination-out");
|
|
92
|
+
// destination-out on an opaque white pixel leaves transparent black.
|
|
93
|
+
expect(value("dest-out")).toBe("0,0,0,0");
|
|
94
|
+
expect(value("point-in")).toBe("true");
|
|
95
|
+
expect(value("point-out")).toBe("false");
|
|
96
|
+
expect(value("stroke-in")).toBe("true");
|
|
97
|
+
expect(value("stroke-out")).toBe("false");
|
|
98
|
+
});
|
|
99
|
+
it("paints offset shadows under the shape", () => {
|
|
100
|
+
const { value } = harness.compileAndRun("canvas-shadow", `
|
|
101
|
+
import { createWindow, run } from "gui";
|
|
102
|
+
|
|
103
|
+
const win = createWindow({ title: "shadow", width: 400, height: 300 });
|
|
104
|
+
win.on("ready", () => {
|
|
105
|
+
const canvas: any = document.getElementById("c");
|
|
106
|
+
const ctx: any = canvas.getContext("2d");
|
|
107
|
+
const px = (x: number, y: number): string => {
|
|
108
|
+
const d = ctx.getImageData(x, y, 1, 1).data;
|
|
109
|
+
return d[0] + "," + d[1] + "," + d[2] + "," + d[3];
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
ctx.shadowColor = "#000000";
|
|
113
|
+
ctx.shadowBlur = 0;
|
|
114
|
+
ctx.shadowOffsetX = 10;
|
|
115
|
+
ctx.shadowOffsetY = 10;
|
|
116
|
+
ctx.fillStyle = "#ff0000";
|
|
117
|
+
ctx.fillRect(10, 10, 20, 20);
|
|
118
|
+
console.log("color=" + ctx.shadowColor);
|
|
119
|
+
console.log("offsets=" + ctx.shadowOffsetX + "," + ctx.shadowOffsetY);
|
|
120
|
+
console.log("shape=" + px(20, 20));
|
|
121
|
+
console.log("shadow=" + px(35, 35));
|
|
122
|
+
console.log("outside=" + px(5, 5));
|
|
123
|
+
|
|
124
|
+
// The shadow is not part of clearRect, and a transparent shadow
|
|
125
|
+
// colour disables it again.
|
|
126
|
+
ctx.shadowColor = "rgba(0,0,0,0)";
|
|
127
|
+
ctx.fillStyle = "#0000ff";
|
|
128
|
+
ctx.fillRect(60, 10, 10, 10);
|
|
129
|
+
console.log("no-shadow=" + px(75, 15));
|
|
130
|
+
win.close();
|
|
131
|
+
});
|
|
132
|
+
win.loadHTML(\`${PAGE}\`);
|
|
133
|
+
run();
|
|
134
|
+
`);
|
|
135
|
+
expect(value("color")).toBe("#000000");
|
|
136
|
+
expect(value("offsets")).toBe("10,10");
|
|
137
|
+
expect(value("shape")).toBe("255,0,0,255");
|
|
138
|
+
expect(value("shadow")).toBe("0,0,0,255");
|
|
139
|
+
expect(value("outside")).toBe("0,0,0,0");
|
|
140
|
+
expect(value("no-shadow")).toBe("0,0,0,0");
|
|
141
|
+
});
|
|
142
|
+
it("honours image smoothing and the inner radial circle", () => {
|
|
143
|
+
const { value } = harness.compileAndRun("canvas-smoothing-radial", `
|
|
144
|
+
import { createWindow, run } from "gui";
|
|
145
|
+
|
|
146
|
+
const win = createWindow({ title: "smoothing", width: 400, height: 300 });
|
|
147
|
+
win.on("ready", () => {
|
|
148
|
+
const canvas: any = document.getElementById("c");
|
|
149
|
+
const ctx: any = canvas.getContext("2d");
|
|
150
|
+
const px = (x: number, y: number): string => {
|
|
151
|
+
const d = ctx.getImageData(x, y, 1, 1).data;
|
|
152
|
+
return d[0] + "," + d[1] + "," + d[2] + "," + d[3];
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// A 2x2 source (red left, blue right), blown up to 40x40.
|
|
156
|
+
const source: any = new OffscreenCanvas(2, 2);
|
|
157
|
+
const sctx: any = source.getContext("2d");
|
|
158
|
+
sctx.putImageData({ width: 2, height: 2, data: [
|
|
159
|
+
255, 0, 0, 255, 0, 0, 255, 255,
|
|
160
|
+
255, 0, 0, 255, 0, 0, 255, 255] }, 0, 0);
|
|
161
|
+
|
|
162
|
+
console.log("smoothing-default=" + ctx.imageSmoothingEnabled);
|
|
163
|
+
ctx.drawImage(source, 0, 0, 40, 40);
|
|
164
|
+
console.log("smooth=" + px(20, 20));
|
|
165
|
+
ctx.clearRect(0, 0, 120, 120);
|
|
166
|
+
ctx.imageSmoothingEnabled = false;
|
|
167
|
+
console.log("smoothing-off=" + ctx.imageSmoothingEnabled);
|
|
168
|
+
ctx.drawImage(source, 0, 0, 40, 40);
|
|
169
|
+
console.log("blocky=" + px(20, 20));
|
|
170
|
+
ctx.imageSmoothingQuality = "high";
|
|
171
|
+
console.log("quality=" + ctx.imageSmoothingQuality);
|
|
172
|
+
|
|
173
|
+
// A radial gradient whose inner circle is off-centre: the point at the
|
|
174
|
+
// inner centre is white, the outer circle black. (A concentric
|
|
175
|
+
// implementation would make both black.)
|
|
176
|
+
const radial = ctx.createRadialGradient(20, 50, 0, 50, 50, 30);
|
|
177
|
+
radial.addColorStop(0, "#ffffff");
|
|
178
|
+
radial.addColorStop(1, "#000000");
|
|
179
|
+
ctx.fillStyle = radial;
|
|
180
|
+
ctx.fillRect(0, 30, 100, 40);
|
|
181
|
+
console.log("radial-inner=" + px(20, 50));
|
|
182
|
+
console.log("radial-outer=" + px(80, 50));
|
|
183
|
+
win.close();
|
|
184
|
+
});
|
|
185
|
+
win.loadHTML(\`${PAGE}\`);
|
|
186
|
+
run();
|
|
187
|
+
`);
|
|
188
|
+
expect(value("smoothing-default")).toBe("true");
|
|
189
|
+
// Bilinear samples between the red and blue texels.
|
|
190
|
+
const smooth = value("smooth").split(",").map(Number);
|
|
191
|
+
expect(smooth[0]).toBeGreaterThan(20);
|
|
192
|
+
expect(smooth[2]).toBeGreaterThan(20);
|
|
193
|
+
expect(value("smoothing-off")).toBe("false");
|
|
194
|
+
expect(value("blocky")).toBe("0,0,255,255");
|
|
195
|
+
expect(value("quality")).toBe("high");
|
|
196
|
+
const radialInner = value("radial-inner").split(",").map(Number);
|
|
197
|
+
expect(radialInner[0]).toBeGreaterThan(245);
|
|
198
|
+
expect(value("radial-outer")).toBe("0,0,0,255");
|
|
199
|
+
});
|
|
200
|
+
it("supports OffscreenCanvas and transferControlToOffscreen", () => {
|
|
201
|
+
const { value } = harness.compileAndRun("canvas-offscreen", `
|
|
202
|
+
import { createWindow, run } from "gui";
|
|
203
|
+
|
|
204
|
+
const win = createWindow({ title: "offscreen", width: 400, height: 300 });
|
|
205
|
+
win.on("ready", () => {
|
|
206
|
+
const canvas: any = document.getElementById("c");
|
|
207
|
+
const ctx: any = canvas.getContext("2d");
|
|
208
|
+
const px = (x: number, y: number): string => {
|
|
209
|
+
const d = ctx.getImageData(x, y, 1, 1).data;
|
|
210
|
+
return d[0] + "," + d[1] + "," + d[2] + "," + d[3];
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const off: any = new OffscreenCanvas(20, 10);
|
|
214
|
+
console.log("size=" + off.width + "x" + off.height);
|
|
215
|
+
console.log("instanceof=" + (off instanceof OffscreenCanvas));
|
|
216
|
+
const octx: any = off.getContext("2d");
|
|
217
|
+
console.log("ctx=" + (octx != null) + "," + (off.getContext("2d") === octx) + "," +
|
|
218
|
+
(octx.canvas === off));
|
|
219
|
+
octx.fillStyle = "#00ff00";
|
|
220
|
+
octx.fillRect(0, 0, 20, 10);
|
|
221
|
+
ctx.drawImage(off, 0, 0);
|
|
222
|
+
console.log("drawn=" + px(10, 5));
|
|
223
|
+
|
|
224
|
+
const bitmap: any = off.transferToImageBitmap();
|
|
225
|
+
console.log("bitmap=" + bitmap.width + "x" + bitmap.height);
|
|
226
|
+
|
|
227
|
+
// alpha:false starts as opaque black, like a DOM canvas.
|
|
228
|
+
const opaque: any = new OffscreenCanvas(4, 4);
|
|
229
|
+
const opaqueCtx: any = opaque.getContext("2d", { alpha: false });
|
|
230
|
+
const opaquePixel = opaqueCtx.getImageData(0, 0, 1, 1).data;
|
|
231
|
+
console.log("opaque=" + opaqueCtx.getContextAttributes().alpha + "," +
|
|
232
|
+
opaquePixel[0] + "," + opaquePixel[1] + "," + opaquePixel[2] + "," + opaquePixel[3]);
|
|
233
|
+
|
|
234
|
+
// Transfer a live element: the element loses its context, the returned
|
|
235
|
+
// OffscreenCanvas keeps drawing into the same bitmap.
|
|
236
|
+
const element: any = document.getElementById("transferred");
|
|
237
|
+
const transferred: any = element.transferControlToOffscreen();
|
|
238
|
+
console.log("transferred=" + (transferred != null));
|
|
239
|
+
console.log("element-ctx=" + (element.getContext("2d") == null));
|
|
240
|
+
const tctx: any = transferred.getContext("2d");
|
|
241
|
+
tctx.fillStyle = "#ff00ff";
|
|
242
|
+
tctx.fillRect(0, 0, 20, 20);
|
|
243
|
+
ctx.drawImage(transferred, 50, 50);
|
|
244
|
+
console.log("transfer-draw=" + px(60, 60));
|
|
245
|
+
|
|
246
|
+
// convertToBlob resolves to a PNG blob.
|
|
247
|
+
off.convertToBlob().then((blob: any): void => {
|
|
248
|
+
console.log("blob=" + blob.type + "," + (blob.size > 0));
|
|
249
|
+
win.close();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
win.loadHTML(\`${PAGE}\`);
|
|
253
|
+
run();
|
|
254
|
+
`, { autocloseMs: 2000 });
|
|
255
|
+
expect(value("size")).toBe("20x10");
|
|
256
|
+
expect(value("instanceof")).toBe("true");
|
|
257
|
+
expect(value("ctx")).toBe("true,true,true");
|
|
258
|
+
expect(value("drawn")).toBe("0,255,0,255");
|
|
259
|
+
expect(value("bitmap")).toBe("20x10");
|
|
260
|
+
expect(value("opaque")).toBe("false,0,0,0,255");
|
|
261
|
+
expect(value("transferred")).toBe("true");
|
|
262
|
+
expect(value("element-ctx")).toBe("true");
|
|
263
|
+
expect(value("transfer-draw")).toBe("255,0,255,255");
|
|
264
|
+
expect(value("blob")).toBe("image/png,true");
|
|
265
|
+
});
|
|
266
|
+
it("paints a canvas data URL as a CSS background-image", () => {
|
|
267
|
+
const { value } = harness.compileAndRun("canvas-background-image", `
|
|
268
|
+
import { createWindow, run } from "gui";
|
|
269
|
+
|
|
270
|
+
const win = createWindow({ title: "bg", width: 400, height: 300 });
|
|
271
|
+
win.on("ready", () => {
|
|
272
|
+
const source: any = document.getElementById("src");
|
|
273
|
+
const sctx: any = source.getContext("2d");
|
|
274
|
+
sctx.fillStyle = "#ff00ff";
|
|
275
|
+
sctx.fillRect(0, 0, 20, 20);
|
|
276
|
+
const url: string = source.toDataURL();
|
|
277
|
+
const bg: any = document.getElementById("bg");
|
|
278
|
+
bg.style.backgroundImage = "url(" + url + ")";
|
|
279
|
+
const list: string = win.paintList();
|
|
280
|
+
console.log("has-image=" + (list.indexOf("src=data:image/png;base64,") >= 0));
|
|
281
|
+
const computed: string = getComputedStyle(bg).backgroundImage;
|
|
282
|
+
console.log("inline=" + (bg.style.backgroundImage.indexOf("url(") === 0));
|
|
283
|
+
console.log("computed-width=" + getComputedStyle(bg).width);
|
|
284
|
+
console.log("computed-head=" + computed.substring(0, 24));
|
|
285
|
+
console.log("computed=" + (computed.indexOf("url(data:image/png") === 0));
|
|
286
|
+
win.close();
|
|
287
|
+
});
|
|
288
|
+
win.loadHTML(\`${PAGE}\`);
|
|
289
|
+
run();
|
|
290
|
+
`);
|
|
291
|
+
expect(value("has-image")).toBe("true");
|
|
292
|
+
expect(value("inline")).toBe("true");
|
|
293
|
+
expect(value("computed-width")).toBe("40px");
|
|
294
|
+
expect(value("computed")).toBe("true");
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=gui-canvas-state.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui-canvas-state.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-canvas-state.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for `data:` image URLs: raster and SVG, base64 and
|
|
3
|
+
* percent-encoded payloads, in `<img>`, `canvas.drawImage(String, …)` and CSS
|
|
4
|
+
* `background-image`.
|
|
5
|
+
*
|
|
6
|
+
* The SVG below deliberately exercises the decoder, not NanoSVG's feature set:
|
|
7
|
+
* the engine rasterises NanoSVG's subset, so an SVG that uses filters still
|
|
8
|
+
* decodes but renders the shapes without the filter effect.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for `data:` image URLs: raster and SVG, base64 and
|
|
3
|
+
* percent-encoded payloads, in `<img>`, `canvas.drawImage(String, …)` and CSS
|
|
4
|
+
* `background-image`.
|
|
5
|
+
*
|
|
6
|
+
* The SVG below deliberately exercises the decoder, not NanoSVG's feature set:
|
|
7
|
+
* the engine rasterises NanoSVG's subset, so an SVG that uses filters still
|
|
8
|
+
* decodes but renders the shapes without the filter effect.
|
|
9
|
+
*/
|
|
10
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
11
|
+
import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
|
|
12
|
+
const harness = createGuiHarness();
|
|
13
|
+
/* 4x4 PNG: left half red, right half blue. */
|
|
14
|
+
const PNG = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAFElEQVR42mP4z8DwH4Sh1H8G0gUALFAf4eNWqTEAAAAASUVORK5CYII=";
|
|
15
|
+
const SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="8" height="6"><rect width="8" height="6" fill="#ff0000"/></svg>';
|
|
16
|
+
const SVG_B64 = Buffer.from(SVG).toString("base64");
|
|
17
|
+
const SVG_ENC = encodeURIComponent(SVG);
|
|
18
|
+
/** The `feTurbulence` example from the request: `<filter>` is not in NanoSVG's
|
|
19
|
+
* subset, but the document still decodes (the rect renders, unfiltered). */
|
|
20
|
+
const NOISE = "data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.8'/%3E%3C/svg%3E";
|
|
21
|
+
const PAGE = `
|
|
22
|
+
<html><head><style>body { margin: 0; }</style></head><body>
|
|
23
|
+
<img id="vec" src="data:image/svg+xml,${SVG_ENC}">
|
|
24
|
+
<img id="vec64" src="data:image/svg+xml;base64,${SVG_B64}">
|
|
25
|
+
<img id="noise" src="${NOISE}">
|
|
26
|
+
<div id="bg" style="width:20px;height:20px"></div>
|
|
27
|
+
<canvas id="c" width="240" height="240"></canvas>
|
|
28
|
+
</body></html>`;
|
|
29
|
+
describe.skipIf(!guiAvailable)("gui extension — data URL images", () => {
|
|
30
|
+
beforeAll(() => harness.setup());
|
|
31
|
+
afterAll(() => harness.cleanup());
|
|
32
|
+
it("decodes SVG data URLs in <img>, drawImage and CSS backgrounds", () => {
|
|
33
|
+
const { value, stderr } = harness.compileAndRun("data-url-svg", `
|
|
34
|
+
import { createWindow, run } from "gui";
|
|
35
|
+
|
|
36
|
+
const win = createWindow({ title: "data-url", width: 500, height: 400 });
|
|
37
|
+
win.on("ready", () => {
|
|
38
|
+
const doc: any = document;
|
|
39
|
+
const ctx: any = doc.getElementById("c").getContext("2d");
|
|
40
|
+
const px = (x: number, y: number): string => {
|
|
41
|
+
const d = ctx.getImageData(x, y, 1, 1).data;
|
|
42
|
+
return d[0] + "," + d[1] + "," + d[2] + "," + d[3];
|
|
43
|
+
};
|
|
44
|
+
const clear = (): void => { ctx.clearRect(0, 0, 240, 240); };
|
|
45
|
+
const box = (id: string): string => {
|
|
46
|
+
const r: any = doc.getElementById(id).getBoundingClientRect();
|
|
47
|
+
return r.width + "x" + r.height;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const png = "data:image/png;base64,${PNG}";
|
|
51
|
+
const svgEnc = "data:image/svg+xml,${SVG_ENC}";
|
|
52
|
+
const svg64 = "data:image/svg+xml;base64,${SVG_B64}";
|
|
53
|
+
const noise = "${NOISE}";
|
|
54
|
+
|
|
55
|
+
console.log("vec-box=" + box("vec"));
|
|
56
|
+
console.log("vec64-box=" + box("vec64"));
|
|
57
|
+
console.log("noise-box=" + box("noise"));
|
|
58
|
+
|
|
59
|
+
// A raster data URL drawn from its string, without an <img>.
|
|
60
|
+
clear();
|
|
61
|
+
ctx.drawImage(png, 0, 0);
|
|
62
|
+
console.log("png-string=" + px(0, 0) + ":" + px(3, 0));
|
|
63
|
+
|
|
64
|
+
// SVG data URLs in both encodings, as a string and as an <img>.
|
|
65
|
+
clear();
|
|
66
|
+
ctx.drawImage(svgEnc, 0, 0);
|
|
67
|
+
console.log("svg-enc-string=" + px(0, 0) + ":" + px(7, 5));
|
|
68
|
+
|
|
69
|
+
clear();
|
|
70
|
+
ctx.drawImage(svg64, 0, 0);
|
|
71
|
+
console.log("svg64-string=" + px(0, 0));
|
|
72
|
+
|
|
73
|
+
clear();
|
|
74
|
+
ctx.drawImage(svgEnc, 0, 0, 16, 12);
|
|
75
|
+
console.log("svg-scaled=" + px(0, 0) + ":" + px(15, 11));
|
|
76
|
+
|
|
77
|
+
clear();
|
|
78
|
+
ctx.drawImage(doc.getElementById("vec"), 0, 0);
|
|
79
|
+
console.log("svg-img=" + px(0, 0));
|
|
80
|
+
|
|
81
|
+
clear();
|
|
82
|
+
ctx.drawImage(doc.getElementById("vec64"), 0, 0);
|
|
83
|
+
console.log("svg64-img=" + px(0, 0));
|
|
84
|
+
|
|
85
|
+
// The request's feTurbulence document: it decodes (opaque rect), while
|
|
86
|
+
// the filter itself remains outside NanoSVG's subset.
|
|
87
|
+
clear();
|
|
88
|
+
ctx.drawImage(noise, 0, 0, 32, 32);
|
|
89
|
+
console.log("noise-alpha=" + ctx.getImageData(0, 0, 1, 1).data[3]);
|
|
90
|
+
|
|
91
|
+
// SVG data URL as a CSS background.
|
|
92
|
+
const bg: any = doc.getElementById("bg");
|
|
93
|
+
bg.style.backgroundImage = 'url("' + svgEnc + '")';
|
|
94
|
+
console.log("bg-css=" + getComputedStyle(bg).backgroundImage.substring(0, 26));
|
|
95
|
+
let hits = 0;
|
|
96
|
+
for (const line of win.paintList().split("\\n")) {
|
|
97
|
+
if (line.indexOf("src=data:image/svg+xml") >= 0) hits++;
|
|
98
|
+
}
|
|
99
|
+
console.log("paint-svg=" + hits);
|
|
100
|
+
|
|
101
|
+
// Let one rendered frame decode the background texture (stderr reports
|
|
102
|
+
// a failure), then close.
|
|
103
|
+
requestAnimationFrame(() => {
|
|
104
|
+
requestAnimationFrame(() => {
|
|
105
|
+
win.close();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
win.loadHTML(\`${PAGE}\`);
|
|
110
|
+
run();
|
|
111
|
+
`, { autocloseMs: 3000 });
|
|
112
|
+
expect(value("vec-box")).toBe("8x6");
|
|
113
|
+
expect(value("vec64-box")).toBe("8x6");
|
|
114
|
+
expect(value("noise-box")).toBe("180x180");
|
|
115
|
+
expect(value("png-string")).toBe("255,0,0,255:0,0,255,255");
|
|
116
|
+
expect(value("svg-enc-string")).toBe("255,0,0,255:255,0,0,255");
|
|
117
|
+
expect(value("svg64-string")).toBe("255,0,0,255");
|
|
118
|
+
expect(value("svg-scaled")).toBe("255,0,0,255:255,0,0,255");
|
|
119
|
+
expect(value("svg-img")).toBe("255,0,0,255");
|
|
120
|
+
expect(value("svg64-img")).toBe("255,0,0,255");
|
|
121
|
+
expect(Number(value("noise-alpha"))).toBeGreaterThan(0);
|
|
122
|
+
expect(value("bg-css")).toMatch(/^url\(data:image\/svg\+xml/);
|
|
123
|
+
expect(value("paint-svg")).toBe("4");
|
|
124
|
+
expect(stderr).not.toContain("could not decode image");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=gui-data-url.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui-data-url.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-data-url.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;AAEnC,8CAA8C;AAC9C,MAAM,GAAG,GACP,0GAA0G,CAAC;AAC7G,MAAM,GAAG,GACP,gHAAgH,CAAC;AACnH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACpD,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;AAExC;4EAC4E;AAC5E,MAAM,KAAK,GACT,4SAA4S,CAAC;AAE/S,MAAM,IAAI,GAAG;;wCAE2B,OAAO;iDACE,OAAO;uBACjC,KAAK;;;eAGb,CAAC;AAEhB,QAAQ,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,iCAAiC,EAAE,GAAG,EAAE;IACrE,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAElC,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAC7C,cAAc,EACd;;;;;;;;;;;;;;;;;6CAiBuC,GAAG;6CACH,OAAO;mDACD,OAAO;yBACjC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAwDP,IAAI;;OAEpB,EACD,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end benchmark for the two immediate-mode drawing surfaces.
|
|
3
|
+
*
|
|
4
|
+
* The `gui-perf` suite measures the retained DOM pipeline (restyle/layout/paint
|
|
5
|
+
* runs). This one measures the two APIs a multi-element scene actually calls
|
|
6
|
+
* thousands of times per frame:
|
|
7
|
+
*
|
|
8
|
+
* - `<canvas>` 2D: solid `fillRect`, multi-segment `stroke`, repeated
|
|
9
|
+
* `fillText` and 1:1 `drawImage`, drawn into a 1280x720 bitmap;
|
|
10
|
+
* - WebGL: 2000 `drawElements` calls with a per-draw matrix, plus a 64 KB
|
|
11
|
+
* `bufferSubData` into a 4 MB buffer.
|
|
12
|
+
*
|
|
13
|
+
* The programs print wall-clock milliseconds per scene (informational: CI may
|
|
14
|
+
* run on a software GPU) and the engine counters that a regression would move:
|
|
15
|
+
* `canvasDraws`/`canvasUploads`/`canvasUploadBytes` and
|
|
16
|
+
* `webglDraws`/`webglPasses`/`webglPipelineMisses`/`webglBufferUploadBytes`
|
|
17
|
+
* from `win.stats()` (see `runtime/ext_gui/perf.h`).
|
|
18
|
+
*
|
|
19
|
+
* The counters are asserted (deterministic). Timings are printed and, on a
|
|
20
|
+
* developer machine, can be bounded with `XBINTSC_GUI_DRAW_PERF_STRICT_MS`.
|
|
21
|
+
*/
|
|
22
|
+
export {};
|