ranger-compiler 3.5.0 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/CHANGELOG.md +1160 -19
  2. package/LICENSE +3 -1
  3. package/README.md +124 -29
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79924 -56922
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,30 @@
1
+ // Compile-time stub. See AndroidStubs.kt.
2
+ package android.os
3
+
4
+ class Bundle
5
+
6
+ interface IBinder
7
+
8
+ /**
9
+ * Enough of `Build` for an API check. The hosts gate on `SDK_INT` where a
10
+ * platform feature is newer than `minSdk`, and a stub that did not have it
11
+ * would make those branches unverifiable — which is the one thing this
12
+ * directory exists to prevent.
13
+ */
14
+ object Build {
15
+ // What `DashboardView.onEmulator` reads to keep a software GPU from being
16
+ // asked to run a full-screen shader.
17
+ @JvmField val FINGERPRINT: String = "stub"
18
+ @JvmField val HARDWARE: String = "stub"
19
+ @JvmField val MODEL: String = "stub"
20
+
21
+ object VERSION {
22
+ @JvmField val SDK_INT: Int = 34
23
+ }
24
+
25
+ object VERSION_CODES {
26
+ const val LOLLIPOP = 21
27
+ const val S = 31
28
+ const val TIRAMISU = 33
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ // Compile-time stub. See AndroidStubs.kt.
2
+ package android.util
3
+
4
+ class DisplayMetrics {
5
+ @JvmField var density: Float = 1f
6
+ }
7
+
8
+ interface AttributeSet
9
+
10
+ @Suppress("UNUSED_PARAMETER")
11
+ object Log {
12
+ fun d(tag: String, msg: String): Int = 0
13
+ fun w(tag: String, msg: String): Int = 0
14
+ fun e(tag: String, msg: String): Int = 0
15
+ }
@@ -0,0 +1,113 @@
1
+ // Compile-time stub. See AndroidStubs.kt.
2
+ @file:Suppress("UNUSED_PARAMETER", "unused")
3
+
4
+ package android.view
5
+
6
+ import android.content.Context
7
+ import android.graphics.Canvas
8
+ import android.util.AttributeSet
9
+
10
+ open class View(context: Context, attrs: AttributeSet? = null) {
11
+ val context: Context = context
12
+ companion object {
13
+ const val LAYER_TYPE_NONE = 0
14
+ const val LAYER_TYPE_SOFTWARE = 1
15
+ const val LAYER_TYPE_HARDWARE = 2
16
+ }
17
+
18
+ val width: Int = 0
19
+ val height: Int = 0
20
+ val resources: android.content.res.Resources = context.resources
21
+
22
+ var isFocusable: Boolean = false
23
+ var isFocusableInTouchMode: Boolean = false
24
+
25
+ fun setLayerType(layerType: Int, paint: android.graphics.Paint?) {}
26
+ open fun invalidate() {}
27
+ open fun requestFocus(): Boolean = false
28
+ open fun setRenderEffect(effect: android.graphics.RenderEffect?) {}
29
+ open fun postOnAnimation(action: Runnable) {}
30
+ open fun onDetachedFromWindow() {}
31
+ open fun post(action: Runnable): Boolean = true
32
+ open fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean = false
33
+ open fun postInvalidateOnAnimation() {}
34
+ protected open fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {}
35
+ protected open fun onDraw(canvas: Canvas) {}
36
+ open fun onTouchEvent(event: MotionEvent): Boolean = false
37
+ val windowToken: android.os.IBinder? = null
38
+ open fun onCheckIsTextEditor(): Boolean = false
39
+ open fun onCreateInputConnection(outAttrs: android.view.inputmethod.EditorInfo): android.view.inputmethod.InputConnection? = null
40
+ }
41
+
42
+ class MotionEvent {
43
+ companion object {
44
+ const val ACTION_DOWN = 0
45
+ const val ACTION_UP = 1
46
+ const val ACTION_MOVE = 2
47
+ const val ACTION_CANCEL = 3
48
+ }
49
+
50
+ val x: Float = 0f
51
+ val y: Float = 0f
52
+ val actionMasked: Int = 0
53
+ }
54
+
55
+ class KeyEvent {
56
+ companion object {
57
+ const val KEYCODE_DPAD_UP = 19
58
+ const val KEYCODE_DPAD_DOWN = 20
59
+ const val KEYCODE_DPAD_LEFT = 21
60
+ const val KEYCODE_DPAD_RIGHT = 22
61
+ const val KEYCODE_PAGE_UP = 92
62
+ const val KEYCODE_PAGE_DOWN = 93
63
+ const val KEYCODE_MOVE_HOME = 122
64
+ const val KEYCODE_MOVE_END = 123
65
+ const val KEYCODE_ENTER = 66
66
+ const val KEYCODE_SPACE = 62
67
+ const val KEYCODE_DEL = 67
68
+ const val KEYCODE_FORWARD_DEL = 112
69
+ const val KEYCODE_TAB = 61
70
+ const val KEYCODE_ESCAPE = 111
71
+ }
72
+
73
+ val keyCode: Int = 0
74
+ val unicodeChar: Int = 0
75
+ val isShiftPressed: Boolean = false
76
+ val isCtrlPressed: Boolean = false
77
+ }
78
+
79
+ class GestureDetector(context: Context, listener: OnGestureListener) {
80
+ interface OnGestureListener
81
+
82
+ open class SimpleOnGestureListener : OnGestureListener {
83
+ open fun onDown(e: MotionEvent): Boolean = false
84
+ open fun onSingleTapUp(e: MotionEvent): Boolean = false
85
+ open fun onDoubleTap(e: MotionEvent): Boolean = false
86
+ open fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean = false
87
+ open fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean = false
88
+ }
89
+
90
+ fun onTouchEvent(event: MotionEvent): Boolean = false
91
+ }
92
+
93
+ class ScaleGestureDetector(context: Context, listener: OnScaleGestureListener) {
94
+ interface OnScaleGestureListener
95
+
96
+ open class SimpleOnScaleGestureListener : OnScaleGestureListener {
97
+ open fun onScale(detector: ScaleGestureDetector): Boolean = false
98
+ }
99
+
100
+ val scaleFactor: Float = 1f
101
+ val focusX: Float = 0f
102
+ val focusY: Float = 0f
103
+ var isQuickScaleEnabled: Boolean = true
104
+ fun onTouchEvent(event: MotionEvent): Boolean = false
105
+ }
106
+
107
+ interface Menu {
108
+ fun add(groupId: Int, itemId: Int, order: Int, title: CharSequence): MenuItem
109
+ }
110
+
111
+ interface MenuItem {
112
+ val itemId: Int
113
+ }
@@ -0,0 +1,16 @@
1
+ // Compile-time stub. See AndroidStubs.kt.
2
+ @file:Suppress("UNUSED_PARAMETER", "unused")
3
+
4
+ package android.widget
5
+
6
+ import android.content.Context
7
+
8
+ class Toast {
9
+ companion object {
10
+ const val LENGTH_SHORT = 0
11
+ const val LENGTH_LONG = 1
12
+ fun makeText(context: Context, text: CharSequence, duration: Int): Toast = Toast()
13
+ }
14
+
15
+ fun show() {}
16
+ }
@@ -0,0 +1,323 @@
1
+ package fi.ranger.evg
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.BitmapFactory
5
+ import android.graphics.BlurMaskFilter
6
+ import android.graphics.Canvas
7
+ import android.graphics.Color
8
+ import android.graphics.LinearGradient
9
+ import android.graphics.Matrix
10
+ import android.graphics.Paint
11
+ import android.graphics.Path
12
+ import android.graphics.RectF
13
+ import android.graphics.Shader
14
+ import android.graphics.Typeface
15
+
16
+ /**
17
+ * The display list, painted with `android.graphics.Canvas`.
18
+ *
19
+ * This is the whole of the platform-specific half of the port: every command
20
+ * kind maps onto something Skia already does — a rounded rect, a shader, a
21
+ * path with a fill type, a run of text at a baseline — so there is no
22
+ * rasteriser here, no atlas, no shader, and nothing that has to agree with the
23
+ * layout engine about anything but coordinates.
24
+ *
25
+ * Text is drawn rather than blitted. EVG measured each run with its own
26
+ * TrueType reader against the same `.ttf` the [FaceSet] loads, and the command
27
+ * carries the run's origin, so Skia only has to put the same glyphs at the same
28
+ * place at whatever size the canvas is currently scaled to. That is why a
29
+ * pinch-zoom stays sharp: nothing was ever rasterised at a fixed size.
30
+ */
31
+ class AndroidEvgSurface(
32
+ private val canvas: Canvas,
33
+ /** Decoded pictures by package part, from [ImageStore]. */
34
+ private val images: ImageStore,
35
+ private val faces: FaceSet,
36
+ ) : EvgSurface {
37
+
38
+ private val fill = Paint(Paint.ANTI_ALIAS_FLAG)
39
+ private val stroke = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
40
+ private val text = Paint(Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG)
41
+ private val shadowPaint = Paint(Paint.ANTI_ALIAS_FLAG)
42
+ private val rect = RectF()
43
+ private val path = Path()
44
+
45
+ /**
46
+ * A `BlurMaskFilter` is exact and cheap — and is **ignored** on a
47
+ * hardware-accelerated canvas, which is the canvas this app wants. So it is
48
+ * used only when the canvas is a software one (a `LAYER_TYPE_SOFTWARE`
49
+ * view, a bitmap-backed canvas, a screenshot); on the GPU the falloff is
50
+ * built out of ordinary draw calls instead. See [drawShadow].
51
+ *
52
+ * The canvas is asked rather than the view, so this is right whichever one
53
+ * we are handed.
54
+ */
55
+ private val canBlur = !canvas.isHardwareAccelerated
56
+
57
+ override fun save() {
58
+ canvas.save()
59
+ }
60
+
61
+ override fun restore() {
62
+ canvas.restore()
63
+ }
64
+
65
+ override fun clipRect(x: Float, y: Float, w: Float, h: Float) {
66
+ canvas.clipRect(x, y, x + w, y + h)
67
+ }
68
+
69
+ override fun rotate(degrees: Float, px: Float, py: Float) {
70
+ canvas.rotate(degrees, px, py)
71
+ }
72
+
73
+ override fun fillRect(
74
+ x: Float, y: Float, w: Float, h: Float,
75
+ radius: Float, color: Int, gradient: EvgGradient?, shadow: EvgShadow?,
76
+ ) {
77
+ if (w <= 0f || h <= 0f) return
78
+ rect.set(x, y, x + w, y + h)
79
+ val r = radius.coerceAtMost(minOf(w, h) / 2f)
80
+ shadow?.let { drawShadowRect(rect, r, it) }
81
+ fill.shader = gradient?.let {
82
+ if (it.vertical) {
83
+ LinearGradient(x, y, x, y + h, it.color1, it.color2, Shader.TileMode.CLAMP)
84
+ } else {
85
+ LinearGradient(x, y, x + w, y, it.color1, it.color2, Shader.TileMode.CLAMP)
86
+ }
87
+ }
88
+ fill.color = color
89
+ if (gradient == null && Color.alpha(color) == 0) return
90
+ if (r > 0.5f) canvas.drawRoundRect(rect, r, r, fill) else canvas.drawRect(rect, fill)
91
+ fill.shader = null
92
+ }
93
+
94
+ override fun strokeRect(
95
+ x: Float, y: Float, w: Float, h: Float,
96
+ radius: Float, thickness: Float, color: Int,
97
+ ) {
98
+ if (w <= 0f || h <= 0f) return
99
+ // EVG keeps a border's band INSIDE the box; Skia centres a stroke on
100
+ // the path, so the rectangle moves in by half the thickness.
101
+ val half = thickness / 2f
102
+ rect.set(x + half, y + half, x + w - half, y + h - half)
103
+ stroke.color = color
104
+ stroke.strokeWidth = thickness
105
+ val r = (radius - half).coerceAtLeast(0f)
106
+ if (r > 0.5f) canvas.drawRoundRect(rect, r, r, stroke) else canvas.drawRect(rect, stroke)
107
+ }
108
+
109
+ override fun fillPath(
110
+ pts: List<Double>, ringEnds: List<Int>, evenOdd: Boolean,
111
+ color: Int, shadow: EvgShadow?,
112
+ ) {
113
+ if (!buildPath(pts, ringEnds, close = true)) return
114
+ path.fillType = if (evenOdd) Path.FillType.EVEN_ODD else Path.FillType.WINDING
115
+ shadow?.let { drawShadowPath(it) }
116
+ fill.shader = null
117
+ fill.color = color
118
+ canvas.drawPath(path, fill)
119
+ }
120
+
121
+ override fun strokePath(pts: List<Double>, ringEnds: List<Int>, thickness: Float, color: Int) {
122
+ if (!buildPath(pts, ringEnds, close = false)) return
123
+ stroke.color = color
124
+ stroke.strokeWidth = thickness
125
+ stroke.strokeJoin = Paint.Join.ROUND
126
+ stroke.strokeCap = Paint.Cap.ROUND
127
+ canvas.drawPath(path, stroke)
128
+ }
129
+
130
+ override fun drawImage(
131
+ src: String, x: Float, y: Float, w: Float, h: Float,
132
+ radius: Float, flipH: Boolean, flipV: Boolean,
133
+ ) {
134
+ if (w <= 0f || h <= 0f) return
135
+ val bmp = images.bitmap(src)
136
+ if (bmp == null) {
137
+ // A picture the package did not carry must look different from an
138
+ // empty slide, or a decoding bug reads as a design choice.
139
+ rect.set(x, y, x + w, y + h)
140
+ fill.shader = null
141
+ fill.color = Color.rgb(180, 198, 230)
142
+ canvas.drawRect(rect, fill)
143
+ return
144
+ }
145
+ val saved = canvas.save()
146
+ if (radius > 0.5f) {
147
+ rect.set(x, y, x + w, y + h)
148
+ path.reset()
149
+ path.addRoundRect(rect, radius, radius, Path.Direction.CW)
150
+ canvas.clipPath(path)
151
+ }
152
+ val m = Matrix()
153
+ m.setScale(w / bmp.width, h / bmp.height)
154
+ m.postTranslate(x, y)
155
+ if (flipH || flipV) {
156
+ // Mirroring is the texture read backwards, about the box's own
157
+ // centre — the quad stays where the layout put it.
158
+ val mm = Matrix()
159
+ mm.setScale(if (flipH) -1f else 1f, if (flipV) -1f else 1f, x + w / 2f, y + h / 2f)
160
+ m.postConcat(mm)
161
+ }
162
+ canvas.drawBitmap(bmp, m, fill.also { it.shader = null; it.color = Color.WHITE })
163
+ canvas.restoreToCount(saved)
164
+ }
165
+
166
+ override fun drawTextRun(
167
+ txt: String, x: Float, top: Float, sizePx: Float,
168
+ family: String, bold: Boolean, italic: Boolean, color: Int,
169
+ ) {
170
+ if (sizePx <= 0f) return
171
+ text.typeface = faces.typeface(family, bold, italic)
172
+ text.textSize = sizePx
173
+ text.color = color
174
+ // `top` is the top of the line box; `ascent` is negative and is the
175
+ // distance from the baseline up to it. Same rule as the WebGL atlas.
176
+ canvas.drawText(txt, x, top - text.fontMetrics.ascent, text)
177
+ }
178
+
179
+ // --- the parts that are only arithmetic ----------------------------------
180
+
181
+ private fun buildPath(pts: List<Double>, ringEnds: List<Int>, close: Boolean): Boolean {
182
+ if (pts.size < 4) return false
183
+ path.reset()
184
+ var start = 0
185
+ var any = false
186
+ for (end in ringEnds) {
187
+ val stop = if (end > pts.size) pts.size else end
188
+ if (stop - start < 4) { start = stop; continue }
189
+ path.moveTo(pts[start].toFloat(), pts[start + 1].toFloat())
190
+ var i = start + 2
191
+ while (i + 1 < stop) {
192
+ path.lineTo(pts[i].toFloat(), pts[i + 1].toFloat())
193
+ i += 2
194
+ }
195
+ if (close) path.close()
196
+ any = true
197
+ start = stop
198
+ }
199
+ return any
200
+ }
201
+
202
+ private fun drawShadowRect(box: RectF, radius: Float, shadow: EvgShadow) {
203
+ val moved = RectF(box)
204
+ moved.offset(shadow.dx, shadow.dy)
205
+ drawShadow(shadow) {
206
+ if (radius > 0.5f) {
207
+ canvas.drawRoundRect(moved, radius, radius, shadowPaint)
208
+ } else {
209
+ canvas.drawRect(moved, shadowPaint)
210
+ }
211
+ }
212
+ }
213
+
214
+ private fun drawShadowPath(shadow: EvgShadow) {
215
+ val saved = canvas.save()
216
+ canvas.translate(shadow.dx, shadow.dy)
217
+ drawShadow(shadow) { canvas.drawPath(path, shadowPaint) }
218
+ canvas.restoreToCount(saved)
219
+ }
220
+
221
+ /**
222
+ * The silhouette, softened, without asking the GPU for something it will
223
+ * quietly refuse.
224
+ *
225
+ * `BlurMaskFilter` is the right answer and Skia ignores it on a
226
+ * hardware-accelerated canvas — it does not fail, it draws a hard-edged
227
+ * grey shape, which is worse than no shadow at all. Forcing the whole view
228
+ * onto a software layer to get it back would trade the GPU for one effect,
229
+ * on a page whose other few hundred commands want the GPU.
230
+ *
231
+ * So on the GPU the falloff is drawn instead of filtered: the silhouette a
232
+ * few times, each pass grown by a stroke of increasing width and drawn at a
233
+ * decreasing alpha. It is a handful of ordinary draw calls, it batches like
234
+ * any other geometry, and at the blur radii a deck actually asks for
235
+ * (`outerShdw` is usually a few points) the difference from a true Gaussian
236
+ * is not something you can see on a slide.
237
+ *
238
+ * `RenderEffect.createBlurEffect` would be exact and is API 31+ and needs
239
+ * its own `RenderNode` per shape; that is the upgrade path if a deck ever
240
+ * turns up whose design depends on the exact falloff.
241
+ */
242
+ private inline fun drawShadow(shadow: EvgShadow, silhouette: () -> Unit) {
243
+ shadowPaint.style = Paint.Style.FILL
244
+ shadowPaint.maskFilter = null
245
+ if (canBlur && shadow.blur > 0.5f) {
246
+ shadowPaint.color = shadow.color
247
+ shadowPaint.maskFilter = BlurMaskFilter(shadow.blur, BlurMaskFilter.Blur.NORMAL)
248
+ silhouette()
249
+ shadowPaint.maskFilter = null
250
+ return
251
+ }
252
+ if (shadow.blur <= 0.5f) {
253
+ shadowPaint.color = shadow.color
254
+ silhouette()
255
+ return
256
+ }
257
+ val alpha = Color.alpha(shadow.color)
258
+ val rgb = shadow.color and 0x00FFFFFF
259
+ var pass = SHADOW_PASSES - 1
260
+ while (pass >= 0) {
261
+ // Outermost pass first and faintest, so the passes accumulate
262
+ // towards the middle the way a blur does.
263
+ val t = (pass + 1).toFloat() / SHADOW_PASSES
264
+ val grow = shadow.blur * t
265
+ val a = (alpha * (1f - t) / SHADOW_PASSES * 2f).toInt().coerceIn(0, 255)
266
+ shadowPaint.color = (a shl 24) or rgb
267
+ if (grow > 0.01f) {
268
+ shadowPaint.style = Paint.Style.FILL_AND_STROKE
269
+ shadowPaint.strokeWidth = grow * 2f
270
+ shadowPaint.strokeJoin = Paint.Join.ROUND
271
+ shadowPaint.strokeCap = Paint.Cap.ROUND
272
+ } else {
273
+ shadowPaint.style = Paint.Style.FILL
274
+ }
275
+ silhouette()
276
+ pass--
277
+ }
278
+ shadowPaint.style = Paint.Style.FILL
279
+ }
280
+
281
+ private companion object {
282
+ /** Enough for a slide's shadow to read as soft; more is not visible. */
283
+ const val SHADOW_PASSES = 4
284
+ }
285
+ }
286
+
287
+ /**
288
+ * The four faces the deck is measured and drawn in.
289
+ *
290
+ * EVG measured every run against these exact `.ttf` bytes, so the same files
291
+ * have to be what Skia draws with — a substituted face would put the same
292
+ * glyphs at widths the layout never agreed to.
293
+ */
294
+ class FaceSet(
295
+ private val regular: Typeface,
296
+ private val bold: Typeface,
297
+ private val italic: Typeface,
298
+ private val boldItalic: Typeface,
299
+ ) {
300
+ fun typeface(@Suppress("UNUSED_PARAMETER") family: String, bold: Boolean, italic: Boolean): Typeface = when {
301
+ bold && italic -> boldItalic
302
+ bold -> this.bold
303
+ italic -> this.italic
304
+ else -> regular
305
+ }
306
+ }
307
+
308
+ /** The deck's own pictures, decoded once and kept until another deck is opened. */
309
+ class ImageStore {
310
+ private val bytes = HashMap<String, ByteArray>()
311
+ private val decoded = HashMap<String, Bitmap?>()
312
+
313
+ fun reset(parts: Map<String, ByteArray>) {
314
+ bytes.clear()
315
+ decoded.clear()
316
+ bytes.putAll(parts)
317
+ }
318
+
319
+ fun bitmap(part: String): Bitmap? = decoded.getOrPut(part) {
320
+ val raw = bytes[part] ?: return@getOrPut null
321
+ runCatching { BitmapFactory.decodeByteArray(raw, 0, raw.size) }.getOrNull()
322
+ }
323
+ }
@@ -0,0 +1,56 @@
1
+ // SPDX-License-Identifier: MIT
2
+ package fi.ranger.evg
3
+
4
+ import android.graphics.Paint
5
+ import fi.ranger.rgr.EVGDefaultMeasurer
6
+ import fi.ranger.rgr.EVGHostTextMeasurer
7
+
8
+ /**
9
+ * Skia measures, EVG breaks the lines.
10
+ *
11
+ * PLAN_NATIVE_HOSTS.md S0, the Android half. `EVGHostTextMeasurer` (Ranger,
12
+ * in the app's generated Kotlin) takes ONE function from the platform — a
13
+ * run's width, and a face's ascent, descent and leading — and every layout
14
+ * the app builds then measures with it. Before this the layout measured with
15
+ * the advance table, a snapshot of one browser's sans, and
16
+ * [AndroidEvgSurface] drew with whatever the [FaceSet] handed it: two faces,
17
+ * and every box sized from the wrong one.
18
+ *
19
+ * The face is the SAME `Typeface` the surface draws with — the [FaceSet] is
20
+ * asked with the same three arguments `drawTextRun` asks it with — so the
21
+ * width the layout measured is the width `Canvas.drawText` puts on the
22
+ * screen, at the size the layout named. The canvas is scaled for density and
23
+ * zoom AFTER that, which is why a pinch stays sharp and why the measurement
24
+ * is in the layout's own pixels rather than the panel's.
25
+ *
26
+ * Install once, before the app's `start`. The `Paint` is used from whatever
27
+ * thread lays out — `gallery/ui/android` starts the page on a worker — and
28
+ * from no other, and is guarded in case a host ever measures from two.
29
+ */
30
+ object AndroidTextMeasurer {
31
+
32
+ /**
33
+ * Make the measurer, attach the platform to it and make it the default
34
+ * every `EVGLayout` and `EVGTextEngine` in the process starts from.
35
+ */
36
+ fun install(faces: FaceSet): EVGHostTextMeasurer {
37
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG)
38
+ val measurer = EVGHostTextMeasurer()
39
+ measurer.attach({ kind, text, family, size, bold, italic ->
40
+ synchronized(paint) {
41
+ paint.typeface = faces.typeface(family, bold, italic)
42
+ paint.textSize = size.toFloat()
43
+ when (kind) {
44
+ 0 -> if (text.isEmpty()) 0.0 else paint.measureText(text).toDouble()
45
+ // `ascent` is negative on Android — the distance from
46
+ // the baseline UP to the top — and EVG wants it positive.
47
+ 1 -> (-paint.fontMetrics.ascent).toDouble()
48
+ 2 -> paint.fontMetrics.descent.toDouble()
49
+ else -> paint.fontMetrics.leading.toDouble()
50
+ }
51
+ }
52
+ }, "android")
53
+ EVGDefaultMeasurer.install(measurer)
54
+ return measurer
55
+ }
56
+ }