ranger-compiler 3.5.0 → 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 +1160 -19
  2. package/LICENSE +3 -1
  3. package/README.md +124 -29
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79924 -56922
  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,421 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGReconcileTest — a rebuilt tree keeps its elements, and says nothing new
5
+ ; ==============================================================================
6
+ ;
7
+ ; There is no browser to measure here: no engine ships a "keyed reconciliation"
8
+ ; you can read pixels off. So the oracle is an INVARIANT rather than a capture,
9
+ ; and the invariant is the strongest one available:
10
+ ;
11
+ ; Reconciling a live tree against a freshly built one must leave it
12
+ ; describing exactly what a tree built from scratch would describe.
13
+ ;
14
+ ; Checked on all four things a tree produces — the display list, the laid-out
15
+ ; boxes, the hit test and the accessible tree. That is what makes the check
16
+ ; field-agnostic: `adoptFrom` copies 180 fields by name, and a field somebody
17
+ ; adds to `EVGElement` and forgets to add there would be silently dropped on
18
+ ; every rebuild. It cannot hide from this, because a dropped field that changes
19
+ ; nothing observable changes nothing at all. (`scripts/check-evg-adopt.mjs`
20
+ ; catches the same mistake earlier and by name.)
21
+ ;
22
+ ; The second half is the point of the exercise: an element that SURVIVES keeps
23
+ ; its transitions, and one that is replaced does not. That is checked by
24
+ ; putting a real flight on a row, reconciling, and asking whether it is still
25
+ ; in the air — which is the difference between a row that slides and a row that
26
+ ; teleports, and the reason `SortableDemo.applyShift()` exists.
27
+ ; ==============================================================================
28
+
29
+ Import "EVGElement.rgr"
30
+ Import "EVGUnit.rgr"
31
+ Import "EVGStyleSheet.rgr"
32
+ Import "EVGLayout.rgr"
33
+ Import "EVGDisplayList.rgr"
34
+ Import "EVGTransition.rgr"
35
+ Import "EVGHitTest.rgr"
36
+ Import "EVGA11yTree.rgr"
37
+ Import "EVGA11yFromTree.rgr"
38
+ Import "EVGReconcile.rgr"
39
+
40
+ class RecCheck {
41
+ def passed:int 0
42
+ def failed:int 0
43
+
44
+ fn ok:void (name:string cond:boolean) {
45
+ if cond {
46
+ passed = (passed + 1)
47
+ print (" PASS " + name)
48
+ } {
49
+ failed = (failed + 1)
50
+ print (" FAIL " + name)
51
+ }
52
+ }
53
+
54
+ fn eqStr:void (name:string got:string want:string) {
55
+ def good:boolean (got == want)
56
+ if (good == false) {
57
+ print (" got " + got)
58
+ print (" want " + want)
59
+ }
60
+ this.ok(name good)
61
+ }
62
+
63
+ fn eqInt:void (name:string got:int want:int) {
64
+ this.eqStr(name (to_string got) (to_string want))
65
+ }
66
+ }
67
+
68
+ class EVGReconcileTest {
69
+
70
+ ; --- the fixture ------------------------------------------------------------
71
+ ; A list of rows named by key, in the order given. Every row carries a
72
+ ; background that differs per row, so a row that ends up in the wrong place
73
+ ; is visible in the display list rather than only in a field nobody reads.
74
+
75
+ sfn sheetText:string () {
76
+ return (""
77
+ + ".list { display: flex; flex-direction: column; width: 200px; gap: 0px; }"
78
+ + ".row { height: 20px; width: 200px; transition: background-color 100ms linear; }"
79
+ + ".row-a { background-color: #ff0000; }"
80
+ + ".row-b { background-color: #00ff00; }"
81
+ + ".row-c { background-color: #0000ff; }"
82
+ + ".row-d { background-color: #ffff00; }")
83
+ }
84
+
85
+ sfn row:EVGElement (name:string keyed:boolean) {
86
+ def el (EVGElement.createDiv())
87
+ el.className = ("row row-" + name)
88
+ el.id = ("row-" + name)
89
+ el.textContent = name
90
+ el.role = "listitem"
91
+ el.a11yLabel = name
92
+ if keyed {
93
+ el.key = name
94
+ }
95
+ return el
96
+ }
97
+
98
+ ; `names` is one character per row: "abc" is three rows.
99
+ sfn list:EVGElement (names:string keyed:boolean) {
100
+ def el (EVGElement.createDiv())
101
+ el.className = "list"
102
+ el.id = "list"
103
+ el.role = "list"
104
+ el.a11yLabel = "rows"
105
+ def i:int 0
106
+ while (i < (strlen names)) {
107
+ ; `substring` here is (start, END) and not (start, length). The
108
+ ; first version passed 1 as the length, so every row after the
109
+ ; first was named "" — an unkeyed, textless row. Every invariant
110
+ ; check below still PASSED on that, because a degenerate fixture is
111
+ ; degenerate identically on both sides of an equality.
112
+ el.addChild((EVGReconcileTest.row((substring names i (i + 1)) keyed)))
113
+ i = (i + 1)
114
+ }
115
+ return el
116
+ }
117
+
118
+ ; --- the four derived artefacts ----------------------------------------------
119
+
120
+ sfn styled:EVGLayout (root:EVGElement) {
121
+ def s (new EVGStyleSheet())
122
+ s.parse((EVGReconcileTest.sheetText()))
123
+ s.setViewport(300.0 300.0 false)
124
+ s.applyTree(root "")
125
+ def lay (new EVGLayout())
126
+ lay.setPageSize(300.0 300.0)
127
+ lay.layout(root)
128
+ return lay
129
+ }
130
+
131
+ sfn paintOf:string (root:EVGElement) {
132
+ def lay:EVGLayout (EVGReconcileTest.styled(root))
133
+ def dl (new EVGDisplayList())
134
+ dl.setTextEngine((lay.getTextEngine()))
135
+ dl.build(root)
136
+ return (dl.toJson())
137
+ }
138
+
139
+ sfn treeOf:string (root:EVGElement) {
140
+ EVGReconcileTest.styled(root)
141
+ def b (new EVGA11yFromTree())
142
+ def t:EVGA11yTree (b.build(root "rec" 1 ""))
143
+ return (t.toJson())
144
+ }
145
+
146
+ ; Who is under each row's middle, top to bottom. One string, so a wrong
147
+ ; answer names itself.
148
+ sfn hitsOf:string (root:EVGElement) {
149
+ EVGReconcileTest.styled(root)
150
+ def h (new EVGHitTest())
151
+ def out:string ""
152
+ def y:double 10.0
153
+ while (y < 100.0) {
154
+ out = ((out + (h.idAt(root 100.0 y))) + "|")
155
+ y = (y + 20.0)
156
+ }
157
+ return out
158
+ }
159
+
160
+ ; --- the invariant ------------------------------------------------------------
161
+
162
+ sfn sameAsFresh:void (c:RecCheck label:string from:string to:string keyed:boolean) {
163
+ def live:EVGElement (EVGReconcileTest.list(from keyed))
164
+ def next:EVGElement (EVGReconcileTest.list(to keyed))
165
+ def r (new EVGReconcile())
166
+ r.reconcile(live next)
167
+
168
+ ; A third tree, built from scratch with the destination's data. `next`
169
+ ; was consumed by the reconcile and cannot be the comparison.
170
+ def fresh:EVGElement (EVGReconcileTest.list(to keyed))
171
+
172
+ c.eqStr((label + ": the display list") (EVGReconcileTest.paintOf(live)) (EVGReconcileTest.paintOf(fresh)))
173
+ c.eqStr((label + ": the accessible tree") (EVGReconcileTest.treeOf(live)) (EVGReconcileTest.treeOf(fresh)))
174
+ c.eqStr((label + ": the hit test") (EVGReconcileTest.hitsOf(live)) (EVGReconcileTest.hitsOf(fresh)))
175
+ c.eqInt((label + ": the child count") (array_length live.children) (array_length fresh.children))
176
+ }
177
+
178
+ sfn testInvariant:void (c:RecCheck) {
179
+ print "--- reconciled == freshly built ---"
180
+ EVGReconcileTest.sameAsFresh(c "unchanged" "abc" "abc" true)
181
+ EVGReconcileTest.sameAsFresh(c "reordered" "abc" "cab" true)
182
+ EVGReconcileTest.sameAsFresh(c "one inserted" "abc" "abdc" true)
183
+ EVGReconcileTest.sameAsFresh(c "one removed" "abc" "ac" true)
184
+ EVGReconcileTest.sameAsFresh(c "emptied" "abc" "" true)
185
+ EVGReconcileTest.sameAsFresh(c "filled from empty" "" "abc" true)
186
+ EVGReconcileTest.sameAsFresh(c "wholly replaced" "ab" "cd" true)
187
+ ; The same set of changes with no keys at all. The RESULT still has to
188
+ ; be right — an unkeyed list is not a broken list, it is a list whose
189
+ ; elements do not follow their data.
190
+ EVGReconcileTest.sameAsFresh(c "unkeyed, reordered" "abc" "cab" false)
191
+ EVGReconcileTest.sameAsFresh(c "unkeyed, one inserted" "abc" "abdc" false)
192
+ EVGReconcileTest.sameAsFresh(c "unkeyed, one removed" "abc" "ac" false)
193
+ }
194
+
195
+ ; --- what survives, which is the whole point ---------------------------------
196
+
197
+ sfn testKeepsElements:void (c:RecCheck) {
198
+ print "--- how much is kept ---"
199
+
200
+ def live:EVGElement (EVGReconcileTest.list("abc" true))
201
+ def r (new EVGReconcile())
202
+ r.reconcile(live (EVGReconcileTest.list("cab" true)))
203
+ ; Three rows in, three rows out, and not one of them rebuilt. Without
204
+ ; keys this same reorder keeps three elements too — but the WRONG
205
+ ; three, which is what the flight test below is for.
206
+ c.eqInt("a reorder keeps every element" r.stats.kept 3)
207
+ c.eqInt("and creates none" r.stats.created 0)
208
+ ; And every one of them actually MOVED. Without this, a reconciler that
209
+ ; ignores keys entirely and pairs children off by position scores the
210
+ ; same three-kept-none-created — it keeps three elements and puts the
211
+ ; wrong data on each. `moved` is what tells the two apart.
212
+ c.eqInt("and every one of them changed position" r.stats.moved 3)
213
+
214
+ def live2:EVGElement (EVGReconcileTest.list("abc" true))
215
+ def r2 (new EVGReconcile())
216
+ r2.reconcile(live2 (EVGReconcileTest.list("abdc" true)))
217
+ c.eqInt("an insert keeps the three that were there" r2.stats.kept 3)
218
+ c.eqInt("and creates exactly the new one" r2.stats.created 1)
219
+ c.eqInt("and drops nothing" r2.stats.dropped 0)
220
+
221
+ def live3:EVGElement (EVGReconcileTest.list("abc" true))
222
+ def r3 (new EVGReconcile())
223
+ r3.reconcile(live3 (EVGReconcileTest.list("ac" true)))
224
+ c.eqInt("a removal drops exactly one" r3.stats.dropped 1)
225
+ c.eqInt("and keeps the rest" r3.stats.kept 2)
226
+
227
+ ; A key names a LOGICAL child, and a tag names a kind of thing. Same
228
+ ; key, different tag is a different element — reusing one as the other
229
+ ; would carry a text node's leftovers into a button.
230
+ def live4 (EVGElement.createDiv())
231
+ def a (EVGElement.createDiv())
232
+ a.key = "x"
233
+ live4.addChild(a)
234
+ def next4 (EVGElement.createDiv())
235
+ def b (EVGElement.createDiv())
236
+ b.tagName = "button"
237
+ b.key = "x"
238
+ next4.addChild(b)
239
+ def r4 (new EVGReconcile())
240
+ r4.reconcile(live4 next4)
241
+ c.eqInt("same key, different tag is not a match" r4.stats.kept 0)
242
+ c.eqInt("it is built instead" r4.stats.created 1)
243
+ }
244
+
245
+ ; --- and what that buys: a flight that survives the rebuild --------------------
246
+ ;
247
+ ; This is the test the whole class exists for. Put a row mid-flight, rebuild
248
+ ; the list around it, and ask whether the flight is still in the air ON THE
249
+ ; ROW IT BELONGS TO. Keyed, the answer is yes and the row slides. Unkeyed,
250
+ ; the element stays but the DATA moves under it, so the flight lands on
251
+ ; whatever row happens to be in that position — which looks like the wrong
252
+ ; row animating, and is exactly the failure the demos work around by never
253
+ ; rebuilding at all.
254
+
255
+ sfn flightCount:int (el:EVGElement) {
256
+ return (array_length el.transitions)
257
+ }
258
+
259
+ sfn childByLabel@(optional):EVGElement (root:EVGElement label:string) {
260
+ def i:int 0
261
+ while (i < (array_length root.children)) {
262
+ def ch:EVGElement (itemAt root.children i)
263
+ if (ch.a11yLabel == label) {
264
+ def hit@(optional):EVGElement ch
265
+ return hit
266
+ }
267
+ i = (i + 1)
268
+ }
269
+ def miss@(optional):EVGElement
270
+ return miss
271
+ }
272
+
273
+ sfn testFlightSurvives:void (c:RecCheck) {
274
+ print "--- a flight survives a rebuild ---"
275
+
276
+ def live:EVGElement (EVGReconcileTest.list("abc" true))
277
+ def t (new EVGTransition())
278
+
279
+ ; Frame one, then SETTLE. The first reconcile of a transitioned
280
+ ; property does start a flight — from whatever the element had before
281
+ ; the sheet spoke — so "nothing is moving yet" has to be established by
282
+ ; running the clock out, not assumed. The first version of this test
283
+ ; assumed it, and read a leftover first-frame flight as proof that the
284
+ ; reconciler had put a row in motion.
285
+ EVGReconcileTest.styled(live)
286
+ t.reconcileTree(live)
287
+ t.advanceTree(live 500.0)
288
+ c.ok("nothing is moving once the first frame has settled" ((t.busy(live)) == false))
289
+
290
+ ; Now change what row `c` is: its class decides its colour, and the
291
+ ; sheet says background-color transitions over 100ms.
292
+ def cRow:EVGElement (unwrap (EVGReconcileTest.childByLabel(live "c")))
293
+ cRow.className = "row row-d"
294
+ EVGReconcileTest.styled(live)
295
+ t.reconcileTree(live)
296
+ t.advanceTree(live 30.0)
297
+ c.ok("the row is in flight before the rebuild" (t.busy(cRow)))
298
+
299
+ ; The rebuild. `c` moves to the front, and the builder does not know or
300
+ ; care that anything was moving.
301
+ def r (new EVGReconcile())
302
+ r.reconcile(live (EVGReconcileTest.list("cab" true)))
303
+
304
+ def moved:EVGElement (unwrap (EVGReconcileTest.childByLabel(live "c")))
305
+ def first:EVGElement (itemAt live.children 0)
306
+ c.eqStr("the row is where the new order puts it" first.a11yLabel "c")
307
+ c.ok("and it is still the same element, still in flight" (t.busy(moved)))
308
+
309
+ ; The other two were never touched and must not have picked anything
310
+ ; up. Asked with `busy` and not with a flight COUNT: a finished flight
311
+ ; stays in the list, so counting cannot tell "moving" from "moved".
312
+ def aRow:EVGElement (unwrap (EVGReconcileTest.childByLabel(live "a")))
313
+ c.ok("a row that did not change is not put in flight" ((t.busy(aRow)) == false))
314
+ }
315
+
316
+ sfn testUnkeyedLosesIt:void (c:RecCheck) {
317
+ print "--- and why the key is not the id ---"
318
+
319
+ ; The same scenario with no keys. The elements are matched by position,
320
+ ; so the element that was row `c` is now row `a` — it keeps its flight,
321
+ ; and the flight is now on the wrong row.
322
+ def live:EVGElement (EVGReconcileTest.list("abc" false))
323
+ def t (new EVGTransition())
324
+ EVGReconcileTest.styled(live)
325
+ t.reconcileTree(live)
326
+ t.advanceTree(live 500.0)
327
+
328
+ def third:EVGElement (itemAt live.children 2)
329
+ third.className = "row row-d"
330
+ EVGReconcileTest.styled(live)
331
+ t.reconcileTree(live)
332
+ t.advanceTree(live 30.0)
333
+ c.ok("the third row is in flight" (t.busy(third)))
334
+
335
+ def r (new EVGReconcile())
336
+ r.reconcile(live (EVGReconcileTest.list("cab" false)))
337
+
338
+ ; Position 2 is row `b` now. It inherited the flight of the element
339
+ ; that used to be there.
340
+ def nowThird:EVGElement (itemAt live.children 2)
341
+ c.eqStr("position two is a different row now" nowThird.a11yLabel "b")
342
+ c.ok("and it inherited the flight that was not its own" (t.busy(nowThird)))
343
+ }
344
+
345
+ ; --- the unkeyed rule that is easy to get wrong -------------------------------
346
+ ;
347
+ ; An unkeyed child is "the k-th unkeyed here is the k-th unkeyed there",
348
+ ; and when the k-th on the two sides disagree about their TAG the answer is
349
+ ; "no match" — not "keep looking". Falling forward past a mismatch pairs
350
+ ; the second unkeyed child of one render with the third of another, which
351
+ ; is how an unkeyed list ends up shifting its state by one on every insert.
352
+ ;
353
+ ; The counts alone cannot see the difference: both rules keep two and build
354
+ ; one here. What sees it is WHICH element survives, asked by putting a
355
+ ; flight on one and looking for it afterwards.
356
+ sfn mixedRow:EVGElement (tag:string label:string) {
357
+ def el (EVGElement.createDiv())
358
+ el.tagName = tag
359
+ el.className = "row row-a"
360
+ el.a11yLabel = label
361
+ return el
362
+ }
363
+
364
+ sfn testUnkeyedDoesNotFallForward:void (c:RecCheck) {
365
+ print "--- an unkeyed mismatch is a miss, not a search ---"
366
+
367
+ def live (EVGElement.createDiv())
368
+ live.className = "list"
369
+ live.addChild((EVGReconcileTest.mixedRow("div" "one")))
370
+ live.addChild((EVGReconcileTest.mixedRow("button" "two")))
371
+ live.addChild((EVGReconcileTest.mixedRow("div" "three")))
372
+
373
+ def t (new EVGTransition())
374
+ EVGReconcileTest.styled(live)
375
+ t.reconcileTree(live)
376
+ t.advanceTree(live 500.0)
377
+
378
+ ; Put the third child, and only it, in flight.
379
+ def third:EVGElement (itemAt live.children 2)
380
+ third.className = "row row-d"
381
+ EVGReconcileTest.styled(live)
382
+ t.reconcileTree(live)
383
+ t.advanceTree(live 30.0)
384
+ c.ok("the third child is in flight" (t.busy(third)))
385
+
386
+ def next (EVGElement.createDiv())
387
+ next.className = "list"
388
+ next.addChild((EVGReconcileTest.mixedRow("div" "one")))
389
+ next.addChild((EVGReconcileTest.mixedRow("div" "two")))
390
+ next.addChild((EVGReconcileTest.mixedRow("div" "three")))
391
+
392
+ def r (new EVGReconcile())
393
+ r.reconcile(live next)
394
+ c.eqInt("the button is not reused as a div" r.stats.kept 2)
395
+ c.eqInt("so one child is built" r.stats.created 1)
396
+
397
+ ; The third unkeyed child on both sides is the third one. Falling
398
+ ; forward would have given the flight to position ONE.
399
+ def nowSecond:EVGElement (itemAt live.children 1)
400
+ def nowThird:EVGElement (itemAt live.children 2)
401
+ c.ok("the flight stayed at position two" (t.busy(nowThird)))
402
+ c.ok("and did not slide up to position one" ((t.busy(nowSecond)) == false))
403
+ }
404
+
405
+ sfn main:void () {
406
+ def c (new RecCheck())
407
+ print "=== EVG keyed reconciliation ==="
408
+ EVGReconcileTest.testInvariant(c)
409
+ EVGReconcileTest.testKeepsElements(c)
410
+ EVGReconcileTest.testFlightSurvives(c)
411
+ EVGReconcileTest.testUnkeyedLosesIt(c)
412
+ EVGReconcileTest.testUnkeyedDoesNotFallForward(c)
413
+ print ""
414
+ print ("passed=" + (to_string c.passed) + " failed=" + (to_string c.failed))
415
+ if (c.failed > 0) {
416
+ print "FAILURES"
417
+ } {
418
+ print "ALL PASS"
419
+ }
420
+ }
421
+ }
@@ -0,0 +1,126 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGReject — what the engine was told and did not understand
5
+ ; ==============================================================================
6
+ ; A layout engine that accepts a CSS-shaped document has exactly two honest
7
+ ; answers to `width: calc(100% - 40px)`: implement it, or say it did not. The
8
+ ; third answer — drop the declaration and lay the box out as though nobody had
9
+ ; asked — is the one that costs a day to find, because a width that silently
10
+ ; became the parent's looks like a layout someone chose.
11
+ ;
12
+ ; Measured before this existed: of nineteen places where an EVG document and
13
+ ; the CSS it was written as produced different boxes, EIGHTEEN were silent.
14
+ ; The one that spoke was `repeat(auto-fit, …)`, and it spoke because the grid
15
+ ; parser happened to have a warning list.
16
+ ;
17
+ ; So every rejection goes here, and `EVGLayout.layout` drains it into the
18
+ ; warnings a build already fails on.
19
+ ;
20
+ ; --- WHY A SINGLETON AND NOT A FIELD ------------------------------------------
21
+ ;
22
+ ; A rejection happens in `EVGElement.setAttribute`, which has no route to the
23
+ ; layout that will later run — and giving every element a list to hold errors
24
+ ; it almost never has would put a field on 100,000 boxes to serve four of them.
25
+ ; The collector is process-wide and the elements stay the size they were.
26
+ ;
27
+ ; --- WHY IT CANNOT GET EXPENSIVE ----------------------------------------------
28
+ ;
29
+ ; The style cache replays a plan per element per frame, so ONE bad declaration
30
+ ; in a sheet is one rejection per element per frame — 22,403 of them on the
31
+ ; bench table. Two things bound that:
32
+ ;
33
+ ; * de-duplication, so the same (kind, property, value) is stored once;
34
+ ; * a hard cap, after which `add` is a single integer increment and the
35
+ ; de-duplication scan does not run at all.
36
+ ;
37
+ ; The scan is therefore bounded by cap x cap over the life of the process and
38
+ ; O(1) after that. `total` keeps counting, so the report can say how many were
39
+ ; folded into how few.
40
+ ; ==============================================================================
41
+
42
+ class EVGRejectStore @singleton(true) {
43
+ def kinds:[string]
44
+ def names:[string]
45
+ def values:[string]
46
+ ; Every rejection, including the ones folded into an entry already stored.
47
+ def total:int 0
48
+ ; Distinct entries kept. Past this, only `total` moves.
49
+ def cap:int 64
50
+ }
51
+
52
+ class EVGReject {
53
+
54
+ sfn store:EVGRejectStore () {
55
+ return (EVGRejectStore.__singleton())
56
+ }
57
+
58
+ ; `kind` is the shape of the complaint ("unknown property", "unsupported
59
+ ; length", …), `name` the CSS property and `value` what was written.
60
+ sfn note:void (kind:string name:string value:string) {
61
+ def s:EVGRejectStore (EVGReject.store())
62
+ s.total = (s.total + 1)
63
+ def n:int (array_length s.names)
64
+ if (n >= s.cap) {
65
+ return
66
+ }
67
+ def i:int 0
68
+ while (i < n) {
69
+ def kn:string (itemAt s.kinds i)
70
+ def nm:string (itemAt s.names i)
71
+ def vl:string (itemAt s.values i)
72
+ if (((kn == kind) && (nm == name)) && (vl == value)) {
73
+ return
74
+ }
75
+ i = (i + 1)
76
+ }
77
+ push s.kinds kind
78
+ push s.names name
79
+ push s.values value
80
+ }
81
+
82
+ sfn noteCount:int () {
83
+ def s:EVGRejectStore (EVGReject.store())
84
+ return (array_length s.names)
85
+ }
86
+
87
+ sfn noteTotal:int () {
88
+ def s:EVGRejectStore (EVGReject.store())
89
+ return s.total
90
+ }
91
+
92
+ sfn noteAt:string (i:int) {
93
+ def s:EVGRejectStore (EVGReject.store())
94
+ def kn:string (itemAt s.kinds i)
95
+ def nm:string (itemAt s.names i)
96
+ def vl:string (itemAt s.values i)
97
+ return ((((kn + ": ") + nm) + ": ") + vl)
98
+ }
99
+
100
+ sfn clearNotes:void () {
101
+ def s:EVGRejectStore (EVGReject.store())
102
+ def empty1:[string]
103
+ def empty2:[string]
104
+ def empty3:[string]
105
+ s.kinds = empty1
106
+ s.names = empty2
107
+ s.values = empty3
108
+ s.total = 0
109
+ }
110
+
111
+ ; A value that means "no value" is not a rejection: it is how a shorthand
112
+ ; is cleared and how a sheet says "use the initial value". Complaining
113
+ ; about these would bury the four real ones in a thousand.
114
+ sfn isAbsent:boolean (value:string) {
115
+ if ((strlen value) == 0) {
116
+ return true
117
+ }
118
+ if (value == "auto") { return true }
119
+ if (value == "none") { return true }
120
+ if (value == "normal") { return true }
121
+ if (value == "initial") { return true }
122
+ if (value == "inherit") { return true }
123
+ if (value == "unset") { return true }
124
+ return false
125
+ }
126
+ }