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,535 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; ==============================================================================
4
+ ; EVGJsonTest — does a command survive being written down?
5
+ ; ==============================================================================
6
+ ;
7
+ ; A display list is drawn two ways: by the software canvas, which reads the
8
+ ; command objects, and by every other backend — WebGL, a canvas host, a remote
9
+ ; viewer — which reads `toJson`. Every test in this repository takes the first
10
+ ; route, so a field the serializer forgot was invisible: the pictures came out
11
+ ; right, the tests passed, and the browser drew something else.
12
+ ;
13
+ ; Three did. Paths were written only when `ringEnds` was set, so a command
14
+ ; built by hand — and several are, here and in the galleries — reached the
15
+ ; software canvas and nothing else: a bracket, an arrow head, the outline of a
16
+ ; rounded box, all simply absent on the GPU. Gradients were never serialized at
17
+ ; all, so a two-stop fill arrived as its first stop, flat.
18
+ ;
19
+ ; So this asks the question the picture tests cannot: given a command with a
20
+ ; field set, does that field appear in the JSON? It is deliberately crude —
21
+ ; substring checks against the text — because the failure it is guarding
22
+ ; against is a field that is not there at all.
23
+ ;
24
+ ; npm run evg:json:test
25
+ ; ==============================================================================
26
+
27
+ Import "EVGDisplayList.rgr"
28
+ Import "EVGColor.rgr"
29
+ Import "EVGElement.rgr"
30
+ Import "EVGLayout.rgr"
31
+ Import "EVGTextEngine.rgr"
32
+
33
+ class EVGJsonTest {
34
+ def passed:int 0
35
+ def failed:int 0
36
+
37
+ sfn m@(main):void () {
38
+ def t (new EVGJsonTest())
39
+ t.run()
40
+ }
41
+
42
+ fn ok:void (what:string cond:boolean) {
43
+ if cond {
44
+ passed = (passed + 1)
45
+ print (" PASS " + what)
46
+ } {
47
+ failed = (failed + 1)
48
+ print (" FAIL " + what)
49
+ }
50
+ }
51
+
52
+ fn has:void (what:string json:string needle:string) {
53
+ this.ok(what ((indexOf json needle) >= 0))
54
+ }
55
+
56
+
57
+ ; --- the two angle conventions -------------------------------------------
58
+ ;
59
+ ; `gd` is a direction code because that is all a GPU backend needs, but the
60
+ ; raster and PDF painters draw along an ANGLE and they do not agree about
61
+ ; what an angle is: the rasteriser builds a vector from (cos, sin) with 0
62
+ ; to the right, while the PDF renderer parses CSS where 0 is to the top.
63
+ ; One code, two right answers, and taking the wrong one turns every
64
+ ; gradient a quarter turn in one target and not the other.
65
+ ;
66
+ ; So this checks the inverses against the reduction just above, on the same
67
+ ; axes, rather than trusting two constants to stay in step.
68
+ fn testGradientAngleConventions:void () {
69
+ print "-- a direction code, back to an angle, in both conventions"
70
+
71
+ ; The axis a CSS angle reduces to, from the same rule the list uses.
72
+ def across:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(90deg, #102030, #c8d2dc)"))
73
+ this.has("90deg is the horizontal axis" (this.listOf(across)) "\"gd\":1")
74
+ def down:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(180deg, #102030, #c8d2dc)"))
75
+ this.has("180deg is the vertical one" (this.listOf(down)) "\"gd\":0")
76
+
77
+ ; Raster: 0 to the right, 90 down.
78
+ this.ok("horizontal rasterises at 0" ((EVGDisplayList.rasterAngleOfDir(1)) == 0.0))
79
+ this.ok("vertical rasterises at 90" ((EVGDisplayList.rasterAngleOfDir(0)) == 90.0))
80
+
81
+ ; CSS: the angle it came from. A round trip has to land on the axis it
82
+ ; started on, which is the property worth asserting — not the number.
83
+ this.ok("horizontal is 90deg in CSS" ((EVGDisplayList.cssAngleOfDir(1)) == 90.0))
84
+ this.ok("vertical is 180deg in CSS" ((EVGDisplayList.cssAngleOfDir(0)) == 180.0))
85
+
86
+ def backAcross:EVGElement (EVGJsonTest.boxWith("background" ("linear-gradient(" + ((EVGDisplayList.num((EVGDisplayList.cssAngleOfDir(1)))) + "deg, #102030, #c8d2dc)"))))
87
+ this.has("and reducing it again gives the same axis" (this.listOf(backAcross)) "\"gd\":1")
88
+ def backDown:EVGElement (EVGJsonTest.boxWith("background" ("linear-gradient(" + ((EVGDisplayList.num((EVGDisplayList.cssAngleOfDir(0)))) + "deg, #102030, #c8d2dc)"))))
89
+ this.has("for the other one too" (this.listOf(backDown)) "\"gd\":0")
90
+ }
91
+
92
+ ; --- WHAT A GRADIENT MAY BE WRITTEN IN ------------------------------------
93
+ ;
94
+ ; The parser looked for `#hex` and nothing else, so a gradient written in
95
+ ; `rgb()` — the form every other colour in a generated document uses, and
96
+ ; the form a model reaches for first — parsed to a gradient with NO stops.
97
+ ; An element with no stops emits no background rectangle at all, so the
98
+ ; node vanished from the picture: not a flat colour, not a wrong colour,
99
+ ; gone. Three properties, three spellings, one silent disappearance.
100
+ ;
101
+ ; The direction was the other half. CSS with no angle runs top to bottom
102
+ ; and `to bottom` says the same thing; this field's default was 0, which is
103
+ ; to the TOP, and `to …` was not read at all — so two of the three ways of
104
+ ; asking for the same ramp came out upside down.
105
+ fn testGradientSpellings:void () {
106
+ print "-- the spellings a gradient may arrive in"
107
+
108
+ def rgbStops:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(180deg, rgb(16,32,48), rgb(200,210,220))"))
109
+ def rgbJson:string (this.listOf(rgbStops))
110
+ this.has("rgb() stops paint at all" rgbJson "\"gd\":0")
111
+ this.has("the near stop" rgbJson "\"c\":[16,32,48,1.00]")
112
+ this.has("the far one" rgbJson "\"c2\":[200,210,220,1.00]")
113
+
114
+ def alpha:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(to right, rgba(16,32,48,0.5), #c8d2dc)"))
115
+ def alphaJson:string (this.listOf(alpha))
116
+ this.has("rgba keeps its alpha" alphaJson "\"c\":[16,32,48,0.50]")
117
+ this.has("and `to right` is the horizontal axis" alphaJson "\"gd\":1")
118
+
119
+ ; The three ways of saying top-to-bottom have to agree with each other.
120
+ def spelled:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(180deg, #102030, #c8d2dc)"))
121
+ def bare:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(#102030, #c8d2dc)"))
122
+ def keyword:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(to bottom, #102030, #c8d2dc)"))
123
+ def a:string (this.listOf(spelled))
124
+ def b:string (this.listOf(bare))
125
+ def c:string (this.listOf(keyword))
126
+ this.ok("no angle means the same as 180deg" (a == b))
127
+ this.ok("and so does `to bottom`" (a == c))
128
+ this.has("with the first colour at the top" a "\"c\":[16,32,48,1.00]")
129
+
130
+ ; `background-gradient` is the name the editable document format
131
+ ; carries, so it has to reach the list the same way `background` does.
132
+ def named:EVGElement (EVGJsonTest.boxWith("background-gradient" "linear-gradient(180deg, rgb(16,32,48), rgb(200,210,220))"))
133
+ this.ok("background-gradient is the same gradient" ((this.listOf(named)) == rgbJson))
134
+ }
135
+
136
+ ; The pair a Figma import speaks, which the list has always understood and
137
+ ; the raster and PDF painters had not.
138
+ fn testTwoStopPairReachesTheList:void () {
139
+ print "-- gradient-from / gradient-to"
140
+ def el:EVGElement (EVGElement.createDiv())
141
+ el.setAttribute("width" "100px")
142
+ el.setAttribute("height" "50px")
143
+ el.setAttribute("gradient-from" "#102030")
144
+ el.setAttribute("gradient-to" "#c8d2dc")
145
+ el.setAttribute("gradient-dir" "1")
146
+ el.markInline("width")
147
+ el.markInline("height")
148
+ this.ok("the element records it" el.gradientSet)
149
+ def j:string (this.listOf(el))
150
+ this.has("the near stop" j "\"c\":[16,32,48,1.00]")
151
+ this.has("the far one" j "\"c2\":[200,210,220,1.00]")
152
+ this.has("and the axis it was given" j "\"gd\":1")
153
+ }
154
+
155
+ fn run:void () {
156
+ print "=== EVGDisplayList.toJson ==="
157
+ this.testPolygonWithRings()
158
+ this.testPolygonBuiltByHand()
159
+ this.testGradient()
160
+ this.testElementGradient()
161
+ this.testGradientAngleConventions()
162
+ this.testGradientSpellings()
163
+ this.testTwoStopPairReachesTheList()
164
+ this.testFlatRectHasNoGradient()
165
+ this.testRectAndBorder()
166
+ this.testTextAndImage()
167
+ this.testEveryNumberIsANumber()
168
+ this.testLetterSpacing()
169
+ this.testParagraphSpacing()
170
+ this.testDocumentTheme()
171
+ print ""
172
+ print ("passed = " + (to_string passed) + " failed = " + (to_string failed))
173
+ if (failed > 0) {
174
+ print "FAILURES"
175
+ } {
176
+ print "ALL PASS"
177
+ }
178
+ }
179
+
180
+ ; WHATEVER GOES IN, A JSON NUMBER COMES OUT.
181
+ ;
182
+ ; `num` writes every coordinate, size, radius and colour in the list, so a
183
+ ; value it cannot spell does not make one command wrong — it makes the
184
+ ; whole frame unparseable, and the page drawing it stops dead. That is what
185
+ ; it looked like from the outside: a ripple frozen mid-flight, with
186
+ ; `SyntaxError: Expected ',' or '}' after property` beside it.
187
+ ;
188
+ ; Two ways in, and neither one announced itself. A value that was not a
189
+ ; number came out as "0.NaN". And the integer divide truncated to 32 bits,
190
+ ; so a magnitude past 2^31 WRAPPED: 1e10 came out as
191
+ ; "1410065408.858993459200", which parses and is merely wrong, and past
192
+ ; about 1e19 the leftover went exponential and stopped being JSON at all.
193
+ ;
194
+ ; So the test is the contract rather than the arithmetic: hand it the worst
195
+ ; values there are and require something a parser will take.
196
+ fn testEveryNumberIsANumber:void () {
197
+ print "-- num writes a number for anything it is given"
198
+ ; The ordinary cases still have to be exactly right — a guard that
199
+ ; rounds real coordinates is worse than the fault it guards against.
200
+ this.ok("a plain value is unchanged" ((EVGDisplayList.num(1336.25)) == "1336.25"))
201
+ this.ok("and a negative one" ((EVGDisplayList.num(-45.0)) == "-45.00"))
202
+ this.ok("and zero" ((EVGDisplayList.num(0.0)) == "0.00"))
203
+ ; Everything up to the clamp keeps its value: the old code went wrong
204
+ ; at 2^31, which is inside this.
205
+ this.ok("and a value past 2^31, which used to wrap"
206
+ ((EVGDisplayList.num(3000000000.0)) == "10000000.00"))
207
+ ; Written as a product because the lexer takes no exponent literals,
208
+ ; and this is well past where the fraction used to go exponential.
209
+ def huge:double (1000000000.0 * 1000000000000.0)
210
+ this.ok("a huge value is pinned, not wrapped"
211
+ ((EVGDisplayList.num(huge)) == "10000000.00"))
212
+ this.ok("and a hugely negative one keeps its sign"
213
+ ((EVGDisplayList.num((0.0 - huge))) == "-10000000.00"))
214
+ ; A NaN fails every comparison, which is exactly how it is caught.
215
+ def nan:double (0.0 / 0.0)
216
+ this.ok("a value that is not a number becomes zero"
217
+ ((EVGDisplayList.num(nan)) == "0.00"))
218
+ def inf:double (1.0 / 0.0)
219
+ this.ok("an infinity is pinned at the limit"
220
+ ((EVGDisplayList.num(inf)) == "10000000.00"))
221
+ this.ok("and a negative infinity"
222
+ ((EVGDisplayList.num((0.0 - inf))) == "-10000000.00"))
223
+ ; And the point of all of it: a command carrying one of these still
224
+ ; produces a list something can read. The needle is what a parser would
225
+ ; choke on — a second dot inside one number.
226
+ def dl (new EVGDisplayList())
227
+ dl.addRect(nan inf huge 10.0 (EVGColor.rgb(1 2 3)))
228
+ def json:string (dl.toJson())
229
+ this.ok("and a command carrying them writes no second dot"
230
+ ((indexOf json ".0.") < 0))
231
+ this.ok("nor an exponent" ((indexOf json "e+") < 0))
232
+ this.ok("nor the word NaN" ((indexOf json "NaN") < 0))
233
+ this.ok("nor an Infinity" ((indexOf json "Infinity") < 0))
234
+ }
235
+
236
+ ; The sanctioned way to add a path. Points, one ring, and a box derived
237
+ ; from the points — the GL backend batches and scissors by that box, and
238
+ ; a path left at 0x0 is a path clipped away.
239
+ fn testPolygonWithRings:void () {
240
+ print "-- a polygon added through addPolygon"
241
+ def dl (new EVGDisplayList())
242
+ def pts:[double] ([] _:double ( 10.0 20.0 110.0 20.0 110.0 70.0 10.0 70.0 ))
243
+ dl.addPolygon(pts (EVGColor.rgb(255 0 0)))
244
+ def json:string (dl.toJson())
245
+ this.has("the points are written" json "\"pts\":[10.00,20.00,110.00,20.00,110.00,70.00,10.00,70.00]")
246
+ this.has("with a ring that closes them" json "\"ends\":[8]")
247
+ def c:EVGDrawCmd (dl.at(0))
248
+ this.ok("and a box derived from the points" ((c.w > 99.0) && (c.h > 49.0)))
249
+ }
250
+
251
+ ; The same path built the way a gallery builds one: points on the command
252
+ ; and nothing else. This is the case that was dropped.
253
+ fn testPolygonBuiltByHand:void () {
254
+ print "-- a polygon built by hand, with no ring list"
255
+ def dl (new EVGDisplayList())
256
+ def c (new EVGDrawCmd())
257
+ c.kind = 6
258
+ c.pts = ([] _:double ( 0.0 0.0 40.0 0.0 40.0 40.0 ))
259
+ c.r = 12
260
+ c.g = 34
261
+ c.b = 56
262
+ c.a = 1.0
263
+ push dl.cmds c
264
+ def json:string (dl.toJson())
265
+ this.has("its points reach the JSON" json "\"pts\":[0.00,0.00,40.00,0.00,40.00,40.00]")
266
+ this.has("as one ring covering all of them" json "\"ends\":[6]")
267
+ this.has("and it keeps its colour" json "\"c\":[12,34,56,1.00]")
268
+ }
269
+
270
+ fn testGradient:void () {
271
+ print "-- a two-stop gradient"
272
+ def dl (new EVGDisplayList())
273
+ def c (new EVGDrawCmd())
274
+ c.kind = 0
275
+ c.x = 0.0
276
+ c.y = 0.0
277
+ c.w = 100.0
278
+ c.h = 50.0
279
+ c.r = 10
280
+ c.g = 20
281
+ c.b = 30
282
+ c.a = 1.0
283
+ c.hasGrad = true
284
+ c.gradDir = 1
285
+ c.r2 = 200
286
+ c.g2 = 210
287
+ c.b2 = 220
288
+ c.a2 = 0.5
289
+ push dl.cmds c
290
+ def json:string (dl.toJson())
291
+ this.has("the near stop is the command's colour" json "\"c\":[10,20,30,1.00]")
292
+ this.has("the far stop is written too" json "\"c2\":[200,210,220,0.50]")
293
+ this.has("along with the direction" json "\"gd\":1")
294
+ }
295
+
296
+ ; --- and the half above the command --------------------------------------
297
+ ;
298
+ ; `testGradient` proves a command with `hasGrad` set is written down. It
299
+ ; cannot prove anything ever SETS it — and for a long time nothing did: the
300
+ ; walk from an element to a display list read `backgroundColor` and no
301
+ ; more, so `background: linear-gradient(...)` came out flat when there was
302
+ ; a colour beside it and emitted no rectangle at all when there was not.
303
+ ;
304
+ ; The two directions the list can carry are down the box and across it, so
305
+ ; an angle is snapped to the nearer axis and the stops are swapped when it
306
+ ; points the other way. Those are the four cases below.
307
+ fn listOf:string (el:EVGElement) {
308
+ def lay (new EVGLayout())
309
+ lay.setPageSize(200.0 100.0)
310
+ lay.layout(el)
311
+ def dl (new EVGDisplayList())
312
+ dl.setTextEngine((lay.getTextEngine()))
313
+ dl.build(el)
314
+ return (dl.toJson())
315
+ }
316
+
317
+ sfn boxWith:EVGElement (name:string value:string) {
318
+ def el (new EVGElement())
319
+ el.setAttribute("width" "100px")
320
+ el.setAttribute("height" "50px")
321
+ el.setAttribute(name value)
322
+ return el
323
+ }
324
+
325
+ fn testElementGradient:void () {
326
+ print "-- an element with a CSS gradient"
327
+ def down:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(180deg, #102030, #c8d2dc)"))
328
+ def j1:string (this.listOf(down))
329
+ this.has("to bottom keeps the stops in order" j1 "\"c\":[16,32,48,1.00]")
330
+ this.has("and names the far one" j1 "\"c2\":[200,210,220,1.00]")
331
+ this.has("running down the box" j1 "\"gd\":0")
332
+
333
+ def across:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(90deg, #102030, #c8d2dc)"))
334
+ this.has("to right runs across it" (this.listOf(across)) "\"gd\":1")
335
+
336
+ ; 0deg is "to top", which the list cannot say — so it is the same axis
337
+ ; with the stops the other way round.
338
+ def up:EVGElement (EVGJsonTest.boxWith("background" "linear-gradient(0deg, #102030, #c8d2dc)"))
339
+ def j3:string (this.listOf(up))
340
+ this.has("to top swaps them instead" j3 "\"c\":[200,210,220,1.00]")
341
+ this.has("and keeps the axis" j3 "\"gd\":0")
342
+
343
+ ; A radial gradient is not a direction, so it is not turned into one:
344
+ ; the box keeps whatever flat colour it had and a viewer sees a missing
345
+ ; effect rather than a wrong one.
346
+ def radial:EVGElement (EVGJsonTest.boxWith("background" "radial-gradient(circle, #102030, #c8d2dc)"))
347
+ radial.setAttribute("background-color" "#010203")
348
+ def j4:string (this.listOf(radial))
349
+ this.ok("a radial gradient is left flat" ((indexOf j4 "\"c2\"") < 0))
350
+ this.has("with the colour it had" j4 "\"c\":[1,2,3,1.00]")
351
+
352
+ ; The RGU1 pair, which is already the list's own vocabulary.
353
+ def pair (new EVGElement())
354
+ pair.setAttribute("width" "100px")
355
+ pair.setAttribute("height" "50px")
356
+ pair.setAttribute("gradient-from" "#102030")
357
+ pair.setAttribute("gradient-to" "#c8d2dc")
358
+ pair.setAttribute("gradient-dir" "1")
359
+ def j5:string (this.listOf(pair))
360
+ this.has("gradient-from/to needs no interpretation" j5 "\"c2\":[200,210,220,1.00]")
361
+ this.has("and carries its own direction" j5 "\"gd\":1")
362
+ }
363
+
364
+ ; A document's `theme` turns on its `.theme-<name> .class` rules. The
365
+ ; layout applied the sheet with no theme at all, so every scoped rule —
366
+ ; the UI kit ships one per piece for a dark screen — styled nothing.
367
+ fn testDocumentTheme:void () {
368
+ print "-- a document's theme"
369
+ def root (new EVGElement())
370
+ root.setAttribute("width" "100px")
371
+ root.setAttribute("height" "50px")
372
+ root.documentCss = ".x { background-color: #ff0000; height: 20px }\n.theme-dark .x { background-color: #00ff00 }"
373
+ def kid (new EVGElement())
374
+ kid.setAttribute("class-name" "x")
375
+ root.addChild(kid)
376
+ this.has("without a theme the plain rule paints" (this.listOf(root)) "\"c\":[255,0,0,1.00]")
377
+ root.setAttribute("theme" "dark")
378
+ this.has("with theme dark the scoped rule wins" (this.listOf(root)) "\"c\":[0,255,0,1.00]")
379
+ }
380
+
381
+ ; The other half of the same rule: a flat fill must NOT claim a gradient,
382
+ ; or every rectangle on the page would be mixed against a colour nobody
383
+ ; asked for.
384
+ fn testFlatRectHasNoGradient:void () {
385
+ print "-- a flat fill"
386
+ def dl (new EVGDisplayList())
387
+ dl.addRect(0.0 0.0 10.0 10.0 (EVGColor.rgb(1 2 3)))
388
+ def json:string (dl.toJson())
389
+ this.ok("says nothing about a second stop" ((indexOf json "\"c2\"") < 0))
390
+ this.ok("and nothing about a direction" ((indexOf json "\"gd\"") < 0))
391
+ }
392
+
393
+ fn testRectAndBorder:void () {
394
+ print "-- a rounded rect and a border"
395
+ def dl (new EVGDisplayList())
396
+ def c (new EVGDrawCmd())
397
+ c.kind = 0
398
+ c.x = 5.0
399
+ c.y = 6.0
400
+ c.w = 70.0
401
+ c.h = 80.0
402
+ c.radius = 9.0
403
+ c.rotate = 45.0
404
+ c.r = 1
405
+ c.g = 2
406
+ c.b = 3
407
+ c.a = 1.0
408
+ push dl.cmds c
409
+ def b (new EVGDrawCmd())
410
+ b.kind = 1
411
+ b.x = 5.0
412
+ b.y = 6.0
413
+ b.w = 70.0
414
+ b.h = 80.0
415
+ b.thickness = 2.0
416
+ b.r = 4
417
+ b.g = 5
418
+ b.b = 6
419
+ b.a = 1.0
420
+ push dl.cmds b
421
+ def json:string (dl.toJson())
422
+ this.has("the corner radius is written" json "\"r\":9.00")
423
+ this.has("so is the rotation" json "\"rot\":45.00")
424
+ this.has("and the border's thickness" json "\"t\":2.00")
425
+ }
426
+
427
+ ; `letter-spacing` — a run is drawn as one string, so the painter is
428
+ ; the only party that can space it and the command has to carry it.
429
+ ; It rides in the JSON as `ls` and in the binary at slot 36, and the
430
+ ; wrap has to agree with the ink: a line measured without the tracking
431
+ ; is a line the box was sized too narrow for.
432
+ fn testLetterSpacing:void () {
433
+ print "-- letter-spacing"
434
+ def root (new EVGElement())
435
+ root.setAttribute("width" "400px")
436
+ root.setAttribute("height" "100px")
437
+ def span:EVGElement (EVGElement.createSpan())
438
+ span.textContent = "abcd"
439
+ span.setAttribute("font-size" "20px")
440
+ span.setAttribute("letter-spacing" "5px")
441
+ root.addChild(span)
442
+ def layout (new EVGLayout())
443
+ layout.layout(root)
444
+ def dl (new EVGDisplayList())
445
+ dl.build(root)
446
+ def js:string (dl.toJson())
447
+ this.has("the command carries it" js "\"ls\":5")
448
+
449
+ ; And the measurement grew by one space per character, the last
450
+ ; one included — which is what CSS says and what a canvas with
451
+ ; `letterSpacing` set measures back.
452
+ def eng (new EVGTextEngine())
453
+ def plain:double ((eng.measureRun("abcd" "Open Sans" 20.0)).width)
454
+ def spaced:double ((eng.measureRunSpaced("abcd" "Open Sans" 20.0 5.0)).width)
455
+ this.ok("and the measurement grew by four spaces" (((spaced - plain) > 19.9) && ((spaced - plain) < 20.1)))
456
+ def tight:double ((eng.measureRunSpaced("abcd" "Open Sans" 20.0 (0.0 - 1.0))).width)
457
+ this.ok("negative tracking narrows it" (((plain - tight) > 3.9) && ((plain - tight) < 4.1)))
458
+ this.ok("and zero is the run as it was" (((eng.measureRunSpaced("abcd" "Open Sans" 20.0 0.0)).width) == plain))
459
+ }
460
+
461
+ ; `paragraph-spacing`: the gap goes above every paragraph the author
462
+ ; typed and above none the box made by wrapping, and the layout has to
463
+ ; reserve it or the last line falls out of the box it was sized for.
464
+ fn testParagraphSpacing:void () {
465
+ print "-- paragraph-spacing"
466
+ def eng (new EVGTextEngine())
467
+ def lines:[EVGTextLine] (eng.breakLines("one\ntwo\nthree" "Open Sans" 12.0 0.0))
468
+ this.ok("three paragraphs, three lines" ((array_length lines) == 3))
469
+ def first:EVGTextLine (itemAt lines 0)
470
+ def second:EVGTextLine (itemAt lines 1)
471
+ this.ok("the first line opens nothing" (first.startsParagraph == false))
472
+ this.ok("the second opens a paragraph" second.startsParagraph)
473
+ def lead:double (eng.paragraphLeading("one\ntwo\nthree" "Open Sans" 12.0 0.0 0.0 10.0))
474
+ this.ok("two breaks reserve two gaps" ((lead > 19.9) && (lead < 20.1)))
475
+ ; A line the WRAP made is not a paragraph, so it gets no gap: this
476
+ ; is the difference between spacing paragraphs and double-spacing
477
+ ; the whole block.
478
+ def wrapped:double (eng.paragraphLeading("aaa bbb ccc ddd" "Open Sans" 12.0 12.0 0.0 10.0))
479
+ this.ok("a wrapped line is not a paragraph" (wrapped == 0.0))
480
+ this.ok("and no spacing reserves nothing" ((eng.paragraphLeading("one\ntwo" "Open Sans" 12.0 0.0 0.0 0.0)) == 0.0))
481
+
482
+ ; And the painter is told where the lines go.
483
+ def root (new EVGElement())
484
+ root.setAttribute("width" "400px")
485
+ root.setAttribute("height" "200px")
486
+ def span:EVGElement (EVGElement.createSpan())
487
+ span.textContent = "one\ntwo"
488
+ span.setAttribute("font-size" "20px")
489
+ span.setAttribute("line-height" "20px")
490
+ span.setAttribute("paragraph-spacing" "30px")
491
+ root.addChild(span)
492
+ def layout (new EVGLayout())
493
+ layout.layout(root)
494
+ def dl (new EVGDisplayList())
495
+ dl.build(root)
496
+ def js:string (dl.toJson())
497
+ ; Line one at y 0, line two a line box AND a gap below it.
498
+ this.has("the second line is pushed down by the gap" js "\"y\":50")
499
+ }
500
+
501
+ fn testTextAndImage:void () {
502
+ print "-- text and a picture"
503
+ def dl (new EVGDisplayList())
504
+ def t (new EVGDrawCmd())
505
+ t.kind = 3
506
+ t.x = 1.0
507
+ t.y = 2.0
508
+ t.text = "hei"
509
+ t.fontFamily = "Open Sans"
510
+ t.fontSize = 12.0
511
+ t.fontWeight = "bold"
512
+ t.textAlign = "italic"
513
+ t.r = 0
514
+ t.g = 0
515
+ t.b = 0
516
+ t.a = 1.0
517
+ push dl.cmds t
518
+ def im (new EVGDrawCmd())
519
+ im.kind = 2
520
+ im.src = "media/image1.png"
521
+ im.flipH = true
522
+ im.w = 10.0
523
+ im.h = 10.0
524
+ im.a = 1.0
525
+ push dl.cmds im
526
+ def json:string (dl.toJson())
527
+ this.has("the run's text" json "\"text\":\"hei\"")
528
+ this.has("its face" json "\"font\":\"Open Sans\"")
529
+ this.has("its size" json "\"size\":12.00")
530
+ this.has("its weight" json "\"weight\":\"bold\"")
531
+ this.has("its slant" json "\"italic\":true")
532
+ this.has("the picture's part" json "\"src\":\"media/image1.png\"")
533
+ this.has("and that it is mirrored" json "\"fx\":true")
534
+ }
535
+ }