@react-x11/components 0.8.0 → 0.10.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.
Files changed (721) hide show
  1. package/README.md +105 -38
  2. package/dist/charts/node.d.ts +12 -2
  3. package/dist/charts/node.d.ts.map +1 -1
  4. package/dist/charts/node.js +50 -16
  5. package/dist/charts/node.js.map +1 -1
  6. package/dist/charts/render.d.ts +12 -3
  7. package/dist/charts/render.d.ts.map +1 -1
  8. package/dist/charts/render.js +94 -25
  9. package/dist/charts/render.js.map +1 -1
  10. package/dist/code/index.d.ts.map +1 -1
  11. package/dist/code/index.js +3 -1
  12. package/dist/code/index.js.map +1 -1
  13. package/dist/code-editor/completion.d.ts.map +1 -1
  14. package/dist/code-editor/completion.js +3 -2
  15. package/dist/code-editor/completion.js.map +1 -1
  16. package/dist/code-editor/index.d.ts.map +1 -1
  17. package/dist/code-editor/index.js +19 -0
  18. package/dist/code-editor/index.js.map +1 -1
  19. package/dist/code-editor/node.d.ts +177 -7
  20. package/dist/code-editor/node.d.ts.map +1 -1
  21. package/dist/code-editor/node.js +1329 -164
  22. package/dist/code-editor/node.js.map +1 -1
  23. package/dist/code-language/languages/glsl.d.ts.map +1 -1
  24. package/dist/code-language/languages/glsl.js +10 -2
  25. package/dist/code-language/languages/glsl.js.map +1 -1
  26. package/dist/code-language/languages/javascript.d.ts.map +1 -1
  27. package/dist/code-language/languages/javascript.js +18 -3
  28. package/dist/code-language/languages/javascript.js.map +1 -1
  29. package/dist/code-language/languages/json.d.ts.map +1 -1
  30. package/dist/code-language/languages/json.js +10 -2
  31. package/dist/code-language/languages/json.js.map +1 -1
  32. package/dist/code-language/languages/shell.d.ts.map +1 -1
  33. package/dist/code-language/languages/shell.js +10 -2
  34. package/dist/code-language/languages/shell.js.map +1 -1
  35. package/dist/code-language/languages/sql.d.ts.map +1 -1
  36. package/dist/code-language/languages/sql.js +20 -2
  37. package/dist/code-language/languages/sql.js.map +1 -1
  38. package/dist/code-language/stream.d.ts +22 -0
  39. package/dist/code-language/stream.d.ts.map +1 -1
  40. package/dist/code-language/stream.js +259 -9
  41. package/dist/code-language/stream.js.map +1 -1
  42. package/dist/code-language/types.d.ts +5 -4
  43. package/dist/code-language/types.d.ts.map +1 -1
  44. package/dist/codeblock/index.d.ts +13 -2
  45. package/dist/codeblock/index.d.ts.map +1 -1
  46. package/dist/codeblock/index.js +20 -3
  47. package/dist/codeblock/index.js.map +1 -1
  48. package/dist/embed/client.d.ts +48 -3
  49. package/dist/embed/client.d.ts.map +1 -1
  50. package/dist/embed/client.js +79 -5
  51. package/dist/embed/client.js.map +1 -1
  52. package/dist/embed/index.d.ts +1 -1
  53. package/dist/embed/index.d.ts.map +1 -1
  54. package/dist/embed/index.js +1 -1
  55. package/dist/embed/index.js.map +1 -1
  56. package/dist/flow/draw.d.ts +50 -0
  57. package/dist/flow/draw.d.ts.map +1 -1
  58. package/dist/flow/draw.js +132 -33
  59. package/dist/flow/draw.js.map +1 -1
  60. package/dist/flow/gl/color.d.ts +13 -0
  61. package/dist/flow/gl/color.d.ts.map +1 -0
  62. package/dist/flow/gl/color.js +82 -0
  63. package/dist/flow/gl/color.js.map +1 -0
  64. package/dist/flow/gl/index.d.ts +60 -0
  65. package/dist/flow/gl/index.d.ts.map +1 -0
  66. package/dist/flow/gl/index.js +283 -0
  67. package/dist/flow/gl/index.js.map +1 -0
  68. package/dist/flow/gl/pack.d.ts +133 -0
  69. package/dist/flow/gl/pack.d.ts.map +1 -0
  70. package/dist/flow/gl/pack.js +408 -0
  71. package/dist/flow/gl/pack.js.map +1 -0
  72. package/dist/flow/gl/renderer.d.ts +95 -0
  73. package/dist/flow/gl/renderer.d.ts.map +1 -0
  74. package/dist/flow/gl/renderer.js +459 -0
  75. package/dist/flow/gl/renderer.js.map +1 -0
  76. package/dist/flow/gl/shaders.d.ts +79 -0
  77. package/dist/flow/gl/shaders.d.ts.map +1 -0
  78. package/dist/flow/gl/shaders.js +346 -0
  79. package/dist/flow/gl/shaders.js.map +1 -0
  80. package/dist/flow/gl/text.d.ts +318 -0
  81. package/dist/flow/gl/text.d.ts.map +1 -0
  82. package/dist/flow/gl/text.js +1103 -0
  83. package/dist/flow/gl/text.js.map +1 -0
  84. package/dist/flow/index.d.ts +1 -1
  85. package/dist/flow/index.d.ts.map +1 -1
  86. package/dist/flow/index.js +619 -64
  87. package/dist/flow/index.js.map +1 -1
  88. package/dist/flow/node.d.ts +621 -72
  89. package/dist/flow/node.d.ts.map +1 -1
  90. package/dist/flow/node.js +2253 -1018
  91. package/dist/flow/node.js.map +1 -1
  92. package/dist/flow/paint.d.ts +35 -0
  93. package/dist/flow/paint.d.ts.map +1 -0
  94. package/dist/flow/paint.js +393 -0
  95. package/dist/flow/paint.js.map +1 -0
  96. package/dist/flow/paths.d.ts +14 -0
  97. package/dist/flow/paths.d.ts.map +1 -1
  98. package/dist/flow/paths.js +45 -19
  99. package/dist/flow/paths.js.map +1 -1
  100. package/dist/flow/scene.d.ts +584 -0
  101. package/dist/flow/scene.d.ts.map +1 -0
  102. package/dist/flow/scene.js +1453 -0
  103. package/dist/flow/scene.js.map +1 -0
  104. package/dist/flow/types.d.ts +111 -1
  105. package/dist/flow/types.d.ts.map +1 -1
  106. package/dist/html/controls.d.ts +28 -0
  107. package/dist/html/controls.d.ts.map +1 -1
  108. package/dist/html/controls.js +52 -2
  109. package/dist/html/controls.js.map +1 -1
  110. package/dist/html/css/calc.d.ts +14 -0
  111. package/dist/html/css/calc.d.ts.map +1 -0
  112. package/dist/html/css/calc.js +344 -0
  113. package/dist/html/css/calc.js.map +1 -0
  114. package/dist/html/css/cascade.d.ts +240 -6
  115. package/dist/html/css/cascade.d.ts.map +1 -1
  116. package/dist/html/css/cascade.js +1327 -66
  117. package/dist/html/css/cascade.js.map +1 -1
  118. package/dist/html/css/color.d.ts +23 -0
  119. package/dist/html/css/color.d.ts.map +1 -0
  120. package/dist/html/css/color.js +740 -0
  121. package/dist/html/css/color.js.map +1 -0
  122. package/dist/html/css/content.d.ts +92 -0
  123. package/dist/html/css/content.d.ts.map +1 -0
  124. package/dist/html/css/content.js +388 -0
  125. package/dist/html/css/content.js.map +1 -0
  126. package/dist/html/css/counter-styles.d.ts +76 -0
  127. package/dist/html/css/counter-styles.d.ts.map +1 -0
  128. package/dist/html/css/counter-styles.js +893 -0
  129. package/dist/html/css/counter-styles.js.map +1 -0
  130. package/dist/html/css/decode.d.ts +12 -0
  131. package/dist/html/css/decode.d.ts.map +1 -0
  132. package/dist/html/css/decode.js +116 -0
  133. package/dist/html/css/decode.js.map +1 -0
  134. package/dist/html/css/parse.d.ts +110 -10
  135. package/dist/html/css/parse.d.ts.map +1 -1
  136. package/dist/html/css/parse.js +1473 -180
  137. package/dist/html/css/parse.js.map +1 -1
  138. package/dist/html/css/style.d.ts +498 -15
  139. package/dist/html/css/style.d.ts.map +1 -1
  140. package/dist/html/css/style.js +3698 -206
  141. package/dist/html/css/style.js.map +1 -1
  142. package/dist/html/css/ua.d.ts.map +1 -1
  143. package/dist/html/css/ua.js +57 -11
  144. package/dist/html/css/ua.js.map +1 -1
  145. package/dist/html/css/values.d.ts +37 -3
  146. package/dist/html/css/values.d.ts.map +1 -1
  147. package/dist/html/css/values.js +122 -48
  148. package/dist/html/css/values.js.map +1 -1
  149. package/dist/html/css/vars.d.ts +52 -0
  150. package/dist/html/css/vars.d.ts.map +1 -0
  151. package/dist/html/css/vars.js +358 -0
  152. package/dist/html/css/vars.js.map +1 -0
  153. package/dist/html/dom.d.ts +30 -4
  154. package/dist/html/dom.d.ts.map +1 -1
  155. package/dist/html/dom.js +278 -17
  156. package/dist/html/dom.js.map +1 -1
  157. package/dist/html/fonts.d.ts +106 -0
  158. package/dist/html/fonts.d.ts.map +1 -0
  159. package/dist/html/fonts.js +565 -0
  160. package/dist/html/fonts.js.map +1 -0
  161. package/dist/html/gif.d.ts +15 -0
  162. package/dist/html/gif.d.ts.map +1 -0
  163. package/dist/html/gif.js +229 -0
  164. package/dist/html/gif.js.map +1 -0
  165. package/dist/html/index.d.ts +50 -11
  166. package/dist/html/index.d.ts.map +1 -1
  167. package/dist/html/index.js +115 -9
  168. package/dist/html/index.js.map +1 -1
  169. package/dist/html/layout/block.d.ts +226 -3
  170. package/dist/html/layout/block.d.ts.map +1 -1
  171. package/dist/html/layout/block.js +2937 -197
  172. package/dist/html/layout/block.js.map +1 -1
  173. package/dist/html/layout/boxes.d.ts +340 -17
  174. package/dist/html/layout/boxes.d.ts.map +1 -1
  175. package/dist/html/layout/boxes.js +1714 -182
  176. package/dist/html/layout/boxes.js.map +1 -1
  177. package/dist/html/layout/cache.d.ts +58 -0
  178. package/dist/html/layout/cache.d.ts.map +1 -0
  179. package/dist/html/layout/cache.js +224 -0
  180. package/dist/html/layout/cache.js.map +1 -0
  181. package/dist/html/layout/collapse.d.ts +45 -0
  182. package/dist/html/layout/collapse.d.ts.map +1 -0
  183. package/dist/html/layout/collapse.js +246 -0
  184. package/dist/html/layout/collapse.js.map +1 -0
  185. package/dist/html/layout/css-grid.d.ts +7 -0
  186. package/dist/html/layout/css-grid.d.ts.map +1 -0
  187. package/dist/html/layout/css-grid.js +900 -0
  188. package/dist/html/layout/css-grid.js.map +1 -0
  189. package/dist/html/layout/flex.d.ts.map +1 -1
  190. package/dist/html/layout/flex.js +1025 -89
  191. package/dist/html/layout/flex.js.map +1 -1
  192. package/dist/html/layout/floats.d.ts +45 -6
  193. package/dist/html/layout/floats.d.ts.map +1 -1
  194. package/dist/html/layout/floats.js +113 -14
  195. package/dist/html/layout/floats.js.map +1 -1
  196. package/dist/html/layout/grid-lines.d.ts +39 -0
  197. package/dist/html/layout/grid-lines.d.ts.map +1 -0
  198. package/dist/html/layout/grid-lines.js +119 -0
  199. package/dist/html/layout/grid-lines.js.map +1 -0
  200. package/dist/html/layout/grid.d.ts +53 -0
  201. package/dist/html/layout/grid.d.ts.map +1 -0
  202. package/dist/html/layout/grid.js +153 -0
  203. package/dist/html/layout/grid.js.map +1 -0
  204. package/dist/html/layout/inline.d.ts +151 -1
  205. package/dist/html/layout/inline.d.ts.map +1 -1
  206. package/dist/html/layout/inline.js +3375 -174
  207. package/dist/html/layout/inline.js.map +1 -1
  208. package/dist/html/layout/shaping.d.ts +6 -0
  209. package/dist/html/layout/shaping.d.ts.map +1 -0
  210. package/dist/html/layout/shaping.js +100 -0
  211. package/dist/html/layout/shaping.js.map +1 -0
  212. package/dist/html/layout/table.d.ts +3 -0
  213. package/dist/html/layout/table.d.ts.map +1 -1
  214. package/dist/html/layout/table.js +681 -175
  215. package/dist/html/layout/table.js.map +1 -1
  216. package/dist/html/layout/tracks.d.ts +44 -0
  217. package/dist/html/layout/tracks.d.ts.map +1 -0
  218. package/dist/html/layout/tracks.js +349 -0
  219. package/dist/html/layout/tracks.js.map +1 -0
  220. package/dist/html/node.d.ts +172 -5
  221. package/dist/html/node.d.ts.map +1 -1
  222. package/dist/html/node.js +1336 -103
  223. package/dist/html/node.js.map +1 -1
  224. package/dist/html/paint.d.ts +92 -3
  225. package/dist/html/paint.d.ts.map +1 -1
  226. package/dist/html/paint.js +3503 -141
  227. package/dist/html/paint.js.map +1 -1
  228. package/dist/html/resources.d.ts +60 -14
  229. package/dist/html/resources.d.ts.map +1 -1
  230. package/dist/html/resources.js +122 -36
  231. package/dist/html/resources.js.map +1 -1
  232. package/dist/html/surfaces.d.ts +23 -0
  233. package/dist/html/surfaces.d.ts.map +1 -0
  234. package/dist/html/surfaces.js +68 -0
  235. package/dist/html/surfaces.js.map +1 -0
  236. package/dist/html/svg.d.ts +80 -0
  237. package/dist/html/svg.d.ts.map +1 -0
  238. package/dist/html/svg.js +435 -0
  239. package/dist/html/svg.js.map +1 -0
  240. package/dist/html/url.d.ts +23 -0
  241. package/dist/html/url.d.ts.map +1 -0
  242. package/dist/html/url.js +80 -0
  243. package/dist/html/url.js.map +1 -0
  244. package/dist/index.d.ts +2 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +1 -1
  247. package/dist/index.js.map +1 -1
  248. package/dist/internal/collate.d.ts +3 -0
  249. package/dist/internal/collate.d.ts.map +1 -0
  250. package/dist/internal/collate.js +11 -0
  251. package/dist/internal/collate.js.map +1 -0
  252. package/dist/{markdown → internal/markdown}/ast.d.ts +23 -0
  253. package/dist/internal/markdown/ast.d.ts.map +1 -0
  254. package/dist/internal/markdown/ast.js +22 -0
  255. package/dist/internal/markdown/ast.js.map +1 -0
  256. package/dist/internal/markdown/parse.d.ts.map +1 -0
  257. package/dist/{markdown → internal/markdown}/parse.js +221 -30
  258. package/dist/internal/markdown/parse.js.map +1 -0
  259. package/dist/internal/markdown/stringify.d.ts +4 -0
  260. package/dist/internal/markdown/stringify.d.ts.map +1 -0
  261. package/dist/internal/markdown/stringify.js +684 -0
  262. package/dist/internal/markdown/stringify.js.map +1 -0
  263. package/dist/internal/markdown/tags.d.ts.map +1 -0
  264. package/dist/internal/markdown/tags.js.map +1 -0
  265. package/dist/internal/prewarm.d.ts +18 -0
  266. package/dist/internal/prewarm.d.ts.map +1 -0
  267. package/dist/internal/prewarm.js +42 -0
  268. package/dist/internal/prewarm.js.map +1 -0
  269. package/dist/internal/scroll.d.ts +3 -2
  270. package/dist/internal/scroll.d.ts.map +1 -1
  271. package/dist/internal/scroll.js +1 -0
  272. package/dist/internal/scroll.js.map +1 -1
  273. package/dist/internal/sdf.d.ts +20 -0
  274. package/dist/internal/sdf.d.ts.map +1 -0
  275. package/dist/internal/sdf.js +216 -0
  276. package/dist/internal/sdf.js.map +1 -0
  277. package/dist/internal/splice.d.ts +12 -0
  278. package/dist/internal/splice.d.ts.map +1 -0
  279. package/dist/internal/splice.js +23 -0
  280. package/dist/internal/splice.js.map +1 -0
  281. package/dist/internal/window.d.ts +12 -0
  282. package/dist/internal/window.d.ts.map +1 -1
  283. package/dist/internal/window.js +23 -6
  284. package/dist/internal/window.js.map +1 -1
  285. package/dist/maps/anchors.d.ts +103 -0
  286. package/dist/maps/anchors.d.ts.map +1 -0
  287. package/dist/maps/anchors.js +790 -0
  288. package/dist/maps/anchors.js.map +1 -0
  289. package/dist/maps/controller.d.ts +340 -0
  290. package/dist/maps/controller.d.ts.map +1 -0
  291. package/dist/maps/controller.js +822 -0
  292. package/dist/maps/controller.js.map +1 -0
  293. package/dist/maps/gl/buckets.d.ts +99 -0
  294. package/dist/maps/gl/buckets.d.ts.map +1 -0
  295. package/dist/maps/gl/buckets.js +365 -0
  296. package/dist/maps/gl/buckets.js.map +1 -0
  297. package/dist/maps/gl/build-worker.d.ts +15 -0
  298. package/dist/maps/gl/build-worker.d.ts.map +1 -0
  299. package/dist/maps/gl/build-worker.js +44 -0
  300. package/dist/maps/gl/build-worker.js.map +1 -0
  301. package/dist/maps/gl/color.d.ts +8 -0
  302. package/dist/maps/gl/color.d.ts.map +1 -0
  303. package/dist/maps/gl/color.js +57 -0
  304. package/dist/maps/gl/color.js.map +1 -0
  305. package/dist/maps/gl/cover.d.ts +70 -0
  306. package/dist/maps/gl/cover.d.ts.map +1 -0
  307. package/dist/maps/gl/cover.js +137 -0
  308. package/dist/maps/gl/cover.js.map +1 -0
  309. package/dist/maps/gl/index.d.ts +3 -0
  310. package/dist/maps/gl/index.d.ts.map +1 -0
  311. package/dist/maps/gl/index.js +20 -0
  312. package/dist/maps/gl/index.js.map +1 -0
  313. package/dist/maps/gl/markers.d.ts +28 -0
  314. package/dist/maps/gl/markers.d.ts.map +1 -0
  315. package/dist/maps/gl/markers.js +60 -0
  316. package/dist/maps/gl/markers.js.map +1 -0
  317. package/dist/maps/gl/overlays.d.ts +68 -0
  318. package/dist/maps/gl/overlays.d.ts.map +1 -0
  319. package/dist/maps/gl/overlays.js +300 -0
  320. package/dist/maps/gl/overlays.js.map +1 -0
  321. package/dist/maps/gl/pane.d.ts +12 -0
  322. package/dist/maps/gl/pane.d.ts.map +1 -0
  323. package/dist/maps/gl/pane.js +37 -0
  324. package/dist/maps/gl/pane.js.map +1 -0
  325. package/dist/maps/gl/placement.d.ts +124 -0
  326. package/dist/maps/gl/placement.d.ts.map +1 -0
  327. package/dist/maps/gl/placement.js +642 -0
  328. package/dist/maps/gl/placement.js.map +1 -0
  329. package/dist/maps/gl/renderer.d.ts +384 -0
  330. package/dist/maps/gl/renderer.d.ts.map +1 -0
  331. package/dist/maps/gl/renderer.js +1184 -0
  332. package/dist/maps/gl/renderer.js.map +1 -0
  333. package/dist/maps/gl/shaders.d.ts +121 -0
  334. package/dist/maps/gl/shaders.d.ts.map +1 -0
  335. package/dist/maps/gl/shaders.js +453 -0
  336. package/dist/maps/gl/shaders.js.map +1 -0
  337. package/dist/maps/gl/store.d.ts +125 -0
  338. package/dist/maps/gl/store.d.ts.map +1 -0
  339. package/dist/maps/gl/store.js +512 -0
  340. package/dist/maps/gl/store.js.map +1 -0
  341. package/dist/maps/gl/text.d.ts +283 -0
  342. package/dist/maps/gl/text.d.ts.map +1 -0
  343. package/dist/maps/gl/text.js +698 -0
  344. package/dist/maps/gl/text.js.map +1 -0
  345. package/dist/maps/gl/view.d.ts +345 -0
  346. package/dist/maps/gl/view.d.ts.map +1 -0
  347. package/dist/maps/gl/view.js +1209 -0
  348. package/dist/maps/gl/view.js.map +1 -0
  349. package/dist/maps/icons.d.ts +32 -0
  350. package/dist/maps/icons.d.ts.map +1 -0
  351. package/dist/maps/icons.js +151 -0
  352. package/dist/maps/icons.js.map +1 -0
  353. package/dist/maps/index.d.ts +3 -1
  354. package/dist/maps/index.d.ts.map +1 -1
  355. package/dist/maps/index.js +218 -52
  356. package/dist/maps/index.js.map +1 -1
  357. package/dist/maps/labels.d.ts +91 -18
  358. package/dist/maps/labels.d.ts.map +1 -1
  359. package/dist/maps/labels.js +376 -140
  360. package/dist/maps/labels.js.map +1 -1
  361. package/dist/maps/node.d.ts +179 -56
  362. package/dist/maps/node.d.ts.map +1 -1
  363. package/dist/maps/node.js +663 -537
  364. package/dist/maps/node.js.map +1 -1
  365. package/dist/maps/overlay.d.ts +72 -9
  366. package/dist/maps/overlay.d.ts.map +1 -1
  367. package/dist/maps/overlay.js +108 -28
  368. package/dist/maps/overlay.js.map +1 -1
  369. package/dist/maps/paint.d.ts +3 -0
  370. package/dist/maps/paint.d.ts.map +1 -1
  371. package/dist/maps/paint.js.map +1 -1
  372. package/dist/maps/proj.d.ts +62 -0
  373. package/dist/maps/proj.d.ts.map +1 -1
  374. package/dist/maps/proj.js +101 -0
  375. package/dist/maps/proj.js.map +1 -1
  376. package/dist/maps/renderer.d.ts +69 -0
  377. package/dist/maps/renderer.d.ts.map +1 -0
  378. package/dist/maps/renderer.js +66 -0
  379. package/dist/maps/renderer.js.map +1 -0
  380. package/dist/maps/sources.d.ts +30 -6
  381. package/dist/maps/sources.d.ts.map +1 -1
  382. package/dist/maps/sources.js +22 -3
  383. package/dist/maps/sources.js.map +1 -1
  384. package/dist/maps/style.d.ts +35 -0
  385. package/dist/maps/style.d.ts.map +1 -1
  386. package/dist/maps/style.js.map +1 -1
  387. package/dist/maps/styles.d.ts +12 -0
  388. package/dist/maps/styles.d.ts.map +1 -1
  389. package/dist/maps/styles.js +120 -6
  390. package/dist/maps/styles.js.map +1 -1
  391. package/dist/maps/theme.d.ts +19 -0
  392. package/dist/maps/theme.d.ts.map +1 -0
  393. package/dist/maps/theme.js +44 -0
  394. package/dist/maps/theme.js.map +1 -0
  395. package/dist/maps/tiles.d.ts +147 -27
  396. package/dist/maps/tiles.d.ts.map +1 -1
  397. package/dist/maps/tiles.js +221 -54
  398. package/dist/maps/tiles.js.map +1 -1
  399. package/dist/maps/types.d.ts +213 -21
  400. package/dist/maps/types.d.ts.map +1 -1
  401. package/dist/markdown/expressions.d.ts +1 -1
  402. package/dist/markdown/expressions.d.ts.map +1 -1
  403. package/dist/markdown/expressions.js.map +1 -1
  404. package/dist/markdown/index.d.ts +7 -6
  405. package/dist/markdown/index.d.ts.map +1 -1
  406. package/dist/markdown/index.js +121 -50
  407. package/dist/markdown/index.js.map +1 -1
  408. package/dist/markdown/spans.d.ts +1 -1
  409. package/dist/markdown/spans.d.ts.map +1 -1
  410. package/dist/markdown/spans.js +6 -0
  411. package/dist/markdown/spans.js.map +1 -1
  412. package/dist/media-player/index.d.ts +11 -3
  413. package/dist/media-player/index.d.ts.map +1 -1
  414. package/dist/media-player/index.js +13 -2
  415. package/dist/media-player/index.js.map +1 -1
  416. package/dist/qml/containers.d.ts.map +1 -1
  417. package/dist/qml/containers.js +6 -1
  418. package/dist/qml/containers.js.map +1 -1
  419. package/dist/qml/interaction.d.ts.map +1 -1
  420. package/dist/qml/interaction.js +38 -5
  421. package/dist/qml/interaction.js.map +1 -1
  422. package/dist/qml/layouts.d.ts.map +1 -1
  423. package/dist/qml/layouts.js +21 -6
  424. package/dist/qml/layouts.js.map +1 -1
  425. package/dist/qml/qtquick.d.ts.map +1 -1
  426. package/dist/qml/qtquick.js +9 -2
  427. package/dist/qml/qtquick.js.map +1 -1
  428. package/dist/qml/react.d.ts.map +1 -1
  429. package/dist/qml/react.js +9 -7
  430. package/dist/qml/react.js.map +1 -1
  431. package/dist/reorder/clock.d.ts +7 -0
  432. package/dist/reorder/clock.d.ts.map +1 -0
  433. package/dist/reorder/clock.js +26 -0
  434. package/dist/reorder/clock.js.map +1 -0
  435. package/dist/reorder/index.d.ts +25 -3
  436. package/dist/reorder/index.d.ts.map +1 -1
  437. package/dist/reorder/index.js +64 -19
  438. package/dist/reorder/index.js.map +1 -1
  439. package/dist/rich-text-editor/clipboard.d.ts +23 -0
  440. package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
  441. package/dist/rich-text-editor/clipboard.js +307 -0
  442. package/dist/rich-text-editor/clipboard.js.map +1 -0
  443. package/dist/rich-text-editor/collab.d.ts +32 -0
  444. package/dist/rich-text-editor/collab.d.ts.map +1 -0
  445. package/dist/rich-text-editor/collab.js +55 -0
  446. package/dist/rich-text-editor/collab.js.map +1 -0
  447. package/dist/rich-text-editor/commands.d.ts +50 -0
  448. package/dist/rich-text-editor/commands.d.ts.map +1 -0
  449. package/dist/rich-text-editor/commands.js +376 -0
  450. package/dist/rich-text-editor/commands.js.map +1 -0
  451. package/dist/rich-text-editor/drag.d.ts +68 -0
  452. package/dist/rich-text-editor/drag.d.ts.map +1 -0
  453. package/dist/rich-text-editor/drag.js +148 -0
  454. package/dist/rich-text-editor/drag.js.map +1 -0
  455. package/dist/rich-text-editor/html.d.ts +145 -0
  456. package/dist/rich-text-editor/html.d.ts.map +1 -0
  457. package/dist/rich-text-editor/html.js +516 -0
  458. package/dist/rich-text-editor/html.js.map +1 -0
  459. package/dist/rich-text-editor/index.d.ts +252 -0
  460. package/dist/rich-text-editor/index.d.ts.map +1 -0
  461. package/dist/rich-text-editor/index.js +856 -0
  462. package/dist/rich-text-editor/index.js.map +1 -0
  463. package/dist/rich-text-editor/inline.d.ts +94 -0
  464. package/dist/rich-text-editor/inline.d.ts.map +1 -0
  465. package/dist/rich-text-editor/inline.js +252 -0
  466. package/dist/rich-text-editor/inline.js.map +1 -0
  467. package/dist/rich-text-editor/keymap.d.ts +71 -0
  468. package/dist/rich-text-editor/keymap.d.ts.map +1 -0
  469. package/dist/rich-text-editor/keymap.js +394 -0
  470. package/dist/rich-text-editor/keymap.js.map +1 -0
  471. package/dist/rich-text-editor/keys.d.ts +40 -0
  472. package/dist/rich-text-editor/keys.d.ts.map +1 -0
  473. package/dist/rich-text-editor/keys.js +202 -0
  474. package/dist/rich-text-editor/keys.js.map +1 -0
  475. package/dist/rich-text-editor/look.d.ts +71 -0
  476. package/dist/rich-text-editor/look.d.ts.map +1 -0
  477. package/dist/rich-text-editor/look.js +342 -0
  478. package/dist/rich-text-editor/look.js.map +1 -0
  479. package/dist/rich-text-editor/markdown.d.ts +18 -0
  480. package/dist/rich-text-editor/markdown.d.ts.map +1 -0
  481. package/dist/rich-text-editor/markdown.js +496 -0
  482. package/dist/rich-text-editor/markdown.js.map +1 -0
  483. package/dist/rich-text-editor/marks.d.ts +9 -0
  484. package/dist/rich-text-editor/marks.d.ts.map +1 -0
  485. package/dist/rich-text-editor/marks.js +83 -0
  486. package/dist/rich-text-editor/marks.js.map +1 -0
  487. package/dist/rich-text-editor/nodes.d.ts +135 -0
  488. package/dist/rich-text-editor/nodes.d.ts.map +1 -0
  489. package/dist/rich-text-editor/nodes.js +397 -0
  490. package/dist/rich-text-editor/nodes.js.map +1 -0
  491. package/dist/rich-text-editor/render.d.ts +68 -0
  492. package/dist/rich-text-editor/render.d.ts.map +1 -0
  493. package/dist/rich-text-editor/render.js +518 -0
  494. package/dist/rich-text-editor/render.js.map +1 -0
  495. package/dist/rich-text-editor/schema.d.ts +16 -0
  496. package/dist/rich-text-editor/schema.d.ts.map +1 -0
  497. package/dist/rich-text-editor/schema.js +386 -0
  498. package/dist/rich-text-editor/schema.js.map +1 -0
  499. package/dist/rich-text-editor/store.d.ts +11 -0
  500. package/dist/rich-text-editor/store.d.ts.map +1 -0
  501. package/dist/rich-text-editor/store.js +43 -0
  502. package/dist/rich-text-editor/store.js.map +1 -0
  503. package/dist/rich-text-editor/suggest.d.ts +127 -0
  504. package/dist/rich-text-editor/suggest.d.ts.map +1 -0
  505. package/dist/rich-text-editor/suggest.js +0 -0
  506. package/dist/rich-text-editor/suggest.js.map +1 -0
  507. package/dist/rich-text-editor/tables.d.ts +41 -0
  508. package/dist/rich-text-editor/tables.d.ts.map +1 -0
  509. package/dist/rich-text-editor/tables.js +204 -0
  510. package/dist/rich-text-editor/tables.js.map +1 -0
  511. package/dist/rich-text-editor/toolbar.d.ts +58 -0
  512. package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
  513. package/dist/rich-text-editor/toolbar.js +548 -0
  514. package/dist/rich-text-editor/toolbar.js.map +1 -0
  515. package/dist/rich-text-editor/view.d.ts +368 -0
  516. package/dist/rich-text-editor/view.d.ts.map +1 -0
  517. package/dist/rich-text-editor/view.js +1968 -0
  518. package/dist/rich-text-editor/view.js.map +1 -0
  519. package/dist/rich-text-editor/virtual.d.ts +54 -0
  520. package/dist/rich-text-editor/virtual.d.ts.map +1 -0
  521. package/dist/rich-text-editor/virtual.js +279 -0
  522. package/dist/rich-text-editor/virtual.js.map +1 -0
  523. package/dist/richtext/node.d.ts +71 -4
  524. package/dist/richtext/node.d.ts.map +1 -1
  525. package/dist/richtext/node.js +233 -28
  526. package/dist/richtext/node.js.map +1 -1
  527. package/dist/richtext/runs.d.ts +13 -8
  528. package/dist/richtext/runs.d.ts.map +1 -1
  529. package/dist/richtext/runs.js +18 -8
  530. package/dist/richtext/runs.js.map +1 -1
  531. package/dist/table/index.d.ts.map +1 -1
  532. package/dist/table/index.js +23 -0
  533. package/dist/table/index.js.map +1 -1
  534. package/dist/table/rows.d.ts +3 -2
  535. package/dist/table/rows.d.ts.map +1 -1
  536. package/dist/table/rows.js +20 -6
  537. package/dist/table/rows.js.map +1 -1
  538. package/dist/terminal/backends.d.ts +4 -1
  539. package/dist/terminal/backends.d.ts.map +1 -1
  540. package/dist/terminal/backends.js.map +1 -1
  541. package/dist/terminal/index.d.ts +18 -7
  542. package/dist/terminal/index.d.ts.map +1 -1
  543. package/dist/terminal/index.js +32 -11
  544. package/dist/terminal/index.js.map +1 -1
  545. package/dist/terminal/vt/pty.d.ts +13 -2
  546. package/dist/terminal/vt/pty.d.ts.map +1 -1
  547. package/dist/terminal/vt/pty.js +18 -3
  548. package/dist/terminal/vt/pty.js.map +1 -1
  549. package/dist/terminal-output/index.d.ts.map +1 -1
  550. package/dist/terminal-output/index.js +6 -1
  551. package/dist/terminal-output/index.js.map +1 -1
  552. package/dist/three/canvas.d.ts.map +1 -1
  553. package/dist/three/canvas.js +85 -7
  554. package/dist/three/canvas.js.map +1 -1
  555. package/dist/three/events.d.ts +22 -4
  556. package/dist/three/events.d.ts.map +1 -1
  557. package/dist/three/events.js +34 -4
  558. package/dist/three/events.js.map +1 -1
  559. package/dist/tree/index.d.ts.map +1 -1
  560. package/dist/tree/index.js +17 -0
  561. package/dist/tree/index.js.map +1 -1
  562. package/package.json +59 -31
  563. package/src/charts/node.ts +68 -28
  564. package/src/charts/render.ts +120 -30
  565. package/src/code/index.ts +3 -1
  566. package/src/code-editor/completion.ts +3 -2
  567. package/src/code-editor/index.ts +19 -0
  568. package/src/code-editor/node.ts +1574 -184
  569. package/src/code-language/languages/glsl.ts +12 -2
  570. package/src/code-language/languages/javascript.ts +21 -4
  571. package/src/code-language/languages/json.ts +12 -2
  572. package/src/code-language/languages/shell.ts +12 -2
  573. package/src/code-language/languages/sql.ts +22 -2
  574. package/src/code-language/stream.ts +257 -17
  575. package/src/code-language/types.ts +5 -4
  576. package/src/codeblock/index.ts +20 -3
  577. package/src/embed/client.ts +102 -8
  578. package/src/embed/index.ts +2 -0
  579. package/src/flow/draw.ts +167 -41
  580. package/src/flow/gl/color.ts +85 -0
  581. package/src/flow/gl/index.ts +342 -0
  582. package/src/flow/gl/pack.ts +585 -0
  583. package/src/flow/gl/renderer.ts +679 -0
  584. package/src/flow/gl/shaders.ts +371 -0
  585. package/src/flow/gl/text.ts +1295 -0
  586. package/src/flow/index.ts +794 -67
  587. package/src/flow/node.ts +2496 -1256
  588. package/src/flow/paint.ts +511 -0
  589. package/src/flow/paths.ts +80 -15
  590. package/src/flow/scene.ts +2199 -0
  591. package/src/flow/types.ts +113 -1
  592. package/src/html/controls.ts +73 -2
  593. package/src/html/css/calc.ts +385 -0
  594. package/src/html/css/cascade.ts +1403 -62
  595. package/src/html/css/color.ts +755 -0
  596. package/src/html/css/content.ts +417 -0
  597. package/src/html/css/counter-styles.ts +973 -0
  598. package/src/html/css/decode.ts +130 -0
  599. package/src/html/css/parse.ts +1514 -160
  600. package/src/html/css/style.ts +4102 -222
  601. package/src/html/css/ua.ts +58 -12
  602. package/src/html/css/values.ts +150 -50
  603. package/src/html/css/vars.ts +348 -0
  604. package/src/html/dom.ts +284 -17
  605. package/src/html/fonts.ts +641 -0
  606. package/src/html/gif.ts +233 -0
  607. package/src/html/index.ts +180 -20
  608. package/src/html/layout/block.ts +3456 -230
  609. package/src/html/layout/boxes.ts +2100 -190
  610. package/src/html/layout/cache.ts +289 -0
  611. package/src/html/layout/collapse.ts +317 -0
  612. package/src/html/layout/css-grid.ts +1063 -0
  613. package/src/html/layout/flex.ts +1115 -106
  614. package/src/html/layout/floats.ts +128 -14
  615. package/src/html/layout/grid-lines.ts +141 -0
  616. package/src/html/layout/grid.ts +181 -0
  617. package/src/html/layout/inline.ts +3943 -192
  618. package/src/html/layout/shaping.ts +140 -0
  619. package/src/html/layout/table.ts +696 -186
  620. package/src/html/layout/tracks.ts +437 -0
  621. package/src/html/node.ts +1486 -121
  622. package/src/html/paint.ts +4293 -169
  623. package/src/html/resources.ts +161 -50
  624. package/src/html/surfaces.ts +81 -0
  625. package/src/html/svg.ts +493 -0
  626. package/src/html/url.ts +86 -0
  627. package/src/index.ts +4 -0
  628. package/src/internal/collate.ts +12 -0
  629. package/src/{markdown → internal/markdown}/ast.ts +35 -7
  630. package/src/{markdown → internal/markdown}/parse.ts +288 -35
  631. package/src/internal/markdown/stringify.ts +772 -0
  632. package/src/internal/prewarm.ts +45 -0
  633. package/src/internal/scroll.ts +5 -3
  634. package/src/internal/sdf.ts +227 -0
  635. package/src/internal/splice.ts +25 -0
  636. package/src/internal/window.ts +36 -5
  637. package/src/maps/anchors.ts +913 -0
  638. package/src/maps/controller.ts +1084 -0
  639. package/src/maps/gl/buckets.ts +461 -0
  640. package/src/maps/gl/build-worker.ts +66 -0
  641. package/src/maps/gl/color.ts +62 -0
  642. package/src/maps/gl/cover.ts +205 -0
  643. package/src/maps/gl/index.ts +23 -0
  644. package/src/maps/gl/markers.ts +83 -0
  645. package/src/maps/gl/overlays.ts +379 -0
  646. package/src/maps/gl/pane.ts +42 -0
  647. package/src/maps/gl/placement.ts +968 -0
  648. package/src/maps/gl/renderer.ts +1660 -0
  649. package/src/maps/gl/shaders.ts +489 -0
  650. package/src/maps/gl/store.ts +615 -0
  651. package/src/maps/gl/text.ts +868 -0
  652. package/src/maps/gl/view.ts +1489 -0
  653. package/src/maps/icons.ts +183 -0
  654. package/src/maps/index.ts +274 -81
  655. package/src/maps/labels.ts +457 -144
  656. package/src/maps/node.ts +832 -665
  657. package/src/maps/overlay.ts +148 -43
  658. package/src/maps/paint.ts +3 -0
  659. package/src/maps/proj.ts +118 -0
  660. package/src/maps/renderer.ts +155 -0
  661. package/src/maps/sources.ts +43 -6
  662. package/src/maps/style.ts +32 -0
  663. package/src/maps/styles.ts +215 -4
  664. package/src/maps/theme.ts +51 -0
  665. package/src/maps/tiles.ts +253 -62
  666. package/src/maps/types.ts +213 -21
  667. package/src/markdown/expressions.ts +5 -1
  668. package/src/markdown/index.ts +163 -78
  669. package/src/markdown/spans.ts +6 -1
  670. package/src/media-player/index.ts +18 -4
  671. package/src/qml/containers.tsx +6 -1
  672. package/src/qml/interaction.tsx +42 -5
  673. package/src/qml/layouts.tsx +21 -6
  674. package/src/qml/qtquick.tsx +9 -2
  675. package/src/qml/react.tsx +7 -5
  676. package/src/reorder/clock.ts +27 -0
  677. package/src/reorder/index.ts +100 -27
  678. package/src/rich-text-editor/clipboard.ts +439 -0
  679. package/src/rich-text-editor/collab.ts +91 -0
  680. package/src/rich-text-editor/commands.ts +448 -0
  681. package/src/rich-text-editor/dom-globals.d.ts +23 -0
  682. package/src/rich-text-editor/drag.ts +211 -0
  683. package/src/rich-text-editor/html.ts +619 -0
  684. package/src/rich-text-editor/index.ts +1364 -0
  685. package/src/rich-text-editor/inline.ts +345 -0
  686. package/src/rich-text-editor/keymap.ts +510 -0
  687. package/src/rich-text-editor/keys.ts +228 -0
  688. package/src/rich-text-editor/look.ts +427 -0
  689. package/src/rich-text-editor/markdown.ts +653 -0
  690. package/src/rich-text-editor/marks.ts +101 -0
  691. package/src/rich-text-editor/nodes.ts +497 -0
  692. package/src/rich-text-editor/render.ts +837 -0
  693. package/src/rich-text-editor/schema.ts +431 -0
  694. package/src/rich-text-editor/store.ts +39 -0
  695. package/src/rich-text-editor/suggest.ts +597 -0
  696. package/src/rich-text-editor/tables.ts +272 -0
  697. package/src/rich-text-editor/toolbar.ts +724 -0
  698. package/src/rich-text-editor/view.ts +2287 -0
  699. package/src/rich-text-editor/virtual.ts +372 -0
  700. package/src/richtext/node.ts +294 -44
  701. package/src/richtext/runs.ts +23 -12
  702. package/src/table/index.ts +29 -0
  703. package/src/table/rows.ts +18 -8
  704. package/src/terminal/backends.ts +4 -1
  705. package/src/terminal/index.ts +47 -15
  706. package/src/terminal/vt/pty.ts +16 -2
  707. package/src/terminal-output/index.ts +6 -1
  708. package/src/three/canvas.ts +102 -8
  709. package/src/three/events.ts +49 -9
  710. package/src/tree/index.ts +19 -0
  711. package/dist/markdown/ast.d.ts.map +0 -1
  712. package/dist/markdown/ast.js +0 -17
  713. package/dist/markdown/ast.js.map +0 -1
  714. package/dist/markdown/parse.d.ts.map +0 -1
  715. package/dist/markdown/parse.js.map +0 -1
  716. package/dist/markdown/tags.d.ts.map +0 -1
  717. package/dist/markdown/tags.js.map +0 -1
  718. /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
  719. /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
  720. /package/dist/{markdown → internal/markdown}/tags.js +0 -0
  721. /package/src/{markdown → internal/markdown}/tags.ts +0 -0
@@ -0,0 +1,868 @@
1
+ // Labels, the text half: strings set by the platform's own text engine,
2
+ // read back as coverage, and packed into one GL texture.
3
+ //
4
+ // A `<glarea>` is stacked over every 2D thing in its window, so a label on a
5
+ // GL map has to be *in* the GL frame — there is no drawing text over it
6
+ // afterwards. The glyphs come from where every other string in the app
7
+ // comes from: `app.fonts.layout()` shapes it (CoreText on the Cocoa
8
+ // backend, ntk's own shaper on X11, font fallback and all), and the layout
9
+ // draws into an offscreen {@link Surface} whose pixels are read back. That
10
+ // is one readback per *batch* of labels, not per label, and each label is
11
+ // set once and drawn every frame after.
12
+ //
13
+ // A label is rasterized **whole**, not glyph by glyph: placement sets every
14
+ // line label on a straight stretch, so a label is one rigid piece of type —
15
+ // one textured quad, rotated as a unit — and shaping, kerning and scripts
16
+ // stay the text engine's business.
17
+ //
18
+ // **One raster per string, at every size.** The engine sets a string once,
19
+ // at the atlas's `base` size, as coverage; what is stored is its signed
20
+ // distance field (`src/internal/sdf.ts`), one byte a texel. A name drawn at 11 pixels
21
+ // and the same name at 20 are one raster scaled, so a zoom ramp that grows
22
+ // the type asks for nothing new, and a halo of any width is a threshold on
23
+ // the same distances. Colour and halo are the shader's (see `./shaders.ts`),
24
+ // so one raster serves every palette and a light-to-dark switch
25
+ // re-rasterizes nothing. What it costs is the engine's hinting — the text
26
+ // is its outline, scaled — which at map-label sizes is the right trade:
27
+ // one shaping and one readback per name for the life of the atlas.
28
+ //
29
+ // An icon's two pieces (`../icons.ts`) are fields here too, drawn as
30
+ // coverage from the same paths the retained renderer fills, at the same
31
+ // base size, and coloured by the same shader.
32
+ import { Surface } from 'react-x11/ntk';
33
+
34
+ import { traceGlyph, tracePlate } from '../icons.js';
35
+ import type { IconPathContext, MapIcon } from '../icons.js';
36
+ import { SDF_EDGE, distanceField } from '../../internal/sdf.js';
37
+
38
+ /** A set string's box, in device pixels. */
39
+ export interface TextBox {
40
+ width: number;
41
+ height: number;
42
+ }
43
+
44
+ /** Which of an icon's two single-colour rasters. */
45
+ export type IconPart = 'plate' | 'glyph';
46
+
47
+ /** One string to set, at `size` device pixels — or, with `icon`, one piece
48
+ * of an icon `size` pixels across, and `text` empty. */
49
+ export interface TextItem {
50
+ text: string;
51
+ size: number;
52
+ icon?: { name: MapIcon; part: IconPart };
53
+ }
54
+
55
+ /** A rasterized string, `pad` pixels of clear margin included: RGBA as
56
+ * read back, coverage in alpha — or, with `stride` 1, the text engine's own
57
+ * coverage, one byte a pixel. */
58
+ export interface TextRaster {
59
+ width: number;
60
+ height: number;
61
+ pixels: Uint8Array;
62
+ /** Bytes a pixel: 4 (the default) for a readback, 1 for coverage. */
63
+ stride?: 1 | 4;
64
+ }
65
+
66
+ /** What the atlas asks of a text engine. */
67
+ export interface TextEngine {
68
+ /** The box `text` sets in, synchronously — placement needs it now. */
69
+ measure(text: string, size: number): TextBox;
70
+ /**
71
+ * Rasterize as many of `items` as fit one batch. Answers per item: a
72
+ * raster; `null` for one that can never be drawn (wider than the engine
73
+ * can set); `undefined` for one left for the next batch.
74
+ */
75
+ rasterize(
76
+ items: readonly TextItem[],
77
+ pad: number,
78
+ ): Promise<(TextRaster | null | undefined)[]>;
79
+ /**
80
+ * One item set now, synchronously, where the engine can: a raster;
81
+ * `null` for one that can never be drawn; `undefined` for one it can only
82
+ * set through {@link rasterize} (an icon's paths, or an engine whose
83
+ * layouts answer no coverage of their own). Optional.
84
+ */
85
+ rasterizeNow?(item: TextItem, pad: number): TextRaster | null | undefined;
86
+ dispose(): void;
87
+ }
88
+
89
+ /** ntk's font cache, structurally — `../labels.ts`' `FontsLike`. */
90
+ interface FontsLike {
91
+ layout(
92
+ content: string,
93
+ style: Record<string, unknown>,
94
+ ): {
95
+ width: number;
96
+ height: number;
97
+ draw(ctx: unknown, x: number, y: number): void;
98
+ /** The engine's own coverage of the layout, one byte a pixel, with
99
+ * `pad` round its box — where the engine answers it
100
+ * (sidorares/react-x11#673). */
101
+ coverage?(options?: {
102
+ pad?: number;
103
+ }): { width: number; height: number; data: Uint8Array } | null;
104
+ };
105
+ }
106
+
107
+ interface ImageLike {
108
+ data: Uint8ClampedArray;
109
+ width: number;
110
+ height: number;
111
+ }
112
+
113
+ interface ContextLike extends Partial<IconPathContext> {
114
+ getImageData(x: number, y: number, w: number, h: number): Promise<ImageLike>;
115
+ destroy?(): void;
116
+ fillStyle?: unknown;
117
+ fill?(): void;
118
+ }
119
+
120
+ /** Whether a context can fill a path — what an icon is drawn with. */
121
+ function fills(
122
+ ctx: ContextLike,
123
+ ): ctx is ContextLike & IconPathContext & { fill(): void } {
124
+ return (
125
+ typeof ctx.beginPath === 'function' &&
126
+ typeof ctx.arc === 'function' &&
127
+ typeof ctx.fill === 'function'
128
+ );
129
+ }
130
+
131
+ interface SurfaceLike {
132
+ getContext(name: '2d'): ContextLike;
133
+ clear(): void;
134
+ destroy(): void;
135
+ }
136
+
137
+ /** The offscreen surface a batch is set on, in device pixels. A readback
138
+ * has to stay inside it — X answers a GetImage past a pixmap's edge with
139
+ * BadMatch — so a batch is whatever fits. */
140
+ const STAGING_WIDTH = 1024;
141
+ const STAGING_HEIGHT = 512;
142
+ /** Milliseconds of drawing one batch may take. A batch runs between two
143
+ * frames, and at 75 Hz the gap between them is a few milliseconds. */
144
+ const DRAW_BUDGET_MS = 1.5;
145
+
146
+ /** The text engine over an app's fonts and an offscreen surface. */
147
+ export class SurfaceTextEngine implements TextEngine {
148
+ private readonly _app: unknown;
149
+ private readonly _fonts: FontsLike;
150
+ private readonly _family: string;
151
+ private readonly _layouts = new Map<
152
+ string,
153
+ ReturnType<FontsLike['layout']>
154
+ >();
155
+ private _surface: SurfaceLike | null = null;
156
+ private _ctx: ContextLike | null = null;
157
+ /** Whether the layouts answer their own coverage: unknown until a string
158
+ * asks, and false for good once one does not. */
159
+ private _coverage: boolean | null = null;
160
+
161
+ constructor(app: unknown, fonts: FontsLike, family: string) {
162
+ this._app = app;
163
+ this._fonts = fonts;
164
+ this._family = family;
165
+ }
166
+
167
+ /** The engine for the app a node belongs to, or null where there is
168
+ * nothing to set text with. */
169
+ static forApp(app: unknown, family: string): SurfaceTextEngine | null {
170
+ const fonts = (app as { fonts?: FontsLike } | null | undefined)?.fonts;
171
+ if (!fonts || typeof fonts.layout !== 'function') return null;
172
+ return new SurfaceTextEngine(app, fonts, family);
173
+ }
174
+
175
+ private _layout(text: string, size: number): ReturnType<FontsLike['layout']> {
176
+ const key = `${size}|${text}`;
177
+ let layout = this._layouts.get(key);
178
+ if (!layout) {
179
+ // Bounded like the retained renderer's shaper: cleared wholesale, and
180
+ // what is on screen is set again once.
181
+ if (this._layouts.size > 8000) this._layouts.clear();
182
+ layout = this._fonts.layout(text, {
183
+ family: this._family,
184
+ size,
185
+ weight: 400,
186
+ style: 'normal',
187
+ color: '#ffffff',
188
+ });
189
+ this._layouts.set(key, layout);
190
+ }
191
+ return layout;
192
+ }
193
+
194
+ measure(text: string, size: number): TextBox {
195
+ const layout = this._layout(text, size);
196
+ return { width: Math.ceil(layout.width), height: Math.ceil(layout.height) };
197
+ }
198
+
199
+ /**
200
+ * Strings the layouts set themselves, where the engine answers a layout's
201
+ * coverage (react-x11#673): no staging surface and no readback. The rest —
202
+ * icons, which are paths, and every string on an engine that cannot — go
203
+ * through the surface.
204
+ */
205
+ /**
206
+ * A string the layout sets itself, synchronously, where the engine
207
+ * answers a layout's coverage — no surface, no readback, nothing to wait
208
+ * for. `undefined` for an icon, and for every string once the engine has
209
+ * shown it cannot.
210
+ */
211
+ rasterizeNow(item: TextItem, pad: number): TextRaster | null | undefined {
212
+ if (item.icon || this._coverage === false) return undefined;
213
+ const coverage =
214
+ this._layout(item.text, item.size).coverage?.({ pad }) ?? null;
215
+ if (!coverage) {
216
+ if (this._coverage === null) this._coverage = false;
217
+ return undefined;
218
+ }
219
+ this._coverage = true;
220
+ return coverage.width > STAGING_WIDTH || coverage.height > STAGING_HEIGHT
221
+ ? null // wider than the surface could set: never drawn, as there
222
+ : {
223
+ width: coverage.width,
224
+ height: coverage.height,
225
+ pixels: coverage.data,
226
+ stride: 1,
227
+ };
228
+ }
229
+
230
+ async rasterize(
231
+ items: readonly TextItem[],
232
+ pad: number,
233
+ ): Promise<(TextRaster | null | undefined)[]> {
234
+ if (this._coverage === false) return this._stage(items, pad);
235
+ const out: (TextRaster | null | undefined)[] = new Array(items.length);
236
+ const rest: number[] = [];
237
+ items.forEach((item, i) => {
238
+ const raster = this.rasterizeNow(item, pad);
239
+ if (raster === undefined) {
240
+ rest.push(i);
241
+ return;
242
+ }
243
+ out[i] = raster;
244
+ });
245
+ if (rest.length === 0) return out;
246
+ const staged = await this._stage(
247
+ rest.map((i) => items[i]),
248
+ pad,
249
+ );
250
+ rest.forEach((i, k) => (out[i] = staged[k]));
251
+ return out;
252
+ }
253
+
254
+ private async _stage(
255
+ items: readonly TextItem[],
256
+ pad: number,
257
+ ): Promise<(TextRaster | null | undefined)[]> {
258
+ const places: (
259
+ { x: number; y: number; w: number; h: number } | null | undefined
260
+ )[] = [];
261
+ let x = 0;
262
+ let y = 0;
263
+ let row = 0;
264
+ for (const item of items) {
265
+ const box = item.icon
266
+ ? { width: Math.ceil(item.size), height: Math.ceil(item.size) }
267
+ : this.measure(item.text, item.size);
268
+ const w = box.width + pad * 2;
269
+ const h = box.height + pad * 2;
270
+ if (w > STAGING_WIDTH || h > STAGING_HEIGHT) {
271
+ places.push(null);
272
+ continue;
273
+ }
274
+ if (x + w > STAGING_WIDTH) {
275
+ x = 0;
276
+ y += row;
277
+ row = 0;
278
+ }
279
+ if (y + h > STAGING_HEIGHT) {
280
+ places.push(undefined);
281
+ continue;
282
+ }
283
+ places.push({ x, y, w, h });
284
+ x += w;
285
+ row = Math.max(row, h);
286
+ }
287
+ if (!places.some((p) => p)) {
288
+ return places.map((p) => (p === null ? null : undefined));
289
+ }
290
+
291
+ if (!this._surface) {
292
+ this._surface = new Surface(this._app as never, {
293
+ width: STAGING_WIDTH,
294
+ height: STAGING_HEIGHT,
295
+ }) as unknown as SurfaceLike;
296
+ this._ctx = this._surface.getContext('2d');
297
+ }
298
+ const surface = this._surface;
299
+ const ctx = this._ctx!;
300
+ surface.clear();
301
+ const started = now();
302
+ // The rows drawn into: what is read back, and no more.
303
+ let used = 0;
304
+ let drawn = 0;
305
+ items.forEach((item, i) => {
306
+ const place = places[i];
307
+ if (!place) return;
308
+ // Drawing is this thread's time; past the budget the rest wait for
309
+ // the next batch — all but the first. A pause before it, a collection
310
+ // or a slow runner, deferred every string: nothing drawn, a readback of
311
+ // no rows, and a throw out of the frame; and a machine that slow would
312
+ // never have set one.
313
+ if (drawn > 0 && now() - started > DRAW_BUDGET_MS) {
314
+ places[i] = undefined;
315
+ return;
316
+ }
317
+ if (item.icon) {
318
+ // White, like the strings: coverage, coloured by the shader.
319
+ if (!fills(ctx)) {
320
+ places[i] = null;
321
+ return;
322
+ }
323
+ const half = item.size / 2;
324
+ const cx = place.x + pad + half;
325
+ const cy = place.y + pad + half;
326
+ ctx.fillStyle = '#ffffff';
327
+ ctx.beginPath();
328
+ if (item.icon.part === 'plate') tracePlate(ctx, cx, cy, item.size);
329
+ else traceGlyph(ctx, item.icon.name, cx, cy, item.size);
330
+ ctx.fill();
331
+ } else {
332
+ this._layout(item.text, item.size).draw(
333
+ ctx,
334
+ place.x + pad,
335
+ place.y + pad,
336
+ );
337
+ }
338
+ used = Math.max(used, place.y + place.h);
339
+ drawn += 1;
340
+ });
341
+ // nothing drawn — every icon here had nothing to fill with — is nothing
342
+ // to read back
343
+ if (drawn === 0) {
344
+ return places.map((p) => (p === null ? null : undefined));
345
+ }
346
+ const image = await ctx.getImageData(0, 0, STAGING_WIDTH, used);
347
+ return places.map((place) => {
348
+ if (!place) return place;
349
+ // Row by row, as the readback has them: a copy, not a pass over the
350
+ // pixels, and uploaded as it is — the shader reads alpha alone.
351
+ const rowBytes = place.w * 4;
352
+ const pixels = new Uint8Array(rowBytes * place.h);
353
+ for (let r = 0; r < place.h; r++) {
354
+ const src = ((place.y + r) * image.width + place.x) * 4;
355
+ pixels.set(image.data.subarray(src, src + rowBytes), r * rowBytes);
356
+ }
357
+ return { width: place.w, height: place.h, pixels };
358
+ });
359
+ }
360
+
361
+ dispose(): void {
362
+ this._ctx?.destroy?.();
363
+ this._ctx = null;
364
+ this._surface?.destroy();
365
+ this._surface = null;
366
+ this._layouts.clear();
367
+ }
368
+ }
369
+
370
+ /** A rasterized label's place in the atlas: its whole padded raster. */
371
+ export interface AtlasEntry {
372
+ key: string;
373
+ x: number;
374
+ y: number;
375
+ width: number;
376
+ height: number;
377
+ /** The distance field, one byte a texel — kept to upload again, after a
378
+ * compaction moves it or into the texture of a new context. */
379
+ pixels: Uint8Array;
380
+ /** In the texture where it is now; only then is it drawn. Set by the
381
+ * renderer that uploads it. */
382
+ ready: boolean;
383
+ /** The frame it was last asked for — what a compaction keeps. */
384
+ used: number;
385
+ }
386
+
387
+ /** A string's key: the text alone, because one field serves every size. */
388
+ const keyOf = (text: string): string => `|${text}`;
389
+ /** An icon piece's key: `#` where a string's has `|`, so no string can
390
+ * be taken for one. */
391
+ const iconKey = (name: MapIcon, part: IconPart): string => `#${part}:${name}`;
392
+
393
+ /**
394
+ * Texels the drawn quad leaves off each side of a field: bilinear samples
395
+ * at its edge then stay inside the field's own margin, never reaching the
396
+ * shelf's unwritten rows or a neighbour.
397
+ */
398
+ export const QUAD_INSET = 1;
399
+
400
+ /**
401
+ * How far past the glyphs' edge a field can see, in its own texels — the
402
+ * widest halo it holds, and the reach of its distances before they
403
+ * saturate — for a field set with `pad` texels of margin and `pad` of
404
+ * spread. Scale by the drawn size over the base for screen pixels.
405
+ */
406
+ export const fieldReach = (pad: number): number =>
407
+ Math.max(0, Math.min(pad * SDF_EDGE, pad - QUAD_INSET) - 0.5);
408
+
409
+ /** The base size a display scale sets fields at, in device pixels: 16 at
410
+ * 1x, 32 at 2x — the size most map labels are drawn at or just under, so
411
+ * a field is mostly sampled down, where it is sharpest. */
412
+ export const fieldBase = (scale: number): number =>
413
+ Math.round(16 * Math.min(2, Math.max(1, scale)));
414
+
415
+ /** A field's margin and spread at a base size: room for a halo of a
416
+ * quarter of the type's height. */
417
+ export const fieldPad = (base: number): number => Math.ceil(base * 0.375);
418
+
419
+ /** Strings a frame measures however little budget it has left, so a frame
420
+ * that starts late still makes progress. One: on X11 a string's first
421
+ * measurement can cost milliseconds, and a floor of several put a pan
422
+ * frame 27 ms over. */
423
+ const MIN_MEASURES = 1;
424
+ /** Strings per rasterization batch at most — a few rows of the staging
425
+ * surface, so the readback and the copies out of it stay small too. */
426
+ const BATCH = 32;
427
+ /** Frames an unused entry survives a compaction for. */
428
+ const KEEP_FRAMES = 120;
429
+
430
+ /**
431
+ * Every label raster, packed into one texture's worth of shelves, with the
432
+ * uploads the renderer owes it.
433
+ *
434
+ * The atlas is CPU-side and outlives any one GL context: it keeps each
435
+ * entry's raster, so a renderer that is new — the surface was recreated —
436
+ * uploads it again from here ({@link restart}), and asks nothing of the text
437
+ * engine. What it holds is bounded by the texture it packs into: 16 MB for
438
+ * the default 2048², whatever is panned past.
439
+ *
440
+ * **Measuring is budgeted, drawing is asynchronous, uploading is metered.**
441
+ * Placement needs a label's box the frame it is considered, which is a
442
+ * synchronous shaping call — tens of microseconds on the Cocoa backend, but
443
+ * milliseconds each the first time on X11, where fonts load and glyphs
444
+ * rasterize in JS — so a frame measures until its deadline and leaves the
445
+ * rest for the next. A raster is asked for only once a label has won a
446
+ * place, and arrives a batch at a time, a readback later; the renderer
447
+ * takes a few dozen a frame into the texture, and a label fades in once its
448
+ * raster is there.
449
+ */
450
+ export class LabelAtlas {
451
+ readonly size: number;
452
+ /** The device-pixel size every string and icon is set at: a label drawn
453
+ * at `size` scales its field by `size / base`. */
454
+ readonly base: number;
455
+ /** The margin set around every field, in its texels, which is also the
456
+ * distance its values span — what a halo grows into. */
457
+ readonly pad: number;
458
+ /** A frame's measuring ran out of budget: there is more to place. */
459
+ starved = false;
460
+ onChange: (() => void) | null = null;
461
+ private _engine: TextEngine | null;
462
+ private readonly _entries = new Map<string, AtlasEntry>();
463
+ /** Entries the texture does not have where they are, oldest first. */
464
+ private _uploads: AtlasEntry[] = [];
465
+ /** Drawable entries a compaction moved: all of them go up in the next
466
+ * frame, ahead of any cap, before it draws. */
467
+ private _moved: AtlasEntry[] = [];
468
+ private readonly _wanted = new Map<string, TextItem>();
469
+ private readonly _failed = new Set<string>();
470
+ /** Rasters read back and waiting for their fields, oldest first — asked
471
+ * for as much as anything in `_wanted`, so a frame never asks again. */
472
+ private _fieldQueue: { key: string; raster: TextRaster }[] = [];
473
+ private readonly _queued = new Set<string>();
474
+ private readonly _measured = new Map<string, TextBox>();
475
+ private _busy = false;
476
+ private _shelves: { y: number; height: number; x: number }[] = [];
477
+ private _top = 0;
478
+ private _frame = 0;
479
+ private _deadline = Infinity;
480
+ private _measures = 0;
481
+
482
+ constructor(
483
+ engine: TextEngine | null,
484
+ options: { size?: number; base?: number; pad?: number } = {},
485
+ ) {
486
+ this._engine = engine;
487
+ this.size = options.size ?? 2048;
488
+ this.base = options.base ?? fieldBase(1);
489
+ this.pad = options.pad ?? fieldPad(this.base);
490
+ }
491
+
492
+ /** Strings asked for and not yet set: waiting, being read back, or
493
+ * waiting for their fields. */
494
+ get pending(): boolean {
495
+ return this._busy || this._wanted.size > 0 || this._fieldQueue.length > 0;
496
+ }
497
+
498
+ /** Rasters waiting for the texture. */
499
+ get uploading(): boolean {
500
+ return this._uploads.length > 0;
501
+ }
502
+
503
+ get entries(): number {
504
+ return this._entries.size;
505
+ }
506
+
507
+ /** A new frame, whose measuring stops at `deadline` (after one). */
508
+ beginFrame(deadline: number): void {
509
+ this._frame++;
510
+ this._deadline = deadline;
511
+ this._measures = 0;
512
+ this.starved = false;
513
+ }
514
+
515
+ /** The box a string sets in at `size`, or null when this frame's budget
516
+ * is spent. Measured once, at the base size, and scaled — the same
517
+ * arithmetic that scales its field, so the box placement collides and
518
+ * the quad the frame draws are one size. */
519
+ measure(text: string, size: number): TextBox | null {
520
+ const key = keyOf(text);
521
+ let box = this._measured.get(key);
522
+ if (!box) {
523
+ const engine = this._engine;
524
+ if (!engine) return null;
525
+ if (this._measures >= MIN_MEASURES && now() > this._deadline) {
526
+ this.starved = true;
527
+ return null;
528
+ }
529
+ this._measures++;
530
+ box = engine.measure(text, this.base);
531
+ if (this._measured.size > 20000) this._measured.clear();
532
+ this._measured.set(key, box);
533
+ }
534
+ const k = size / this.base;
535
+ return { width: box.width * k, height: box.height * k };
536
+ }
537
+
538
+ /** The string's field, once the texture has it; null until then —
539
+ * asking is what gets it set. One field whatever size it is drawn at. */
540
+ entry(text: string): AtlasEntry | null {
541
+ return this._lookup(keyOf(text), text, null, 'plate');
542
+ }
543
+
544
+ /** One piece of an icon, as {@link entry} answers for a string. */
545
+ icon(name: MapIcon, part: IconPart): AtlasEntry | null {
546
+ return this._lookup(iconKey(name, part), '', name, part);
547
+ }
548
+
549
+ private _lookup(
550
+ key: string,
551
+ text: string,
552
+ icon: MapIcon | null,
553
+ part: IconPart,
554
+ ): AtlasEntry | null {
555
+ const entry = this._entries.get(key);
556
+ if (entry) {
557
+ entry.used = this._frame;
558
+ return entry.ready ? entry : null;
559
+ }
560
+ if (
561
+ !this._failed.has(key) &&
562
+ !this._wanted.has(key) &&
563
+ !this._queued.has(key)
564
+ ) {
565
+ const size = this.base;
566
+ this._wanted.set(
567
+ key,
568
+ icon ? { text, size, icon: { name: icon, part } } : { text, size },
569
+ );
570
+ }
571
+ return null;
572
+ }
573
+
574
+ /** Whether an icon can never be drawn — the engine has no path to fill
575
+ * it with. A name set beside it is then set alone. */
576
+ iconFailed(name: MapIcon): boolean {
577
+ return (
578
+ this._failed.has(iconKey(name, 'plate')) ||
579
+ this._failed.has(iconKey(name, 'glyph'))
580
+ );
581
+ }
582
+
583
+ /** Start rasterizing what has been asked for, unless a batch is out. */
584
+ pump(): void {
585
+ const engine = this._engine;
586
+ if (!engine || this._busy || this._wanted.size === 0) return;
587
+ const keys: string[] = [];
588
+ const batch: TextItem[] = [];
589
+ for (const [key, item] of this._wanted) {
590
+ keys.push(key);
591
+ batch.push(item);
592
+ if (batch.length >= BATCH) break;
593
+ }
594
+ this._busy = true;
595
+ engine.rasterize(batch, this.pad).then(
596
+ (rasters) => {
597
+ this._busy = false;
598
+ rasters.forEach((raster, i) => {
599
+ if (raster === undefined) return;
600
+ const key = keys[i];
601
+ this._wanted.delete(key);
602
+ // A string with no raster never will have one; a raster with no
603
+ // room is a fact about this moment, and the string is asked for
604
+ // again by the next frame that still shows it.
605
+ if (raster === null) {
606
+ this._failed.add(key);
607
+ } else {
608
+ this._fieldQueue.push({ key, raster });
609
+ this._queued.add(key);
610
+ }
611
+ });
612
+ // The staging surface is free again as soon as the pixels are
613
+ // copied out, so the next batch is read back while this one waits
614
+ // for its fields; and a frame is asked for, to make them.
615
+ this.pump();
616
+ this.onChange?.();
617
+ },
618
+ () => {
619
+ // A readback that fails once fails every time (no surface, a
620
+ // backend without one): stop asking, and draw no labels.
621
+ this._busy = false;
622
+ this._engine = null;
623
+ this._wanted.clear();
624
+ this.onChange?.();
625
+ },
626
+ );
627
+ }
628
+
629
+ /** Rasters for the texture: every one a compaction moved, then up to
630
+ * `max` new ones, oldest first. The renderer marks each `ready` once it
631
+ * is uploaded — a moved one already is, because the frame that takes it
632
+ * draws after taking it. */
633
+ takeUploads(max: number): AtlasEntry[] {
634
+ const moved = this._moved;
635
+ this._moved = [];
636
+ return moved.length > 0
637
+ ? moved.concat(this._uploads.splice(0, max))
638
+ : this._uploads.splice(0, max);
639
+ }
640
+
641
+ /** The texture is new, and has none of it: everything goes up again. */
642
+ restart(): void {
643
+ for (const entry of this._entries.values()) entry.ready = false;
644
+ this._uploads = [...this._entries.values()];
645
+ this._moved = [];
646
+ }
647
+
648
+ dispose(): void {
649
+ this._engine?.dispose();
650
+ this._engine = null;
651
+ this._fieldQueue = [];
652
+ this._queued.clear();
653
+ }
654
+
655
+ /** Read back and waiting for their fields: another frame is worth
656
+ * drawing, to make them. */
657
+ get fielding(): boolean {
658
+ return this._fieldQueue.length > 0;
659
+ }
660
+
661
+ /**
662
+ * Make fields for what has been read back until `deadline` — at least
663
+ * one — in the frame, whose own draw then takes them into the texture.
664
+ *
665
+ * A field is about 0.2 ms. A batch of them made as it landed was 4-9 ms
666
+ * beside the frames, measured as event-loop stalls on a jump to a view
667
+ * whose every name was new; slices on timers of their own each waited
668
+ * behind a frame, and names arrived late. In the frame, on a budget,
669
+ * they are made at a known cost and drawn the frame after.
670
+ */
671
+ /**
672
+ * Set what placement asked for, in the frame, until `deadline` (at least
673
+ * one): what was read back already, then every string the engine can set
674
+ * synchronously. What is set here is drawable in this frame — it goes
675
+ * into the texture ahead of any cap, before this frame draws (the
676
+ * `labelsWhileMoving` path, `view.ts`). Icons, and an engine with no
677
+ * synchronous path, still go through {@link pump}.
678
+ */
679
+ setNow(deadline: number): void {
680
+ const engine = this._engine;
681
+ if (!engine) return;
682
+ let made = 0;
683
+ while (this._fieldQueue.length > 0 && (made === 0 || now() < deadline)) {
684
+ const { key, raster } = this._fieldQueue.shift()!;
685
+ this._queued.delete(key);
686
+ this._add(key, raster.width, raster.height, this._field(raster), true);
687
+ made++;
688
+ }
689
+ if (!engine.rasterizeNow) return;
690
+ for (const [key, item] of this._wanted) {
691
+ if (made > 0 && now() >= deadline) {
692
+ this.starved = true;
693
+ break;
694
+ }
695
+ const raster = engine.rasterizeNow(item, this.pad);
696
+ if (raster === undefined) continue;
697
+ this._wanted.delete(key);
698
+ if (raster === null) {
699
+ this._failed.add(key);
700
+ continue;
701
+ }
702
+ this._add(key, raster.width, raster.height, this._field(raster), true);
703
+ made++;
704
+ }
705
+ }
706
+
707
+ makeFields(deadline: number): void {
708
+ if (!this._engine) return;
709
+ let made = 0;
710
+ while (this._fieldQueue.length > 0 && (made === 0 || now() < deadline)) {
711
+ const { key, raster } = this._fieldQueue.shift()!;
712
+ this._queued.delete(key);
713
+ this._add(key, raster.width, raster.height, this._field(raster));
714
+ made++;
715
+ }
716
+ }
717
+
718
+ /** A raster's coverage as its distance field. The coverage is the
719
+ * readback's alpha; the field spans `pad` texels either side of the
720
+ * edge, which is the margin the engine set it with. */
721
+ private _field(raster: TextRaster): Uint8Array {
722
+ const stride = raster.stride ?? 4;
723
+ return distanceField(
724
+ raster.pixels,
725
+ raster.width,
726
+ raster.height,
727
+ this.pad,
728
+ stride,
729
+ stride === 4 ? 3 : 0,
730
+ );
731
+ }
732
+
733
+ private _add(
734
+ key: string,
735
+ width: number,
736
+ height: number,
737
+ pixels: Uint8Array,
738
+ /** Drawable in this frame: uploaded ahead of any cap before it draws. */
739
+ immediate = false,
740
+ ): boolean {
741
+ let place =
742
+ this._allocate(width, height) ?? this._reuseShelf(width, height);
743
+ if (!place && this._compactable()) {
744
+ this._compact();
745
+ place = this._allocate(width, height);
746
+ }
747
+ if (!place) return false;
748
+ const entry: AtlasEntry = {
749
+ key,
750
+ x: place.x,
751
+ y: place.y,
752
+ width,
753
+ height,
754
+ pixels,
755
+ ready: immediate,
756
+ used: this._frame,
757
+ };
758
+ this._entries.set(key, entry);
759
+ if (immediate) this._moved.push(entry);
760
+ else this._uploads.push(entry);
761
+ return true;
762
+ }
763
+
764
+ /** A shelf packer: rows of one height class (rounded up to 8 pixels),
765
+ * filled left to right, a new row below the last when none has room. */
766
+ private _allocate(w: number, h: number): { x: number; y: number } | null {
767
+ if (w > this.size || h > this.size) return null;
768
+ const height = Math.ceil(h / 8) * 8;
769
+ for (const shelf of this._shelves) {
770
+ if (shelf.height === height && shelf.x + w <= this.size) {
771
+ const at = { x: shelf.x, y: shelf.y };
772
+ shelf.x += w;
773
+ return at;
774
+ }
775
+ }
776
+ if (this._top + height > this.size) return null;
777
+ const shelf = { y: this._top, height, x: w };
778
+ this._shelves.push(shelf);
779
+ this._top += height;
780
+ return { x: 0, y: shelf.y };
781
+ }
782
+
783
+ /**
784
+ * Room made in place: the shelf of this height whose rasters were drawn
785
+ * longest ago, emptied and filled again from its left.
786
+ *
787
+ * **Nothing that stays moves.** A compaction moves every raster it keeps,
788
+ * and a moved raster is not drawn until it is in the texture again — at
789
+ * {@link takeUploads}' pace, so every label on screen went out together
790
+ * and came back over the next few frames, at full opacity. A full atlas
791
+ * is the ordinary state of a session (a thousand strings at 1x, a quarter
792
+ * of that at 2x), so that was a flash of the whole label layer at the end
793
+ * of most settles. A shelf any label of the last two frames stands on is not
794
+ * taken: what is dropped is off screen, and asked for again if it
795
+ * returns.
796
+ */
797
+ private _reuseShelf(w: number, h: number): { x: number; y: number } | null {
798
+ if (w > this.size) return null;
799
+ const height = Math.ceil(h / 8) * 8;
800
+ const newest = new Map<number, number>();
801
+ for (const entry of this._entries.values()) {
802
+ const seen = newest.get(entry.y);
803
+ if (seen === undefined || entry.used > seen)
804
+ newest.set(entry.y, entry.used);
805
+ }
806
+ let shelf: { y: number; height: number; x: number } | null = null;
807
+ // Not a shelf any label of this frame or the last stands on: fields can
808
+ // be made before a frame's labels are batched (`setNow`), when a label
809
+ // still fading out has not been asked for yet.
810
+ let oldest = this._frame - 1;
811
+ for (const candidate of this._shelves) {
812
+ if (candidate.height !== height) continue;
813
+ const used = newest.get(candidate.y) ?? -Infinity;
814
+ if (used < oldest) {
815
+ oldest = used;
816
+ shelf = candidate;
817
+ }
818
+ }
819
+ if (!shelf) return null;
820
+ const y = shelf.y;
821
+ for (const [key, entry] of this._entries) {
822
+ if (entry.y === y) this._entries.delete(key);
823
+ }
824
+ this._uploads = this._uploads.filter((entry) => entry.y !== y);
825
+ this._moved = this._moved.filter((entry) => entry.y !== y);
826
+ shelf.x = w;
827
+ return { x: 0, y };
828
+ }
829
+
830
+ /** Whether a compaction would free anything: something kept past its
831
+ * last use. One that keeps everything only moves it — every label on
832
+ * screen out of the texture for the frames its upload takes, for no
833
+ * room at all. */
834
+ private _compactable(): boolean {
835
+ for (const entry of this._entries.values()) {
836
+ if (entry.used < this._frame - KEEP_FRAMES) return true;
837
+ }
838
+ return false;
839
+ }
840
+
841
+ /** Drop what has not been drawn for a while and pack the rest again,
842
+ * tallest first — the last resort, when no shelf of the height wanted
843
+ * can be taken in place. What was drawable stays drawable: it is
844
+ * uploaded where it now is, all of it, by the next frame before that
845
+ * frame draws ({@link takeUploads}); what was waiting still waits. */
846
+ private _compact(): void {
847
+ const keep = [...this._entries.values()]
848
+ .filter((e) => e.used >= this._frame - KEEP_FRAMES)
849
+ .sort((a, b) => b.height - a.height);
850
+ this._entries.clear();
851
+ this._shelves = [];
852
+ this._top = 0;
853
+ this._uploads = [];
854
+ this._moved = [];
855
+ for (const entry of keep) {
856
+ const place = this._allocate(entry.width, entry.height);
857
+ if (!place) continue;
858
+ entry.x = place.x;
859
+ entry.y = place.y;
860
+ this._entries.set(entry.key, entry);
861
+ if (entry.ready) this._moved.push(entry);
862
+ else this._uploads.push(entry);
863
+ }
864
+ }
865
+ }
866
+
867
+ const globals = globalThis as { performance?: { now(): number } };
868
+ const now = (): number => globals.performance?.now() ?? Date.now();