@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 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 = "89726f3e1b530de7fe61d30c407c68de7930bcb4ad30694b2cbf6789b95f2715";
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 + DisplayTransport.copySequence,
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 + DisplayTransport.copyFlags,
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 + DisplayTransport.copyLength,
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 + DisplayTransport.copySequence,
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 + DisplayTransport.surfaceSequence, 1);
119
- Atomics.store(this.words, this.word + DisplayTransport.surfaceWidth, Math.max(1, Math.round(width)));
120
- Atomics.store(this.words, this.word + DisplayTransport.surfaceHeight, Math.max(1, Math.round(height)));
121
- Atomics.store(this.words, this.word + DisplayTransport.surfaceScaleMilli,
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 + DisplayTransport.surfaceSequence, 1);
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 + DisplayTransport.paletteSequence, 1);
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 + DisplayTransport.paletteSequence, 1);
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 + DisplayTransport.flags) & A.DOLLY_DISPLAY_GRAPHICS_ACTIVE) !== 0;
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 + DisplayTransport.animationFrameSequence, 1);
146
- Atomics.notify(this.words, this.word + DisplayTransport.animationFrameSequence);
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 + DisplayTransport.cursorStyle,
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 + DisplayTransport.fontSizeMilli) / 1000;
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 + DisplayTransport.terminalCols),
163
- rows: Atomics.load(this.words, this.word + DisplayTransport.terminalRows),
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 + DisplayTransport.cursorCol) >>> 0,
170
- cursorRow: Atomics.load(this.words, this.word + DisplayTransport.cursorRow) >>> 0,
171
- cellWidth: Atomics.load(this.words, this.word + DisplayTransport.cellWidth) >>> 0,
172
- cellHeight: Atomics.load(this.words, this.word + DisplayTransport.cellHeight) >>> 0,
173
- paddingX: Atomics.load(this.words, this.word + DisplayTransport.paddingX) >>> 0,
174
- paddingY: Atomics.load(this.words, this.word + DisplayTransport.paddingY) >>> 0,
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 + DisplayTransport.frameSequence, this.sequence | 0);
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 + DisplayTransport.frameSequence) >>> 0;
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 + DisplayTransport.frameSequence) >>> 0;
258
- const index = Atomics.load(words, word + DisplayTransport.frameIndex) >>> 0;
259
- const width = Atomics.load(words, word + DisplayTransport.frameWidth) >>> 0;
260
- const height = Atomics.load(words, word + DisplayTransport.frameHeight) >>> 0;
261
- const stride = Atomics.load(words, word + DisplayTransport.frameStride) >>> 0;
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 + DisplayTransport.frameSequence) >>> 0;
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 + DisplayTransport.frameSequence) >>> 0 };
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
@@ -11,5 +11,6 @@
11
11
  "process": [],
12
12
  "headers": ["display.h", "display-abi.h"],
13
13
  "kernel": ["kernel.c"],
14
- "client": ["client.c"]
14
+ "client": ["client.c"],
15
+ "package": "libdolly-display"
15
16
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "0.1.5-rc.0",
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.5-rc.0"
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": {