react-x11 2.22.1 → 2.22.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-x11",
3
- "version": "2.22.1",
3
+ "version": "2.22.2",
4
4
  "description": "react renderer with X11 as a target",
5
5
  "main": "./src/index.js",
6
6
  "files": [
@@ -285,11 +285,15 @@ export class BackendContext2D {
285
285
  * @param surfaceOf () => current surface handle — the owner replaces the
286
286
  * surface on resize, and this context follows it.
287
287
  * @param genOf () => surface generation number
288
+ * @param options.readback whether the bitmap this context draws into can
289
+ * be read back while it is being drawn into, cheaply — a CPU bitmap, as
290
+ * every Cocoa surface is (`readbackSource`)
288
291
  */
289
- constructor(native, surfaceOf, genOf) {
292
+ constructor(native, surfaceOf, genOf, { readback = false } = {}) {
290
293
  this._native = native;
291
294
  this._surfaceOf = surfaceOf;
292
295
  this._genOf = genOf;
296
+ this._readback = readback;
293
297
  this._gen = -1;
294
298
  this._stack = [];
295
299
  this._state = {
@@ -338,6 +342,28 @@ export class BackendContext2D {
338
342
  this._strokeChunking = !NO_STROKE_CHUNKING;
339
343
  }
340
344
 
345
+ /**
346
+ * The bitmap this context draws into, as a source `drawImage` reads — for
347
+ * a caller that keeps a few of its pixels before drawing over them and
348
+ * puts them back after, which is how a rounded box clips its children
349
+ * without a path clip (src/nodes/roundclip.js, issue #693). A `copy` of
350
+ * it at a whole-pixel translate is `blitSurface`'s memcpy. Null where the
351
+ * owner has not said the bitmap reads back cheaply while it is drawn
352
+ * into: a GPU target is a different cost, and nobody has measured it.
353
+ */
354
+ readbackSource() {
355
+ if (!this._readback) return null;
356
+ const ctx = this;
357
+ const { width, height } = this._native.surfaceSize(this._s());
358
+ return {
359
+ width,
360
+ height,
361
+ get _surfaceHandle() {
362
+ return ctx._s();
363
+ },
364
+ };
365
+ }
366
+
341
367
  _s() {
342
368
  const surface = this._surfaceOf();
343
369
  const gen = this._genOf();
@@ -127,6 +127,8 @@ export class CocoaOverlayPane {
127
127
  this._ensureSurface();
128
128
  return this._gen;
129
129
  },
130
+ // a CPU bitmap: a rounded box keeps its corners by reading it back
131
+ { readback: true },
130
132
  );
131
133
  this._ctx._fonts = this.app.fonts;
132
134
  this._ctx._onDirty = () => {
@@ -195,6 +195,8 @@ export class CocoaPaneWindow {
195
195
  this._ensureSurface();
196
196
  return this._surfaceGen;
197
197
  },
198
+ // a CPU bitmap: a rounded box keeps its corners by reading it back
199
+ { readback: true },
198
200
  );
199
201
  this._ctx._fonts = this.app.fonts;
200
202
  this._ctx._onDirty = () => {
@@ -435,6 +435,8 @@ export class RasterState {
435
435
  presenter.native,
436
436
  () => this.surface,
437
437
  () => this.gen,
438
+ // a CPU bitmap: a rounded box keeps its corners by reading it back
439
+ { readback: true },
438
440
  );
439
441
  this.ctx._fonts = presenter.fonts;
440
442
  }
@@ -117,6 +117,8 @@ export class CocoaSurface {
117
117
  this._native,
118
118
  () => this._handle(),
119
119
  () => 1,
120
+ // a CPU bitmap: a rounded box keeps its corners by reading it back
121
+ { readback: true },
120
122
  );
121
123
  this._ctx._fonts = this._fonts;
122
124
  }
@@ -806,6 +806,8 @@ export class CocoaWindow {
806
806
  this._ensureSurface();
807
807
  return this._surfaceGen;
808
808
  },
809
+ // a CPU bitmap: a rounded box keeps its corners by reading it back
810
+ { readback: true },
809
811
  );
810
812
  this._ctx._fonts = this.app.fonts;
811
813
  this._ctx._onDirty = () => {
@@ -7,8 +7,9 @@
7
7
  //
8
8
  // That needs a context that can read its own pixels back into a surface of
9
9
  // its own and composite a coverage surface: ntk's, whose `picture` is the
10
- // server-side picture it draws through. Anywhere else the caller clips to the
11
- // outline as it always has.
10
+ // server-side picture it draws through, and a Cocoa one, whose bitmap is CPU
11
+ // memory it names as a `drawImage` source (`readbackSource`, issue #693).
12
+ // Anywhere else the caller clips to the outline as it always has.
12
13
 
13
14
  import { Surface } from '../offscreen.js';
14
15
 
@@ -65,6 +66,20 @@ function cornerPath(ctx, box, { radius: r, side: s }, corner) {
65
66
  ctx.closePath();
66
67
  }
67
68
 
69
+ /**
70
+ * A square to hold a coverage in: an a8 surface where the backend has them,
71
+ * and elsewhere a colour one whose alpha is the coverage — which is all the
72
+ * `destination-in` and `destination-out` it is drawn with read of it. The
73
+ * Cocoa backend has no a8 surfaces and says so by throwing.
74
+ */
75
+ function coverageSurface(app, side) {
76
+ try {
77
+ return new Surface(app, { width: side, height: side, format: 'a8' });
78
+ } catch {
79
+ return new Surface(app, { width: side, height: side });
80
+ }
81
+ }
82
+
68
83
  /**
69
84
  * How much of each pixel of a corner square lies outside the outline, as an
70
85
  * a8 surface the size of the square: the square filled, and the outline's
@@ -77,7 +92,7 @@ function outsideCoverage(app, corners, corner) {
77
92
  const key = `${corner}|${corners.radius}|${s}`;
78
93
  let surface = state.coverage.get(key);
79
94
  if (surface) return surface;
80
- surface = new Surface(app, { width: s, height: s, format: 'a8' });
95
+ surface = coverageSurface(app, s);
81
96
  // a box whose corner lands on the square's own, in the square's space
82
97
  const far = corner === 'tr' || corner === 'br';
83
98
  const low = corner === 'bl' || corner === 'br';
@@ -126,16 +141,21 @@ function readback(ctx) {
126
141
  if (!m || m.a !== 1 || m.b !== 0 || m.c !== 0 || m.d !== 1) return null;
127
142
  if (!Number.isInteger(m.e) || !Number.isInteger(m.f)) return null;
128
143
  // reading it settles the picture's clip, which the next drawing re-stamps
129
- if (!ctx.picture || !Number.isFinite(ctx.width)) return null;
130
- return {
131
- dx: m.e,
132
- dy: m.f,
133
- source: {
134
- width: ctx.width,
135
- height: ctx.height,
136
- picture: () => ctx.picture,
137
- },
138
- };
144
+ if (ctx.picture && Number.isFinite(ctx.width)) {
145
+ return {
146
+ dx: m.e,
147
+ dy: m.f,
148
+ source: {
149
+ width: ctx.width,
150
+ height: ctx.height,
151
+ picture: () => ctx.picture,
152
+ },
153
+ };
154
+ }
155
+ // a backend context whose owner says its bitmap reads back cheaply
156
+ const source =
157
+ typeof ctx.readbackSource === 'function' ? ctx.readbackSource() : null;
158
+ return source ? { dx: m.e, dy: m.f, source } : null;
139
159
  }
140
160
 
141
161
  /**