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,375 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGRelayoutTest — the same tree laid out again at a new page size
5
+ ; ==============================================================================
6
+ ;
7
+ ; A retained tree is laid out many times, and when the window changes size it
8
+ ; is laid out at a size it has never had. What comes out must be what a FRESH
9
+ ; copy of the tree laid out once at that size would give: nothing computed at
10
+ ; the old size may be read back as an input at the new one.
11
+ ;
12
+ ; Found in the EVGUI Separator demo, whose page is this shape:
13
+ ;
14
+ ; .pg { display:flex; flex-wrap:wrap; gap:16px } cards in a wrapping row
15
+ ; .card { flex-direction:column; width:418px; height:248px }
16
+ ; .stage { flex-grow:1 } grown to the card
17
+ ; .menu { flex-direction:row; align-items:stretch } columns + 1px rules
18
+ ; @media (max-width:600px) { .card { width:100%; height:auto } … }
19
+ ;
20
+ ; (The demo's columns are `width: 30%` only under the media rule. Here they
21
+ ; always are: a property a media rule set is not put back by the sheet when
22
+ ; the rule stops matching, which is the sheet's business and not what this
23
+ ; file tests.)
24
+ ;
25
+ ; Laid out at 900 and then at 332, two answers from the first pass came back:
26
+ ;
27
+ ; 1. `.stage` kept the height the column's flex-grow gave it
28
+ ; (`calculatedFlexHeight`), so every card stayed 248px tall after the
29
+ ; phone rules made it `height: auto`.
30
+ ; 2. `.menu`, auto-height, read its old `calculatedInnerHeight` as the
31
+ ; height to stretch its items to, so the columns whose text now wrapped
32
+ ; onto three lines kept their one-line height and the rules with them.
33
+ ;
34
+ ; The demo worked around it by clearing those fields itself before every
35
+ ; fresh layout. This holds the engine to doing it.
36
+ ;
37
+ ; --- WHAT IS ASSERTED ---------------------------------------------------------
38
+ ;
39
+ ; * 900 → 332 → 900: after each pass every element's rectangle equals the
40
+ ; one a fresh identical tree gets at that size.
41
+ ; * In each pass the menu's rules and columns are as tall as the menu row
42
+ ; (align-items: stretch in an auto-height row, which on a FIRST layout
43
+ ; used to leave a 1px rule 0px tall — it only came right on later
44
+ ; passes, from the stale inner height in 2. above).
45
+ ; * The same with the cards kept (`keepLayout`).
46
+ ; * A column that shrinks declared heights gives the same answer on every
47
+ ; pass. It used to by accident: the shrink cleared `height.isSet` and the
48
+ ; next pass reused the stale flex height, so clearing that height (the
49
+ ; fix above) needs the shrink to keep the declaration.
50
+ ; * A kept box with no stylesheet whose child is sized in `vw` is laid out
51
+ ; again at a new page size, though nothing the flow hands the box changed.
52
+ ; * And the cache still does its job: the same size twice, nothing changed,
53
+ ; and the kept boxes are answered from what they hold.
54
+ ; ==============================================================================
55
+
56
+ Import "EVGElement.rgr"
57
+ Import "EVGUnit.rgr"
58
+ Import "EVGLayout.rgr"
59
+ Import "EVGStyleSheet.rgr"
60
+
61
+ class RelayoutCheck {
62
+ def passed:int 0
63
+ def failed:int 0
64
+ def shown:int 0
65
+
66
+ Constructor () {
67
+ }
68
+
69
+ fn ok:void (name:string cond:boolean) {
70
+ if cond {
71
+ passed = (passed + 1)
72
+ print (" PASS " + name)
73
+ } {
74
+ failed = (failed + 1)
75
+ print (" FAIL " + name)
76
+ }
77
+ }
78
+
79
+ fn css:string () {
80
+ def s:string ""
81
+ s = (s + ".pg { display: flex; flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 16px; padding: 24px; width: 100%; }\n")
82
+ s = (s + ".card { display: flex; flex-direction: column; flex-wrap: nowrap; width: 418px; height: 248px; border: 1px solid #e4e4e7; }\n")
83
+ s = (s + ".cap { height: 40px; line-height: 40px; padding: 0 16px; font-size: 12px; }\n")
84
+ s = (s + ".stage { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: center; justify-content: center; flex-grow: 1; padding: 16px 24px; }\n")
85
+ s = (s + ".menu { display: flex; flex-direction: row; flex-wrap: nowrap; align-items: stretch; gap: 16px; }\n")
86
+ s = (s + ".mcol { display: flex; flex-direction: column; flex-wrap: nowrap; gap: 2px; width: 30%; }\n")
87
+ s = (s + ".txt { font-size: 14px; line-height: 20px; }\n")
88
+ s = (s + ".rule { width: 1px; flex-shrink: 0; align-self: stretch; background-color: #e4e4e7; }\n")
89
+ s = (s + ".vwbox { display: flex; flex-direction: column; width: 300px; }\n")
90
+ s = (s + ".vwkid { width: 10vw; height: 5vw; }\n")
91
+ s = (s + "@media (max-width: 600px) {\n")
92
+ s = (s + " .pg { padding: 12px; gap: 12px; }\n")
93
+ s = (s + " .card { width: 100%; height: auto; }\n")
94
+ s = (s + " .stage { padding: 20px 16px; }\n")
95
+ s = (s + " .menu { gap: 10px; width: 100%; }\n")
96
+ s = (s + "}\n")
97
+ return s
98
+ }
99
+
100
+ fn div:EVGElement (cls:string) {
101
+ def d (EVGElement.createDiv())
102
+ d.className = cls
103
+ return d
104
+ }
105
+
106
+ fn text:EVGElement (t:string) {
107
+ def d (this.div("txt"))
108
+ d.textContent = t
109
+ return d
110
+ }
111
+
112
+ fn menuCol:EVGElement (a:string b:string) {
113
+ def c (this.div("mcol"))
114
+ c.addChild((this.text(a)))
115
+ c.addChild((this.text(b)))
116
+ return c
117
+ }
118
+
119
+ fn card:EVGElement (caption:string withMenu:boolean) {
120
+ def c (this.div("card"))
121
+ def cap (this.div("cap"))
122
+ cap.textContent = caption
123
+ c.addChild(cap)
124
+ def stage (this.div("stage"))
125
+ if withMenu {
126
+ def menu (this.div("menu"))
127
+ menu.addChild((this.menuCol("Blog" "Latest posts and updates from the team")))
128
+ menu.addChild((this.div("rule")))
129
+ menu.addChild((this.menuCol("Docs" "Guides and reference for every component")))
130
+ menu.addChild((this.div("rule")))
131
+ menu.addChild((this.menuCol("Source" "The code on GitHub")))
132
+ stage.addChild(menu)
133
+ } {
134
+ stage.addChild((this.text("A short line")))
135
+ }
136
+ c.addChild(stage)
137
+ return c
138
+ }
139
+
140
+ ; No width of its own in the sheet: the page gives it one.
141
+ fn build:EVGElement (keep:boolean) {
142
+ def pg (this.div("pg"))
143
+ def c1 (this.card("Horizontal" false))
144
+ def c2 (this.card("Vertical" true))
145
+ def c3 (this.card("Menu" true))
146
+ def vb (this.div("vwbox"))
147
+ vb.addChild((this.div("vwkid")))
148
+ vb.addChild((this.div("vwkid")))
149
+ if keep {
150
+ c1.keepLayout = true
151
+ c2.keepLayout = true
152
+ c3.keepLayout = true
153
+ vb.keepLayout = true
154
+ }
155
+ pg.addChild(c1)
156
+ pg.addChild(c2)
157
+ pg.addChild(c3)
158
+ pg.addChild(vb)
159
+ return pg
160
+ }
161
+
162
+ fn layoutAt:void (root:EVGElement sheet:EVGStyleSheet w:double) {
163
+ sheet.applyTreeIn(root "" w 640.0 false)
164
+ def lay (new EVGLayout())
165
+ lay.setPageSize(w 640.0)
166
+ lay.layout(root)
167
+ }
168
+
169
+ fn freshAt:EVGElement (keep:boolean w:double) {
170
+ def root (this.build(keep))
171
+ def sheet (new EVGStyleSheet())
172
+ sheet.parse((this.css()))
173
+ this.layoutAt(root sheet w)
174
+ return root
175
+ }
176
+
177
+ fn near:boolean (a:double b:double) {
178
+ def d:double (a - b)
179
+ if (d < 0.0) {
180
+ d = (0.0 - d)
181
+ }
182
+ return (d < 0.01)
183
+ }
184
+
185
+ fn rect:string (e:EVGElement) {
186
+ def s:string ((to_string e.calculatedX) + "," + (to_string e.calculatedY))
187
+ s = (s + " " + (to_string e.calculatedWidth) + "x" + (to_string e.calculatedHeight))
188
+ return s
189
+ }
190
+
191
+ ; Mismatches under `a` against `b`, walked in step; the first few named.
192
+ fn diff:int (a:EVGElement b:EVGElement path:string) {
193
+ def bad:int 0
194
+ def same:boolean (((this.near(a.calculatedX b.calculatedX)) && (this.near(a.calculatedY b.calculatedY)))
195
+ && ((this.near(a.calculatedWidth b.calculatedWidth)) && (this.near(a.calculatedHeight b.calculatedHeight))))
196
+ if (same == false) {
197
+ bad = 1
198
+ if (shown < 12) {
199
+ shown = (shown + 1)
200
+ def got:string (this.rect(a))
201
+ def want:string (this.rect(b))
202
+ print (" " + path + " " + a.className + " got " + got + " want " + want)
203
+ }
204
+ }
205
+ def i:int 0
206
+ while (i < (a.getChildCount())) {
207
+ bad = (bad + (this.diff((a.getChild(i)) (b.getChild(i)) ((path + "/") + (to_string i)))))
208
+ i = (i + 1)
209
+ }
210
+ return bad
211
+ }
212
+
213
+ ; Every item of each `.menu` row as tall as the row: align-items:
214
+ ; stretch, which in an auto-height row can only be answered once the
215
+ ; row has measured its line.
216
+ fn spans:boolean (root:EVGElement) {
217
+ def good:boolean true
218
+ def c:int 1
219
+ while (c <= 2) {
220
+ def card:EVGElement (root.getChild(c))
221
+ def stage:EVGElement (card.getChild(1))
222
+ def menu:EVGElement (stage.getChild(0))
223
+ def k:int 0
224
+ while (k < (menu.getChildCount())) {
225
+ def it:EVGElement (menu.getChild(k))
226
+ if ((this.near(it.calculatedHeight menu.calculatedInnerHeight)) == false) {
227
+ good = false
228
+ print (" " + it.className + " is " + (to_string it.calculatedHeight) + " in a " + (to_string menu.calculatedInnerHeight) + "px row")
229
+ }
230
+ k = (k + 1)
231
+ }
232
+ c = (c + 1)
233
+ }
234
+ return good
235
+ }
236
+
237
+ fn sweep:void (keep:boolean label:string) {
238
+ def root (this.build(keep))
239
+ def sheet (new EVGStyleSheet())
240
+ sheet.parse((this.css()))
241
+ def widths:[double] ([] _:double (900.0 332.0 900.0 332.0))
242
+ def i:int 0
243
+ while (i < (array_length widths)) {
244
+ def w:double (itemAt widths i)
245
+ this.layoutAt(root sheet w)
246
+ shown = 0
247
+ def bad:int (this.diff(root (this.freshAt(keep w)) "root"))
248
+ def name:string (label + " pass " + (to_string (i + 1)) + " at " + (to_string w) + " matches a fresh tree")
249
+ this.ok(name (bad == 0))
250
+ this.ok((label + " pass " + (to_string (i + 1)) + ": the rules and columns span the menu row")
251
+ (this.spans(root)))
252
+ i = (i + 1)
253
+ }
254
+ }
255
+
256
+ fn run:void () {
257
+ print "EVGRelayoutTest"
258
+
259
+ this.sweep(false "plain tree:")
260
+ this.sweep(true "kept cards:")
261
+
262
+ ; The cache still answers a relayout at the same size.
263
+ def root (this.build(true))
264
+ def sheet (new EVGStyleSheet())
265
+ sheet.parse((this.css()))
266
+ this.layoutAt(root sheet 900.0)
267
+ this.layoutAt(root sheet 900.0)
268
+ def allSkipped:boolean true
269
+ def k:int 0
270
+ while (k < (root.getChildCount())) {
271
+ def kid:EVGElement (root.getChild(k))
272
+ if (kid.layoutSkipped == false) {
273
+ allSkipped = false
274
+ }
275
+ k = (k + 1)
276
+ }
277
+ this.ok("same size twice: every kept box is answered from its last layout" allSkipped)
278
+ shown = 0
279
+ this.ok("…and the answer is the fresh one"
280
+ ((this.diff(root (this.freshAt(true 900.0)) "root")) == 0))
281
+
282
+ this.shrunkTwice()
283
+ this.keptInViewport()
284
+
285
+ print ""
286
+ print ((("passed=" + (to_string passed)) + " failed=") + (to_string failed))
287
+ if (failed > 0) {
288
+ print "FAILURES"
289
+ } {
290
+ print "ALL PASS"
291
+ }
292
+ }
293
+
294
+ ; A column that shrinks declared heights to fit. The shrink is the
295
+ ; column's answer this pass, not a new declaration: laid out a second
296
+ ; time the children are still `height: 80px` and are shrunk again.
297
+ fn shrinkTree:EVGElement () {
298
+ def col (EVGElement.createDiv())
299
+ col.setAttribute("display" "flex")
300
+ col.setAttribute("flex-direction" "column")
301
+ col.setAttribute("flex-wrap" "nowrap")
302
+ col.setAttribute("height" "100px")
303
+ def a (EVGElement.createDiv())
304
+ a.setAttribute("height" "80px")
305
+ def b (EVGElement.createDiv())
306
+ b.setAttribute("height" "80px")
307
+ col.addChild(a)
308
+ col.addChild(b)
309
+ def pg (EVGElement.createDiv())
310
+ pg.setAttribute("width" "100%")
311
+ pg.addChild(col)
312
+ return pg
313
+ }
314
+
315
+ fn plainAt:void (root:EVGElement w:double) {
316
+ def lay (new EVGLayout())
317
+ lay.setPageSize(w 640.0)
318
+ lay.layout(root)
319
+ }
320
+
321
+ fn shrunkTwice:void () {
322
+ def t (this.shrinkTree())
323
+ this.plainAt(t 900.0)
324
+ def first:int (this.diff(t (this.freshShrink(900.0)) "root"))
325
+ this.plainAt(t 900.0)
326
+ shown = 0
327
+ def second:int (this.diff(t (this.freshShrink(900.0)) "root"))
328
+ this.plainAt(t 332.0)
329
+ shown = 0
330
+ def third:int (this.diff(t (this.freshShrink(332.0)) "root"))
331
+ this.ok("a column that shrinks its children: the same on every pass"
332
+ (((first + second) + third) == 0))
333
+ }
334
+
335
+ fn freshShrink:EVGElement (w:double) {
336
+ def t (this.shrinkTree())
337
+ this.plainAt(t w)
338
+ return t
339
+ }
340
+
341
+ ; A kept box with no stylesheet to mark it dirty: nothing the flow hands
342
+ ; it depends on the page, but its children are sized in `vw`, so a new
343
+ ; page size is a new layout for it however clean it says it is.
344
+ fn keptInViewport:void () {
345
+ def pg (EVGElement.createDiv())
346
+ def box (EVGElement.createDiv())
347
+ box.setAttribute("width" "300px")
348
+ box.setAttribute("height" "100px")
349
+ def kid (EVGElement.createDiv())
350
+ kid.setAttribute("width" "10vw")
351
+ kid.setAttribute("height" "20px")
352
+ box.addChild(kid)
353
+ pg.addChild(box)
354
+ box.keepLayout = true
355
+ this.plainAt(pg 900.0)
356
+ box.layoutClean = true
357
+ kid.layoutClean = true
358
+ this.plainAt(pg 900.0)
359
+ this.ok("a clean kept box at the same page size is answered from its last layout"
360
+ box.layoutSkipped)
361
+ this.plainAt(pg 332.0)
362
+ this.ok("…and at a new page size is laid out again (10vw of 332)"
363
+ (this.near(kid.calculatedWidth 33.2)))
364
+ box.layoutClean = true
365
+ kid.layoutClean = true
366
+ this.plainAt(pg 332.0)
367
+ this.ok("…after which the same size is answered from it again"
368
+ box.layoutSkipped)
369
+ }
370
+
371
+ sfn m@(main):void () {
372
+ def c (new RelayoutCheck())
373
+ c.run()
374
+ }
375
+ }
@@ -0,0 +1,319 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGRtlLayoutTest — one switch, and the whole interface turns around
5
+ ; ==============================================================================
6
+ ;
7
+ ; Mirroring a user interface for Arabic and Hebrew is not a job for the three
8
+ ; editors. They all draw through the same layout engine, so the direction
9
+ ; belongs in that engine, once, as the property CSS already has for it — and
10
+ ; then every panel, strip, toolbar and grid built on it turns around together
11
+ ; and anything built later turns around the day it lands.
12
+ ;
13
+ ; It is done by reflecting each container's children about its content box
14
+ ; after they have been placed. That choice is the reason this is thirty lines
15
+ ; rather than a rewrite of two engines, and it is worth stating why it is not
16
+ ; a shortcut: every way a container can place a child horizontally — flex row,
17
+ ; row-reverse, wrapping, every value of justify-content, gap, grid tracks,
18
+ ; named grid lines, dense packing — ends with children at x positions inside a
19
+ ; content box. Reflect those and all of it is right at once.
20
+ ;
21
+ ; The cases below are the ones that separate that from something that merely
22
+ ; reverses a list:
23
+ ;
24
+ ; * the ORDER reverses and the packing end changes with it
25
+ ; * a nested container turns around too, because the property inherits —
26
+ ; that is what makes it one switch rather than one per panel
27
+ ; * an island can opt back out, which is what a left-to-right code block or
28
+ ; a phone number inside an Arabic page needs
29
+ ; * grid column 1 becomes the RIGHTMOST column
30
+ ; * absolutely positioned children do NOT move: `left: 0` is the left edge
31
+ ; in any direction
32
+ ; * `margin-left` stays physically on the left, which is CSS's rule and the
33
+ ; one of the two readings that is easy to get wrong
34
+ ; * and the older `direction: row` still means the flow axis, because two
35
+ ; properties share that name and only the VALUE tells them apart
36
+ ;
37
+ ; npm run evg:rtl:test
38
+ ; ==============================================================================
39
+
40
+ Import "EVGLayout.rgr"
41
+
42
+ class RtlCheck {
43
+ def passed:int 0
44
+ def failed:int 0
45
+
46
+ fn ok:void (name:string cond:boolean) {
47
+ if cond {
48
+ passed = (passed + 1)
49
+ print (" PASS " + name)
50
+ } {
51
+ failed = (failed + 1)
52
+ print (" FAIL " + name)
53
+ }
54
+ }
55
+
56
+ fn eqNum:void (name:string got:double want:double) {
57
+ def d:double (got - want)
58
+ if (d < 0.0) {
59
+ d = (0.0 - d)
60
+ }
61
+ this.ok(((((name + " (got ") + (to_string got)) + " want ") + ((to_string want) + ")")) (d < 0.5))
62
+ }
63
+ }
64
+
65
+ class EVGRtlLayoutTest {
66
+ def c:RtlCheck (new RtlCheck)
67
+
68
+ sfn main:void () {
69
+ def t (new EVGRtlLayoutTest())
70
+ t.run()
71
+ }
72
+
73
+ ; A fixed-size box with an id, which is all these cases need.
74
+ sfn box:EVGElement (id:string w:double h:double) {
75
+ def e (new EVGElement())
76
+ e.id = id
77
+ e.width = (EVGUnit.px(w))
78
+ e.height = (EVGUnit.px(h))
79
+ return e
80
+ }
81
+
82
+ ; A 300-wide row with no padding, holding three boxes of 40, 60 and 20.
83
+ ; Their widths differ on purpose: equal boxes would look mirrored even if
84
+ ; the reflection were wrong by a constant.
85
+ sfn strip:EVGElement (rtl:boolean) {
86
+ def root (new EVGElement())
87
+ root.id = "root"
88
+ root.width = (EVGUnit.px(300.0))
89
+ root.height = (EVGUnit.px(50.0))
90
+ root.display = "flex"
91
+ root.flexDirection = "row"
92
+ if rtl {
93
+ root.setAttribute("direction" "rtl")
94
+ }
95
+ root.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
96
+ root.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
97
+ root.addChild((EVGRtlLayoutTest.box("c" 20.0 20.0)))
98
+ return root
99
+ }
100
+
101
+ sfn childX:double (parent:EVGElement i:int) {
102
+ def ch:EVGElement (parent.getChild(i))
103
+ return ch.calculatedX
104
+ }
105
+
106
+ fn laidOut:EVGElement (root:EVGElement) {
107
+ def lay (new EVGLayout())
108
+ lay.setPageSize(300.0 200.0)
109
+ lay.layout(root)
110
+ return root
111
+ }
112
+
113
+ fn run:void () {
114
+ print "=== EVGRtlLayoutTest ==="
115
+ this.testOrder()
116
+ this.testGrid()
117
+ this.testInheritance()
118
+ this.testIsland()
119
+ this.testAbsolute()
120
+ this.testMargins()
121
+ this.testLegacyDirection()
122
+ print ""
123
+ print (("passed = " + (to_string c.passed)) + (" failed = " + (to_string c.failed)))
124
+ if (c.failed == 0) {
125
+ print "ALL PASS"
126
+ } {
127
+ print "SOME FAILED"
128
+ }
129
+ }
130
+
131
+ fn testOrder:void () {
132
+ print "--- the order, and which end it packs against ---"
133
+ def ltr:EVGElement (this.laidOut((EVGRtlLayoutTest.strip(false))))
134
+ c.eqNum("a starts at the left edge" (EVGRtlLayoutTest.childX(ltr 0)) 0.0)
135
+ c.eqNum("b follows it" (EVGRtlLayoutTest.childX(ltr 1)) 40.0)
136
+ c.eqNum("and c follows b" (EVGRtlLayoutTest.childX(ltr 2)) 100.0)
137
+
138
+ ; Reflected about a 300-wide box: a's right edge was at 40, so its
139
+ ; left edge is now at 260; b spanned 40..100 and now spans 200..260;
140
+ ; c spanned 100..120 and now spans 180..200.
141
+ def rtl:EVGElement (this.laidOut((EVGRtlLayoutTest.strip(true))))
142
+ c.eqNum("a is now against the RIGHT edge" (EVGRtlLayoutTest.childX(rtl 0)) 260.0)
143
+ c.eqNum("b sits to its left" (EVGRtlLayoutTest.childX(rtl 1)) 200.0)
144
+ c.eqNum("and c to the left of b" (EVGRtlLayoutTest.childX(rtl 2)) 180.0)
145
+ ; The children are still in their authored order in the tree — only
146
+ ; where they are DRAWN changed. Anything that walks the tree to read a
147
+ ; document, an accessibility tree included, still reads it in the
148
+ ; order it was written.
149
+ c.ok("the tree order is untouched" (((ltr.getChild(0)).id) == "a"))
150
+ c.ok("in the mirrored one too" (((rtl.getChild(0)).id) == "a"))
151
+ ; And nothing left the box.
152
+ c.ok("nothing was pushed off the left edge" ((EVGRtlLayoutTest.childX(rtl 2)) >= 0.0))
153
+ }
154
+
155
+ fn testGrid:void () {
156
+ print "--- and the grid turns with it ---"
157
+ ; A grid is placed by a different engine entirely — tracks, spans,
158
+ ; named lines, dense packing — and none of it had to be touched. The
159
+ ; children still end up at x positions inside a content box, and
160
+ ; reflecting those makes column 1 the RIGHTMOST column, which is what
161
+ ; a grid in a right-to-left page is.
162
+ def g (new EVGElement())
163
+ g.id = "grid"
164
+ g.width = (EVGUnit.px(300.0))
165
+ g.height = (EVGUnit.px(60.0))
166
+ g.display = "grid"
167
+ g.setAttribute("grid-template-columns" "100px 200px")
168
+ g.setAttribute("direction" "rtl")
169
+ def one:EVGElement (EVGRtlLayoutTest.box("one" 100.0 20.0))
170
+ def two:EVGElement (EVGRtlLayoutTest.box("two" 200.0 20.0))
171
+ g.addChild(one)
172
+ g.addChild(two)
173
+ this.laidOut(g)
174
+ ; Column 1 is 100 wide and spans 200..300 mirrored; column 2 is 200
175
+ ; wide and spans 0..200.
176
+ c.eqNum("the first column is on the right" one.calculatedX 200.0)
177
+ c.eqNum("and the second beside it" two.calculatedX 0.0)
178
+
179
+ ; The same grid the other way round, so the numbers above are read as
180
+ ; a mirror rather than as whatever the engine happened to produce.
181
+ def g2 (new EVGElement())
182
+ g2.id = "grid2"
183
+ g2.width = (EVGUnit.px(300.0))
184
+ g2.height = (EVGUnit.px(60.0))
185
+ g2.display = "grid"
186
+ g2.setAttribute("grid-template-columns" "100px 200px")
187
+ def one2:EVGElement (EVGRtlLayoutTest.box("one" 100.0 20.0))
188
+ def two2:EVGElement (EVGRtlLayoutTest.box("two" 200.0 20.0))
189
+ g2.addChild(one2)
190
+ g2.addChild(two2)
191
+ this.laidOut(g2)
192
+ c.eqNum("left to right, the first column is on the left" one2.calculatedX 0.0)
193
+ c.eqNum("and the second follows it" two2.calculatedX 100.0)
194
+ }
195
+
196
+ fn testInheritance:void () {
197
+ print "--- one switch, not one per panel ---"
198
+ ; The direction is set ONCE, on the page. The strip inside it is never
199
+ ; told anything, and turns around because `direction` inherits — which
200
+ ; is the whole point: an interface is mirrored by saying so at the top,
201
+ ; not by finding every container in it.
202
+ def page (new EVGElement())
203
+ page.id = "page"
204
+ page.width = (EVGUnit.px(300.0))
205
+ page.height = (EVGUnit.px(200.0))
206
+ page.display = "flex"
207
+ page.flexDirection = "column"
208
+ page.setAttribute("direction" "rtl")
209
+ def strip (new EVGElement())
210
+ strip.id = "strip"
211
+ strip.width = (EVGUnit.px(300.0))
212
+ strip.height = (EVGUnit.px(50.0))
213
+ strip.display = "flex"
214
+ strip.flexDirection = "row"
215
+ strip.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
216
+ strip.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
217
+ page.addChild(strip)
218
+ this.laidOut(page)
219
+ c.ok("the nested strip inherited the direction" strip.resolvedRtl)
220
+ c.eqNum("so its first button is on the right" (EVGRtlLayoutTest.childX(strip 0)) 260.0)
221
+ c.eqNum("and its second is beside it" (EVGRtlLayoutTest.childX(strip 1)) 200.0)
222
+ }
223
+
224
+ fn testIsland:void () {
225
+ print "--- and an island can opt back out ---"
226
+ ; A code block, a formula bar, a phone number: things that read left to
227
+ ; right inside a page that does not. Without this, a switch at the top
228
+ ; would be a blunt instrument nobody could use on a real document.
229
+ def page (new EVGElement())
230
+ page.id = "page"
231
+ page.width = (EVGUnit.px(300.0))
232
+ page.height = (EVGUnit.px(200.0))
233
+ page.display = "flex"
234
+ page.flexDirection = "column"
235
+ page.setAttribute("direction" "rtl")
236
+ def code (new EVGElement())
237
+ code.id = "code"
238
+ code.width = (EVGUnit.px(300.0))
239
+ code.height = (EVGUnit.px(50.0))
240
+ code.display = "flex"
241
+ code.flexDirection = "row"
242
+ code.setAttribute("direction" "ltr")
243
+ code.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
244
+ code.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
245
+ page.addChild(code)
246
+ this.laidOut(page)
247
+ c.ok("the island is left to right" ((code.resolvedRtl) == false))
248
+ c.eqNum("so its first box is on the left" (EVGRtlLayoutTest.childX(code 0)) 0.0)
249
+ c.eqNum("and the second follows it" (EVGRtlLayoutTest.childX(code 1)) 40.0)
250
+ }
251
+
252
+ fn testAbsolute:void () {
253
+ print "--- what must NOT move ---"
254
+ ; `left: 0` is the left edge in any direction. An absolutely
255
+ ; positioned child was placed against the edge it named, and mirroring
256
+ ; it would send a close button to the wrong corner.
257
+ def page (new EVGElement())
258
+ page.id = "page"
259
+ page.width = (EVGUnit.px(300.0))
260
+ page.height = (EVGUnit.px(200.0))
261
+ page.display = "flex"
262
+ page.flexDirection = "row"
263
+ page.setAttribute("direction" "rtl")
264
+ def pinned:EVGElement (EVGRtlLayoutTest.box("pinned" 30.0 30.0))
265
+ pinned.isAbsolute = true
266
+ pinned.left = (EVGUnit.px(0.0))
267
+ pinned.top = (EVGUnit.px(0.0))
268
+ page.addChild(pinned)
269
+ this.laidOut(page)
270
+ c.eqNum("an absolute child stays where it was pinned" pinned.calculatedX 0.0)
271
+ }
272
+
273
+ fn testMargins:void () {
274
+ print "--- margins stay physical ---"
275
+ ; CSS's rule, and the half of it that is easy to get wrong. What a
276
+ ; right-to-left container reverses is the ORDER of its children and
277
+ ; the end they pack against — not which side of a child its own
278
+ ; `margin-left` sits on. An author who wants the margin to follow the
279
+ ; direction says `margin-inline-start`.
280
+ ;
281
+ ; With symmetric margins the two readings agree, which is why picking
282
+ ; the wrong one would have survived a long time before anything looked
283
+ ; a pixel out. So this uses a margin on ONE side only.
284
+ def root (new EVGElement())
285
+ root.id = "root"
286
+ root.width = (EVGUnit.px(300.0))
287
+ root.height = (EVGUnit.px(50.0))
288
+ root.display = "flex"
289
+ root.flexDirection = "row"
290
+ root.setAttribute("direction" "rtl")
291
+ def only:EVGElement (EVGRtlLayoutTest.box("only" 40.0 20.0))
292
+ only.box.marginLeft = (EVGUnit.px(10.0))
293
+ root.addChild(only)
294
+ this.laidOut(root)
295
+ ; Its margin box spans 0..50 (10 of margin, then 40 of box). Mirrored
296
+ ; about 0..300 that margin box lands at 250..300, and the border box
297
+ ; sits at its own margin-left inside it: 260.
298
+ c.eqNum("the left margin is still on the left of the box" only.calculatedX 260.0)
299
+ }
300
+
301
+ fn testLegacyDirection:void () {
302
+ print "--- and the property that already had the name ---"
303
+ ; `direction` here has always meant the flow AXIS, and still does for
304
+ ; those values. Two properties cannot share a name, so the VALUE
305
+ ; decides — and a page that says `direction: row` must not quietly
306
+ ; become a right-to-left one.
307
+ def e (new EVGElement())
308
+ e.setAttribute("direction" "row")
309
+ c.ok("row is still the axis" (e.direction == "row"))
310
+ c.ok("and says nothing about handedness" (e.textDir == ""))
311
+ def e2 (new EVGElement())
312
+ e2.setAttribute("direction" "column")
313
+ c.ok("so is column" (e2.direction == "column"))
314
+ def e3 (new EVGElement())
315
+ e3.setAttribute("direction" "rtl")
316
+ c.ok("rtl is the handedness" (e3.textDir == "rtl"))
317
+ c.ok("and leaves the axis alone" (e3.direction == "row"))
318
+ }
319
+ }