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,626 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGOverlayTest — surfaces that leave the flow but not the tree
5
+ ; ==============================================================================
6
+ ;
7
+ ; An overlay is a menu's dropdown, a tooltip, a popover: a box that has to paint
8
+ ; above the page and sit next to something, without becoming a child of some
9
+ ; overlay root. Here it stays exactly where it was put — still its parent's
10
+ ; child, still the owner of its subtree — and only layout and paint treat it
11
+ ; differently. That is the difference between this and a portal, and the reason
12
+ ; events, ownership and the accessibility walk keep working.
13
+ ;
14
+ ; What is asserted, in order of how badly each one bites when it is wrong:
15
+ ;
16
+ ; * an overlay takes no space in its parent's flow, so a menu is as wide as
17
+ ; its trigger and not as wide as the panel hanging off it;
18
+ ; * it is placed against its anchor, which it finds among its own siblings;
19
+ ; * an overlay INSIDE another overlay anchors to the moved rectangle, which
20
+ ; is what makes a submenu work with no submenu case anywhere;
21
+ ; * a surface with no anchor is REPORTED. Silently at (0,0) it looks like a
22
+ ; stylesheet mistake and is not one;
23
+ ; * it PAINTS above the page, not merely later in the tree — a menu whose
24
+ ; trigger comes first must still cover the menu next to it;
25
+ ; * and a click in the area it covers HITS IT, not what is underneath, which
26
+ ; is the same rule as painting and is therefore the same list;
27
+ ; * near an edge it FLIPS to the other side of its anchor and SHIFTS along
28
+ ; the edge, because a menu drawn half off the page is worse than a menu
29
+ ; drawn above its trigger.
30
+ ; ==============================================================================
31
+
32
+ Import "EVGElement.rgr"
33
+ Import "EVGUnit.rgr"
34
+ Import "EVGLayout.rgr"
35
+ Import "EVGDisplayList.rgr"
36
+ Import "EVGHitTest.rgr"
37
+
38
+ class OverlayCheck {
39
+ def passed:int 0
40
+ def failed:int 0
41
+
42
+ fn ok:void (name:string cond:boolean) {
43
+ if cond {
44
+ passed = (passed + 1)
45
+ print (" PASS " + name)
46
+ } {
47
+ failed = (failed + 1)
48
+ print (" FAIL " + name)
49
+ }
50
+ }
51
+
52
+ fn eqStr:void (name:string got:string want:string) {
53
+ def good:boolean (got == want)
54
+ if (good == false) {
55
+ print (" got '" + got + "' want '" + want + "'")
56
+ }
57
+ this.ok(name good)
58
+ }
59
+
60
+ fn eqInt:void (name:string got:int want:int) {
61
+ def good:boolean (got == want)
62
+ if (good == false) {
63
+ print (" got " + (to_string got) + " want " + (to_string want))
64
+ }
65
+ this.ok(name good)
66
+ }
67
+ }
68
+
69
+ class EVGOverlayTest {
70
+
71
+ sfn box:EVGElement (id:string cls:string w:double h:double) {
72
+ def el (EVGElement.createDiv())
73
+ el.id = id
74
+ el.className = cls
75
+ el.setAttribute("width" ((to_string (to_int w)) + "px"))
76
+ el.setAttribute("height" ((to_string (to_int h)) + "px"))
77
+ return el
78
+ }
79
+
80
+ sfn laidOut:EVGLayout (root:EVGElement) {
81
+ def lay (new EVGLayout())
82
+ lay.setPageSize(800.0 600.0)
83
+ lay.layout(root)
84
+ return lay
85
+ }
86
+
87
+ ; A menu: a page holding a row, holding a menu, holding a trigger and the
88
+ ; surface that hangs off it.
89
+ sfn buildMenu:EVGElement (withAnchor:boolean) {
90
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
91
+ def row:EVGElement (EVGOverlayTest.box("row" "row" 400.0 40.0))
92
+ row.setAttribute("display" "flex")
93
+ row.setAttribute("flex-direction" "row")
94
+ row.setAttribute("flex-wrap" "nowrap")
95
+
96
+ def menu:EVGElement (EVGElement.createDiv())
97
+ menu.id = "menu"
98
+ menu.setAttribute("display" "flex")
99
+ menu.setAttribute("flex-direction" "column")
100
+ menu.setAttribute("width" "fit-content")
101
+
102
+ def trigger:EVGElement (EVGOverlayTest.box("trigger" "trigger" 60.0 30.0))
103
+ if withAnchor {
104
+ trigger.setAttribute("overlay-anchor-role" "true")
105
+ }
106
+
107
+ def surface:EVGElement (EVGOverlayTest.box("surface" "surface" 200.0 120.0))
108
+ surface.setAttribute("overlay" "true")
109
+ surface.setAttribute("overlay-side" "bottom")
110
+ surface.setAttribute("overlay-align" "start")
111
+ surface.setAttribute("overlay-gap" "4")
112
+
113
+ menu.addChild(trigger)
114
+ menu.addChild(surface)
115
+ row.addChild(menu)
116
+ page.addChild(row)
117
+ return page
118
+ }
119
+
120
+ ; Breadth-first over a worklist rather than a recursive search: Ranger will
121
+ ; not resolve a static that returns an optional and calls itself, which is
122
+ ; noted next to UiHost.findEl for the same reason.
123
+ ; Not called `at`: that is a Ranger operator, and a static of the same
124
+ ; name does not resolve.
125
+ sfn nodeById:EVGElement (root:EVGElement id:string) {
126
+ def work:[EVGElement]
127
+ push work root
128
+ def i:int 0
129
+ while (i < (array_length work)) {
130
+ def el:EVGElement (itemAt work i)
131
+ if (el.id == id) {
132
+ return el
133
+ }
134
+ def j:int 0
135
+ while (j < (array_length el.children)) {
136
+ push work (itemAt el.children j)
137
+ j = (j + 1)
138
+ }
139
+ i = (i + 1)
140
+ }
141
+ ; A miss returns an empty element, so a wrong id fails an assertion
142
+ ; rather than taking the process down.
143
+ return (EVGElement.createDiv())
144
+ }
145
+
146
+ sfn testOutOfFlow:void (c:OverlayCheck) {
147
+ print "--- an overlay takes no space in its parent's flow ---"
148
+ def page:EVGElement (EVGOverlayTest.buildMenu(true))
149
+ EVGOverlayTest.laidOut(page)
150
+ def menu:EVGElement (EVGOverlayTest.nodeById(page "menu"))
151
+ ; The menu holds a 60px trigger and a 200px surface. If the surface were
152
+ ; in the flow the menu would be 200 wide; it is the trigger's width.
153
+ c.eqInt("the menu is as wide as its trigger" (to_int menu.calculatedWidth) 60)
154
+ c.eqInt("and as tall" (to_int menu.calculatedHeight) 30)
155
+ }
156
+
157
+ sfn testPlacement:void (c:OverlayCheck) {
158
+ print "--- a surface is placed against its anchor ---"
159
+ def page:EVGElement (EVGOverlayTest.buildMenu(true))
160
+ EVGOverlayTest.laidOut(page)
161
+ def trigger:EVGElement (EVGOverlayTest.nodeById(page "trigger"))
162
+ def surface:EVGElement (EVGOverlayTest.nodeById(page "surface"))
163
+ ; bottom + start + a 4px gap
164
+ c.eqInt("left edges line up" (to_int surface.calculatedX) (to_int trigger.calculatedX))
165
+ c.eqInt("and it sits under the trigger, past the gap"
166
+ (to_int surface.calculatedY)
167
+ (to_int ((trigger.calculatedY + trigger.calculatedHeight) + 4.0)))
168
+ }
169
+
170
+ sfn testSubtreeTravels:void (c:OverlayCheck) {
171
+ print "--- the surface's children travel with it ---"
172
+ def page:EVGElement (EVGOverlayTest.buildMenu(true))
173
+ def surface:EVGElement (EVGOverlayTest.nodeById(page "surface"))
174
+ ; To the RIGHT, so the surface moves along BOTH axes: a surface that
175
+ ; only ever moves down would let a child that stayed behind
176
+ ; horizontally pass this unnoticed.
177
+ surface.setAttribute("overlay-side" "right")
178
+ def kid:EVGElement (EVGOverlayTest.box("kid" "kid" 100.0 20.0))
179
+ surface.addChild(kid)
180
+ EVGOverlayTest.laidOut(page)
181
+ def s2:EVGElement (EVGOverlayTest.nodeById(page "surface"))
182
+ def k2:EVGElement (EVGOverlayTest.nodeById(page "kid"))
183
+ ; The child was laid out inside the surface before the surface moved.
184
+ ; If the move did not take it along it would be left behind at the top.
185
+ c.ok("the child is inside its surface" (k2.calculatedY >= s2.calculatedY))
186
+ c.eqInt("and moved sideways with it too" (to_int k2.calculatedX) (to_int s2.calculatedX))
187
+ }
188
+
189
+ ; THE PASS THAT SKIPS. `placeOverlaysIn` no longer walks every element:
190
+ ; a subtree the layout KEPT moved whole, so a surface inside it moved with
191
+ ; the anchor it sits against, and the pass takes the answer it cached
192
+ ; rather than descending. That saving is worth nothing if it puts a
193
+ ; surface in the wrong place, and the way it would fail is quiet — a menu
194
+ ; that opens where it opened last time — so it is checked directly:
195
+ ;
196
+ ; the same tree, laid out twice, with the kept subtree MOVED between
197
+ ; the two, must place the surface where a tree that was never kept
198
+ ; places it.
199
+ ; The same menu, with a spacer of `pad` pixels before it, so the whole
200
+ ; thing starts further down the page.
201
+ sfn menuBelow:EVGElement (pad:double) {
202
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
203
+ if (pad > 0.0) {
204
+ page.addChild((EVGOverlayTest.box("spacer" "spacer" 400.0 pad)))
205
+ }
206
+ def built:EVGElement (EVGOverlayTest.buildMenu(true))
207
+ def row:EVGElement (EVGOverlayTest.nodeById(built "row"))
208
+ page.addChild(row)
209
+ return page
210
+ }
211
+
212
+ sfn testKeptSubtree:void (c:OverlayCheck) {
213
+ print "--- a surface inside a subtree the layout kept ---"
214
+ def page:EVGElement (EVGOverlayTest.menuBelow(0.0))
215
+ def menu:EVGElement (EVGOverlayTest.nodeById(page "menu"))
216
+ menu.keepLayout = true
217
+ menu.layoutClean = true
218
+ EVGOverlayTest.laidOut(page)
219
+ ; NUMBERS, not elements: the tree is the same objects on both sides of
220
+ ; the move, so an element held across it reads the new value.
221
+ def s1:EVGElement (EVGOverlayTest.nodeById(page "surface"))
222
+ def t1:EVGElement (EVGOverlayTest.nodeById(page "trigger"))
223
+ def t1y:double t1.calculatedY
224
+ def gap1:int (to_int (s1.calculatedY - t1.calculatedY))
225
+ def dx1:int (to_int (s1.calculatedX - t1.calculatedX))
226
+ c.ok("it is placed the first time" (gap1 > 0))
227
+
228
+ ; Now MOVE it: the row it sits in is pushed down and across, so the
229
+ ; kept subtree arrives somewhere else. If the skip were wrong the
230
+ ; surface would keep its old absolute position and the gap would open.
231
+ def moved:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
232
+ moved.addChild((EVGOverlayTest.box("spacer" "spacer" 400.0 70.0)))
233
+ def keptRow:EVGElement (EVGOverlayTest.nodeById(page "row"))
234
+ moved.addChild(keptRow)
235
+ EVGOverlayTest.laidOut(moved)
236
+ def page2:EVGElement moved
237
+ def s2:EVGElement (EVGOverlayTest.nodeById(page2 "surface"))
238
+ def t2:EVGElement (EVGOverlayTest.nodeById(page2 "trigger"))
239
+ c.ok("the trigger moved down" (t2.calculatedY > t1y))
240
+ c.eqInt("and the surface kept its distance from it"
241
+ (to_int (s2.calculatedY - t2.calculatedY)) gap1)
242
+ c.eqInt("on the other axis too"
243
+ (to_int (s2.calculatedX - t2.calculatedX)) dx1)
244
+
245
+ ; And a tree that never kept anything must agree, which is what makes
246
+ ; the two paths one behaviour rather than two.
247
+ def plain:EVGElement (EVGOverlayTest.menuBelow(70.0))
248
+ EVGOverlayTest.laidOut(plain)
249
+ def s3:EVGElement (EVGOverlayTest.nodeById(plain "surface"))
250
+ c.eqInt("the slow path puts it in the same place"
251
+ (to_int s2.calculatedY) (to_int s3.calculatedY))
252
+ c.eqInt("and at the same x" (to_int s2.calculatedX) (to_int s3.calculatedX))
253
+ }
254
+
255
+ ; The one that makes a submenu ordinary: a surface whose anchor is itself
256
+ ; inside another surface, and therefore has already been moved.
257
+ sfn testNested:void (c:OverlayCheck) {
258
+ print "--- a surface inside a surface anchors to the moved rectangle ---"
259
+ def page:EVGElement (EVGOverlayTest.buildMenu(true))
260
+ def surface:EVGElement (EVGOverlayTest.nodeById(page "surface"))
261
+
262
+ def sub:EVGElement (EVGElement.createDiv())
263
+ sub.id = "submenu"
264
+ sub.setAttribute("display" "flex")
265
+ sub.setAttribute("flex-direction" "column")
266
+ sub.setAttribute("width" "fit-content")
267
+
268
+ def subRow:EVGElement (EVGOverlayTest.box("subrow" "subrow" 80.0 20.0))
269
+ subRow.setAttribute("overlay-anchor-role" "true")
270
+ def subSurface:EVGElement (EVGOverlayTest.box("subsurface" "subsurface" 150.0 60.0))
271
+ subSurface.setAttribute("overlay" "true")
272
+ subSurface.setAttribute("overlay-side" "right")
273
+ subSurface.setAttribute("overlay-align" "start")
274
+ subSurface.setAttribute("overlay-gap" "4")
275
+ sub.addChild(subRow)
276
+ sub.addChild(subSurface)
277
+ surface.addChild(sub)
278
+
279
+ EVGOverlayTest.laidOut(page)
280
+ def row2:EVGElement (EVGOverlayTest.nodeById(page "subrow"))
281
+ def surf2:EVGElement (EVGOverlayTest.nodeById(page "subsurface"))
282
+ c.eqInt("it opens to the right of its row, past the gap"
283
+ (to_int surf2.calculatedX)
284
+ (to_int ((row2.calculatedX + row2.calculatedWidth) + 4.0)))
285
+ c.eqInt("and lines up with it" (to_int surf2.calculatedY) (to_int row2.calculatedY))
286
+ ; The outer surface moved down by the trigger's height plus the gap, so
287
+ ; a submenu anchored to the pre-move rectangle would be 34px too high.
288
+ c.ok("which is BELOW the menu bar, not at the top of the page" (surf2.calculatedY > 30.0))
289
+ }
290
+
291
+ sfn testUnanchored:void (c:OverlayCheck) {
292
+ print "--- a surface with no anchor is reported ---"
293
+ def page:EVGElement (EVGOverlayTest.buildMenu(false))
294
+ def lay:EVGLayout (EVGOverlayTest.laidOut(page))
295
+ def errs:[string] (lay.getOverlayErrors())
296
+ c.eqInt("one error" (array_length errs) 1)
297
+ if ((array_length errs) > 0) {
298
+ def msg:string (itemAt errs 0)
299
+ c.ok("naming the surface" ((indexOf msg "surface") >= 0))
300
+ c.ok("and saying what to do" ((indexOf msg "overlay-anchor-role") >= 0))
301
+ }
302
+ }
303
+
304
+ sfn testCentered:void (c:OverlayCheck) {
305
+ print "--- a centred surface needs no anchor ---"
306
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
307
+ def modal:EVGElement (EVGOverlayTest.box("modal" "modal" 200.0 100.0))
308
+ modal.setAttribute("overlay" "true")
309
+ modal.setAttribute("overlay-side" "center")
310
+ page.addChild(modal)
311
+ def lay:EVGLayout (EVGOverlayTest.laidOut(page))
312
+ def m:EVGElement (EVGOverlayTest.nodeById(page "modal"))
313
+ c.eqInt("centred across" (to_int m.calculatedX) 300)
314
+ c.eqInt("and down" (to_int m.calculatedY) 250)
315
+ c.eqInt("with nothing reported" (array_length (lay.getOverlayErrors())) 0)
316
+ }
317
+
318
+ ; ---- paint order and hit testing -----------------------------------------
319
+ ; Being placed correctly is not enough. A surface that paints in tree order
320
+ ; is above the page only by luck of where its menu sits, and a click that
321
+ ; walks the tree lands on whatever is UNDER the panel. Both follow from one
322
+ ; list: the normal tree, then the surfaces, in the order they opened.
323
+
324
+ ; A bar with two menus where the FIRST one is open. Its panel overhangs the
325
+ ; second menu's trigger, so tree order paints the trigger on top of the
326
+ ; panel and a tree-order hit test answers "trigger" for a point inside the
327
+ ; panel. Both are wrong, and both are wrong in the same place.
328
+ sfn buildTwoMenus:EVGElement () {
329
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
330
+ def row:EVGElement (EVGOverlayTest.box("row" "row" 400.0 40.0))
331
+ row.setAttribute("display" "flex")
332
+ row.setAttribute("flex-direction" "row")
333
+ row.setAttribute("flex-wrap" "nowrap")
334
+
335
+ def first:EVGElement (EVGElement.createDiv())
336
+ first.id = "first"
337
+ first.setAttribute("display" "flex")
338
+ first.setAttribute("flex-direction" "column")
339
+ first.setAttribute("width" "fit-content")
340
+ def t1:EVGElement (EVGOverlayTest.box("t1" "trigger" 60.0 30.0))
341
+ t1.setAttribute("overlay-anchor-role" "true")
342
+ def panel:EVGElement (EVGOverlayTest.box("panel" "surface" 200.0 120.0))
343
+ panel.setAttribute("overlay" "true")
344
+ panel.setAttribute("overlay-side" "bottom")
345
+ panel.setAttribute("overlay-align" "start")
346
+ panel.setAttribute("overlay-gap" "4")
347
+ panel.setAttribute("background-color" "#ffffff")
348
+ first.addChild(t1)
349
+ first.addChild(panel)
350
+
351
+ ; The second menu is closed — a trigger and nothing else — and it sits
352
+ ; beside the first, so the open panel hangs over it.
353
+ def second:EVGElement (EVGElement.createDiv())
354
+ second.id = "second"
355
+ second.setAttribute("display" "flex")
356
+ second.setAttribute("flex-direction" "column")
357
+ second.setAttribute("width" "fit-content")
358
+ def t2:EVGElement (EVGOverlayTest.box("t2" "trigger" 60.0 30.0))
359
+ t2.setAttribute("background-color" "#ff0000")
360
+ t2.setAttribute("height" "300px")
361
+ second.addChild(t2)
362
+
363
+ row.addChild(first)
364
+ row.addChild(second)
365
+ page.addChild(row)
366
+ return page
367
+ }
368
+
369
+ ; Where in the display list this element's own background was drawn, or -1.
370
+ sfn rectIndex:int (dl:EVGDisplayList el:EVGElement) {
371
+ def i:int 0
372
+ while (i < (array_length dl.cmds)) {
373
+ def c:EVGDrawCmd (itemAt dl.cmds i)
374
+ if (c.kind == 0) {
375
+ def sameX:boolean ((to_int c.x) == (to_int el.calculatedX))
376
+ def sameY:boolean ((to_int c.y) == (to_int el.calculatedY))
377
+ def sameW:boolean ((to_int c.w) == (to_int el.calculatedWidth))
378
+ if (sameX && (sameY && sameW)) {
379
+ return i
380
+ }
381
+ }
382
+ i = (i + 1)
383
+ }
384
+ return -1
385
+ }
386
+
387
+ sfn testPaintOrder:void (c:OverlayCheck) {
388
+ print "--- a surface paints above the page, not in tree order ---"
389
+ def page:EVGElement (EVGOverlayTest.buildTwoMenus())
390
+ def lay:EVGLayout (EVGOverlayTest.laidOut(page))
391
+ def dl (new EVGDisplayList())
392
+ dl.setTextEngine((lay.getTextEngine()))
393
+ dl.build(page)
394
+ def panel:EVGElement (EVGOverlayTest.nodeById(page "panel"))
395
+ def t2:EVGElement (EVGOverlayTest.nodeById(page "t2"))
396
+ def pi:int (EVGOverlayTest.rectIndex(dl panel))
397
+ def ti:int (EVGOverlayTest.rectIndex(dl t2))
398
+ c.ok("both were drawn" ((pi >= 0) && (ti >= 0)))
399
+ ; The panel's menu comes FIRST in the bar, so tree order draws the
400
+ ; second menu's trigger over it.
401
+ c.ok("the panel is drawn after the trigger it overhangs" (pi > ti))
402
+ }
403
+
404
+ sfn testHitTopmost:void (c:OverlayCheck) {
405
+ print "--- a click in the panel hits the panel ---"
406
+ def page:EVGElement (EVGOverlayTest.buildTwoMenus())
407
+ EVGOverlayTest.laidOut(page)
408
+ def panel:EVGElement (EVGOverlayTest.nodeById(page "panel"))
409
+ def hit (new EVGHitTest())
410
+ ; A point inside the panel AND inside the trigger beside it: the whole
411
+ ; question is which one answers.
412
+ def px:double (panel.calculatedX + 150.0)
413
+ def py:double (panel.calculatedY + 10.0)
414
+ def t2:EVGElement (EVGOverlayTest.nodeById(page "t2"))
415
+ c.ok("the point really is over both" ((px > t2.calculatedX) && (py < (t2.calculatedY + t2.calculatedHeight))))
416
+ c.ok("and the panel answers" ((hit.idAt(page px py)) == "panel"))
417
+ ; Outside every surface, the page still answers normally.
418
+ c.ok("a point outside answers the element under it"
419
+ ((hit.idAt(page (t2.calculatedX + 10.0) (t2.calculatedY + 200.0))) == "t2"))
420
+ }
421
+
422
+ ; ---- collisions ----------------------------------------------------------
423
+ ; A menu near the bottom of the page opens upwards. Every real menu does
424
+ ; this, and the reason is not aesthetics: the part that falls off the page
425
+ ; cannot be clicked or read, so a surface that ignores the edge silently
426
+ ; loses rows.
427
+
428
+ ; One anchor at a given spot, with a surface hanging off it. The page is
429
+ ; 800x600, so putting the anchor near an edge is how the collision is set up.
430
+ sfn buildAt:EVGElement (ax:double ay:double side:string align:string sw:double sh:double) {
431
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
432
+ def holder:EVGElement (EVGElement.createDiv())
433
+ holder.id = "holder"
434
+ holder.setAttribute("position" "absolute")
435
+ holder.setAttribute("left" ((to_string (to_int ax)) + "px"))
436
+ holder.setAttribute("top" ((to_string (to_int ay)) + "px"))
437
+ holder.setAttribute("width" "60px")
438
+ holder.setAttribute("height" "30px")
439
+
440
+ def anchor:EVGElement (EVGOverlayTest.box("anchor" "anchor" 60.0 30.0))
441
+ anchor.setAttribute("overlay-anchor-role" "true")
442
+ def surface:EVGElement (EVGOverlayTest.box("surface" "surface" sw sh))
443
+ surface.setAttribute("overlay" "true")
444
+ surface.setAttribute("overlay-side" side)
445
+ surface.setAttribute("overlay-align" align)
446
+ surface.setAttribute("overlay-gap" "4")
447
+
448
+ holder.addChild(anchor)
449
+ holder.addChild(surface)
450
+ page.addChild(holder)
451
+ return page
452
+ }
453
+
454
+ sfn testFlip:void (c:OverlayCheck) {
455
+ print "--- a surface near an edge opens the other way ---"
456
+ ; Room below: nothing moves. This one is here so the flip cannot be a
457
+ ; test that passes because the code always flips.
458
+ def roomy:EVGElement (EVGOverlayTest.buildAt(100.0 100.0 "bottom" "start" 200.0 120.0))
459
+ EVGOverlayTest.laidOut(roomy)
460
+ def s1:EVGElement (EVGOverlayTest.nodeById(roomy "surface"))
461
+ def a1:EVGElement (EVGOverlayTest.nodeById(roomy "anchor"))
462
+ c.eqStr("with room, it stays where it was asked to be" s1.overlayPlacedSide "bottom")
463
+ c.eqInt("under the anchor" (to_int s1.calculatedY) (to_int ((a1.calculatedY + a1.calculatedHeight) + 4.0)))
464
+
465
+ ; 520 + 30 + 4 + 120 = 674, which is off a 600-tall page.
466
+ def tight:EVGElement (EVGOverlayTest.buildAt(100.0 520.0 "bottom" "start" 200.0 120.0))
467
+ EVGOverlayTest.laidOut(tight)
468
+ def s2:EVGElement (EVGOverlayTest.nodeById(tight "surface"))
469
+ def a2:EVGElement (EVGOverlayTest.nodeById(tight "anchor"))
470
+ c.eqStr("with no room below, it opens upwards" s2.overlayPlacedSide "top")
471
+ c.eqInt("above the anchor, past the gap"
472
+ (to_int s2.calculatedY)
473
+ (to_int ((a2.calculatedY - 120.0) - 4.0)))
474
+ c.ok("and is fully on the page" ((s2.calculatedY >= 0.0) && (((s2.calculatedY + 120.0)) <= 600.0)))
475
+
476
+ ; The same, sideways: a submenu at the right edge opens to the left.
477
+ def right:EVGElement (EVGOverlayTest.buildAt(700.0 100.0 "right" "start" 200.0 120.0))
478
+ EVGOverlayTest.laidOut(right)
479
+ def s3:EVGElement (EVGOverlayTest.nodeById(right "surface"))
480
+ def a3:EVGElement (EVGOverlayTest.nodeById(right "anchor"))
481
+ c.eqStr("a submenu at the right edge opens to the left" s3.overlayPlacedSide "left")
482
+ c.eqInt("beside the anchor, past the gap"
483
+ (to_int s3.calculatedX)
484
+ (to_int ((a3.calculatedX - 200.0) - 4.0)))
485
+ }
486
+
487
+ sfn testShift:void (c:OverlayCheck) {
488
+ print "--- and slides along the edge rather than hanging off it ---"
489
+ ; Anchored at x=700 with a 200-wide surface aligned to its left edge:
490
+ ; 700 + 200 = 900, off an 800-wide page. The side is fine; the CROSS
491
+ ; axis is not, and the fix is to slide, not to flip.
492
+ def page:EVGElement (EVGOverlayTest.buildAt(700.0 100.0 "bottom" "start" 200.0 120.0))
493
+ EVGOverlayTest.laidOut(page)
494
+ def s:EVGElement (EVGOverlayTest.nodeById(page "surface"))
495
+ def a:EVGElement (EVGOverlayTest.nodeById(page "anchor"))
496
+ c.eqStr("it is still below" s.overlayPlacedSide "bottom")
497
+ c.eqInt("and its right edge is the page's" (to_int (s.calculatedX + 200.0)) 800)
498
+ ; Sliding it back has to keep it attached to what opened it. A panel
499
+ ; that no longer overlaps its trigger has stopped being that trigger's.
500
+ c.ok("while still overlapping its anchor"
501
+ ((s.calculatedX < (a.calculatedX + a.calculatedWidth)) && ((s.calculatedX + 200.0) > a.calculatedX)))
502
+ ; The subtree comes along, as it does for the first placement.
503
+ c.ok("and the move is the whole surface" (s.calculatedX < a.calculatedX))
504
+ }
505
+
506
+ sfn testNoRoomEitherWay:void (c:OverlayCheck) {
507
+ print "--- with no room on either side it takes the roomier one ---"
508
+ ; A surface taller than the page cannot fit above or below. Drawing it
509
+ ; off the top would lose the first rows, which are the ones a menu puts
510
+ ; its most-used item in.
511
+ ;
512
+ ; The anchor sits at y=300 on a 600-tall page, so there are 296px above
513
+ ; it and 266 below: neither is enough for 700, and `top` loses less. It
514
+ ; asked for `bottom` and gets `top`, which is the rule doing its job
515
+ ; rather than a fits/does-not-fit test.
516
+ def page:EVGElement (EVGOverlayTest.buildAt(100.0 300.0 "bottom" "start" 200.0 700.0))
517
+ EVGOverlayTest.laidOut(page)
518
+ def s:EVGElement (EVGOverlayTest.nodeById(page "surface"))
519
+ c.eqInt("it starts at the top of the page" (to_int s.calculatedY) 0)
520
+ c.eqStr("on the side that loses less" s.overlayPlacedSide "top")
521
+ }
522
+
523
+ ; A modal's backdrop: the page itself, not the card the dialog was declared
524
+ ; in. This is the case a percentage cannot express — `width: 100%` resolves
525
+ ; against the PARENT, and the parent of a dialog is whatever part of the
526
+ ; page happened to declare it.
527
+ sfn testCover:void (c:OverlayCheck) {
528
+ print "--- a backdrop covers the page, not its parent ---"
529
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
530
+ def card:EVGElement (EVGOverlayTest.box("card" "card" 200.0 100.0))
531
+ def backdrop:EVGElement (EVGOverlayTest.box("backdrop" "backdrop" 50.0 20.0))
532
+ backdrop.setAttribute("overlay" "true")
533
+ backdrop.setAttribute("overlay-side" "cover")
534
+ def dialog:EVGElement (EVGOverlayTest.box("dialog" "dialog" 300.0 200.0))
535
+ dialog.setAttribute("overlay" "true")
536
+ dialog.setAttribute("overlay-side" "center")
537
+ card.addChild(backdrop)
538
+ card.addChild(dialog)
539
+ page.addChild(card)
540
+ def lay:EVGLayout (EVGOverlayTest.laidOut(page))
541
+
542
+ def b:EVGElement (EVGOverlayTest.nodeById(page "backdrop"))
543
+ c.eqInt("it starts at the page's origin" (to_int (b.calculatedX + b.calculatedY)) 0)
544
+ c.eqInt("as wide as the page" (to_int b.calculatedWidth) 800)
545
+ c.eqInt("and as tall" (to_int b.calculatedHeight) 600)
546
+ def d:EVGElement (EVGOverlayTest.nodeById(page "dialog"))
547
+ c.eqInt("the dialog is centred on the page, not on the card" (to_int d.calculatedX) 250)
548
+ c.eqInt("and down" (to_int d.calculatedY) 200)
549
+ ; The card it was declared in is unchanged: a modal takes no space.
550
+ def cd:EVGElement (EVGOverlayTest.nodeById(page "card"))
551
+ c.eqInt("and the card it was declared in is untouched" (to_int cd.calculatedWidth) 200)
552
+ ; Painted after everything, and the dialog after the backdrop, so the
553
+ ; dim never covers the dialog.
554
+ def hit (new EVGHitTest())
555
+ c.eqStr("a press in the middle hits the dialog" (hit.idAt(page 400.0 300.0)) "dialog")
556
+ c.eqStr("and one at the edge hits the backdrop, not the page behind it"
557
+ (hit.idAt(page 20.0 560.0)) "backdrop")
558
+ c.eqInt("with nothing reported" (array_length (lay.getOverlayErrors())) 0)
559
+ }
560
+
561
+ ; `fit-content` arrived for a floating panel, where what has to be measured
562
+ ; is a column of rows. A badge is the other half of the same idea: a pill
563
+ ; that hugs its word, where the content is TEXT and there are no children
564
+ ; to measure at all.
565
+ ;
566
+ ; It already worked, and not through `contentExtent` — which sees no
567
+ ; children and gives up — but because `fit-content` parses with `isSet`
568
+ ; false, and a width-less box holding only text is measured from the text.
569
+ ; That is worth a test rather than a shrug: it is load-bearing for every
570
+ ; badge in the sortable demo, and nothing else says so.
571
+ sfn testFitText:void (c:OverlayCheck) {
572
+ print "--- fit-content measures text, not only children ---"
573
+ def page:EVGElement (EVGOverlayTest.box("page" "page" 800.0 600.0))
574
+ def badge:EVGElement (EVGElement.createDiv())
575
+ badge.id = "badge"
576
+ badge.setAttribute("width" "fit-content")
577
+ badge.setAttribute("padding" "4px 12px")
578
+ badge.setAttribute("font-size" "13px")
579
+ badge.textContent = "document"
580
+ def wide:EVGElement (EVGElement.createDiv())
581
+ wide.id = "wide"
582
+ wide.setAttribute("width" "fit-content")
583
+ wide.setAttribute("padding" "4px 12px")
584
+ wide.setAttribute("font-size" "13px")
585
+ wide.textContent = "a much longer label"
586
+ page.addChild(badge)
587
+ page.addChild(wide)
588
+ EVGOverlayTest.laidOut(page)
589
+
590
+ def b:EVGElement (EVGOverlayTest.nodeById(page "badge"))
591
+ def w:EVGElement (EVGOverlayTest.nodeById(page "wide"))
592
+ ; Not the page's width, which is what a width-less box gets.
593
+ c.ok("a badge is narrower than the page it sits in" (b.calculatedWidth < 200.0))
594
+ ; And wide enough for the word plus its padding: 24px of padding, and a
595
+ ; 13px face is never wider than the string times the font size.
596
+ c.ok("but wide enough for its word" (b.calculatedWidth > 40.0))
597
+ c.ok("a longer label is wider" (w.calculatedWidth > b.calculatedWidth))
598
+ c.ok("and still not the whole page" (w.calculatedWidth < 400.0))
599
+ }
600
+
601
+ sfn main:void () {
602
+ def c (new OverlayCheck())
603
+ print "=== EVG overlay surfaces ==="
604
+ EVGOverlayTest.testOutOfFlow(c)
605
+ EVGOverlayTest.testPlacement(c)
606
+ EVGOverlayTest.testSubtreeTravels(c)
607
+ EVGOverlayTest.testKeptSubtree(c)
608
+ EVGOverlayTest.testNested(c)
609
+ EVGOverlayTest.testUnanchored(c)
610
+ EVGOverlayTest.testCentered(c)
611
+ EVGOverlayTest.testPaintOrder(c)
612
+ EVGOverlayTest.testHitTopmost(c)
613
+ EVGOverlayTest.testFlip(c)
614
+ EVGOverlayTest.testShift(c)
615
+ EVGOverlayTest.testNoRoomEitherWay(c)
616
+ EVGOverlayTest.testCover(c)
617
+ EVGOverlayTest.testFitText(c)
618
+ print ""
619
+ print ("passed=" + (to_string c.passed) + " failed=" + (to_string c.failed))
620
+ if (c.failed > 0) {
621
+ print "FAILURES"
622
+ } {
623
+ print "ALL PASS"
624
+ }
625
+ }
626
+ }