@daugasauron/dolly-host-display 0.1.5-rc.0 → 0.1.6
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/abi.mjs +1 -1
- package/display.mjs +34 -58
- package/module.json +2 -1
- package/package.json +2 -2
package/abi.mjs
CHANGED
|
@@ -60,4 +60,4 @@ export const DOLLY_DISPLAY_WAIT_FRAME = 101;
|
|
|
60
60
|
export const DOLLY_DISPLAY_SET_CURSOR = 102;
|
|
61
61
|
export const DOLLY_DISPLAY_RELEASE = 103;
|
|
62
62
|
export const DOLLY_ERRNO = Object.freeze({ E2BIG: 1, EACCES: 2, EADDRINUSE: 3, EADDRNOTAVAIL: 4, EAFNOSUPPORT: 5, EAGAIN: 6, EALREADY: 7, EBADF: 8, EBADMSG: 9, EBUSY: 10, ECANCELED: 11, ECHILD: 12, ECONNABORTED: 13, ECONNREFUSED: 14, ECONNRESET: 15, EDEADLK: 16, EDESTADDRREQ: 17, EDOM: 18, EDQUOT: 19, EEXIST: 20, EFAULT: 21, EFBIG: 22, EHOSTUNREACH: 23, EIDRM: 24, EILSEQ: 25, EINPROGRESS: 26, EINTR: 27, EINVAL: 28, EIO: 29, EISCONN: 30, EISDIR: 31, ELOOP: 32, EMFILE: 33, EMLINK: 34, EMSGSIZE: 35, EMULTIHOP: 36, ENAMETOOLONG: 37, ENETDOWN: 38, ENETRESET: 39, ENETUNREACH: 40, ENFILE: 41, ENOBUFS: 42, ENODEV: 43, ENOENT: 44, ENOEXEC: 45, ENOLCK: 46, ENOLINK: 47, ENOMEM: 48, ENOMSG: 49, ENOPROTOOPT: 50, ENOSPC: 51, ENOSYS: 52, ENOTCONN: 53, ENOTDIR: 54, ENOTEMPTY: 55, ENOTRECOVERABLE: 56, ENOTSOCK: 57, ENOTTY: 59, ENXIO: 60, EOVERFLOW: 61, EOWNERDEAD: 62, EPERM: 63, EPIPE: 64, EPROTO: 65, EPROTONOSUPPORT: 66, EPROTOTYPE: 67, ERANGE: 68, EROFS: 69, ESPIPE: 70, ESRCH: 71, ESTALE: 72, ETIMEDOUT: 73, ETXTBSY: 74, EXDEV: 75, ENODATA: 116, ENOTSUP: 138 });
|
|
63
|
-
export const DOLLY_DISPLAY_ABI_DIGEST = "
|
|
63
|
+
export const DOLLY_DISPLAY_ABI_DIGEST = "5dd9ff91db8d8a620e89fdd146b79b9cb40d3b9c7be8b5a4e32038e7fbf69671";
|
package/display.mjs
CHANGED
|
@@ -38,31 +38,6 @@ function readPalette(style, rgb) {
|
|
|
38
38
|
// The Worker's end of the display mailbox: it reads frames, the terminal's
|
|
39
39
|
// geometry and its selection, and writes the surface and the animation frame.
|
|
40
40
|
export class DisplayTransport {
|
|
41
|
-
static flags = A.DOLLY_DISPLAY_WORD_FLAGS;
|
|
42
|
-
static frameSequence = A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE;
|
|
43
|
-
static frameIndex = A.DOLLY_DISPLAY_WORD_FRAME_INDEX;
|
|
44
|
-
static frameWidth = A.DOLLY_DISPLAY_WORD_FRAME_WIDTH;
|
|
45
|
-
static frameHeight = A.DOLLY_DISPLAY_WORD_FRAME_HEIGHT;
|
|
46
|
-
static frameStride = A.DOLLY_DISPLAY_WORD_FRAME_STRIDE;
|
|
47
|
-
static terminalCols = A.DOLLY_DISPLAY_WORD_TERMINAL_COLS;
|
|
48
|
-
static terminalRows = A.DOLLY_DISPLAY_WORD_TERMINAL_ROWS;
|
|
49
|
-
static fontSizeMilli = A.DOLLY_DISPLAY_WORD_FONT_SIZE_MILLI;
|
|
50
|
-
static copySequence = A.DOLLY_DISPLAY_WORD_COPY_SEQUENCE;
|
|
51
|
-
static copyLength = A.DOLLY_DISPLAY_WORD_COPY_LENGTH;
|
|
52
|
-
static copyFlags = A.DOLLY_DISPLAY_WORD_COPY_FLAGS;
|
|
53
|
-
static cursorCol = A.DOLLY_DISPLAY_WORD_CURSOR_COL;
|
|
54
|
-
static cursorRow = A.DOLLY_DISPLAY_WORD_CURSOR_ROW;
|
|
55
|
-
static cellWidth = A.DOLLY_DISPLAY_WORD_CELL_WIDTH;
|
|
56
|
-
static cellHeight = A.DOLLY_DISPLAY_WORD_CELL_HEIGHT;
|
|
57
|
-
static paddingX = A.DOLLY_DISPLAY_WORD_PADDING_X;
|
|
58
|
-
static paddingY = A.DOLLY_DISPLAY_WORD_PADDING_Y;
|
|
59
|
-
static cursorStyle = A.DOLLY_DISPLAY_WORD_CURSOR_STYLE;
|
|
60
|
-
static animationFrameSequence = A.DOLLY_DISPLAY_WORD_ANIMATION_FRAME_SEQUENCE;
|
|
61
|
-
static surfaceSequence = A.DOLLY_DISPLAY_WORD_SURFACE_SEQUENCE;
|
|
62
|
-
static surfaceWidth = A.DOLLY_DISPLAY_WORD_SURFACE_WIDTH;
|
|
63
|
-
static surfaceHeight = A.DOLLY_DISPLAY_WORD_SURFACE_HEIGHT;
|
|
64
|
-
static surfaceScaleMilli = A.DOLLY_DISPLAY_WORD_SURFACE_SCALE_MILLI;
|
|
65
|
-
static paletteSequence = A.DOLLY_DISPLAY_WORD_PALETTE_SEQUENCE;
|
|
66
41
|
|
|
67
42
|
// The copy buffer's size is the contract's; a test may shrink it.
|
|
68
43
|
constructor(buffer, address, copyAddress, { copyCapacity = A.DOLLY_DISPLAY_COPY_CAPACITY } = {}) {
|
|
@@ -86,15 +61,15 @@ export class DisplayTransport {
|
|
|
86
61
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
87
62
|
const before = Atomics.load(
|
|
88
63
|
this.words,
|
|
89
|
-
this.word +
|
|
64
|
+
this.word + A.DOLLY_DISPLAY_WORD_COPY_SEQUENCE,
|
|
90
65
|
) >>> 0;
|
|
91
66
|
const flags = Atomics.load(
|
|
92
67
|
this.words,
|
|
93
|
-
this.word +
|
|
68
|
+
this.word + A.DOLLY_DISPLAY_WORD_COPY_FLAGS,
|
|
94
69
|
) >>> 0;
|
|
95
70
|
const length = Atomics.load(
|
|
96
71
|
this.words,
|
|
97
|
-
this.word +
|
|
72
|
+
this.word + A.DOLLY_DISPLAY_WORD_COPY_LENGTH,
|
|
98
73
|
) >>> 0;
|
|
99
74
|
if ((flags & A.DOLLY_DISPLAY_COPY_AVAILABLE) === 0) return null;
|
|
100
75
|
if ((flags & A.DOLLY_DISPLAY_COPY_TRUNCATED) !== 0 ||
|
|
@@ -106,7 +81,7 @@ export class DisplayTransport {
|
|
|
106
81
|
);
|
|
107
82
|
const after = Atomics.load(
|
|
108
83
|
this.words,
|
|
109
|
-
this.word +
|
|
84
|
+
this.word + A.DOLLY_DISPLAY_WORD_COPY_SEQUENCE,
|
|
110
85
|
) >>> 0;
|
|
111
86
|
if (before === after) return textDecoder.decode(bytes);
|
|
112
87
|
}
|
|
@@ -115,12 +90,12 @@ export class DisplayTransport {
|
|
|
115
90
|
|
|
116
91
|
// The surface frames are shown on: the terminal lays its grid out for it.
|
|
117
92
|
publishSurface(width, height, devicePixelRatio) {
|
|
118
|
-
Atomics.add(this.words, this.word +
|
|
119
|
-
Atomics.store(this.words, this.word +
|
|
120
|
-
Atomics.store(this.words, this.word +
|
|
121
|
-
Atomics.store(this.words, this.word +
|
|
93
|
+
Atomics.add(this.words, this.word + A.DOLLY_DISPLAY_WORD_SURFACE_SEQUENCE, 1);
|
|
94
|
+
Atomics.store(this.words, this.word + A.DOLLY_DISPLAY_WORD_SURFACE_WIDTH, Math.max(1, Math.round(width)));
|
|
95
|
+
Atomics.store(this.words, this.word + A.DOLLY_DISPLAY_WORD_SURFACE_HEIGHT, Math.max(1, Math.round(height)));
|
|
96
|
+
Atomics.store(this.words, this.word + A.DOLLY_DISPLAY_WORD_SURFACE_SCALE_MILLI,
|
|
122
97
|
Math.max(500, Math.min(4000, Math.round(devicePixelRatio * 1000))));
|
|
123
|
-
Atomics.add(this.words, this.word +
|
|
98
|
+
Atomics.add(this.words, this.word + A.DOLLY_DISPLAY_WORD_SURFACE_SEQUENCE, 1);
|
|
124
99
|
}
|
|
125
100
|
|
|
126
101
|
// The terminal's colours, 0xRRGGBB each: { background, foreground, cursor, colors: [16] }.
|
|
@@ -129,49 +104,49 @@ export class DisplayTransport {
|
|
|
129
104
|
if (colors.length !== 16 || !words.every(word => Number.isInteger(word) && word >= 0 && word <= 0xffffff)) {
|
|
130
105
|
throw new Error("Dolly display palette must be 19 colours of 0xRRGGBB");
|
|
131
106
|
}
|
|
132
|
-
Atomics.add(this.words, this.word +
|
|
107
|
+
Atomics.add(this.words, this.word + A.DOLLY_DISPLAY_WORD_PALETTE_SEQUENCE, 1);
|
|
133
108
|
for (const [index, word] of words.entries()) {
|
|
134
109
|
Atomics.store(this.words, this.word + A.DOLLY_DISPLAY_WORD_PALETTE_BACKGROUND + index, word);
|
|
135
110
|
}
|
|
136
|
-
Atomics.add(this.words, this.word +
|
|
111
|
+
Atomics.add(this.words, this.word + A.DOLLY_DISPLAY_WORD_PALETTE_SEQUENCE, 1);
|
|
137
112
|
}
|
|
138
113
|
|
|
139
114
|
graphicsActive() {
|
|
140
|
-
return (Atomics.load(this.words, this.word +
|
|
115
|
+
return (Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_FLAGS) & A.DOLLY_DISPLAY_GRAPHICS_ACTIVE) !== 0;
|
|
141
116
|
}
|
|
142
117
|
|
|
143
118
|
publishAnimationFrame() {
|
|
144
119
|
if (!this.graphicsActive()) return;
|
|
145
|
-
Atomics.add(this.words, this.word +
|
|
146
|
-
Atomics.notify(this.words, this.word +
|
|
120
|
+
Atomics.add(this.words, this.word + A.DOLLY_DISPLAY_WORD_ANIMATION_FRAME_SEQUENCE, 1);
|
|
121
|
+
Atomics.notify(this.words, this.word + A.DOLLY_DISPLAY_WORD_ANIMATION_FRAME_SEQUENCE);
|
|
147
122
|
}
|
|
148
123
|
|
|
149
124
|
cursorStyle() {
|
|
150
125
|
return Atomics.load(
|
|
151
126
|
this.words,
|
|
152
|
-
this.word +
|
|
127
|
+
this.word + A.DOLLY_DISPLAY_WORD_CURSOR_STYLE,
|
|
153
128
|
) >>> 0;
|
|
154
129
|
}
|
|
155
130
|
|
|
156
131
|
fontSize() {
|
|
157
|
-
return Atomics.load(this.words, this.word +
|
|
132
|
+
return Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_FONT_SIZE_MILLI) / 1000;
|
|
158
133
|
}
|
|
159
134
|
|
|
160
135
|
dimensions() {
|
|
161
136
|
return {
|
|
162
|
-
cols: Atomics.load(this.words, this.word +
|
|
163
|
-
rows: Atomics.load(this.words, this.word +
|
|
137
|
+
cols: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_TERMINAL_COLS),
|
|
138
|
+
rows: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_TERMINAL_ROWS),
|
|
164
139
|
};
|
|
165
140
|
}
|
|
166
141
|
|
|
167
142
|
geometry() {
|
|
168
143
|
return {
|
|
169
|
-
cursorCol: Atomics.load(this.words, this.word +
|
|
170
|
-
cursorRow: Atomics.load(this.words, this.word +
|
|
171
|
-
cellWidth: Atomics.load(this.words, this.word +
|
|
172
|
-
cellHeight: Atomics.load(this.words, this.word +
|
|
173
|
-
paddingX: Atomics.load(this.words, this.word +
|
|
174
|
-
paddingY: Atomics.load(this.words, this.word +
|
|
144
|
+
cursorCol: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_CURSOR_COL) >>> 0,
|
|
145
|
+
cursorRow: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_CURSOR_ROW) >>> 0,
|
|
146
|
+
cellWidth: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_CELL_WIDTH) >>> 0,
|
|
147
|
+
cellHeight: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_CELL_HEIGHT) >>> 0,
|
|
148
|
+
paddingX: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_PADDING_X) >>> 0,
|
|
149
|
+
paddingY: Atomics.load(this.words, this.word + A.DOLLY_DISPLAY_WORD_PADDING_Y) >>> 0,
|
|
175
150
|
};
|
|
176
151
|
}
|
|
177
152
|
}
|
|
@@ -218,7 +193,7 @@ export class FramebufferPresenter {
|
|
|
218
193
|
if (now < activeUntil) return request();
|
|
219
194
|
// One wait at a time: any notify after it began ends it.
|
|
220
195
|
if (!waiting) {
|
|
221
|
-
const parked = Atomics.waitAsync(words, word +
|
|
196
|
+
const parked = Atomics.waitAsync(words, word + A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE, this.sequence | 0);
|
|
222
197
|
waiting = parked.async;
|
|
223
198
|
if (waiting) parked.value.then(() => { waiting = false; this.wake(); });
|
|
224
199
|
else this.wake();
|
|
@@ -251,17 +226,18 @@ export class FramebufferPresenter {
|
|
|
251
226
|
// Copies a newly published frame to the canvas; returns whether it painted one.
|
|
252
227
|
paint() {
|
|
253
228
|
const { words, word } = this.transport;
|
|
254
|
-
const sequence = Atomics.load(words, word +
|
|
229
|
+
const sequence = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE) >>> 0;
|
|
255
230
|
if (sequence === this.sequence) return false;
|
|
256
231
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
257
|
-
const before = Atomics.load(words, word +
|
|
258
|
-
const index = Atomics.load(words, word +
|
|
259
|
-
const width = Atomics.load(words, word +
|
|
260
|
-
const height = Atomics.load(words, word +
|
|
261
|
-
const stride = Atomics.load(words, word +
|
|
232
|
+
const before = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE) >>> 0;
|
|
233
|
+
const index = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_INDEX) >>> 0;
|
|
234
|
+
const width = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_WIDTH) >>> 0;
|
|
235
|
+
const height = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_HEIGHT) >>> 0;
|
|
236
|
+
const stride = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_STRIDE) >>> 0;
|
|
262
237
|
const length = stride * height;
|
|
263
238
|
const address = this.frameAddresses[index];
|
|
264
239
|
if (index >= A.DOLLY_DISPLAY_FRAME_COUNT || width === 0 || height === 0 || stride !== width * 4 ||
|
|
240
|
+
width > A.DOLLY_DISPLAY_MAX_WIDTH || height > A.DOLLY_DISPLAY_MAX_HEIGHT ||
|
|
265
241
|
length > this.capacity || address + length > this.buffer.byteLength) {
|
|
266
242
|
throw new Error("Dolly published an invalid framebuffer");
|
|
267
243
|
}
|
|
@@ -272,7 +248,7 @@ export class FramebufferPresenter {
|
|
|
272
248
|
this.frames = [];
|
|
273
249
|
}
|
|
274
250
|
this.image.data.set(this.frames[index] ??= new Uint8ClampedArray(this.buffer, address, length));
|
|
275
|
-
const after = Atomics.load(words, word +
|
|
251
|
+
const after = Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE) >>> 0;
|
|
276
252
|
if (before !== after) continue;
|
|
277
253
|
// A frame is opaque, as a window is: the fourth byte of a pixel is not shown.
|
|
278
254
|
const pixels = this.image.data;
|
|
@@ -410,7 +386,7 @@ export function worker({ get, send, configuration }) {
|
|
|
410
386
|
const { cols, rows } = transport.dimensions();
|
|
411
387
|
const state = { graphicsActive: transport.graphicsActive(), cursor: transport.cursorStyle(),
|
|
412
388
|
fontSize: transport.fontSize(), cols, rows, geometry: transport.geometry(),
|
|
413
|
-
frame: Atomics.load(words, word +
|
|
389
|
+
frame: Atomics.load(words, word + A.DOLLY_DISPLAY_WORD_FRAME_SEQUENCE) >>> 0 };
|
|
414
390
|
const text = JSON.stringify(state);
|
|
415
391
|
if (text === reported) return;
|
|
416
392
|
reported = text;
|
package/module.json
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.6",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"name": "@daugasauron/dolly-host-display",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@daugasauron/dolly": "0.1.
|
|
7
|
+
"@daugasauron/dolly": "0.1.6"
|
|
8
8
|
},
|
|
9
9
|
"description": "Dolly's display@0 host module: the terminal and programs' frames; the selection on Ctrl+Shift+C.",
|
|
10
10
|
"repository": {
|