xbintsc 0.5.23 → 0.5.32

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 (481) hide show
  1. package/AGENTS.md +11 -2
  2. package/README.md +47 -16
  3. package/README.zh-CN.md +21 -2
  4. package/dist/scripts/support-matrix.d.ts +18 -0
  5. package/dist/scripts/support-matrix.js +141 -0
  6. package/dist/scripts/support-matrix.js.map +1 -0
  7. package/dist/src/ast/common.d.ts +2 -2
  8. package/dist/src/ast/declarations.d.ts +7 -1
  9. package/dist/src/ast/expressions.d.ts +5 -0
  10. package/dist/src/ast/kinds.d.ts +2 -0
  11. package/dist/src/ast/kinds.js +2 -0
  12. package/dist/src/ast/kinds.js.map +1 -1
  13. package/dist/src/binder/binder.d.ts +2 -1
  14. package/dist/src/binder/binder.js +2 -0
  15. package/dist/src/binder/binder.js.map +1 -1
  16. package/dist/src/binder/declarations.d.ts +9 -0
  17. package/dist/src/binder/declarations.js +64 -0
  18. package/dist/src/binder/declarations.js.map +1 -1
  19. package/dist/src/binder/references.js +99 -4
  20. package/dist/src/binder/references.js.map +1 -1
  21. package/dist/src/binder/types.d.ts +32 -0
  22. package/dist/src/binder/types.js.map +1 -1
  23. package/dist/src/canonical.d.ts +29 -0
  24. package/dist/src/canonical.js +35 -0
  25. package/dist/src/canonical.js.map +1 -0
  26. package/dist/src/checker/assignability.d.ts +13 -0
  27. package/dist/src/checker/assignability.js +146 -0
  28. package/dist/src/checker/assignability.js.map +1 -0
  29. package/dist/src/checker/calls.d.ts +13 -0
  30. package/dist/src/checker/calls.js +127 -0
  31. package/dist/src/checker/calls.js.map +1 -0
  32. package/dist/src/checker/checker.d.ts +26 -0
  33. package/dist/src/checker/checker.js +31 -0
  34. package/dist/src/checker/checker.js.map +1 -0
  35. package/dist/src/checker/declarations.d.ts +9 -0
  36. package/dist/src/checker/declarations.js +15 -0
  37. package/dist/src/checker/declarations.js.map +1 -0
  38. package/dist/src/checker/flow.d.ts +21 -0
  39. package/dist/src/checker/flow.js +241 -0
  40. package/dist/src/checker/flow.js.map +1 -0
  41. package/dist/src/checker/globals.d.ts +9 -0
  42. package/dist/src/checker/globals.js +29 -0
  43. package/dist/src/checker/globals.js.map +1 -0
  44. package/dist/src/checker/source.d.ts +38 -0
  45. package/dist/src/checker/source.js +48 -0
  46. package/dist/src/checker/source.js.map +1 -0
  47. package/dist/src/checker/type-infer.d.ts +18 -0
  48. package/dist/src/checker/type-infer.js +173 -0
  49. package/dist/src/checker/type-infer.js.map +1 -0
  50. package/dist/src/checker/type-model.d.ts +73 -0
  51. package/dist/src/checker/type-model.js +151 -0
  52. package/dist/src/checker/type-model.js.map +1 -0
  53. package/dist/src/checker/type-system.d.ts +58 -0
  54. package/dist/src/checker/type-system.js +569 -0
  55. package/dist/src/checker/type-system.js.map +1 -0
  56. package/dist/src/checker/typecheck-types.d.ts +22 -0
  57. package/dist/src/checker/typecheck-types.js +109 -0
  58. package/dist/src/checker/typecheck-types.js.map +1 -0
  59. package/dist/src/checker/typecheck.d.ts +62 -0
  60. package/dist/src/checker/typecheck.js +574 -0
  61. package/dist/src/checker/typecheck.js.map +1 -0
  62. package/dist/src/checker/undefined.d.ts +14 -0
  63. package/dist/src/checker/undefined.js +32 -0
  64. package/dist/src/checker/undefined.js.map +1 -0
  65. package/dist/src/checker/walk.d.ts +10 -0
  66. package/dist/src/checker/walk.js +15 -0
  67. package/dist/src/checker/walk.js.map +1 -0
  68. package/dist/src/cli/help.d.ts +7 -0
  69. package/dist/src/cli/help.js +64 -0
  70. package/dist/src/cli/help.js.map +1 -0
  71. package/dist/src/cli/hints.js +2 -1
  72. package/dist/src/cli/hints.js.map +1 -1
  73. package/dist/src/cli/main.js +12 -48
  74. package/dist/src/cli/main.js.map +1 -1
  75. package/dist/src/codegen/generator/calls/access.js +8 -8
  76. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  77. package/dist/src/codegen/generator/calls/invocation.js +9 -4
  78. package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
  79. package/dist/src/codegen/generator/calls/super.d.ts +9 -1
  80. package/dist/src/codegen/generator/calls/super.js +56 -5
  81. package/dist/src/codegen/generator/calls/super.js.map +1 -1
  82. package/dist/src/codegen/generator/context.d.ts +13 -2
  83. package/dist/src/codegen/generator/context.js +25 -19
  84. package/dist/src/codegen/generator/context.js.map +1 -1
  85. package/dist/src/codegen/generator/debug.js +2 -1
  86. package/dist/src/codegen/generator/debug.js.map +1 -1
  87. package/dist/src/codegen/generator/expressions/primary.d.ts +4 -1
  88. package/dist/src/codegen/generator/expressions/primary.js +68 -8
  89. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  90. package/dist/src/codegen/generator/generator.js +11 -1
  91. package/dist/src/codegen/generator/generator.js.map +1 -1
  92. package/dist/src/codegen/generator/module.d.ts +3 -0
  93. package/dist/src/codegen/generator/module.js +116 -26
  94. package/dist/src/codegen/generator/module.js.map +1 -1
  95. package/dist/src/codegen/generator/state.d.ts +11 -1
  96. package/dist/src/codegen/generator/state.js.map +1 -1
  97. package/dist/src/codegen/generator/statements/variables.js +26 -7
  98. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  99. package/dist/src/codegen/generator/tables.d.ts +2 -0
  100. package/dist/src/codegen/generator/tables.js +4 -0
  101. package/dist/src/codegen/generator/tables.js.map +1 -1
  102. package/dist/src/driver/build-key.d.ts +2 -0
  103. package/dist/src/driver/build-key.js +1 -0
  104. package/dist/src/driver/build-key.js.map +1 -1
  105. package/dist/src/driver/bundler/graph.js +5 -1
  106. package/dist/src/driver/bundler/graph.js.map +1 -1
  107. package/dist/src/driver/bundler/merge.js +16 -1
  108. package/dist/src/driver/bundler/merge.js.map +1 -1
  109. package/dist/src/driver/bundler/types.d.ts +12 -0
  110. package/dist/src/driver/compiler.d.ts +1 -1
  111. package/dist/src/driver/compiler.js +3 -0
  112. package/dist/src/driver/compiler.js.map +1 -1
  113. package/dist/src/driver/fingerprint.js +2 -1
  114. package/dist/src/driver/fingerprint.js.map +1 -1
  115. package/dist/src/driver/frontend.d.ts +8 -6
  116. package/dist/src/driver/frontend.js +4 -0
  117. package/dist/src/driver/frontend.js.map +1 -1
  118. package/dist/src/driver/options.d.ts +6 -0
  119. package/dist/src/driver/version.d.ts +1 -1
  120. package/dist/src/driver/version.js +1 -1
  121. package/dist/src/extensions/gui/css.d.ts +26 -0
  122. package/dist/src/extensions/gui/css.js +100 -0
  123. package/dist/src/extensions/gui/css.js.map +1 -0
  124. package/dist/src/extensions/gui/html.js +28 -7
  125. package/dist/src/extensions/gui/html.js.map +1 -1
  126. package/dist/src/extensions/gui/index.js +79 -2
  127. package/dist/src/extensions/gui/index.js.map +1 -1
  128. package/dist/src/extensions/gui/three.d.ts +16 -0
  129. package/dist/src/extensions/gui/three.js +22 -0
  130. package/dist/src/extensions/gui/three.js.map +1 -0
  131. package/dist/src/extensions/media/index.d.ts +6 -5
  132. package/dist/src/extensions/media/index.js +12 -14
  133. package/dist/src/extensions/media/index.js.map +1 -1
  134. package/dist/src/extensions/registry.d.ts +38 -0
  135. package/dist/src/extensions/registry.js +10 -0
  136. package/dist/src/extensions/registry.js.map +1 -1
  137. package/dist/src/index.d.ts +1 -0
  138. package/dist/src/index.js +1 -0
  139. package/dist/src/index.js.map +1 -1
  140. package/dist/src/parser/declarations/classes.js +7 -0
  141. package/dist/src/parser/declarations/classes.js.map +1 -1
  142. package/dist/src/parser/expressions.js +14 -1
  143. package/dist/src/parser/expressions.js.map +1 -1
  144. package/dist/src/parser/literals.js +6 -2
  145. package/dist/src/parser/literals.js.map +1 -1
  146. package/dist/tests/binder/binder.test.js +29 -0
  147. package/dist/tests/binder/binder.test.js.map +1 -1
  148. package/dist/tests/canonical.test.d.ts +1 -0
  149. package/dist/tests/canonical.test.js +19 -0
  150. package/dist/tests/canonical.test.js.map +1 -0
  151. package/dist/tests/checker/checker.test.d.ts +1 -0
  152. package/dist/tests/checker/checker.test.js +245 -0
  153. package/dist/tests/checker/checker.test.js.map +1 -0
  154. package/dist/tests/cli/check.test.js +20 -0
  155. package/dist/tests/cli/check.test.js.map +1 -1
  156. package/dist/tests/conformance/matrix.test.d.ts +6 -0
  157. package/dist/tests/conformance/matrix.test.js +23 -0
  158. package/dist/tests/conformance/matrix.test.js.map +1 -0
  159. package/dist/tests/conformance/test262/manifest.d.ts +115 -0
  160. package/dist/tests/conformance/test262/manifest.js +257 -0
  161. package/dist/tests/conformance/test262/manifest.js.map +1 -0
  162. package/dist/tests/conformance/test262.test.d.ts +11 -0
  163. package/dist/tests/conformance/test262.test.js +74 -0
  164. package/dist/tests/conformance/test262.test.js.map +1 -0
  165. package/dist/tests/docs/structure.test.js +9 -11
  166. package/dist/tests/docs/structure.test.js.map +1 -1
  167. package/dist/tests/e2e/child-process.test.js +3 -2
  168. package/dist/tests/e2e/child-process.test.js.map +1 -1
  169. package/dist/tests/e2e/compile-builtins.test.js +45 -0
  170. package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
  171. package/dist/tests/e2e/compile-objects-classes.test.js +77 -0
  172. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  173. package/dist/tests/e2e/differential-syntax.test.d.ts +5 -0
  174. package/dist/tests/e2e/differential-syntax.test.js +95 -0
  175. package/dist/tests/e2e/differential-syntax.test.js.map +1 -0
  176. package/dist/tests/e2e/differential-values.test.js +15 -0
  177. package/dist/tests/e2e/differential-values.test.js.map +1 -1
  178. package/dist/tests/e2e/gui-browser.test.d.ts +13 -0
  179. package/dist/tests/e2e/gui-browser.test.js +163 -0
  180. package/dist/tests/e2e/gui-browser.test.js.map +1 -0
  181. package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
  182. package/dist/tests/e2e/gui-effects.test.js +262 -0
  183. package/dist/tests/e2e/gui-effects.test.js.map +1 -0
  184. package/dist/tests/e2e/gui-example-browser.test.js +2 -2
  185. package/dist/tests/e2e/gui-example-browser.test.js.map +1 -1
  186. package/dist/tests/e2e/gui-example-canvas.test.js +5 -4
  187. package/dist/tests/e2e/gui-example-canvas.test.js.map +1 -1
  188. package/dist/tests/e2e/gui-example-svg.test.js +4 -3
  189. package/dist/tests/e2e/gui-example-svg.test.js.map +1 -1
  190. package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
  191. package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
  192. package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
  193. package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
  194. package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
  195. package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
  196. package/dist/tests/e2e/gui-example.test.js +4 -3
  197. package/dist/tests/e2e/gui-example.test.js.map +1 -1
  198. package/dist/tests/e2e/gui-helpers.js +4 -3
  199. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  200. package/dist/tests/e2e/gui-layout.test.js +48 -0
  201. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  202. package/dist/tests/e2e/gui-media.test.js +10 -8
  203. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  204. package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
  205. package/dist/tests/e2e/gui-webgl.test.js +179 -0
  206. package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
  207. package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
  208. package/dist/tests/e2e/gui-webgl2.test.js +238 -0
  209. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
  210. package/dist/tests/e2e/harness.d.ts +9 -0
  211. package/dist/tests/e2e/harness.js +14 -2
  212. package/dist/tests/e2e/harness.js.map +1 -1
  213. package/dist/tests/e2e/native-extensions.test.js +2 -1
  214. package/dist/tests/e2e/native-extensions.test.js.map +1 -1
  215. package/dist/tests/e2e/property-descriptors.test.js +20 -0
  216. package/dist/tests/e2e/property-descriptors.test.js.map +1 -1
  217. package/dist/tests/e2e/unicode-output.test.js +5 -3
  218. package/dist/tests/e2e/unicode-output.test.js.map +1 -1
  219. package/dist/tests/e2e/weak-collections.test.js +16 -2
  220. package/dist/tests/e2e/weak-collections.test.js.map +1 -1
  221. package/dist/tests/extensions/gui.test.js +41 -0
  222. package/dist/tests/extensions/gui.test.js.map +1 -1
  223. package/dist/tests/extensions/media.test.js +7 -3
  224. package/dist/tests/extensions/media.test.js.map +1 -1
  225. package/dist/tests/helpers.d.ts +1 -0
  226. package/dist/tests/helpers.js +1 -0
  227. package/dist/tests/helpers.js.map +1 -1
  228. package/dist/tests/parser/declarations.test.js +20 -0
  229. package/dist/tests/parser/declarations.test.js.map +1 -1
  230. package/dist/tests/parser/expressions.test.js +36 -0
  231. package/dist/tests/parser/expressions.test.js.map +1 -1
  232. package/dist/tests/platform.d.ts +32 -0
  233. package/dist/tests/platform.js +40 -0
  234. package/dist/tests/platform.js.map +1 -0
  235. package/dist/tests/platform.test.d.ts +12 -0
  236. package/dist/tests/platform.test.js +51 -0
  237. package/dist/tests/platform.test.js.map +1 -0
  238. package/dist/tests/version.test.js +4 -4
  239. package/dist/tests/version.test.js.map +1 -1
  240. package/doc/ai/README.md +10 -4
  241. package/doc/ai/build-recipe.md +1 -0
  242. package/doc/ai/cli.md +17 -5
  243. package/doc/ai/contributing.md +59 -2
  244. package/doc/ai/extensions.md +38 -7
  245. package/doc/ai/language-support.md +25 -16
  246. package/doc/ai/troubleshooting.md +12 -8
  247. package/doc/ai/zh-CN/README.md +9 -4
  248. package/doc/ai/zh-CN/build-recipe.md +1 -0
  249. package/doc/ai/zh-CN/cli.md +13 -3
  250. package/doc/ai/zh-CN/contributing.md +49 -3
  251. package/doc/ai/zh-CN/extensions.md +33 -6
  252. package/doc/ai/zh-CN/language-support.md +23 -14
  253. package/doc/ai/zh-CN/troubleshooting.md +10 -6
  254. package/doc/gui/api.md +47 -1
  255. package/doc/gui/build.md +72 -16
  256. package/doc/gui/canvas.md +11 -3
  257. package/doc/gui/dom.md +33 -18
  258. package/doc/gui/known-issues.md +58 -15
  259. package/doc/gui/layout.md +18 -0
  260. package/doc/gui/media.md +17 -13
  261. package/doc/gui/rendering.md +50 -3
  262. package/doc/gui/runtime.md +18 -0
  263. package/doc/gui/webgl.md +256 -0
  264. package/doc/gui-scripts.md +7 -0
  265. package/doc/gui.md +108 -17
  266. package/doc/implemented/binder.md +2 -0
  267. package/doc/implemented/checker.md +117 -0
  268. package/doc/implemented/cli.md +13 -1
  269. package/doc/implemented/codegen.md +3 -2
  270. package/doc/implemented/driver.md +2 -2
  271. package/doc/implemented/operators.md +2 -1
  272. package/doc/implemented/parser.md +3 -2
  273. package/doc/implemented/pipeline.md +8 -1
  274. package/doc/implemented/stdlib.md +2 -1
  275. package/doc/implemented/tests.md +3 -1
  276. package/doc/implemented.md +2 -0
  277. package/doc/npm-package.md +419 -0
  278. package/doc/requirements.md +22 -10
  279. package/doc/support-matrix.md +83 -0
  280. package/doc/unimplemented/classes.md +3 -0
  281. package/doc/unimplemented/deviations.md +3 -2
  282. package/doc/unimplemented/toolchain.md +1 -1
  283. package/doc/unimplemented/types.md +24 -8
  284. package/doc/unimplemented.md +1 -1
  285. package/doc/zh-CN/gui/api.md +43 -1
  286. package/doc/zh-CN/gui/build.md +64 -15
  287. package/doc/zh-CN/gui/canvas.md +9 -2
  288. package/doc/zh-CN/gui/dom.md +20 -7
  289. package/doc/zh-CN/gui/known-issues.md +46 -13
  290. package/doc/zh-CN/gui/layout.md +14 -0
  291. package/doc/zh-CN/gui/media.md +15 -11
  292. package/doc/zh-CN/gui/rendering.md +41 -4
  293. package/doc/zh-CN/gui/runtime.md +16 -0
  294. package/doc/zh-CN/gui/webgl.md +115 -0
  295. package/doc/zh-CN/gui-scripts.md +5 -0
  296. package/doc/zh-CN/gui.md +89 -14
  297. package/doc/zh-CN/implemented/binder.md +2 -0
  298. package/doc/zh-CN/implemented/checker.md +99 -0
  299. package/doc/zh-CN/implemented/cli.md +12 -1
  300. package/doc/zh-CN/implemented/codegen.md +3 -2
  301. package/doc/zh-CN/implemented/driver.md +2 -2
  302. package/doc/zh-CN/implemented/operators.md +1 -1
  303. package/doc/zh-CN/implemented/parser.md +3 -2
  304. package/doc/zh-CN/implemented/pipeline.md +3 -1
  305. package/doc/zh-CN/implemented/stdlib.md +2 -1
  306. package/doc/zh-CN/implemented/tests.md +3 -1
  307. package/doc/zh-CN/implemented.md +2 -0
  308. package/doc/zh-CN/npm-package.md +394 -0
  309. package/doc/zh-CN/post/announce.md +47 -47
  310. package/doc/zh-CN/requirements.md +16 -7
  311. package/doc/zh-CN/support-matrix.md +82 -0
  312. package/doc/zh-CN/unimplemented/classes.md +3 -0
  313. package/doc/zh-CN/unimplemented/deviations.md +3 -2
  314. package/doc/zh-CN/unimplemented/toolchain.md +1 -1
  315. package/doc/zh-CN/unimplemented/types.md +16 -6
  316. package/doc/zh-CN/unimplemented.md +1 -1
  317. package/llms.txt +6 -1
  318. package/package.json +2 -1
  319. package/runtime/ext_gui/audio.cpp +316 -0
  320. package/runtime/ext_gui/browser.cpp +573 -0
  321. package/runtime/ext_gui/browser_escape.cpp +85 -0
  322. package/runtime/ext_gui/browser_loop.cpp +83 -0
  323. package/runtime/ext_gui/canvas.cpp +12 -21
  324. package/runtime/ext_gui/canvas_internal.h +10 -0
  325. package/runtime/ext_gui/canvas_raster.cpp +79 -1
  326. package/runtime/ext_gui/clip_values.cpp +246 -0
  327. package/runtime/ext_gui/css.cpp +94 -0
  328. package/runtime/ext_gui/css.h +22 -1
  329. package/runtime/ext_gui/css_match.cpp +3 -0
  330. package/runtime/ext_gui/css_selector.cpp +9 -0
  331. package/runtime/ext_gui/css_sheet.cpp +89 -45
  332. package/runtime/ext_gui/document.cpp +4 -1
  333. package/runtime/ext_gui/document.h +2 -0
  334. package/runtime/ext_gui/dom.h +16 -0
  335. package/runtime/ext_gui/dom_api.cpp +37 -0
  336. package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
  337. package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
  338. package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
  339. package/runtime/ext_gui/dom_api_document.cpp +96 -5
  340. package/runtime/ext_gui/dom_api_events.cpp +20 -0
  341. package/runtime/ext_gui/dom_api_internal.h +278 -0
  342. package/runtime/ext_gui/dom_api_proto.cpp +6 -0
  343. package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
  344. package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
  345. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
  346. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
  347. package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
  348. package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
  349. package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
  350. package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
  351. package/runtime/ext_gui/effect_values.cpp +312 -0
  352. package/runtime/ext_gui/gradient_values.cpp +476 -0
  353. package/runtime/ext_gui/grid_values.cpp +230 -0
  354. package/runtime/ext_gui/gui.cpp +90 -23
  355. package/runtime/ext_gui/gui_canvas.cpp +50 -2
  356. package/runtime/ext_gui/gui_engine.h +71 -0
  357. package/runtime/ext_gui/gui_events.cpp +4 -1
  358. package/runtime/ext_gui/gui_media.cpp +1 -1
  359. package/runtime/ext_gui/gui_webgl.cpp +83 -0
  360. package/runtime/ext_gui/layout.cpp +21 -0
  361. package/runtime/ext_gui/layout_flow.cpp +81 -4
  362. package/runtime/ext_gui/layout_flow_internal.h +31 -0
  363. package/runtime/ext_gui/layout_grid.cpp +374 -0
  364. package/runtime/ext_gui/media.h +1 -1
  365. package/runtime/ext_gui/media_api.h +2 -2
  366. package/runtime/ext_gui/media_query.cpp +211 -0
  367. package/runtime/ext_gui/paint.cpp +111 -77
  368. package/runtime/ext_gui/paint.h +33 -3
  369. package/runtime/ext_gui/paint_background.cpp +229 -0
  370. package/runtime/ext_gui/paint_clip.cpp +268 -0
  371. package/runtime/ext_gui/paint_effects.cpp +324 -0
  372. package/runtime/ext_gui/paint_internal.h +85 -0
  373. package/runtime/ext_gui/renderer.cpp +8 -31
  374. package/runtime/ext_gui/renderer_clip.cpp +196 -0
  375. package/runtime/ext_gui/renderer_image.cpp +13 -8
  376. package/runtime/ext_gui/renderer_internal.h +15 -8
  377. package/runtime/ext_gui/renderer_text.cpp +6 -31
  378. package/runtime/ext_gui/style.cpp +343 -20
  379. package/runtime/ext_gui/style.h +144 -3
  380. package/runtime/ext_gui/style_print.cpp +134 -1
  381. package/runtime/ext_gui/style_values.cpp +152 -126
  382. package/runtime/ext_gui/style_values_internal.h +35 -0
  383. package/runtime/ext_gui/webgl.h +466 -0
  384. package/runtime/ext_gui/webgl2_constants.h +274 -0
  385. package/runtime/ext_gui/webgl_buffer.cpp +565 -0
  386. package/runtime/ext_gui/webgl_constants.h +317 -0
  387. package/runtime/ext_gui/webgl_context.cpp +466 -0
  388. package/runtime/ext_gui/webgl_draw.cpp +495 -0
  389. package/runtime/ext_gui/webgl_glsl.h +125 -0
  390. package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
  391. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
  392. package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
  393. package/runtime/ext_gui/webgl_msl.cpp +62 -0
  394. package/runtime/ext_gui/webgl_msl.h +33 -0
  395. package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
  396. package/runtime/ext_gui/webgl_program_internal.h +18 -0
  397. package/runtime/ext_gui/webgl_shader.cpp +582 -0
  398. package/runtime/ext_gui/webgl_texture.cpp +293 -0
  399. package/runtime/ext_gui/webgl_uniform.cpp +167 -0
  400. package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
  401. package/runtime/ext_gui/window.cpp +9 -0
  402. package/runtime/ext_media/media.cpp +1 -1
  403. package/runtime/ext_media/media_bridge.c +9 -3
  404. package/runtime/ext_node/path/path.c +7 -7
  405. package/runtime/ext_node/url/url.c +4 -2
  406. package/runtime/rt.h +15 -0
  407. package/runtime/rt_internal.h +1 -0
  408. package/runtime/xt_constructors.c +2 -1
  409. package/runtime/xt_containers/access.inc +8 -0
  410. package/runtime/xt_containers/objects.inc +22 -2
  411. package/runtime/xt_io/exception.inc +4 -2
  412. package/runtime/xt_regex/api.inc +2 -0
  413. package/runtime/xt_regex/matcher.inc +16 -3
  414. package/runtime/xt_regex/parser.inc +8 -2
  415. package/runtime/xt_regex/types.inc +3 -0
  416. package/runtime/xt_stdlib/math.inc +62 -0
  417. package/runtime/xt_stdlib2/date.inc +7 -1
  418. package/runtime/xt_stdlib2/objects.inc +14 -0
  419. package/runtime/xt_stdlib2/regexp-match.inc +60 -21
  420. package/runtime/xt_stdlib2/regexp.inc +1 -0
  421. package/runtime/xt_typed_array.c +1 -1
  422. package/scripts/build-gui.ts +90 -3
  423. package/scripts/build-media.ts +323 -58
  424. package/scripts/setup-vs-toolchain.ps1 +152 -0
  425. package/scripts/support-matrix.ts +167 -0
  426. package/src/ast/common.ts +2 -0
  427. package/src/ast/declarations.ts +12 -1
  428. package/src/ast/expressions.ts +6 -0
  429. package/src/ast/kinds.ts +2 -0
  430. package/src/binder/binder.ts +3 -0
  431. package/src/binder/declarations.ts +70 -0
  432. package/src/binder/references.ts +97 -4
  433. package/src/binder/types.ts +30 -0
  434. package/src/canonical.ts +37 -0
  435. package/src/checker/assignability.ts +134 -0
  436. package/src/checker/calls.ts +135 -0
  437. package/src/checker/checker.ts +47 -0
  438. package/src/checker/declarations.ts +26 -0
  439. package/src/checker/flow.ts +236 -0
  440. package/src/checker/globals.ts +40 -0
  441. package/src/checker/source.ts +53 -0
  442. package/src/checker/type-infer.ts +185 -0
  443. package/src/checker/type-model.ts +212 -0
  444. package/src/checker/type-system.ts +578 -0
  445. package/src/checker/typecheck-types.ts +112 -0
  446. package/src/checker/typecheck.ts +586 -0
  447. package/src/checker/undefined.ts +43 -0
  448. package/src/checker/walk.ts +16 -0
  449. package/src/cli/help.ts +65 -0
  450. package/src/cli/hints.ts +2 -1
  451. package/src/cli/main.ts +12 -49
  452. package/src/codegen/generator/calls/access.ts +8 -8
  453. package/src/codegen/generator/calls/invocation.ts +8 -5
  454. package/src/codegen/generator/calls/super.ts +67 -5
  455. package/src/codegen/generator/context.ts +31 -19
  456. package/src/codegen/generator/debug.ts +2 -1
  457. package/src/codegen/generator/expressions/primary.ts +84 -13
  458. package/src/codegen/generator/generator.ts +11 -1
  459. package/src/codegen/generator/module.ts +115 -24
  460. package/src/codegen/generator/state.ts +11 -1
  461. package/src/codegen/generator/statements/variables.ts +26 -6
  462. package/src/codegen/generator/tables.ts +5 -0
  463. package/src/driver/build-key.ts +3 -0
  464. package/src/driver/bundler/graph.ts +6 -2
  465. package/src/driver/bundler/merge.ts +14 -1
  466. package/src/driver/bundler/types.ts +13 -0
  467. package/src/driver/compiler.ts +4 -1
  468. package/src/driver/fingerprint.ts +2 -1
  469. package/src/driver/frontend.ts +13 -2
  470. package/src/driver/options.ts +6 -0
  471. package/src/driver/version.ts +1 -1
  472. package/src/extensions/gui/css.ts +113 -0
  473. package/src/extensions/gui/html.ts +31 -11
  474. package/src/extensions/gui/index.ts +81 -2
  475. package/src/extensions/gui/three.ts +25 -0
  476. package/src/extensions/media/index.ts +13 -16
  477. package/src/extensions/registry.ts +48 -0
  478. package/src/index.ts +1 -0
  479. package/src/parser/declarations/classes.ts +7 -0
  480. package/src/parser/expressions.ts +13 -1
  481. package/src/parser/literals.ts +6 -2
@@ -0,0 +1,83 @@
1
+ /*
2
+ * xbintsc GUI engine — the frame pump for browser-style pages.
3
+ *
4
+ * A program that calls `run()` hands the frame loop to the engine: `xt_gui_run`
5
+ * polls input, renders and drains microtasks until the last window closes. A
6
+ * *page* — the kind xbintsc compiles straight from browser code — never calls
7
+ * `run()`. It asks for the next frame with `requestAnimationFrame` and expects
8
+ * the host to keep serving frames; without a pump the window would open and
9
+ * then never paint.
10
+ *
11
+ * This unit closes that gap with one repeating runtime timer. Each tick
12
+ * dispatches input, renders (which also drains the queued animation-frame
13
+ * callbacks before layout, so a mutation a callback makes lands in the same
14
+ * frame) and re-arms itself only while callbacks are still queued. A page that
15
+ * stops animating therefore lets the event loop drain, and the program exits on
16
+ * its own — the same lifecycle a browser tab has when it goes idle.
17
+ *
18
+ * `XT_GUI_AUTOCLOSE_MS` is honoured here too, so a headless run of such a page
19
+ * cannot hang.
20
+ */
21
+
22
+ #include "gui_engine.h"
23
+
24
+ namespace {
25
+
26
+ /** The tick callback, built once and rooted for the life of the program. */
27
+ xt_value g_tick = XT_UNDEFINED;
28
+ int g_tick_pending = 0;
29
+ double g_tick_started_ms = 0;
30
+ double g_tick_deadline_ms = 0;
31
+
32
+ xt_value browser_tick(xt_value self, xt_value env, int32_t argc, xt_value *argv);
33
+
34
+ void arm_tick(void) {
35
+ /* `run()` renders its own frames; a second pump would paint each window
36
+ * twice per tick. */
37
+ if (g_tick_pending || xt_gui_run_active()) return;
38
+ if (!XT_IS_FUNCTION(g_tick)) {
39
+ g_tick = xt_closure_new((void *)browser_tick, 0, NULL);
40
+ xt_gc_add_root(&g_tick);
41
+ }
42
+ xt_value args[2] = {g_tick, xt_number(16)};
43
+ g_tick_pending = 1;
44
+ xt_set_timeout(2, args);
45
+ }
46
+
47
+ xt_value browser_tick(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
48
+ (void)self;
49
+ (void)env;
50
+ (void)argc;
51
+ (void)argv;
52
+ g_tick_pending = 0;
53
+ if (xt_gui_run_active()) return XT_UNDEFINED;
54
+ if (g_tick_deadline_ms > 0 && (double)SDL_GetTicks() >= g_tick_deadline_ms) {
55
+ /* Shared with `run()`: stop animating and let the program exit instead of
56
+ * hanging a headless run. */
57
+ xt_gui_quit(0, NULL);
58
+ return XT_UNDEFINED;
59
+ }
60
+ xt_value win = xt_browser_window(0, NULL);
61
+ if (XT_IS_UNDEFINED(win)) return XT_UNDEFINED;
62
+ XtGuiWindow *record = xt_gui_window_from_this(win);
63
+ if (record == NULL || !record->open) return XT_UNDEFINED;
64
+ xt_gui_pump_events();
65
+ xt_gui_render_window(record);
66
+ if (record->open && !record->animation_frames.empty()) arm_tick();
67
+ return XT_UNDEFINED;
68
+ }
69
+
70
+ } // namespace
71
+
72
+ /** Make sure a frame will be served: start the clock on the first request and
73
+ * arm the repeating tick unless one is already queued. */
74
+ extern "C" void xt_browser_schedule_frame(void) {
75
+ if (g_tick_started_ms == 0.0) {
76
+ g_tick_started_ms = (double)SDL_GetTicks();
77
+ const char *autoclose = SDL_getenv("XT_GUI_AUTOCLOSE_MS");
78
+ if (autoclose != NULL && autoclose[0] != '\0') {
79
+ g_tick_deadline_ms = g_tick_started_ms + (double)SDL_atoi(autoclose);
80
+ }
81
+ }
82
+ arm_tick();
83
+ }
@@ -24,10 +24,16 @@ namespace {
24
24
  std::atomic<uint64_t> g_next_canvas_id{1};
25
25
 
26
26
  /** Process-wide id -> canvas table. The engine is single-threaded; the table
27
- * lives for the process while the objects are owned by the window. */
27
+ * lives for the process while the objects are owned by the window.
28
+ *
29
+ * Deliberately leaked: `g_windows` is a global array, so the canvases it owns
30
+ * are destroyed *after* this function-local static would have been, and
31
+ * `~Canvas2D` has to remove itself from the table. Ordering that destruction by
32
+ * hand is not worth it — the table is one map for the whole process. */
28
33
  std::unordered_map<uint64_t, Canvas2D *> &canvas_registry() {
29
- static std::unordered_map<uint64_t, Canvas2D *> registry;
30
- return registry;
34
+ static std::unordered_map<uint64_t, Canvas2D *> *registry =
35
+ new std::unordered_map<uint64_t, Canvas2D *>();
36
+ return *registry;
31
37
  }
32
38
 
33
39
  CanvasPoint lerp(const CanvasPoint &a, const CanvasPoint &b, float t) {
@@ -451,24 +457,9 @@ void Canvas2D::draw_image(const Image &source, float dx, float dy, float dw, flo
451
457
  canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, x0, y0, x1 - x0,
452
458
  y1 - y0, sx, sy, sw, sh, state_.global_alpha);
453
459
  } else {
454
- float cornersX[4], cornersY[4];
455
- const float corners[4][2] = {
456
- {dx, dy}, {dx + dw, dy}, {dx + dw, dy + dh}, {dx, dy + dh}};
457
- float minX = 0.0f, minY = 0.0f, maxX = 0.0f, maxY = 0.0f;
458
- for (int i = 0; i < 4; i++) {
459
- to_device(corners[i][0], corners[i][1], &cornersX[i], &cornersY[i]);
460
- if (i == 0) {
461
- minX = maxX = cornersX[i];
462
- minY = maxY = cornersY[i];
463
- } else {
464
- minX = std::min(minX, cornersX[i]);
465
- maxX = std::max(maxX, cornersX[i]);
466
- minY = std::min(minY, cornersY[i]);
467
- maxY = std::max(maxY, cornersY[i]);
468
- }
469
- }
470
- canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, minX, minY,
471
- maxX - minX, maxY - minY, sx, sy, sw, sh, state_.global_alpha);
460
+ canvas_detail::draw_image_affine(image_.pixels, image_.width, image_.height, source, dx, dy,
461
+ dw, dh, sx, sy, sw, sh, state_.transform,
462
+ state_.global_alpha);
472
463
  }
473
464
  generation_++;
474
465
  }
@@ -48,6 +48,16 @@ void draw_image(std::vector<unsigned char> &pixels, int width, int height, const
48
48
  float dx, float dy, float dw, float dh, float sx, float sy, float sw, float sh,
49
49
  float alpha);
50
50
 
51
+ /** Blit an RGBA8 source through a full affine transform. The destination
52
+ * rectangle is mapped to a parallelogram by `transform`; each device pixel is
53
+ * inverse-mapped and sampled from the source rectangle. This is the path that
54
+ * makes rotated/skewed `drawImage` (and perspective-grid canvas textures) draw
55
+ * the image instead of squashing it into the bounding box. */
56
+ void draw_image_affine(std::vector<unsigned char> &pixels, int width, int height,
57
+ const Image &source, float dx, float dy, float dw, float dh, float sx,
58
+ float sy, float sw, float sh, const CanvasTransform &transform,
59
+ float alpha);
60
+
51
61
  /** Composite one grayscale glyph bitmap at `(x, baselineY)` with `paint`. */
52
62
  void blit_glyph(std::vector<unsigned char> &pixels, int width, int height,
53
63
  const std::vector<unsigned char> &glyph, int glyphWidth, int glyphHeight, int left,
@@ -53,6 +53,15 @@ void paint_color_at(const CanvasPaint &paint, float x, float y, float out[4]) {
53
53
  } // namespace
54
54
 
55
55
  void blend_pixel(unsigned char *pixel, const float color[4], float coverage, float alpha) {
56
+ /* Fully opaque source-over is a plain copy; this is the hot path for paper
57
+ textures, terrain and the opaque parts of every sprite. */
58
+ if (alpha >= 0.999f && coverage >= 0.999f && color[3] >= 0.999f) {
59
+ pixel[0] = (unsigned char)clamp_byte(color[0] * 255.0f);
60
+ pixel[1] = (unsigned char)clamp_byte(color[1] * 255.0f);
61
+ pixel[2] = (unsigned char)clamp_byte(color[2] * 255.0f);
62
+ pixel[3] = 255;
63
+ return;
64
+ }
56
65
  float sa = color[3] * coverage * alpha;
57
66
  if (sa <= 0.0f) return;
58
67
  if (sa > 1.0f) sa = 1.0f;
@@ -245,8 +254,77 @@ void draw_image(std::vector<unsigned char> &pixels, int width, int height, const
245
254
  if (syi >= source.height) syi = source.height - 1;
246
255
  const unsigned char *texel =
247
256
  source.pixels.data() + ((size_t)syi * (size_t)source.width + (size_t)sxi) * 4;
257
+ unsigned char *dst = pixels.data() + ((size_t)py * (size_t)width + (size_t)px) * 4;
258
+ if (alpha >= 0.999f) {
259
+ const unsigned char ta = texel[3];
260
+ if (ta == 255) {
261
+ dst[0] = texel[0]; dst[1] = texel[1]; dst[2] = texel[2]; dst[3] = 255;
262
+ continue;
263
+ }
264
+ if (ta == 0) continue;
265
+ }
266
+ float color[4] = {texel[0] / 255.0f, texel[1] / 255.0f, texel[2] / 255.0f, texel[3] / 255.0f};
267
+ blend_pixel(dst, color, 1.0f, alpha);
268
+ }
269
+ }
270
+ }
271
+
272
+
273
+ void draw_image_affine(std::vector<unsigned char> &pixels, int width, int height,
274
+ const Image &source, float dx, float dy, float dw, float dh, float sx,
275
+ float sy, float sw, float sh, const CanvasTransform &transform,
276
+ float alpha) {
277
+ if (source.width <= 0 || source.height <= 0 || dw <= 0.0f || dh <= 0.0f || sw <= 0.0f ||
278
+ sh <= 0.0f)
279
+ return;
280
+ CanvasTransform inverse = transform.inverted();
281
+ float cornersX[4];
282
+ float cornersY[4];
283
+ const float corners[4][2] = {{dx, dy}, {dx + dw, dy}, {dx + dw, dy + dh}, {dx, dy + dh}};
284
+ float minX = 0.0f, minY = 0.0f, maxX = 0.0f, maxY = 0.0f;
285
+ for (int i = 0; i < 4; i++) {
286
+ transform.apply(corners[i][0], corners[i][1], &cornersX[i], &cornersY[i]);
287
+ if (i == 0) {
288
+ minX = maxX = cornersX[i];
289
+ minY = maxY = cornersY[i];
290
+ } else {
291
+ minX = std::min(minX, cornersX[i]);
292
+ maxX = std::max(maxX, cornersX[i]);
293
+ minY = std::min(minY, cornersY[i]);
294
+ maxY = std::max(maxY, cornersY[i]);
295
+ }
296
+ }
297
+ int ix0 = std::max(0, (int)std::floor(minX));
298
+ int ix1 = std::min(width, (int)std::ceil(maxX));
299
+ int iy0 = std::max(0, (int)std::floor(minY));
300
+ int iy1 = std::min(height, (int)std::ceil(maxY));
301
+ for (int py = iy0; py < iy1; py++) {
302
+ for (int px = ix0; px < ix1; px++) {
303
+ float ux = 0.0f;
304
+ float uy = 0.0f;
305
+ inverse.apply((float)px + 0.5f, (float)py + 0.5f, &ux, &uy);
306
+ float u = (ux - dx) / dw;
307
+ float v = (uy - dy) / dh;
308
+ if (u < 0.0f || u >= 1.0f || v < 0.0f || v >= 1.0f) continue;
309
+ int sxi = (int)(sx + u * sw);
310
+ int syi = (int)(sy + v * sh);
311
+ if (sxi < 0) sxi = 0;
312
+ if (syi < 0) syi = 0;
313
+ if (sxi >= source.width) sxi = source.width - 1;
314
+ if (syi >= source.height) syi = source.height - 1;
315
+ const unsigned char *texel =
316
+ source.pixels.data() + ((size_t)syi * (size_t)source.width + (size_t)sxi) * 4;
317
+ unsigned char *dst = pixels.data() + ((size_t)py * (size_t)width + (size_t)px) * 4;
318
+ if (alpha >= 0.999f) {
319
+ const unsigned char ta = texel[3];
320
+ if (ta == 255) {
321
+ dst[0] = texel[0]; dst[1] = texel[1]; dst[2] = texel[2]; dst[3] = 255;
322
+ continue;
323
+ }
324
+ if (ta == 0) continue;
325
+ }
248
326
  float color[4] = {texel[0] / 255.0f, texel[1] / 255.0f, texel[2] / 255.0f, texel[3] / 255.0f};
249
- blend_pixel(pixels.data() + ((size_t)py * (size_t)width + (size_t)px) * 4, color, 1.0f, alpha);
327
+ blend_pixel(dst, color, 1.0f, alpha);
250
328
  }
251
329
  }
252
330
  }
@@ -0,0 +1,246 @@
1
+ /*
2
+ * xbintsc GUI engine — `clip-path` value parsing.
3
+ *
4
+ * The geometry is resolved in `paint_clip.cpp`, where the element's border box
5
+ * and transform are known. Values here keep CSS lengths unresolved so `%`, em
6
+ * and viewport units survive the cascade.
7
+ */
8
+ #include <cctype>
9
+ #include <string>
10
+ #include <utility>
11
+ #include <vector>
12
+
13
+ #include "css_internal.h"
14
+ #include "style_internal.h"
15
+ #include "style_values_internal.h"
16
+
17
+ namespace xtgui {
18
+
19
+ namespace {
20
+
21
+ std::vector<std::string> splitTokens(const std::string &text) {
22
+ std::vector<std::string> parts;
23
+ std::string current;
24
+ int depth = 0;
25
+ for (char c : text) {
26
+ if (c == '(') depth++;
27
+ if (c == ')') depth--;
28
+ if ((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ',') && depth == 0) {
29
+ if (!current.empty()) {
30
+ parts.push_back(current);
31
+ current.clear();
32
+ }
33
+ } else {
34
+ current.push_back(c);
35
+ }
36
+ }
37
+ if (!current.empty()) parts.push_back(current);
38
+ return parts;
39
+ }
40
+
41
+ /** Split `text` on a top-level keyword (`at` / `round`), keeping both sides. */
42
+ bool splitKeyword(const std::string &text, const std::string &keyword, std::string *left,
43
+ std::string *right) {
44
+ std::string lower = xt_css_lower(text);
45
+ int depth = 0;
46
+ for (size_t i = 0; i + keyword.size() <= text.size(); i++) {
47
+ char c = text[i];
48
+ if (c == '(') depth++;
49
+ else if (c == ')') depth--;
50
+ if (depth != 0) continue;
51
+ if (lower.compare(i, keyword.size(), keyword) != 0) continue;
52
+ bool before = i == 0 || xt_is_css_space(text[i - 1]) || text[i - 1] == ',';
53
+ bool after = i + keyword.size() >= text.size() ||
54
+ xt_is_css_space(text[i + keyword.size()]) || text[i + keyword.size()] == ',';
55
+ if (!before || !after) continue;
56
+ *left = xt_css_trim(text.substr(0, i));
57
+ *right = xt_css_trim(text.substr(i + keyword.size()));
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+
63
+ bool parsePositionToken(const std::string &raw, Length *out, bool *vertical) {
64
+ std::string text = xt_css_lower(xt_css_trim(raw));
65
+ if (text == "left") { *out = {0.0f, Unit::Percent}; *vertical = false; return true; }
66
+ if (text == "right") { *out = {100.0f, Unit::Percent}; *vertical = false; return true; }
67
+ if (text == "top") { *out = {0.0f, Unit::Percent}; *vertical = true; return true; }
68
+ if (text == "bottom") { *out = {100.0f, Unit::Percent}; *vertical = true; return true; }
69
+ if (text == "center") { *out = {50.0f, Unit::Percent}; *vertical = false; return true; }
70
+ Length length = xt_css_parse_length(text);
71
+ if (length.unit == Unit::Invalid || length.unit == Unit::Auto || length.unit == Unit::None)
72
+ return false;
73
+ *out = length;
74
+ *vertical = false;
75
+ return true;
76
+ }
77
+
78
+ bool parseCenter(const std::string &text, Length *x, Length *y) {
79
+ std::vector<std::string> tokens = splitTokens(text);
80
+ if (tokens.empty() || tokens.size() > 2) return false;
81
+ Length values[2];
82
+ bool vertical[2] = {false, false};
83
+ for (size_t i = 0; i < tokens.size(); i++) {
84
+ if (!parsePositionToken(tokens[i], &values[i], &vertical[i])) return false;
85
+ }
86
+ if (tokens.size() == 1) {
87
+ if (vertical[0]) {
88
+ *x = {50.0f, Unit::Percent};
89
+ *y = values[0];
90
+ } else {
91
+ *x = values[0];
92
+ *y = {50.0f, Unit::Percent};
93
+ }
94
+ return true;
95
+ }
96
+ if (vertical[0] && !vertical[1]) {
97
+ *x = values[1];
98
+ *y = values[0];
99
+ } else {
100
+ *x = values[0];
101
+ *y = values[1];
102
+ }
103
+ return true;
104
+ }
105
+
106
+ /** Parse the 1–4 side lengths of `inset(...)` and an optional round radius. */
107
+ bool parseInset(const std::string &body, ClipPathSpec *spec) {
108
+ std::string sides = body;
109
+ std::string round;
110
+ if (splitKeyword(body, "round", &sides, &round)) {
111
+ std::vector<std::string> radiusTokens = splitTokens(round);
112
+ if (!radiusTokens.empty()) {
113
+ Length radius = xt_css_parse_length(radiusTokens[0]);
114
+ if (radius.unit != Unit::Invalid && radius.unit != Unit::Auto &&
115
+ radius.unit != Unit::None)
116
+ spec->inset_radius = radius;
117
+ }
118
+ }
119
+ std::vector<std::string> tokens = splitTokens(sides);
120
+ if (tokens.empty() || tokens.size() > 4) return false;
121
+ Length values[4];
122
+ for (size_t i = 0; i < tokens.size(); i++) {
123
+ values[i] = xt_css_parse_length(tokens[i]);
124
+ if (values[i].unit == Unit::Invalid) return false;
125
+ }
126
+ switch (tokens.size()) {
127
+ case 1:
128
+ spec->inset_top = spec->inset_right = spec->inset_bottom = spec->inset_left = values[0];
129
+ break;
130
+ case 2:
131
+ spec->inset_top = spec->inset_bottom = values[0];
132
+ spec->inset_right = spec->inset_left = values[1];
133
+ break;
134
+ case 3:
135
+ spec->inset_top = values[0];
136
+ spec->inset_right = spec->inset_left = values[1];
137
+ spec->inset_bottom = values[2];
138
+ break;
139
+ default:
140
+ spec->inset_top = values[0];
141
+ spec->inset_right = values[1];
142
+ spec->inset_bottom = values[2];
143
+ spec->inset_left = values[3];
144
+ break;
145
+ }
146
+ spec->type = ClipPathSpec::Type::Inset;
147
+ return true;
148
+ }
149
+
150
+ bool parseCircle(const std::string &body, ClipPathSpec *spec) {
151
+ std::string radius;
152
+ std::string center;
153
+ if (splitKeyword(body, "at", &radius, &center)) {
154
+ if (!parseCenter(center, &spec->center_x, &spec->center_y)) return false;
155
+ } else {
156
+ radius = body;
157
+ }
158
+ std::vector<std::string> tokens = splitTokens(radius);
159
+ if (!tokens.empty()) {
160
+ Length length = xt_css_parse_length(tokens[0]);
161
+ if (length.unit == Unit::Invalid) return false;
162
+ spec->radius_x = length;
163
+ spec->radius_y = length;
164
+ spec->radius_explicit = true;
165
+ }
166
+ spec->type = ClipPathSpec::Type::Circle;
167
+ return true;
168
+ }
169
+
170
+ bool parseEllipse(const std::string &body, ClipPathSpec *spec) {
171
+ std::string radii = body;
172
+ std::string center;
173
+ splitKeyword(body, "at", &radii, &center);
174
+ if (!center.empty() && !parseCenter(center, &spec->center_x, &spec->center_y)) return false;
175
+ std::vector<std::string> tokens = splitTokens(radii);
176
+ if (!tokens.empty()) {
177
+ Length rx = xt_css_parse_length(tokens[0]);
178
+ Length ry = tokens.size() > 1 ? xt_css_parse_length(tokens[1]) : rx;
179
+ if (rx.unit == Unit::Invalid || ry.unit == Unit::Invalid) return false;
180
+ spec->radius_x = rx;
181
+ spec->radius_y = ry;
182
+ spec->radius_explicit = true;
183
+ }
184
+ spec->type = ClipPathSpec::Type::Ellipse;
185
+ return true;
186
+ }
187
+
188
+ bool parsePolygon(const std::string &body, ClipPathSpec *spec) {
189
+ std::string text = xt_css_trim(body);
190
+ std::string lower = xt_css_lower(text);
191
+ if (lower.rfind("nonzero", 0) == 0) text = xt_css_trim(text.substr(7));
192
+ else if (lower.rfind("evenodd", 0) == 0) text = xt_css_trim(text.substr(7));
193
+ /* Pairs are separated by commas in CSS, but whitespace is accepted too. */
194
+ std::vector<std::string> tokens = splitTokens(text);
195
+ if (tokens.size() < 3) return false;
196
+ std::vector<Length> points;
197
+ for (const std::string &token : tokens) {
198
+ Length length = xt_css_parse_length(token);
199
+ if (length.unit == Unit::Invalid) return false;
200
+ points.push_back(length);
201
+ }
202
+ if (points.size() < 3) return false;
203
+ if (points.size() % 2 != 0) points.pop_back();
204
+ spec->polygon = std::move(points);
205
+ spec->type = ClipPathSpec::Type::Polygon;
206
+ return true;
207
+ }
208
+
209
+ } // namespace
210
+
211
+ bool xt_style_apply_clip_path(XtStyle *style, const std::string &property,
212
+ const std::string &value) {
213
+ if (property != "clip-path") return false;
214
+ std::string text = xt_css_trim(value);
215
+ std::string lower = xt_css_lower(text);
216
+ ClipPathSpec spec;
217
+ if (lower == "none" || text.empty()) {
218
+ style->clip_path = spec;
219
+ return true;
220
+ }
221
+ if (text.size() < 8 || text.back() != ')') {
222
+ style->clip_path = spec;
223
+ return true;
224
+ }
225
+ if (lower.rfind("inset(", 0) == 0) {
226
+ if (parseInset(text.substr(6, text.size() - 7), &spec)) style->clip_path = spec;
227
+ return true;
228
+ }
229
+ if (lower.rfind("circle(", 0) == 0) {
230
+ if (parseCircle(text.substr(7, text.size() - 8), &spec)) style->clip_path = spec;
231
+ return true;
232
+ }
233
+ if (lower.rfind("ellipse(", 0) == 0) {
234
+ if (parseEllipse(text.substr(8, text.size() - 9), &spec)) style->clip_path = spec;
235
+ return true;
236
+ }
237
+ if (lower.rfind("polygon(", 0) == 0) {
238
+ if (parsePolygon(text.substr(8, text.size() - 9), &spec)) style->clip_path = spec;
239
+ return true;
240
+ }
241
+ /* `url(#…)`, `path()` and other shapes are not part of the subset. */
242
+ style->clip_path = spec;
243
+ return true;
244
+ }
245
+
246
+ } // namespace xtgui
@@ -45,6 +45,39 @@ std::vector<std::string> xt_css_split_whitespace(const std::string &text) {
45
45
  return parts;
46
46
  }
47
47
 
48
+ std::vector<std::string> xt_css_split_commas(const std::string &text) {
49
+ std::vector<std::string> parts;
50
+ std::string current;
51
+ int depth = 0;
52
+ char quote = 0;
53
+ for (char c : text) {
54
+ if (quote != 0) {
55
+ current.push_back(c);
56
+ if (c == quote) quote = 0;
57
+ continue;
58
+ }
59
+ if (c == '"' || c == '\'') {
60
+ quote = c;
61
+ current.push_back(c);
62
+ } else if (c == '(' || c == '[') {
63
+ depth++;
64
+ current.push_back(c);
65
+ } else if (c == ')' || c == ']') {
66
+ if (depth > 0) depth--;
67
+ current.push_back(c);
68
+ } else if (c == ',' && depth == 0) {
69
+ std::string part = xt_css_trim(current);
70
+ if (!part.empty()) parts.push_back(part);
71
+ current.clear();
72
+ } else {
73
+ current.push_back(c);
74
+ }
75
+ }
76
+ std::string part = xt_css_trim(current);
77
+ if (!part.empty()) parts.push_back(part);
78
+ return parts;
79
+ }
80
+
48
81
  /* -- numbers / lengths / colors ------------------------------------------- */
49
82
 
50
83
  bool xt_css_parse_number(const std::string &value, float *out) {
@@ -59,6 +92,60 @@ bool xt_css_parse_number(const std::string &value, float *out) {
59
92
  return true;
60
93
  }
61
94
 
95
+
96
+ /** Split a CSS function's argument list at top-level commas. */
97
+ static std::vector<std::string> splitFunctionArgs(const std::string &text) {
98
+ std::vector<std::string> args;
99
+ std::string current;
100
+ int depth = 0;
101
+ for (char c : text) {
102
+ if (c == '(') depth++;
103
+ if (c == ')') depth--;
104
+ if (c == ',' && depth == 0) {
105
+ args.push_back(xt_css_trim(current));
106
+ current.clear();
107
+ } else {
108
+ current.push_back(c);
109
+ }
110
+ }
111
+ if (!current.empty() || !args.empty()) args.push_back(xt_css_trim(current));
112
+ return args;
113
+ }
114
+
115
+ /** `clamp(min, value, max)`, `min(...)` and `max(...)` over lengths. The
116
+ * arguments stay unresolved; layout resolves them against the element's em and
117
+ * the viewport. `env(safe-area-inset-*)` has no notch information in a desktop
118
+ * window, so it resolves to zero (its fallback is ignored, matching the
119
+ * browser's value without insets). */
120
+ static Length parseFunctionLength(const std::string &name, const std::string &inner) {
121
+ Length result;
122
+ if (name == "env") {
123
+ result.unit = Unit::Px;
124
+ return result;
125
+ }
126
+ if (name != "clamp" && name != "min" && name != "max") {
127
+ result.unit = Unit::Invalid;
128
+ return result;
129
+ }
130
+ std::vector<std::string> args = splitFunctionArgs(inner);
131
+ size_t expected = name == "clamp" ? 3 : 1;
132
+ if (args.size() < expected) {
133
+ result.unit = Unit::Invalid;
134
+ return result;
135
+ }
136
+ result.unit = name == "clamp" ? Unit::Clamp : (name == "min" ? Unit::Min : Unit::Max);
137
+ for (const std::string &arg : args) {
138
+ Length value = xt_css_parse_length(arg);
139
+ if (value.unit == Unit::Invalid) {
140
+ result.unit = Unit::Invalid;
141
+ result.args.clear();
142
+ return result;
143
+ }
144
+ result.args.push_back(value);
145
+ }
146
+ return result;
147
+ }
148
+
62
149
  Length xt_css_parse_length(const std::string &value) {
63
150
  Length length;
64
151
  std::string text = xt_css_lower(xt_css_trim(value));
@@ -74,6 +161,13 @@ Length xt_css_parse_length(const std::string &value) {
74
161
  length.unit = Unit::None;
75
162
  return length;
76
163
  }
164
+ size_t open = text.find('(');
165
+ if (open != std::string::npos && !text.empty() && text.back() == ')') {
166
+ std::string name = text.substr(0, open);
167
+ if (name == "clamp" || name == "min" || name == "max" || name == "env") {
168
+ return parseFunctionLength(name, text.substr(open + 1, text.size() - open - 2));
169
+ }
170
+ }
77
171
  char *end = nullptr;
78
172
  float number = strtof(text.c_str(), &end);
79
173
  if (end == text.c_str()) {
@@ -17,11 +17,15 @@
17
17
 
18
18
  namespace xtgui {
19
19
 
20
- enum class Unit { Auto, None, Px, Percent, Em, Rem, Vw, Vh, Number, Invalid };
20
+ enum class Unit { Auto, None, Px, Percent, Em, Rem, Vw, Vh, Number, Clamp, Min, Max, Invalid };
21
21
 
22
22
  struct Length {
23
23
  float value = 0.0f;
24
24
  Unit unit = Unit::Auto;
25
+ /* Arguments of `clamp(...)`, `min(...)` and `max(...)`; empty for a scalar
26
+ * length. Kept unresolved so vw/vh/em are resolved against the element that
27
+ * uses the length, not the viewport at parse time. */
28
+ std::vector<Length> args = {};
25
29
  };
26
30
 
27
31
  struct Color {
@@ -52,6 +56,9 @@ struct CompoundSelector {
52
56
  std::vector<std::string> classes;
53
57
  std::vector<AttrSelector> attrs;
54
58
  std::vector<std::string> pseudoClasses;
59
+ /** `before`/`after` for a `::before`/`::after` (or legacy `:before`)
60
+ * pseudo-element; empty for an ordinary selector. */
61
+ std::string pseudo_element;
55
62
  };
56
63
 
57
64
  enum class Combinator { Descendant, Child, Adjacent, Sibling };
@@ -66,6 +73,10 @@ struct Rule {
66
73
  std::vector<ComplexSelector> selectors;
67
74
  std::vector<Declaration> declarations;
68
75
  int order = 0;
76
+ /** Raw `@media` prelude this rule came from (empty = unconditional). The
77
+ * query is evaluated against the current viewport during the cascade, so a
78
+ * resize restyles with the right rules. */
79
+ std::string media;
69
80
  };
70
81
 
71
82
  struct StyleSheet {
@@ -85,6 +96,16 @@ std::vector<Declaration> xt_css_parse_declarations(const std::string &text);
85
96
  bool xt_css_match(const Node *node, const ComplexSelector &selector);
86
97
  bool xt_css_match(const Node *node, const ComplexSelector &selector, const MatchState &state);
87
98
 
99
+ /** True when a raw `@media` prelude matches a viewport. Supports media types
100
+ * (`all`/`screen`), comma-separated query lists, `not`/`only`, `and`, and the
101
+ * width/height/orientation/hover/pointer/colour-scheme features (with
102
+ * `min-`/`max-` ranges). Unknown features never match, as in a browser. */
103
+ bool xt_css_media_matches(const std::string &query, float viewport_width, float viewport_height);
104
+
105
+ /** Split `text` at top-level commas (outside `(...)`, `[...]` and quotes),
106
+ * trimming each part and dropping empty ones. */
107
+ std::vector<std::string> xt_css_split_commas(const std::string &text);
108
+
88
109
  Length xt_css_parse_length(const std::string &value);
89
110
  Color xt_css_parse_color(const std::string &value);
90
111
  bool xt_css_parse_number(const std::string &value, float *out);
@@ -132,6 +132,9 @@ bool matchPseudo(const Node *node, const std::string &pseudo, const MatchState &
132
132
 
133
133
  bool matchCompound(const Node *node, const CompoundSelector &compound, const MatchState &state) {
134
134
  if (!node->isElement()) return false;
135
+ /* A pseudo-element selector matches a generated node, never the origin
136
+ * element; the cascade matches it separately in `style.cpp`. */
137
+ if (!compound.pseudo_element.empty()) return false;
135
138
  if (!compound.tag.empty() && node->tag != compound.tag) return false;
136
139
  if (!compound.id.empty()) {
137
140
  const std::string *id = node->attr("id");