ranger-compiler 3.5.1 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/CHANGELOG.md +1064 -20
  2. package/LICENSE +3 -1
  3. package/README.md +123 -28
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79923 -56921
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,883 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGInspect — what the tree IS, for a panel that can ask
5
+ ; ==============================================================================
6
+ ;
7
+ ; An EVG app in a browser is one <canvas>, and a browser's dev tools have
8
+ ; nothing to say about it. Three descriptions already come out of the same
9
+ ; laid-out tree — `EVGDisplayList` (what to draw), `EVGHitTest` (what is under
10
+ ; the pointer) and `EVGA11yFromTree` (what it means). This is the fourth, and
11
+ ; it obeys the same rule they do: it is DERIVED from the tree that was laid
12
+ ; out, on the same pass, and it recomputes nothing.
13
+ ;
14
+ ; That rule is the whole design. Every rectangle reported here is the one
15
+ ; `EVGLayout` computed and the display list drew, read off `calculatedX` and
16
+ ; friends. Nothing here has a second opinion about geometry, so the panel
17
+ ; cannot disagree with the picture.
18
+ ;
19
+ ; --- IDENTITY -----------------------------------------------------------------
20
+ ;
21
+ ; `EVGElement.id` is not an identity: it is optional, it is the app's own test
22
+ ; id, and most elements have none. So the identity is a PATH, assigned here and
23
+ ; nowhere else:
24
+ ;
25
+ ; "0" the root
26
+ ; "0/3" its fourth child
27
+ ; "0/3/k:share" a child with `key` set uses the key instead of the index
28
+ ;
29
+ ; The same trick `EVGComponentHost` plays with `enter`/`leave`: a name unique
30
+ ; among siblings composes into a name unique in the tree, with no registry.
31
+ ;
32
+ ; It is STRUCTURAL, and the cost is honest — insert an unkeyed row above the
33
+ ; selected one and the path names a different element. Keyed children are
34
+ ; immune, which is the set a list rebuild actually reorders. A panel whose
35
+ ; path stops resolving must drop the selection and say so, never re-point it
36
+ ; at whatever is now at that index.
37
+ ;
38
+ ; --- WHY THE ELEMENT CARRIES A SLOT -------------------------------------------
39
+ ;
40
+ ; `build` stamps `el.inspectSlot`. Two things need to go from an element back
41
+ ; to a node and Ranger has no identity comparison for objects: the hit test,
42
+ ; which answers with an element, and the display list, which stamps the
43
+ ; emitting element on each command. One int on the element buys both, and the
44
+ ; alternative — a second walk that reimplements the paint order — is exactly
45
+ ; the drift this file exists to avoid.
46
+ ; ==============================================================================
47
+
48
+ Import "EVGElement.rgr"
49
+ Import "EVGBox.rgr"
50
+ Import "EVGColor.rgr"
51
+ Import "EVGHitTest.rgr"
52
+ Import "EVGStyleSheet.rgr"
53
+ Import "EVGDisplayList.rgr"
54
+
55
+ ; ==============================================================================
56
+ ; EVGInspectForce — states held on, by node path
57
+ ; ==============================================================================
58
+ ;
59
+ ; A menu that closes when the pointer leaves it cannot be looked at, and a
60
+ ; `:hover` rule cannot be edited while the only way to see it is to keep the
61
+ ; mouse somewhere other than the panel. Chrome answers this with the `:hov`
62
+ ; toggles and so does this: the four interaction bits are held ON for a node
63
+ ; until they are let go.
64
+ ;
65
+ ; They are the four `EVGPseudo.holds` reads — `isHovered`, `isFocused`,
66
+ ; `isPressed`, `a11yDisabled` — so nothing new has to be taught to the cascade.
67
+ ; A held state is an ordinary state as far as every rule is concerned.
68
+ ;
69
+ ; KEYED BY PATH, NOT BY ELEMENT, and that is the whole reason this works at
70
+ ; all. A page built from tree literals throws its elements away on every input,
71
+ ; so a flag written onto an element would last one frame. A path is a fact
72
+ ; about the tree's shape, so it names whatever element is in that position on
73
+ ; the next pass too.
74
+ ;
75
+ ; A singleton because the table has to outlive the walk that reads it and every
76
+ ; element in the tree, and because the alternative is a field on every app that
77
+ ; wants the feature.
78
+ ;
79
+ ; ON only, like the browser's. Forcing a state OFF is a different thing — it
80
+ ; would be arguing with the app about what is happening rather than holding
81
+ ; still something that already is.
82
+ ; ==============================================================================
83
+
84
+ class EVGInspectForce @singleton(true) {
85
+ def paths:[string]
86
+ def bits:[int]
87
+
88
+ Constructor () {
89
+ def a:[string]
90
+ paths = a
91
+ def b:[int]
92
+ bits = b
93
+ }
94
+
95
+ sfn HOVER:int () { return 1 }
96
+ sfn FOCUS:int () { return 2 }
97
+ sfn PRESSED:int () { return 4 }
98
+ sfn DISABLED:int () { return 8 }
99
+
100
+ fn indexOf:int (path:string) {
101
+ def i:int 0
102
+ while (i < (array_length paths)) {
103
+ if ((itemAt paths i) == path) {
104
+ return i
105
+ }
106
+ i = (i + 1)
107
+ }
108
+ return (0 - 1)
109
+ }
110
+
111
+ ; `b` of 0 lets the node go rather than recording "nothing held", so an
112
+ ; empty table is exactly "nothing is held" and the check that skips the
113
+ ; whole feature is one array length.
114
+ fn set:void (path:string b:int) {
115
+ def at:int (this.indexOf(path))
116
+ if (b == 0) {
117
+ if (at >= 0) {
118
+ remove_index paths at
119
+ remove_index bits at
120
+ }
121
+ return
122
+ }
123
+ if (at < 0) {
124
+ push paths path
125
+ push bits b
126
+ return
127
+ }
128
+ set_at bits at b
129
+ }
130
+
131
+ fn get:int (path:string) {
132
+ def at:int (this.indexOf(path))
133
+ if (at < 0) {
134
+ return 0
135
+ }
136
+ return (itemAt bits at)
137
+ }
138
+
139
+ fn count:int () {
140
+ return (array_length paths)
141
+ }
142
+
143
+ fn clearAll:void () {
144
+ def a:[string]
145
+ paths = a
146
+ def b:[int]
147
+ bits = b
148
+ }
149
+ }
150
+
151
+ class EVGInspect {
152
+ ; Parallel arrays, indexed by slot. A flat tree with a parent id is the
153
+ ; shape `EVGA11yTree` already crosses this seam with, so a host learns one
154
+ ; format and not two.
155
+ def paths:[string]
156
+ def parentPaths:[string]
157
+ def els:[EVGElement]
158
+ def index:[string:int]
159
+ def built:boolean false
160
+
161
+ Constructor () {
162
+ def a:[string]
163
+ paths = a
164
+ def b:[string]
165
+ parentPaths = b
166
+ def c:[EVGElement]
167
+ els = c
168
+ def d:[string:int]
169
+ index = d
170
+ }
171
+
172
+ ; --- the walk -------------------------------------------------------------
173
+
174
+ fn build:void (root:EVGElement) {
175
+ def a:[string]
176
+ paths = a
177
+ def b:[string]
178
+ parentPaths = b
179
+ def c:[EVGElement]
180
+ els = c
181
+ def d:[string:int]
182
+ index = d
183
+ this.visit(root "0" "")
184
+ built = true
185
+ }
186
+
187
+ fn visit:void (el:EVGElement path:string parentPath:string) {
188
+ def slot:int (array_length paths)
189
+ push paths path
190
+ push parentPaths parentPath
191
+ push els el
192
+ set index path slot
193
+ el.inspectSlot = slot
194
+ def i:int 0
195
+ while (i < (array_length el.children)) {
196
+ def kid:EVGElement (itemAt el.children i)
197
+ def seg:string (to_string i)
198
+ if ((strlen kid.key) > 0) {
199
+ seg = ("k:" + kid.key)
200
+ }
201
+ def kidPath:string ((path + "/") + seg)
202
+ this.visit(kid kidPath path)
203
+ i = (i + 1)
204
+ }
205
+ }
206
+
207
+ fn count:int () {
208
+ return (array_length paths)
209
+ }
210
+
211
+ fn pathAt:string (slot:int) {
212
+ if (slot < 0) {
213
+ return ""
214
+ }
215
+ if (slot >= (array_length paths)) {
216
+ return ""
217
+ }
218
+ return (itemAt paths slot)
219
+ }
220
+
221
+ ; The path of a node's parent. `visit` already recorded it, so this is a
222
+ ; lookup and not a string operation — which matters because a keyed segment
223
+ ; ("0/3/k:share") cannot be cut off by searching for the last "/".
224
+ fn parentOf:string (path:string) {
225
+ def slot:int (this.slotOf(path))
226
+ if (slot < 0) {
227
+ return ""
228
+ }
229
+ return (itemAt parentPaths slot)
230
+ }
231
+
232
+ fn slotOf:int (path:string) {
233
+ def at@(optional):int (get index path)
234
+ if (null? at) {
235
+ return (0 - 1)
236
+ }
237
+ return (unwrap at)
238
+ }
239
+
240
+ fn elementAt@(optional):EVGElement (path:string) {
241
+ def slot:int (this.slotOf(path))
242
+ if (slot < 0) {
243
+ def miss@(optional):EVGElement
244
+ return miss
245
+ }
246
+ def hit@(optional):EVGElement (itemAt els slot)
247
+ return hit
248
+ }
249
+
250
+ ; A point to a node, through the REAL hit test — the same paint order the
251
+ ; display list draws in, overlays deferred, topmost wins. Nothing about
252
+ ; that order is restated here; the element that comes back is turned into
253
+ ; a path by the slot it was stamped with.
254
+ fn hitPath:string (root:EVGElement px:double py:double) {
255
+ def hit (new EVGHitTest())
256
+ def order:[EVGElement] (hit.paintOrderAt(root px py))
257
+ def i:int ((array_length order) - 1)
258
+ while (i >= 0) {
259
+ def el:EVGElement (itemAt order i)
260
+ if (EVGHitTest.containsPoint(el px py)) {
261
+ return (this.pathAt(el.inspectSlot))
262
+ }
263
+ i = (i - 1)
264
+ }
265
+ return ""
266
+ }
267
+
268
+ ; --- the tree -------------------------------------------------------------
269
+
270
+ fn treeJson:string (title:string gen:int w:double h:double) {
271
+ def out:string "{\"evginspect\":1,\"title\":"
272
+ out = (out + (EVGInspect.jsonString(title)))
273
+ out = (out + ",\"gen\":" + (to_string gen))
274
+ out = (out + ",\"w\":" + (EVGDisplayList.num(w)))
275
+ out = (out + ",\"h\":" + (EVGDisplayList.num(h)))
276
+ out = (out + ",\"root\":\"0\",\"nodes\":[")
277
+ def i:int 0
278
+ while (i < (array_length paths)) {
279
+ if (i > 0) {
280
+ out = (out + ",")
281
+ }
282
+ out = (out + (this.nodeBrief(i)))
283
+ i = (i + 1)
284
+ }
285
+ return (out + "]}")
286
+ }
287
+
288
+ fn nodeBrief:string (slot:int) {
289
+ def el:EVGElement (itemAt els slot)
290
+ def bx:EVGBox el.box
291
+ def out:string "{\"id\":"
292
+ out = (out + (EVGInspect.jsonString((itemAt paths slot))))
293
+ def pp:string (itemAt parentPaths slot)
294
+ if ((strlen pp) > 0) {
295
+ out = (out + ",\"p\":" + (EVGInspect.jsonString(pp)))
296
+ }
297
+ out = (out + ",\"slot\":" + (to_string slot))
298
+ out = (out + ",\"tag\":" + (EVGInspect.jsonString(el.tagName)))
299
+ if ((strlen el.id) > 0) {
300
+ out = (out + ",\"tid\":" + (EVGInspect.jsonString(el.id)))
301
+ }
302
+ if ((strlen el.className) > 0) {
303
+ out = (out + ",\"cls\":" + (EVGInspect.jsonString(el.className)))
304
+ }
305
+ if ((strlen el.role) > 0) {
306
+ out = (out + ",\"role\":" + (EVGInspect.jsonString(el.role)))
307
+ }
308
+ def txt:string (EVGInspect.clip(el.textContent 80))
309
+ if ((strlen txt) > 0) {
310
+ out = (out + ",\"text\":" + (EVGInspect.jsonString(txt)))
311
+ }
312
+ ; The border box: what was painted, what the hit test tests.
313
+ out = (out + ",\"box\":[" + (EVGDisplayList.num(el.calculatedX)))
314
+ out = (out + "," + (EVGDisplayList.num(el.calculatedY)))
315
+ out = (out + "," + (EVGDisplayList.num(el.calculatedWidth)))
316
+ out = (out + "," + (EVGDisplayList.num(el.calculatedHeight)) + "]")
317
+ ; The four rings, resolved to pixels by `EVGBox`. The authored units
318
+ ; are in the detail, where the difference between `1em` and `12px` is
319
+ ; the answer to a different question.
320
+ out = (out + ",\"m\":[" + (EVGDisplayList.num(bx.marginTopPx)))
321
+ out = (out + "," + (EVGDisplayList.num(bx.marginRightPx)))
322
+ out = (out + "," + (EVGDisplayList.num(bx.marginBottomPx)))
323
+ out = (out + "," + (EVGDisplayList.num(bx.marginLeftPx)) + "]")
324
+ out = (out + ",\"b\":" + (EVGDisplayList.num(bx.borderWidthPx)))
325
+ out = (out + ",\"pd\":[" + (EVGDisplayList.num(bx.paddingTopPx)))
326
+ out = (out + "," + (EVGDisplayList.num(bx.paddingRightPx)))
327
+ out = (out + "," + (EVGDisplayList.num(bx.paddingBottomPx)))
328
+ out = (out + "," + (EVGDisplayList.num(bx.paddingLeftPx)) + "]")
329
+ def flags:string (this.flagsOf(el))
330
+ if ((strlen flags) > 0) {
331
+ out = (out + ",\"flags\":[" + flags + "]")
332
+ }
333
+ out = (out + ",\"kids\":" + (to_string (array_length el.children)))
334
+ return (out + "}")
335
+ }
336
+
337
+ ; The booleans that change how a node BEHAVES rather than how it looks.
338
+ ; The state ones are here because a `:hover` rule that won is unreadable
339
+ ; without knowing the element is hovered.
340
+ fn flagsOf:string (el:EVGElement) {
341
+ def out:string ""
342
+ if el.isAbsolute {
343
+ out = (EVGInspect.addFlag(out "abs"))
344
+ }
345
+ if (el.isSurface()) {
346
+ out = (EVGInspect.addFlag(out "overlay"))
347
+ }
348
+ if (el.clipsContent()) {
349
+ out = (EVGInspect.addFlag(out "clip"))
350
+ }
351
+ if el.isInline {
352
+ out = (EVGInspect.addFlag(out "inline"))
353
+ }
354
+ if el.isHovered {
355
+ out = (EVGInspect.addFlag(out "hover"))
356
+ }
357
+ if el.isFocused {
358
+ out = (EVGInspect.addFlag(out "focus"))
359
+ }
360
+ if el.isPressed {
361
+ out = (EVGInspect.addFlag(out "pressed"))
362
+ }
363
+ if el.a11yHidden {
364
+ out = (EVGInspect.addFlag(out "a11y-hidden"))
365
+ }
366
+ return out
367
+ }
368
+
369
+ sfn addFlag:string (soFar:string name:string) {
370
+ if ((strlen soFar) == 0) {
371
+ return ("\"" + name + "\"")
372
+ }
373
+ return (((soFar + ",\"") + name) + "\"")
374
+ }
375
+
376
+ ; --- the detail -----------------------------------------------------------
377
+ ;
378
+ ; Fetched for one node at a time and never for the whole tree: a dashboard
379
+ ; is twelve hundred elements and nobody is going to read every computed
380
+ ; property of all of them.
381
+ ;
382
+ ; `inline` is not guessed. `EVGElement.inlineProps` is what the cascade
383
+ ; itself consults to know what it must not overwrite, so it is the authoring
384
+ ; layer's own record of what was set on the element, read rather than
385
+ ; inferred.
386
+
387
+ fn nodeJson:string (path:string) {
388
+ def slot:int (this.slotOf(path))
389
+ if (slot < 0) {
390
+ return "{\"error\":\"no such node\"}"
391
+ }
392
+ def el:EVGElement (itemAt els slot)
393
+ def bx:EVGBox el.box
394
+ def out:string "{\"id\":"
395
+ out = (out + (EVGInspect.jsonString(path)))
396
+ out = (out + ",\"computed\":{")
397
+ def n:int 0
398
+ n = (this.prop(n "display" el.display))
399
+ ; `position` is reported as the layout USED it, not as the field reads.
400
+ ;
401
+ ; The cascade has no `position` branch — `EVGElement.setAttribute` does
402
+ ; not know the name — so a rule saying `position: absolute` never
403
+ ; reaches the field, and `hasAbsolutePosition` decides out-of-flow from
404
+ ; the offsets, the overlay flag and the tag instead. An element that a
405
+ ; rule made absolute therefore still reads "relative", and a panel
406
+ ; printing the field would be reporting a value nothing consulted.
407
+ ;
408
+ ; Two consequences worth knowing rather than hiding: `position:
409
+ ; absolute` with no offsets is silently ignored by this engine, and the
410
+ ; check in `inspect-check.mjs` is what would catch it, because the
411
+ ; effective value would then disagree with the rule that asked for it.
412
+ def pos:string el.position
413
+ if el.isAbsolute {
414
+ pos = "absolute"
415
+ }
416
+ n = (this.prop(n "position" pos))
417
+ n = (this.prop(n "flex-direction" el.flexDirection))
418
+ n = (this.prop(n "justify-content" el.justifyContent))
419
+ n = (this.prop(n "align-items" el.alignItems))
420
+ n = (this.prop(n "align-content" el.alignContent))
421
+ n = (this.prop(n "flex-wrap" el.flexWrap))
422
+ n = (this.numProp(n "flex-grow" el.flex))
423
+ n = (this.numProp(n "flex-shrink" el.flexShrink))
424
+ n = (this.unitProp(n "flex-basis" el.flexBasis))
425
+ n = (this.prop(n "grid-template-columns" el.gridTemplateColumns))
426
+ n = (this.prop(n "grid-template-rows" el.gridTemplateRows))
427
+ n = (this.prop(n "grid-area" el.gridArea))
428
+ n = (this.unitProp(n "gap" el.gap))
429
+ n = (this.unitProp(n "width" el.width))
430
+ n = (this.unitProp(n "height" el.height))
431
+ n = (this.unitProp(n "min-width" el.minWidth))
432
+ n = (this.unitProp(n "min-height" el.minHeight))
433
+ n = (this.unitProp(n "max-width" el.maxWidth))
434
+ n = (this.unitProp(n "max-height" el.maxHeight))
435
+ n = (this.unitProp(n "left" el.left))
436
+ n = (this.unitProp(n "top" el.top))
437
+ n = (this.unitProp(n "right" el.right))
438
+ n = (this.unitProp(n "bottom" el.bottom))
439
+ n = (this.pxProp(n "margin-top" bx.marginTopPx))
440
+ n = (this.pxProp(n "margin-right" bx.marginRightPx))
441
+ n = (this.pxProp(n "margin-bottom" bx.marginBottomPx))
442
+ n = (this.pxProp(n "margin-left" bx.marginLeftPx))
443
+ n = (this.pxProp(n "padding-top" bx.paddingTopPx))
444
+ n = (this.pxProp(n "padding-right" bx.paddingRightPx))
445
+ n = (this.pxProp(n "padding-bottom" bx.paddingBottomPx))
446
+ n = (this.pxProp(n "padding-left" bx.paddingLeftPx))
447
+ n = (this.pxProp(n "border-width" bx.borderWidthPx))
448
+ n = (this.pxProp(n "border-radius" bx.borderRadiusPx))
449
+ n = (this.colorProp(n "border-color" bx.borderColor))
450
+ n = (this.colorProp(n "background-color" el.backgroundColor))
451
+ n = (this.colorProp(n "color" el.color))
452
+ n = (this.numProp(n "opacity" el.opacity))
453
+ n = (this.prop(n "background-gradient" el.backgroundGradient))
454
+ n = (this.prop(n "font-family" el.fontFamily))
455
+ n = (this.unitProp(n "font-size" el.fontSize))
456
+ n = (this.prop(n "font-weight" el.fontWeight))
457
+ n = (this.numProp(n "line-height" el.lineHeight))
458
+ n = (this.prop(n "text-align" el.textAlign))
459
+ n = (this.prop(n "overflow" el.overflow))
460
+ n = (this.prop(n "cursor" el.cursor))
461
+ n = (this.prop(n "transition" el.transitionSpec))
462
+ n = (this.prop(n "transform" el.transformSpec))
463
+ n = (this.numProp(n "rotate" el.rotate))
464
+ n = (this.numProp(n "scale" el.scale))
465
+ n = (this.prop(n "class" el.className))
466
+ n = (this.prop(n "theme" el.theme))
467
+ n = (this.prop(n "src" el.src))
468
+ n = (this.prop(n "object-fit" el.objectFit))
469
+ out = (out + acc)
470
+ out = (out + "}")
471
+
472
+ ; The authoring layer's own record, not a guess. An entry here outranks
473
+ ; every stylesheet rule and that is why the cascade keeps the list.
474
+ out = (out + ",\"inline\":[")
475
+ def k:int 0
476
+ while (k < (array_length el.inlineProps)) {
477
+ if (k > 0) {
478
+ out = (out + ",")
479
+ }
480
+ out = (out + (EVGInspect.jsonString((itemAt el.inlineProps k))))
481
+ k = (k + 1)
482
+ }
483
+ out = (out + "]")
484
+
485
+ ; Geometry a panel draws the box diagram from, in one place so the
486
+ ; diagram is not four subtractions done in a browser.
487
+ def cx:double ((el.calculatedX + bx.borderWidthPx) + bx.paddingLeftPx)
488
+ def cy:double ((el.calculatedY + bx.borderWidthPx) + bx.paddingTopPx)
489
+ def chW:double (bx.getPaddingHorizontal())
490
+ def chH:double (bx.getPaddingVertical())
491
+ def bw2:double (bx.borderWidthPx * 2.0)
492
+ def cw:double (((el.calculatedWidth - chW) - bw2))
493
+ def ch:double (((el.calculatedHeight - chH) - bw2))
494
+ out = (out + ",\"content\":[" + (EVGDisplayList.num(cx)))
495
+ out = (out + "," + (EVGDisplayList.num(cy)))
496
+ out = (out + "," + (EVGDisplayList.num(cw)))
497
+ out = (out + "," + (EVGDisplayList.num(ch)) + "]")
498
+
499
+ out = (out + (this.cascadeJson(el)))
500
+ out = (out + ",\"forced\":" + (to_string (EVGInspect.forcedState(path))))
501
+ out = (out + ",\"styleSlot\":" + (to_string el.styleSlot))
502
+ out = (out + ",\"styleClass\":" + (EVGInspect.jsonString(el.styleClass)))
503
+ out = (out + ",\"page\":" + (to_string el.calculatedPage))
504
+ def full:string (EVGInspect.clip(el.textContent 400))
505
+ out = (out + ",\"textFull\":" + (EVGInspect.jsonString(full)))
506
+ return (out + "}")
507
+ }
508
+
509
+ ; --- what set this value --------------------------------------------------
510
+ ;
511
+ ; Which classes reach this element, and which rules under them wrote what.
512
+ ;
513
+ ; Read out of the PLAN, which is where `buildPlan` recorded the rule beside
514
+ ; every declaration it flattened. Nothing is re-matched and no specificity
515
+ ; is scored here: the plan's order is the cascade's order, so the LAST
516
+ ; entry for a property is the winner and the ones before it are the ones it
517
+ ; beat. That is why the panel cannot disagree with the engine about who
518
+ ; won — it is not deciding, it is reading.
519
+ ;
520
+ ; Empty when no sheet was given, which is the honest answer for a host that
521
+ ; has not offered one rather than a guess assembled from the element.
522
+
523
+ def sheet@(optional):EVGStyleSheet
524
+ def tally:[string]
525
+ def tallyCount:[int]
526
+
527
+ fn useSheet:void (s:EVGStyleSheet) {
528
+ sheet = s
529
+ }
530
+
531
+ ; How many elements in this tree carry a class. The panel shows it before
532
+ ; you edit a rule, because this cascade selects on classes alone: there is
533
+ ; no way to reach one instance without giving it a class of its own, and
534
+ ; ".db-card" is four cards whether or not that was the intention.
535
+ fn countClass:int (want:string) {
536
+ def n:int 0
537
+ def i:int 0
538
+ while (i < (array_length els)) {
539
+ def el:EVGElement (itemAt els i)
540
+ def classes:[string] (EVGInspect.splitWs(el.className))
541
+ def j:int 0
542
+ while (j < (array_length classes)) {
543
+ if ((itemAt classes j) == want) {
544
+ n = (n + 1)
545
+ j = (array_length classes)
546
+ } {
547
+ j = (j + 1)
548
+ }
549
+ }
550
+ i = (i + 1)
551
+ }
552
+ return n
553
+ }
554
+
555
+ fn cascadeJson:string (el:EVGElement) {
556
+ def out:string ",\"classes\":["
557
+ def classes:[string] (EVGInspect.splitWs(el.className))
558
+ def c:int 0
559
+ while (c < (array_length classes)) {
560
+ if (c > 0) {
561
+ out = (out + ",")
562
+ }
563
+ def nm:string (itemAt classes c)
564
+ out = (out + "{\"name\":" + (EVGInspect.jsonString(nm)))
565
+ out = (out + ",\"matches\":" + (to_string (this.countClass(nm))) + "}")
566
+ c = (c + 1)
567
+ }
568
+ out = (out + "]")
569
+ if (null? sheet) {
570
+ return (out + ",\"cascade\":[]")
571
+ }
572
+ def sh:EVGStyleSheet (unwrap sheet)
573
+ def slot:int el.styleSlot
574
+ def n:int (sh.planLength(slot))
575
+ if (n == 0) {
576
+ return (out + ",\"cascade\":[]")
577
+ }
578
+ ; The winner of each property is the last entry that names it, so one
579
+ ; backwards pass marks the winners and everything else lost.
580
+ def wonAt:[int]
581
+ def seen:[string]
582
+ def i:int (n - 1)
583
+ while (i >= 0) {
584
+ def nm2:string (sh.planNameAt(slot i))
585
+ def already:boolean false
586
+ def k:int 0
587
+ while (k < (array_length seen)) {
588
+ if ((itemAt seen k) == nm2) {
589
+ already = true
590
+ k = (array_length seen)
591
+ } {
592
+ k = (k + 1)
593
+ }
594
+ }
595
+ if already {
596
+ push wonAt 0
597
+ } {
598
+ push wonAt 1
599
+ push seen nm2
600
+ }
601
+ i = (i - 1)
602
+ }
603
+ ; `wonAt` was filled backwards, so entry `i` is at `n - 1 - i`.
604
+ out = (out + ",\"cascade\":[")
605
+ def w:int 0
606
+ while (w < n) {
607
+ if (w > 0) {
608
+ out = (out + ",")
609
+ }
610
+ def ruleIdx:int (sh.planRuleAt(slot w))
611
+ out = (out + "{\"p\":" + (EVGInspect.jsonString((sh.planNameAt(slot w)))))
612
+ out = (out + ",\"v\":" + (EVGInspect.jsonString((sh.planValueAt(slot w)))))
613
+ out = (out + ",\"sel\":" + (EVGInspect.jsonString((sh.selectorOf(ruleIdx)))))
614
+ def med:string (sh.ruleMediaOf(ruleIdx))
615
+ if ((strlen med) > 0) {
616
+ out = (out + ",\"media\":" + (EVGInspect.jsonString(med)))
617
+ }
618
+ def cls:string (sh.ruleClassOf(ruleIdx))
619
+ if ((strlen cls) > 0) {
620
+ out = (out + ",\"cls\":" + (EVGInspect.jsonString(cls)))
621
+ }
622
+ def isWin:int (itemAt wonAt ((n - 1) - w))
623
+ if (isWin == 1) {
624
+ out = (out + ",\"win\":true")
625
+ }
626
+ ; An inline attribute outranks every rule, so a declaration the
627
+ ; element has set on itself never lands however the plan reads.
628
+ ; Marked rather than dropped: "the app writes this one" is the
629
+ ; answer to why editing the sheet did nothing.
630
+ def nm3:string (sh.planNameAt(slot w))
631
+ if (el.hasInline(nm3)) {
632
+ out = (out + ",\"beatenByInline\":true")
633
+ }
634
+ out = (out + "}")
635
+ w = (w + 1)
636
+ }
637
+ return (out + "]")
638
+ }
639
+
640
+ sfn splitWs:[string] (v:string) {
641
+ def out:[string]
642
+ def cur:string ""
643
+ def i:int 0
644
+ while (i < (strlen v)) {
645
+ def ch:int (charAt v i)
646
+ if ((((ch == 32) || (ch == 9)) || (ch == 10)) || (ch == 13)) {
647
+ if ((strlen cur) > 0) {
648
+ push out cur
649
+ cur = ""
650
+ }
651
+ } {
652
+ cur = (cur + (strfromcode ch))
653
+ }
654
+ i = (i + 1)
655
+ }
656
+ if ((strlen cur) > 0) {
657
+ push out cur
658
+ }
659
+ return out
660
+ }
661
+
662
+ ; The property writer. An accumulator field rather than a returned string,
663
+ ; because fifty `out = (out + this.prop(...))` lines would each be a
664
+ ; concatenation of the whole buffer so far.
665
+ def acc:string ""
666
+
667
+ fn prop:int (n:int name:string value:string) {
668
+ if ((strlen value) == 0) {
669
+ return n
670
+ }
671
+ return (this.write(n name value))
672
+ }
673
+
674
+ fn pxProp:int (n:int name:string v:double) {
675
+ def s:string ((EVGDisplayList.num(v)) + "px")
676
+ return (this.write(n name s))
677
+ }
678
+
679
+ fn numProp:int (n:int name:string v:double) {
680
+ return (this.write(n name (EVGDisplayList.num(v))))
681
+ }
682
+
683
+ ; The unit fields are optional on the element, so the null is a real
684
+ ; answer here and not a defensive check: "this element never said anything
685
+ ; about width" is different from "it said auto".
686
+ fn unitProp:int (n:int name:string u@(optional):EVGUnit) {
687
+ if (null? u) {
688
+ return n
689
+ }
690
+ def uu:EVGUnit (unwrap u)
691
+ if (uu.isSet == false) {
692
+ return n
693
+ }
694
+ def s:string (uu.toString())
695
+ def px:string (EVGDisplayList.num(uu.pixels))
696
+ def asPx:string (px + "px")
697
+ if (s != asPx) {
698
+ s = ((s + " -> ") + asPx)
699
+ }
700
+ return (this.write(n name s))
701
+ }
702
+
703
+ fn colorProp:int (n:int name:string c@(optional):EVGColor) {
704
+ if (null? c) {
705
+ return n
706
+ }
707
+ def cc:EVGColor (unwrap c)
708
+ if (cc.isSet == false) {
709
+ return n
710
+ }
711
+ def s:string (cc.toCSSString())
712
+ return (this.write(n name s))
713
+ }
714
+
715
+ fn write:int (n:int name:string value:string) {
716
+ if (n == 0) {
717
+ acc = ""
718
+ }
719
+ if (n > 0) {
720
+ acc = (acc + ",")
721
+ }
722
+ acc = (acc + (EVGInspect.jsonString(name)))
723
+ acc = (acc + ":")
724
+ acc = (acc + (EVGInspect.jsonString(value)))
725
+ return (n + 1)
726
+ }
727
+
728
+ ; Hold what the panel asked to be held, on the tree as it is now.
729
+ ;
730
+ ; A host calls this between marking its OWN interaction states and running
731
+ ; the cascade — the order matters and it is the only thing a host has to
732
+ ; get right: after the app has said what is hovered, before the sheet is
733
+ ; asked which rules that makes true.
734
+ ;
735
+ ; Costs one array length when nothing is held, which is the normal case and
736
+ ; the whole shape of the guard.
737
+ sfn applyForced:void (root:EVGElement) {
738
+ def force:EVGInspectForce (EVGInspectForce.__singleton())
739
+ if ((force.count()) == 0) {
740
+ return
741
+ }
742
+ def ins (new EVGInspect())
743
+ ins.build(root)
744
+ def i:int 0
745
+ while (i < (array_length ins.paths)) {
746
+ def b:int (force.get((itemAt ins.paths i)))
747
+ if (b != 0) {
748
+ def el:EVGElement (itemAt ins.els i)
749
+ if ((b % 2) == 1) {
750
+ el.isHovered = true
751
+ }
752
+ def f:int (idiv b 2)
753
+ if ((f % 2) == 1) {
754
+ el.isFocused = true
755
+ }
756
+ def p:int (idiv b 4)
757
+ if ((p % 2) == 1) {
758
+ el.isPressed = true
759
+ }
760
+ def d:int (idiv b 8)
761
+ if ((d % 2) == 1) {
762
+ el.a11yDisabled = true
763
+ }
764
+ }
765
+ i = (i + 1)
766
+ }
767
+ }
768
+
769
+ sfn forceState:void (path:string bits:int) {
770
+ def force:EVGInspectForce (EVGInspectForce.__singleton())
771
+ force.set(path bits)
772
+ }
773
+
774
+ sfn forcedState:int (path:string) {
775
+ def force:EVGInspectForce (EVGInspectForce.__singleton())
776
+ return (force.get(path))
777
+ }
778
+
779
+ sfn forcedCount:int () {
780
+ def force:EVGInspectForce (EVGInspectForce.__singleton())
781
+ return (force.count())
782
+ }
783
+
784
+ sfn clearForced:void () {
785
+ def force:EVGInspectForce (EVGInspectForce.__singleton())
786
+ force.clearAll()
787
+ }
788
+
789
+ ; --- the three calls a host actually makes ---------------------------------
790
+ ;
791
+ ; A fresh walk per call rather than a cached instance, and deliberately: a
792
+ ; panel asks a handful of times per interaction, a walk over twelve hundred
793
+ ; elements is microseconds, and an instance kept between calls would be a
794
+ ; fourth thing that can go stale against a tree that was rebuilt. The paths
795
+ ; are a pure function of the tree's shape, so two walks over the same tree
796
+ ; agree by construction and `nodeOf` can be called without `treeOf` first.
797
+
798
+ sfn treeOf:string (root:EVGElement title:string gen:int w:double h:double) {
799
+ def ins (new EVGInspect())
800
+ ins.build(root)
801
+ return (ins.treeJson(title gen w h))
802
+ }
803
+
804
+ sfn nodeOf:string (root:EVGElement path:string) {
805
+ def ins (new EVGInspect())
806
+ ins.build(root)
807
+ return (ins.nodeJson(path))
808
+ }
809
+
810
+ ; The same, with the cascade. A host that has its stylesheet in hand should
811
+ ; call this one: without the sheet the detail can still say what the value IS,
812
+ ; and only with it can it say what SET it.
813
+ sfn nodeOfIn:string (root:EVGElement path:string sheet:EVGStyleSheet) {
814
+ def ins (new EVGInspect())
815
+ ins.build(root)
816
+ ins.useSheet(sheet)
817
+ return (ins.nodeJson(path))
818
+ }
819
+
820
+ sfn hitOf:string (root:EVGElement px:double py:double) {
821
+ def ins (new EVGInspect())
822
+ ins.build(root)
823
+ return (ins.hitPath(root px py))
824
+ }
825
+
826
+ ; The display list with every command carrying the element that emitted it.
827
+ ; The walk runs FIRST because attribution reads `inspectSlot`, and a slot
828
+ ; that has not been stamped this pass is -1 — which would attribute the
829
+ ; whole frame to nothing at all.
830
+ sfn frameOf:string (root:EVGElement) {
831
+ def ins (new EVGInspect())
832
+ ins.build(root)
833
+ def dl (new EVGDisplayList())
834
+ dl.attribute = true
835
+ dl.build(root)
836
+ return (dl.toJson())
837
+ }
838
+
839
+ ; --- helpers --------------------------------------------------------------
840
+
841
+ sfn clip:string (v:string limit:int) {
842
+ if ((strlen v) <= limit) {
843
+ return v
844
+ }
845
+ def cut:string (substring v 0 limit)
846
+ return (cut + "…")
847
+ }
848
+
849
+ sfn jsonString:string (v:string) {
850
+ def out:string "\""
851
+ def i:int 0
852
+ while (i < (strlen v)) {
853
+ def ch:int (charAt v i)
854
+ if (ch == 34) {
855
+ out = (out + "\\\"")
856
+ } {
857
+ if (ch == 92) {
858
+ out = (out + "\\\\")
859
+ } {
860
+ if (ch == 10) {
861
+ out = (out + "\\n")
862
+ } {
863
+ if (ch == 13) {
864
+ out = (out + "\\r")
865
+ } {
866
+ if (ch == 9) {
867
+ out = (out + "\\t")
868
+ } {
869
+ if (ch < 32) {
870
+ out = (out + " ")
871
+ } {
872
+ out = (out + (strfromcode ch))
873
+ }
874
+ }
875
+ }
876
+ }
877
+ }
878
+ }
879
+ i = (i + 1)
880
+ }
881
+ return (out + "\"")
882
+ }
883
+ }