react-x11 2.52.0 → 2.53.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/README.md +10 -10
- package/docs/README.md +160 -314
- package/docs/accessibility.md +176 -229
- package/docs/appearance.md +77 -176
- package/docs/click-to-component.md +18 -51
- package/docs/clipboard.md +40 -59
- package/docs/components.md +518 -1036
- package/docs/dbus.md +61 -133
- package/docs/debugging.md +152 -245
- package/docs/desktop-calendar.md +51 -88
- package/docs/desktop.md +222 -347
- package/docs/devtools.md +50 -167
- package/docs/drag-and-drop.md +126 -204
- package/docs/ecosystem/animation.md +91 -125
- package/docs/ecosystem/data-fetching.md +38 -53
- package/docs/ecosystem/dev-tooling.md +159 -202
- package/docs/ecosystem/forms.md +61 -97
- package/docs/ecosystem/headless.md +64 -89
- package/docs/ecosystem/i18n.md +18 -21
- package/docs/ecosystem/icons.md +93 -126
- package/docs/ecosystem/layout.md +42 -52
- package/docs/ecosystem/routing.md +18 -29
- package/docs/ecosystem/state.md +71 -88
- package/docs/ecosystem/testing.md +131 -157
- package/docs/ecosystem/theming.md +119 -165
- package/docs/ecosystem.md +145 -179
- package/docs/elements.md +1091 -1774
- package/docs/embedding.md +83 -132
- package/docs/events.md +412 -695
- package/docs/extending.md +784 -1326
- package/docs/eyedropper.md +63 -122
- package/docs/filedialog.md +71 -107
- package/docs/frame.md +195 -339
- package/docs/gl.md +65 -62
- package/docs/globalmenu.md +63 -146
- package/docs/macos.md +531 -3234
- package/docs/notifications.md +33 -47
- package/docs/packaging.md +166 -309
- package/docs/permissions.md +9 -14
- package/docs/react-features.md +81 -106
- package/docs/remote.md +32 -76
- package/docs/scale.md +72 -186
- package/docs/styling.md +329 -547
- package/docs/system.md +200 -280
- package/docs/testing.md +63 -83
- package/docs/typescript.md +6 -48
- package/docs/uri-schemes.md +67 -107
- package/docs/wayland-backend.md +200 -459
- package/docs/windows-integrations.md +75 -131
- package/docs/windows.md +343 -1367
- package/package.json +3 -2
- package/src/Reconciler.js +2 -2
- package/src/a11y.js +1 -1
- package/src/backend/context2d.js +3 -3
- package/src/bootstrap.js +1 -1
- package/src/cocoa/app.js +6 -6
- package/src/cocoa/bezels.js +1 -1
- package/src/cocoa/fonts.js +1 -1
- package/src/cocoa/globalmenu.js +1 -1
- package/src/cocoa/keymap.js +1 -1
- package/src/cocoa/panewindow.js +1 -1
- package/src/cocoa/player.js +1 -1
- package/src/cocoa/presenter.js +2 -2
- package/src/cocoa/promotion.js +1 -1
- package/src/cocoa/relaunch.js +1 -1
- package/src/cocoa/threaded.js +1 -1
- package/src/cocoa/video.js +1 -1
- package/src/cocoa/window.js +4 -4
- package/src/components/Menu.js +7 -2
- package/src/components/Switch.js +1 -1
- package/src/components/native.js +1 -1
- package/src/dnd.js +2 -2
- package/src/glnodes.js +1 -1
- package/src/grid.js +1 -1
- package/src/layouts.js +1 -1
- package/src/nodes/animation.js +1 -1
- package/src/nodes/invalidate.js +1 -1
- package/src/nodes/layouthost.js +1 -1
- package/src/nodes/video.js +19 -8
- package/src/nodes/window/droptarget.js +1 -1
- package/src/pacing.js +1 -1
- package/src/refresh/index.js +2 -1
- package/src/types/video.d.ts +5 -2
- package/src/videobackend.js +28 -0
- package/src/videoframes.js +29 -16
- package/src/wayland/app.js +27 -0
- package/src/wayland/video.js +376 -0
- package/src/win32/a11y.js +1 -1
- package/src/win32/app.js +2 -2
- package/src/win32/fonts.js +1 -1
- package/src/win32/glarea.js +4 -4
- package/src/win32/overlay.js +1 -1
- package/src/win32/panewindow.js +3 -3
- package/src/win32/shell.js +1 -1
- package/src/win32/window.js +2 -2
- package/src/windowid.js +1 -1
- package/src/xvideo.js +189 -0
- package/docs/architecture/accessibility.md +0 -470
- package/docs/architecture/animation.md +0 -707
- package/docs/architecture/container-queries.md +0 -525
- package/docs/architecture/custom-layout.md +0 -334
- package/docs/architecture/drag-and-drop.md +0 -941
- package/docs/architecture/element-layer-contents.md +0 -622
- package/docs/architecture/frame-pacing.md +0 -255
- package/docs/architecture/grid-layout.md +0 -358
- package/docs/architecture/protocol-efficiency.md +0 -357
- package/docs/architecture/video.md +0 -1149
- package/docs/architecture/windowed-regions.md +0 -854
- package/docs/glx.md +0 -137
- package/docs/wayland.md +0 -545
- package/docs/windows-embedding.md +0 -271
- package/docs/windows-gl.md +0 -221
package/docs/debugging.md
CHANGED
|
@@ -6,20 +6,17 @@ raises: _what went on the wire_ (`REACT_X11_TRACE`), _what got repainted_
|
|
|
6
6
|
both). They complement [devtools.md](devtools.md) (component tree) and
|
|
7
7
|
`REACT_X11_DEBUG_LAYOUT=1` (outline every drawn node, colour by depth).
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
switches
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
`
|
|
20
|
-
`REACT_X11_DEBUG_PAINT=full` or `+stacks`, and the per-frame reason
|
|
21
|
-
bookkeeping is a handful of set insertions. Measuring the renderer must
|
|
22
|
-
not change what it measures.
|
|
9
|
+
The failure mode they exist for is the silent full-window repaint: correct
|
|
10
|
+
pixels, quietly costing the whole window every frame. X11 is a network
|
|
11
|
+
protocol even on a local socket, and damage rects are invisible at runtime
|
|
12
|
+
without these.
|
|
13
|
+
|
|
14
|
+
Everything here costs nothing when off. The environment switches are read
|
|
15
|
+
**once at startup** unless a section says otherwise, and the `NO_…` and
|
|
16
|
+
`STRICT_…` switches answer only to `1` — any other value leaves the default
|
|
17
|
+
in place. The tracer module is not imported unless `REACT_X11_TRACE` is set
|
|
18
|
+
or you import `react-x11/debug` yourself, and stacks are captured only under
|
|
19
|
+
`REACT_X11_DEBUG_PAINT=full` or `+stacks`.
|
|
23
20
|
|
|
24
21
|
## Protocol tracing — `REACT_X11_TRACE`
|
|
25
22
|
|
|
@@ -37,21 +34,16 @@ REACT_X11_TRACE=summary npm run examples:dashboard
|
|
|
37
34
|
- `requests` — one stderr line per request as it is sent
|
|
38
35
|
(`x11 → Render.FillRectangles 36B`), plus one line per painted frame
|
|
39
36
|
(`frame 412: 320x24@8,40 reasons=style-state landed=16.4ms`). X errors are
|
|
40
|
-
decoded and name the failing request. `landed` is
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
against 20ms there _is_ a server-side problem (software-fallback RENDER
|
|
49
|
-
ops, a virtualized GPU) rather than a renderer one.
|
|
50
|
-
`npm run bench:frames` reports the same split as a summary. A frame the
|
|
51
|
-
frame pacer held ([elements.md](elements.md#framerate--pacing-the-frames-under-a-flood))
|
|
37
|
+
decoded and name the failing request. `landed` is how long the previous
|
|
38
|
+
frame took to be answered. A window presents by default, so this is
|
|
39
|
+
time-to-display and reads about **one refresh period** — 16ms on a 60Hz
|
|
40
|
+
screen is the system working. On `frameClock: 'fence'` it is a server
|
|
41
|
+
round trip instead, and a paint that builds in 0.3ms against 20ms there
|
|
42
|
+
_is_ a server-side problem (software-fallback RENDER ops, a virtualized
|
|
43
|
+
GPU) rather than a renderer one. A frame the frame pacer held
|
|
44
|
+
([elements.md](elements.md#framerate--pacing-the-frames-under-a-flood))
|
|
52
45
|
carries `waited=18.0ms` — how long the claim waited before the clock got
|
|
53
|
-
it
|
|
54
|
-
the lines they always were.
|
|
46
|
+
it.
|
|
55
47
|
- `chrome:/tmp/trace.json` — [Chrome Trace Event
|
|
56
48
|
JSON](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU),
|
|
57
49
|
written at exit. Open it in Perfetto or `about:tracing`: React commits
|
|
@@ -60,15 +52,14 @@ REACT_X11_TRACE=summary npm run examples:dashboard
|
|
|
60
52
|
`CompositeGlyphs32` inside one commit".
|
|
61
53
|
|
|
62
54
|
Append `+stacks` to `requests` or `chrome` to capture a JS stack per
|
|
63
|
-
request
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`Error` capture per request, so it is opt-in.
|
|
55
|
+
request. An X error arrives long after the call that caused it returned,
|
|
56
|
+
and the captured stack is the only thing that maps it back to your code. It
|
|
57
|
+
costs an `Error` capture per request, so it is opt-in.
|
|
67
58
|
|
|
68
59
|
The tracer attaches to a connection _after_ its handshake, so the
|
|
69
|
-
connection-setup packet — the one carrying the X auth cookie — is
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
connection-setup packet — the one carrying the X auth cookie — is never
|
|
61
|
+
seen, and payload bytes are never recorded: only opcode, length and
|
|
62
|
+
direction.
|
|
72
63
|
|
|
73
64
|
### `startTrace()` — the same thing as an API
|
|
74
65
|
|
|
@@ -81,12 +72,9 @@ const { requests, bytesOut, replies, byOpcode } = trace.stop();
|
|
|
81
72
|
```
|
|
82
73
|
|
|
83
74
|
With no `app` the trace follows every connection the renderer has open or
|
|
84
|
-
opens later; pass `startTrace({ app })` to trace one specific connection
|
|
85
|
-
|
|
86
|
-
`'
|
|
87
|
-
splitter `npm run bench` uses, promoted to a runtime feature; for
|
|
88
|
-
committed regression numbers still use the bench (`scripts/bench/`), whose
|
|
89
|
-
in-process server keeps them deterministic.
|
|
75
|
+
opens later; pass `startTrace({ app })` to trace one specific connection.
|
|
76
|
+
`byOpcode` maps decoded request names — `'CopyArea'`,
|
|
77
|
+
`'Render.CompositeGlyphs32'` — to counts.
|
|
90
78
|
|
|
91
79
|
## Repaint flashing — `REACT_X11_DEBUG_PAINT`
|
|
92
80
|
|
|
@@ -114,71 +102,67 @@ Error: invalidated here
|
|
|
114
102
|
at ...
|
|
115
103
|
```
|
|
116
104
|
|
|
117
|
-
Full repaints are the
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
mount, ntk invalidating its backing store — and their reasons say so.
|
|
105
|
+
Full repaints are the main performance bug to look for. Expected ones exist
|
|
106
|
+
too — a resize, the first frame after a mount, the backing store being
|
|
107
|
+
invalidated — and their reasons say so.
|
|
121
108
|
|
|
122
|
-
A bounded frame can still be doing the work of an unbounded one
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
109
|
+
A bounded frame can still be doing the work of an unbounded one: an element
|
|
110
|
+
that draws a whole **scene** into one node — a graph view, a chart, an
|
|
111
|
+
editor — is one node to the damage machinery, so a tight outline around
|
|
112
|
+
what moved can sit over a pane that redrew all of itself inside it. Such an
|
|
113
|
+
element reads the pass's rect and claims its own commits
|
|
114
|
+
([extending.md](extending.md#drawing-a-scene-into-one-node)).
|
|
128
115
|
|
|
129
116
|
## `REACT_X11_NO_SCOPED_FLOORS=1`
|
|
130
117
|
|
|
131
118
|
Measures the content floors over the whole tree on every layout change,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
a box ever comes out the wrong size after its content changes. Read once at
|
|
138
|
-
startup; answers only to `1`.
|
|
119
|
+
instead of measuring a change inside an absolutely positioned box with its
|
|
120
|
+
own width and height in that box alone, or a change down a column whose
|
|
121
|
+
height is its content's (a document, a log, a feed in a scroll pane) alone
|
|
122
|
+
with the column summed. For comparing the two on the same build, and as
|
|
123
|
+
first aid if a box ever comes out the wrong size after its content changes.
|
|
139
124
|
|
|
140
125
|
## `REACT_X11_NO_UNREAD_WIDTHS=1`
|
|
141
126
|
|
|
142
127
|
Measures every box's min-content width in the width passes — over the whole
|
|
143
|
-
tree, and over a box measured alone —
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
600 KB of Markdown was a second of the first frame. For measuring the two against each other, and as first aid if
|
|
128
|
+
tree, and over a box measured alone — instead of only the widths a floor is
|
|
129
|
+
written from. By default a leaf whose width nothing reads (a paragraph down
|
|
130
|
+
a column in a document) is not set a word to a line to find one, which
|
|
131
|
+
matters for a large first frame. For comparing the two, and as first aid if
|
|
148
132
|
something in a row ever comes out narrower than its content after the first
|
|
149
|
-
frame.
|
|
133
|
+
frame.
|
|
150
134
|
|
|
151
135
|
## `REACT_X11_NO_REFIT_HOLD=1`
|
|
152
136
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
the new content at the old size — a label that grew wraps,
|
|
157
|
-
for the round trip before the resize lands. For
|
|
158
|
-
|
|
159
|
-
|
|
137
|
+
By default, the frame on which an `'auto'`-sized window's content asks for a
|
|
138
|
+
new size waits for the server's answer ([elements.md](elements.md#natural-size)).
|
|
139
|
+
This switch lays it out at the size it has on that frame instead, so on X11
|
|
140
|
+
that frame shows the new content at the old size — a label that grew wraps,
|
|
141
|
+
and is cut off — for the round trip before the resize lands. For comparing
|
|
142
|
+
the two, and as first aid if an `'auto'` window ever stops repainting after
|
|
143
|
+
its content changes.
|
|
160
144
|
|
|
161
145
|
## `REACT_X11_NO_SCROLL_BLIT=1`
|
|
162
146
|
|
|
163
|
-
Disables the scroll-blit fast path (a pure scroll
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
[`scrollContents`](extending.md#panning-a-scene-you-drew), which a pane
|
|
172
|
-
that pans a scene it drew itself calls — so a scene that misrenders while
|
|
173
|
-
panning is one variable away from being told apart from one that misdraws
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
147
|
+
Disables the scroll-blit fast path (a pure scroll copies the surviving band
|
|
148
|
+
and repaints only the exposed strip), so a scroll frame repaints its whole
|
|
149
|
+
viewport again. For measuring the blit against the plain path on the same
|
|
150
|
+
build, and as first aid if a scroll ever misrenders.
|
|
151
|
+
|
|
152
|
+
It also covers the other paths that move retained pixels instead of
|
|
153
|
+
repainting them:
|
|
154
|
+
|
|
155
|
+
- [`scrollContents`](extending.md#panning-a-scene-you-drew), which a pane
|
|
156
|
+
that pans a scene it drew itself calls — so a scene that misrenders while
|
|
157
|
+
panning is one variable away from being told apart from one that misdraws;
|
|
158
|
+
- the `<glarea>` overlay's copy, where a child of a surface that only moved
|
|
159
|
+
is moved on its pane rather than repainted ([elements.md](elements.md#glarea));
|
|
160
|
+
- the window's own copy of a subtree that only moved: a card with a
|
|
161
|
+
background nothing shows through, dragged across a pane, is copied where
|
|
162
|
+
it went and the frame paints the strip it uncovered
|
|
163
|
+
([extending.md](extending.md#an-element-that-covers-its-box)).
|
|
164
|
+
|
|
165
|
+
With this set, each of them repaints instead.
|
|
182
166
|
|
|
183
167
|
## `REACT_X11_NO_PANE_SHAPE=1`
|
|
184
168
|
|
|
@@ -188,8 +172,7 @@ actually paints ([elements.md](elements.md#glarea)). A rectangle covers the
|
|
|
188
172
|
GL frame with the surface's `clearColor` wherever the child's reach goes
|
|
189
173
|
past its ink — a `<Flow>` graph's edges stop short of every card and lose
|
|
190
174
|
their arrowheads — so this is for measuring the cut against the rectangle,
|
|
191
|
-
and as first aid if a pane's cut is ever wrong.
|
|
192
|
-
answers only to `1`.
|
|
175
|
+
and as first aid if a pane's cut is ever wrong.
|
|
193
176
|
|
|
194
177
|
## `REACT_X11_STRICT_TOKENS=1`
|
|
195
178
|
|
|
@@ -199,11 +182,10 @@ By default a token the palette in force does not define is dropped, named
|
|
|
199
182
|
loudly on stderr — token, element, owning component, and every token the
|
|
200
183
|
palette _does_ have — and counted as a failure through `process.exitCode`.
|
|
201
184
|
The widget paints one property short, which is visible, and the rest of the
|
|
202
|
-
app keeps running.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
tree from an X event with no React on the stack at all.
|
|
185
|
+
app keeps running. (A throw there could not be caught by most boundaries:
|
|
186
|
+
the check runs as a node's ancestry completes, often while React completes
|
|
187
|
+
the `<window>` or from a desktop light/dark switch with no React on the
|
|
188
|
+
stack.)
|
|
207
189
|
|
|
208
190
|
Set this when you would rather stop than paint something wrong — a kiosk, or
|
|
209
191
|
a CI job that should fail at the first bad token rather than at the
|
|
@@ -213,84 +195,64 @@ screenshot diff:
|
|
|
213
195
|
REACT_X11_STRICT_TOKENS=1 npm run examples:theming
|
|
214
196
|
```
|
|
215
197
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
desktop appearance switch; there strict mode crashes.
|
|
223
|
-
|
|
224
|
-
Read once at startup like the switches above, and answers only to `1`.
|
|
198
|
+
The error is raised from the offending node's own `commitMount`, on its own
|
|
199
|
+
fiber, so an [error boundary](react-features.md) at any depth inside the
|
|
200
|
+
window catches it and renders a fallback for that subtree rather than
|
|
201
|
+
losing the window. With no boundary above it, it reaches `onUncaughtError`
|
|
202
|
+
and the process stops. The one path that cannot be routed is the desktop
|
|
203
|
+
appearance switch; there strict mode crashes.
|
|
225
204
|
|
|
226
205
|
## `REACT_X11_NO_BOUNDS_CACHE=1`
|
|
227
206
|
|
|
228
|
-
Disables the cached paint reach
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
a
|
|
234
|
-
|
|
235
|
-
from a bounded repaint — culled by a reach nobody updated — this is the
|
|
236
|
-
first thing to try, and a fix that lands here is a change nobody announced
|
|
237
|
-
through `invalidate`. Read once at startup; answers only to `1`.
|
|
207
|
+
Disables the cached paint reach — the rect of a node unioned with its
|
|
208
|
+
descendants', which a bounded frame asks of every subtree on the way to its
|
|
209
|
+
rect, and which is kept until layout, a child list change, a style swap, a
|
|
210
|
+
state flip or the node's own `invalidate` moves it. With this set every walk
|
|
211
|
+
is fresh, so if a node ever goes missing from a bounded repaint — culled by
|
|
212
|
+
a reach nobody updated — this is the first thing to try, and a fix that
|
|
213
|
+
lands here is a change nobody announced through `invalidate`.
|
|
238
214
|
|
|
239
215
|
## `REACT_X11_NO_STROKE_CHUNKING=1` (macOS, Windows)
|
|
240
216
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
`ctx.strokeChunking = false` is the same switch for one context. Read once
|
|
252
|
-
at startup, like the switches above, and answers only to `1`.
|
|
253
|
-
|
|
254
|
-
Nothing on X11 reads it: there a stroke is one coverage mask over the
|
|
255
|
-
path's bounding box, so a bigger path is _fewer_ uploads and the split
|
|
217
|
+
The 2d context the Cocoa and win32 backends share splits a stroke with many
|
|
218
|
+
subpaths into several platform calls, which makes a stroke of thousands of
|
|
219
|
+
subpaths many times faster; the antialiased fringe where two subpaths'
|
|
220
|
+
strokes overlap is then half-covered twice rather than covered once, and
|
|
221
|
+
reads a little lighter. This switch hands every stroke to the platform in
|
|
222
|
+
one call. Set it to compare the two on the same build, or as first aid if a
|
|
223
|
+
drawing that strokes thousands of subpaths ever looks wrong at its seams.
|
|
224
|
+
`ctx.strokeChunking = false` is the same switch for one context.
|
|
225
|
+
|
|
226
|
+
Nothing on X11 reads it: there a stroke is one coverage mask, so splitting
|
|
256
227
|
would be a loss.
|
|
257
228
|
|
|
258
229
|
## `REACT_X11_NO_TRANSPARENCY=1`
|
|
259
230
|
|
|
260
231
|
Makes every display answer the way one with no 32-bit visual does:
|
|
261
232
|
[`transparent`](elements.md#transparent--rounded-corners-and-translucency)
|
|
262
|
-
is ignored, windows are created on
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
`useSupports('transparency')` is false.
|
|
233
|
+
is ignored, windows are created on the ordinary visual,
|
|
234
|
+
`'@supports transparency'` ([styling.md](styling.md#capability-queries))
|
|
235
|
+
never matches, and `useSupports('transparency')` is false.
|
|
266
236
|
|
|
267
237
|
```sh
|
|
268
238
|
REACT_X11_NO_TRANSPARENCY=1 npm run examples:tooltips
|
|
269
239
|
```
|
|
270
240
|
|
|
271
|
-
It
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
this switch at once, deliberately: a window that took the ARGB visual under
|
|
277
|
-
a `useSupports` that said no would size a popup for chrome it then refused
|
|
278
|
-
to draw.
|
|
241
|
+
It lets you see the fallback design — rounded menus, the tooltip's arrow,
|
|
242
|
+
any `@supports` block of your own — without stopping the compositor, which
|
|
243
|
+
would take every other window on the desktop with it. Both halves answer
|
|
244
|
+
this switch at once, so a window never takes the ARGB visual under a
|
|
245
|
+
`useSupports` that said no.
|
|
279
246
|
|
|
280
247
|
What it models is a display with **no 32-bit visual** — XQuartz, a plain
|
|
281
248
|
remote server. The other degraded case, an ARGB window with _nothing
|
|
282
|
-
compositing it_
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
`NO_TRANSPARENCY=0` cannot quietly mean the opposite of what it says.
|
|
290
|
-
Unlike them it is read per call rather than once at startup — it is asked
|
|
291
|
-
when a window is created and when a `@supports` block resolves, never on
|
|
292
|
-
the frame path, and being live is what lets a test turn it on around a
|
|
293
|
-
single mount.
|
|
249
|
+
compositing it_ (a cleared corner comes out black rather than showing the
|
|
250
|
+
desktop), needs a real session with the compositor off, or
|
|
251
|
+
`setCompositingForTests`. Both should render the same.
|
|
252
|
+
|
|
253
|
+
Unlike the switches above it is read per call rather than once at startup —
|
|
254
|
+
when a window is created and when a `@supports` block resolves, never on the
|
|
255
|
+
frame path — so a test can turn it on around a single mount.
|
|
294
256
|
|
|
295
257
|
## The paint cache — `REACT_X11_NO_PAINT_CACHE`, `REACT_X11_PAINT_CACHE=verify`
|
|
296
258
|
|
|
@@ -327,35 +289,16 @@ Three switches, all read once at startup:
|
|
|
327
289
|
|
|
328
290
|
## Rounded boxes — the corner-glyph fast path
|
|
329
291
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
is exactly one axis-aligned `roundRect` on integer geometry goes out as
|
|
338
|
-
**four cached corner glyphs plus `FillRectangles`** — the corners ride the
|
|
339
|
-
glyph path every X server optimizes, cached server-side after first use,
|
|
340
|
-
and the straight runs between them are plain rectangles. Nothing is
|
|
341
|
-
rasterized or uploaded in steady state. `_paintBackground` and
|
|
342
|
-
`_paintBorder` already draw exactly that shape, so every `borderRadius` box
|
|
343
|
-
takes the route with no change to your code.
|
|
344
|
-
|
|
345
|
-
What it is worth, measured on this repo's `bench:frames` cards mode against
|
|
346
|
-
a glamor/virgl server — 48 cards, all recoloured every frame:
|
|
292
|
+
On X11, a `fill()` or `stroke()` whose path is exactly one axis-aligned
|
|
293
|
+
`roundRect` on integer geometry — what every `borderRadius` box draws — goes
|
|
294
|
+
out as four cached corner glyphs plus rectangles, with nothing rasterized or
|
|
295
|
+
uploaded in steady state. A box that falls back still renders, identically,
|
|
296
|
+
as a polygon, which on a server without accelerated trapezoids (a
|
|
297
|
+
virtualized GPU) can cost an order of magnitude more per frame. The fallback
|
|
298
|
+
is silent, so the counters below are how you notice it.
|
|
347
299
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
| `--border=2` (fast path) | 57.8 | 0.78 ms | 0.70 ms | 13 KB |
|
|
351
|
-
| `--border=2 --no-glyphs` | 3.8 | 7.53 ms | 287 ms | 342 KB |
|
|
352
|
-
|
|
353
|
-
(measured on the fence clock, where the column is server drain — on the
|
|
354
|
-
default vertical-blank clock the fast-path row would read about one refresh
|
|
355
|
-
period instead, and the cliff would show in `fps` and `dropped`)
|
|
356
|
-
|
|
357
|
-
A bail-out is a silent perf cliff — the box still renders, identically,
|
|
358
|
-
just via the route above — so the counters matter more than usual.
|
|
300
|
+
Design notes and measurements:
|
|
301
|
+
[design/debugging.md](../design/debugging.md#rounded-boxes--the-corner-glyph-fast-path).
|
|
359
302
|
|
|
360
303
|
### Seeing which boxes took it
|
|
361
304
|
|
|
@@ -371,43 +314,25 @@ REACT_X11_TRACE=summary npm run examples:tasks
|
|
|
371
314
|
|
|
372
315
|
The same tally is on `trace.stop().shapes` as `{ hits, misses }`, and ntk
|
|
373
316
|
prints a process-wide version under `NTK_DEBUG_SHAPES=1`. In the opcode
|
|
374
|
-
histogram the
|
|
375
|
-
`Render.FillRectangles
|
|
376
|
-
`PutImage`-heavy `Render.Composite
|
|
317
|
+
histogram the fast path shows as `Render.CompositeGlyphs8` and
|
|
318
|
+
`Render.FillRectangles`; the fallback as `Render.Trapezoids`,
|
|
319
|
+
`Render.AddTraps` or a `PutImage`-heavy `Render.Composite`.
|
|
377
320
|
|
|
378
321
|
### Why a box falls back
|
|
379
322
|
|
|
380
323
|
`misses` counts by reason. In rough order of how often they bite:
|
|
381
324
|
|
|
382
|
-
- `fractional` — the box, or the stroke's band, is not on whole pixels
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
On ntk < 7 an _odd_ border width bailed too, and it was the one to know
|
|
387
|
-
about. `_paintBorder` strokes the box inset by half the border width,
|
|
388
|
-
putting the stroke's centre-line radius at `borderRadius - borderWidth/2`
|
|
389
|
-
— half-integer whenever the border is odd — and the stroke path wanted an
|
|
390
|
-
integer radius. A 1px or 3px rounded border therefore kept its corners on
|
|
391
|
-
the polygon route while the fill underneath took the fast one, which on
|
|
392
|
-
the 48-card wall was 26x the wire per frame (341 KB against 13 KB) and 5x
|
|
393
|
-
the client paint. ntk 7 takes those radii (sidorares/ntk#218), so a 1px
|
|
394
|
-
border is now as cheap as a 2px one and no border width needs choosing
|
|
395
|
-
around this.
|
|
396
|
-
|
|
325
|
+
- `fractional` — the box, or the stroke's band, is not on whole pixels:
|
|
326
|
+
usually a box laid out on a half-pixel. Any border width, odd or even,
|
|
327
|
+
takes the fast path.
|
|
397
328
|
- `radius-cap` — the corner radius is over `shapePolicy.maxRadius` (64 by
|
|
398
|
-
default
|
|
399
|
-
the off switch reports.
|
|
329
|
+
default). Also what the off switch reports.
|
|
400
330
|
- `gradient` — the fill or stroke style is not a solid colour.
|
|
401
331
|
- `clip-mask` — a non-rectangular clip is in effect. Rectangular clips are
|
|
402
|
-
fine
|
|
403
|
-
a
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
card or pane stays on the route. The exceptions still clip to the
|
|
407
|
-
outline: a box that is corner all the way along a side (a pill whose
|
|
408
|
-
corner squares would overlap), and one laid out off the pixel grid. So a
|
|
409
|
-
`clip-mask` miss points at one of those, or at a clip an element sets
|
|
410
|
-
itself.
|
|
332
|
+
fine, and so, on X11, is a rounded box's own `overflow` clip: everything
|
|
333
|
+
inside a rounded card or pane stays on the fast path. The exceptions are a
|
|
334
|
+
box that is corner all the way along a side (a pill), one laid out off the
|
|
335
|
+
pixel grid, and a clip an element sets itself.
|
|
411
336
|
- `dashes` — `borderStyle: 'dashed'`.
|
|
412
337
|
- `transform` — the context's matrix is not translate-only.
|
|
413
338
|
- `composite-op`, `geometry`, `radii-mix`, `join` — a non-`source-over`
|
|
@@ -425,40 +350,22 @@ root.app.shapePolicy = { maxRadius: 32, cacheBytes: 128 << 10 };
|
|
|
425
350
|
```
|
|
426
351
|
|
|
427
352
|
`NTK_NO_SHAPE_GLYPHS=1` does the same from the environment. Both are for
|
|
428
|
-
A/B measurement and for cornering a suspected rendering difference —
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
npm run bench:frames -- cards 8 --border=2 --no-glyphs # same scene, polygons
|
|
434
|
-
npm run bench:frames -- cards 8 --border=1 # the odd-width cliff
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
The two routes are not bit-identical: they rasterize the same arc by
|
|
438
|
-
different means, so corner pixels differ by antialiasing — under 4/255 for
|
|
439
|
-
fills, up to 48/255 on a stroked corner. Everything outside the corner
|
|
440
|
-
boxes is exact, which is the property the decomposition rests on (the
|
|
441
|
-
glyphs and the rectangles partition the pixels, so no pixel is painted
|
|
442
|
-
twice and translucent colours are safe). `test/rounded-box-glyphs.test.js`
|
|
443
|
-
asserts exactly that split.
|
|
444
|
-
|
|
445
|
-
In practice the difference does not reach a screenshot: regenerating
|
|
446
|
-
`docs/img/*.png` with the route off moves between 0 and 0.06% of pixels,
|
|
447
|
-
by at most 8/255. If `npm run screenshots` ever produces a bigger diff than
|
|
448
|
-
that after a toolkit bump, the cause is somewhere else — ntk 6.7.0's other
|
|
449
|
-
change, an arc flattener that subdivides curves more exactly, moved those
|
|
450
|
-
same screenshots far more than this route did.
|
|
353
|
+
A/B measurement and for cornering a suspected rendering difference — an
|
|
354
|
+
application should not need to turn it off. The two routes differ only in
|
|
355
|
+
corner antialiasing (under 4/255 for fills, up to 48/255 on a stroked
|
|
356
|
+
corner); every pixel outside the corners is exact, and translucent colours
|
|
357
|
+
are safe.
|
|
451
358
|
|
|
452
359
|
## Invalidation reasons
|
|
453
360
|
|
|
454
|
-
Every internal `invalidate()` call
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
`
|
|
458
|
-
`
|
|
459
|
-
`
|
|
460
|
-
frame's collected reasons are what `REACT_X11_TRACE=requests`
|
|
461
|
-
the chrome trace's frame slices
|
|
462
|
-
|
|
463
|
-
|
|
361
|
+
Every internal `invalidate()` call names why it ran, from a small closed
|
|
362
|
+
set: `props`, `position`, `style-state`, `shadow`, `outline`, `theme`,
|
|
363
|
+
`ink`, `direction`, `scale`, `units`, `animation`, `scroll`, `text`,
|
|
364
|
+
`selection`, `content`, `measure`, `child-list`, `focus`, `caret`,
|
|
365
|
+
`resize`, `mount`, `expose`, `highlight`, `trace-updates`, `capabilities`,
|
|
366
|
+
`layout` (`INVALIDATE_REASONS` in `src/nodes/damage.js` says what each one
|
|
367
|
+
means). A frame's collected reasons are what `REACT_X11_TRACE=requests`
|
|
368
|
+
frame lines, the chrome trace's frame slices and the full-repaint warning
|
|
369
|
+
print. After a frame they are readable on the window node as
|
|
370
|
+
`root._lastReasons` (an instrumentation surface, like
|
|
464
371
|
`root._lastDamageRects` — not public API).
|