react-x11 2.42.0 → 2.43.0
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/package.json +1 -1
- package/src/node.d.ts +18 -0
- package/src/wayland/context2d.js +68 -6
- package/src/wayland/device.js +2 -1
- package/src/wayland/surface.js +10 -0
package/package.json
CHANGED
package/src/node.d.ts
CHANGED
|
@@ -220,6 +220,24 @@ export interface Context2D {
|
|
|
220
220
|
dw: number,
|
|
221
221
|
dh: number,
|
|
222
222
|
): void;
|
|
223
|
+
/**
|
|
224
|
+
* Draw an image through a projection, in one draw: its pixel (u, v) lands
|
|
225
|
+
* where the 3×3 `matrix` — row-major, `[a, b, c, d, e, f, g, h, i]` — takes
|
|
226
|
+
* it, ((a·u + b·v + c) / w, (d·u + e·v + f) / w) with
|
|
227
|
+
* w = g·u + h·v + i, and the current transform takes that; clipped and
|
|
228
|
+
* faded by `globalAlpha` as `drawImage` is. A plane turned out of the page
|
|
229
|
+
* — CSS `rotateY()` in a `perspective` — is one draw where it would be
|
|
230
|
+
* hundreds of tiles each drawn through the affine matrix nearest it.
|
|
231
|
+
* Answers false, drawing nothing, where a corner of the image has w ≤ 0,
|
|
232
|
+
* behind the viewer.
|
|
233
|
+
*
|
|
234
|
+
* The Wayland context only. A GPU interpolates texture coordinates in
|
|
235
|
+
* perspective; XRender on glamor divides at the corners and folds the
|
|
236
|
+
* image along its diagonal, and CoreGraphics and Direct2D draw an image
|
|
237
|
+
* through an affine matrix alone. Test for it with `'drawImageProjected'
|
|
238
|
+
* in ctx`, and tile where it is absent.
|
|
239
|
+
*/
|
|
240
|
+
drawImageProjected?(image: unknown, matrix: readonly number[]): boolean;
|
|
223
241
|
createLinearGradient(
|
|
224
242
|
x0: number,
|
|
225
243
|
y0: number,
|
package/src/wayland/context2d.js
CHANGED
|
@@ -65,6 +65,8 @@ const MODE_TEXTURE = 1;
|
|
|
65
65
|
const MODE_GLYPH = 2;
|
|
66
66
|
const MODE_RRECT = 3;
|
|
67
67
|
const MODE_GRADIENT = 4;
|
|
68
|
+
/** A texture read through a projection: `vParams` is (s/w, t/w, 1/w). */
|
|
69
|
+
const MODE_PROJECTIVE = 5;
|
|
68
70
|
|
|
69
71
|
/**
|
|
70
72
|
* The stencil buffer, shared between two uses: bit 7 is the clip (set where
|
|
@@ -114,7 +116,9 @@ const FRAG = `
|
|
|
114
116
|
precision mediump float;
|
|
115
117
|
varying vec2 vUV;
|
|
116
118
|
varying vec4 vColor;
|
|
117
|
-
|
|
119
|
+
// highp: in MODE_PROJECTIVE these are texture coordinates over w, divided
|
|
120
|
+
// per fragment, and half floats would put a large texture a pixel out
|
|
121
|
+
varying highp vec4 vParams;
|
|
118
122
|
uniform int uMode;
|
|
119
123
|
uniform int uSwizzle;
|
|
120
124
|
uniform sampler2D uTex;
|
|
@@ -156,6 +160,10 @@ void main() {
|
|
|
156
160
|
else if (w < 0.0) a = 1.0 - smoothstep(w, -w, d);
|
|
157
161
|
else a = 1.0 - smoothstep(-0.5, 0.5, d);
|
|
158
162
|
gl_FragColor = vColor * a;
|
|
163
|
+
} else if (uMode == 5) {
|
|
164
|
+
// Interpolated across the quad in the plane of the screen, s/w, t/w and
|
|
165
|
+
// 1/w are each exact, and so is their quotient: a texture in perspective.
|
|
166
|
+
gl_FragColor = vColor * sampleTex(vParams.xy / vParams.z);
|
|
159
167
|
} else {
|
|
160
168
|
// Gradients are evaluated per fragment from its device position, so any
|
|
161
169
|
// shape — a cover quad over a path included — can be filled with one.
|
|
@@ -1450,6 +1458,56 @@ export class WaylandContext2D {
|
|
|
1450
1458
|
);
|
|
1451
1459
|
}
|
|
1452
1460
|
|
|
1461
|
+
/**
|
|
1462
|
+
* Draw `img` through a projection, as one quad: its pixel (u, v) lands
|
|
1463
|
+
* where the 3×3 `m` — row-major, `[a, b, c, d, e, f, g, h, i]` — takes it,
|
|
1464
|
+
* ((a·u + b·v + c) / w, (d·u + e·v + f) / w) with w = g·u + h·v + i, and
|
|
1465
|
+
* the current transform takes that. Clipped and faded by `globalAlpha` as
|
|
1466
|
+
* `drawImage` is. Each corner carries its texture coordinates over its w,
|
|
1467
|
+
* which are exact anywhere across the quad, and the fragment divides them
|
|
1468
|
+
* back: the image in perspective, where a quad's own interpolation would
|
|
1469
|
+
* fold it along its diagonal. That fold is what RENDER on glamor draws for
|
|
1470
|
+
* a projective picture transform, and why X11 has no such call.
|
|
1471
|
+
*
|
|
1472
|
+
* Draws nothing and answers false where a corner has w ≤ 0, behind the
|
|
1473
|
+
* viewer: the caller draws the part in front another way.
|
|
1474
|
+
*/
|
|
1475
|
+
drawImageProjected(img, m) {
|
|
1476
|
+
this._claim();
|
|
1477
|
+
const src = this._textureFor(img);
|
|
1478
|
+
if (!src) return false;
|
|
1479
|
+
const [a, b, c, d, e, f, g, h, i] = m;
|
|
1480
|
+
const W = src.w;
|
|
1481
|
+
const H = src.h;
|
|
1482
|
+
const ctm = this._m;
|
|
1483
|
+
const pos = new Array(8);
|
|
1484
|
+
const params = new Array(16);
|
|
1485
|
+
const us = [0, W, W, 0];
|
|
1486
|
+
const vs = [0, 0, H, H];
|
|
1487
|
+
for (let k = 0; k < 4; k++) {
|
|
1488
|
+
const u = us[k];
|
|
1489
|
+
const v = vs[k];
|
|
1490
|
+
const w = g * u + h * v + i;
|
|
1491
|
+
if (!(w > 1e-9)) return false;
|
|
1492
|
+
const x = (a * u + b * v + c) / w;
|
|
1493
|
+
const y = (d * u + e * v + f) / w;
|
|
1494
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return false;
|
|
1495
|
+
pos[k * 2] = applyX(ctm, x, y);
|
|
1496
|
+
pos[k * 2 + 1] = applyY(ctm, x, y);
|
|
1497
|
+
const s = u / W;
|
|
1498
|
+
// a render target's row 0 is the bottom of what was drawn into it
|
|
1499
|
+
const t = src.flipY ? 1 - v / H : v / H;
|
|
1500
|
+
params[k * 4] = s / w;
|
|
1501
|
+
params[k * 4 + 1] = t / w;
|
|
1502
|
+
params[k * 4 + 2] = 1 / w;
|
|
1503
|
+
params[k * 4 + 3] = 0;
|
|
1504
|
+
}
|
|
1505
|
+
this._setMode(MODE_PROJECTIVE, src.tex, src.swizzle);
|
|
1506
|
+
const alpha = this.globalAlpha;
|
|
1507
|
+
this._quad(pos, ZERO8, [alpha, alpha, alpha, alpha], params);
|
|
1508
|
+
return true;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1453
1511
|
/**
|
|
1454
1512
|
* Write pixels, ignoring the transform and the clip (the canvas rule).
|
|
1455
1513
|
* `dirtyX/Y/Width/Height` select part of the data, as the spec has it.
|
|
@@ -1926,7 +1984,8 @@ export class WaylandContext2D {
|
|
|
1926
1984
|
}
|
|
1927
1985
|
}
|
|
1928
1986
|
|
|
1929
|
-
/** Two triangles from four corners, in order TL, TR, BR, BL.
|
|
1987
|
+
/** Two triangles from four corners, in order TL, TR, BR, BL. `params` is
|
|
1988
|
+
* one vec4 for every corner, or sixteen numbers, a vec4 a corner. */
|
|
1930
1989
|
_quad(pos, uv, color, params) {
|
|
1931
1990
|
// Buffering is taking the device, not a step before it: the quad is GL
|
|
1932
1991
|
// work that has been decided on and not yet issued, and the handover in
|
|
@@ -1935,9 +1994,11 @@ export class WaylandContext2D {
|
|
|
1935
1994
|
this._claim();
|
|
1936
1995
|
if (this._n + 6 > MAX_VERTS) this._flush();
|
|
1937
1996
|
const v = this._verts;
|
|
1997
|
+
const each = params.length === 16 ? 4 : 0;
|
|
1938
1998
|
let o = this._n * STRIDE;
|
|
1939
1999
|
for (let k = 0; k < 6; k++) {
|
|
1940
2000
|
const i = TRI[k];
|
|
2001
|
+
const p = i * each;
|
|
1941
2002
|
v[o++] = pos[i * 2];
|
|
1942
2003
|
v[o++] = pos[i * 2 + 1];
|
|
1943
2004
|
v[o++] = uv[i * 2];
|
|
@@ -1946,10 +2007,10 @@ export class WaylandContext2D {
|
|
|
1946
2007
|
v[o++] = color[1];
|
|
1947
2008
|
v[o++] = color[2];
|
|
1948
2009
|
v[o++] = color[3];
|
|
1949
|
-
v[o++] = params[
|
|
1950
|
-
v[o++] = params[1];
|
|
1951
|
-
v[o++] = params[2];
|
|
1952
|
-
v[o++] = params[3];
|
|
2010
|
+
v[o++] = params[p];
|
|
2011
|
+
v[o++] = params[p + 1];
|
|
2012
|
+
v[o++] = params[p + 2];
|
|
2013
|
+
v[o++] = params[p + 3];
|
|
1953
2014
|
}
|
|
1954
2015
|
this._n += 6;
|
|
1955
2016
|
this.shapeStats.quads++;
|
|
@@ -2081,6 +2142,7 @@ export class WaylandContext2D {
|
|
|
2081
2142
|
|
|
2082
2143
|
const UV_UNIT = Object.freeze([0, 0, 1, 0, 1, 1, 0, 1]);
|
|
2083
2144
|
const ZERO4 = Object.freeze([0, 0, 0, 0]);
|
|
2145
|
+
const ZERO8 = Object.freeze([0, 0, 0, 0, 0, 0, 0, 0]);
|
|
2084
2146
|
|
|
2085
2147
|
// ---- geometry helpers ------------------------------------------------------------
|
|
2086
2148
|
|
package/src/wayland/device.js
CHANGED
|
@@ -70,7 +70,8 @@ export function releaseDevice(gl) {
|
|
|
70
70
|
* The owner is the only context that can be holding anything (see above), so
|
|
71
71
|
* flushing it is flushing the device. Call before *reading* a target's pixels
|
|
72
72
|
* behind the contexts' backs — a framebuffer blit, a scroll copy — the way
|
|
73
|
-
* `releaseDevice` is called after writing them
|
|
73
|
+
* `releaseDevice` is called after writing them, and before deleting a target
|
|
74
|
+
* a buffered draw may still read (`WaylandSurface.destroy`).
|
|
74
75
|
*/
|
|
75
76
|
export function flushDevice(gl) {
|
|
76
77
|
const device = shared(gl) ? devices.get(gl) : null;
|
package/src/wayland/surface.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
// back by hand either.
|
|
26
26
|
|
|
27
27
|
import { WaylandContext2D } from './context2d.js';
|
|
28
|
+
import { flushDevice } from './device.js';
|
|
28
29
|
import { GLTarget } from './target.js';
|
|
29
30
|
|
|
30
31
|
export class WaylandSurface {
|
|
@@ -130,6 +131,15 @@ export class WaylandSurface {
|
|
|
130
131
|
if (this._destroyed) return;
|
|
131
132
|
this._destroyed = true;
|
|
132
133
|
this.app.makeCurrent();
|
|
134
|
+
// A draw that reads this surface may still be buffered in the context
|
|
135
|
+
// that made it — a window's quad, to be drawn in one call with the rest
|
|
136
|
+
// of its batch — and a texture deleted under a draw not yet issued is
|
|
137
|
+
// sampled as GLES samples a texture that is not there: opaque black. A
|
|
138
|
+
// surface painted for one paint, drawn, and destroyed in a `finally`
|
|
139
|
+
// drew as a black box (`<Html>`'s transformed boxes too large to keep).
|
|
140
|
+
// The owner is the only context holding anything (device.js), so
|
|
141
|
+
// flushing it issues every draw that could read this one.
|
|
142
|
+
flushDevice(this.target.gl);
|
|
133
143
|
this._ctx?.destroy();
|
|
134
144
|
this._ctx = null;
|
|
135
145
|
this.target.destroy();
|