react-x11 2.23.2 → 2.24.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-x11",
3
- "version": "2.23.2",
3
+ "version": "2.24.0",
4
4
  "description": "react renderer with X11 as a target",
5
5
  "main": "./src/index.js",
6
6
  "files": [
package/src/node.d.ts CHANGED
@@ -515,6 +515,16 @@ export declare class Node {
515
515
  * paint, whatever the props. A translucent element answers `null`.
516
516
  */
517
517
  opaqueRect(): Rect | null;
518
+ /**
519
+ * How far this element's own drawing reaches past its box, in device
520
+ * pixels on every side — 0, the default, for an element that stays inside
521
+ * it. Core claims and culls the element by its box grown by this, as it
522
+ * does for an outline or a shadow; an element that paints past its box
523
+ * without saying so leaves the old ink's edge behind when it changes. Read
524
+ * when the cached paint bounds are rebuilt: answer a bound for anything
525
+ * the element may draw, not for what it drew last.
526
+ */
527
+ paintOverhang(): number;
518
528
  /**
519
529
  * The rect this paint pass is repainting, or null when it is repainting
520
530
  * the whole window — and null outside a paint, which means the same
@@ -114,6 +114,26 @@ export class NodeInvalidate {
114
114
  return null;
115
115
  }
116
116
 
117
+ /**
118
+ * How far this element's own drawing reaches past its box — device
119
+ * pixels, on every side — or 0, the default, for one that stays inside
120
+ * it. Core claims and culls the element, and sizes a fade's surface, by
121
+ * the box grown by it, as it does for an outline or a shadow. Drawing
122
+ * past the box without saying so, an element was claimed by its box
123
+ * alone: an edit left the old ink's edge behind and drew the new one's
124
+ * without it, and a row scrolled just out of view lost the ink it still
125
+ * put in. A code chip padded past the run it sits behind is the case —
126
+ * at the start of a line the pad is outside the box.
127
+ *
128
+ * Read whenever the cached paint bounds are rebuilt, which a claim of the
129
+ * node does: answer a bound that holds for anything the element may
130
+ * draw, not for what it drew last, or the claim after a change stops
131
+ * covering what the frame before put down.
132
+ */
133
+ paintOverhang() {
134
+ return 0;
135
+ }
136
+
117
137
  /**
118
138
  * A layout-affecting change confined to this node: claim the subtree as
119
139
  * it stands now, and queue it for a second claim once layout has run —
@@ -206,7 +226,8 @@ export class NodeInvalidate {
206
226
 
207
227
  /**
208
228
  * This node's own rect, grown by anything it draws outside it — the
209
- * outline and the shadow, the only two. Per node rather than once at the
229
+ * outline and the shadow, and whatever an element says it draws past its
230
+ * box (`paintOverhang`). Per node rather than once at the
210
231
  * top, because either can belong to any node and the bound has to cover it
211
232
  * wherever it is; and the outline is counted even when the ring is
212
233
  * currently *off*, because the frame that erases it is claimed after the
@@ -219,7 +240,11 @@ export class NodeInvalidate {
219
240
  * instead, where both the old style and the new one are in hand.
220
241
  */
221
242
  _ownPaintBounds() {
222
- const extent = Math.max(this._outlineExtent(), this._shadowExtent());
243
+ const extent = Math.max(
244
+ this._outlineExtent(),
245
+ this._shadowExtent(),
246
+ this.paintOverhang() || 0,
247
+ );
223
248
  if (extent <= 0) return this.abs;
224
249
  return {
225
250
  x: this.abs.x - extent,
@@ -549,15 +574,6 @@ export class WindowInvalidate {
549
574
  return damageToPaint(rects);
550
575
  }
551
576
 
552
- /**
553
- * The rects this frame will repaint, or null for the whole window.
554
- *
555
- * Clamped to the window: damage is recorded when a node invalidates, and
556
- * the window may have been resized since. A region that no longer
557
- * intersects the window means there is nothing to do, but the frame still
558
- * has to clear the flag, so it degrades to a full repaint rather than
559
- * painting nothing.
560
- */
561
577
  /**
562
578
  * How many rects a frame's damage may hold before `addDamageRect` merges
563
579
  * the closest pair. Four on X11 (`MAX_DAMAGE_RECTS`), where every pass
@@ -571,6 +587,17 @@ export class WindowInvalidate {
571
587
  return Number.isInteger(cap) && cap > 0 ? cap : MAX_DAMAGE_RECTS;
572
588
  }
573
589
 
590
+ /**
591
+ * The rects this frame will repaint, or null for the whole window.
592
+ *
593
+ * Clamped to the window: damage is recorded when a node invalidates, and
594
+ * the window may have been resized since — or the node drew past its
595
+ * edge, where a claim lands whole. A frame whose every claim lies outside
596
+ * the window has nothing to repaint and paints nothing, as a frame whose
597
+ * claims were all answered on layers does; it used to repaint the whole
598
+ * window, so a card dragged past the edge of a graph, or a pan that
599
+ * claimed only its far side, cost a full frame.
600
+ */
574
601
  _takeDamage(width, height) {
575
602
  const damage = this._damage;
576
603
  this._damage = null;
@@ -608,7 +635,11 @@ export class WindowInvalidate {
608
635
  if (clamped === FULL_DAMAGE) return null;
609
636
  if (clamped) rects.push(clamped);
610
637
  }
611
- if (!rects.length) return null;
638
+ if (!rects.length) {
639
+ this._lastDamageRects = [];
640
+ this._lastDamage = { x: 0, y: 0, width: 0, height: 0 };
641
+ return [];
642
+ }
612
643
  this._lastDamageRects = damageToPaint(rects);
613
644
  this._lastDamage = rectsBounds(this._lastDamageRects);
614
645
  return this._lastDamageRects;
@@ -355,11 +355,15 @@ export class NodePaint {
355
355
  }
356
356
 
357
357
  /** `order` painted in turn, each child culled against the window, its
358
- * clipping ancestors and the pass. */
358
+ * clipping ancestors and the pass — by what it paints, not by its box: a
359
+ * row scrolled just out of a pane still reaches into it with whatever
360
+ * hangs off it, a descender past a trimmed line box or a child that
361
+ * overflows it, and culled by its box it drew none of that in a full
362
+ * repaint while a scroll's copy carried it. */
359
363
  _paintChildList(ctx, order) {
360
364
  for (const child of order) {
361
365
  if (child._promoted) continue; // on a layer of its own: a hole here
362
- if (child._offscreen(child.abs, DAMAGE_SLOP)) continue;
366
+ if (child._offscreen(child._subtreeBounds(), DAMAGE_SLOP)) continue;
363
367
  if (child._outsideDamage()) continue;
364
368
  child.paint(ctx);
365
369
  }
@@ -371,8 +375,9 @@ export class NodePaint {
371
375
  */
372
376
  _paintsInto(rect) {
373
377
  if (this._promoted) return false;
374
- if (!rectsOverlap(this._subtreeBounds(), rect, DAMAGE_SLOP)) return false;
375
- return !this._offscreen(this.abs, DAMAGE_SLOP);
378
+ const reach = this._subtreeBounds();
379
+ if (!rectsOverlap(reach, rect, DAMAGE_SLOP)) return false;
380
+ return !this._offscreen(reach, DAMAGE_SLOP);
376
381
  }
377
382
 
378
383
  /**