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,1162 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; WebPDecoderTest.rgr - tests for lib/image/WebPDecoder.rgr and its parts.
4
+ ;
5
+ ; bash lib/image/tests/run_webp_tests.sh (JavaScript and C++)
6
+ ;
7
+ ; 1. every fixture in testdata/webp decodes to the size and RGBA checksum
8
+ ; that libwebp (via Pillow) gives, see fixtures.txt, and together the
9
+ ; fixtures reach every coding tool the decoder has;
10
+ ; 2. broken input fails cleanly: truncation, wrong magic, zero and oversized
11
+ ; dimensions, bad chunk sizes, corrupted bytes;
12
+ ; 3. unit tests of the pieces: the boolean decoder against an RFC 6386
13
+ ; encoder, prefix-code tables, the inverse DCT / WHT against the RFC's
14
+ ; reference code, the 14 VP8L predictors, the color cache hash, the alpha
15
+ ; filters.
16
+ ;
17
+ ; An optional first argument is the fixture folder (default
18
+ ; lib/image/testdata/webp/, relative to the repository root).
19
+
20
+ Import "../WebPDecoder.rgr"
21
+
22
+ ; RFC 6386 section 7.3 boolean encoder; `bottom` is kept in a double so its
23
+ ; 32 bits survive on every target.
24
+ class BoolEncoderT {
25
+ def out:[int]
26
+ def range:int 255
27
+ def bottom:double 0.0
28
+ def bitCount:int 24
29
+
30
+ fn addOne:void () {
31
+ def i:int ((array_length out) - 1)
32
+ while (i >= 0) {
33
+ if ((itemAt out i) == 255) {
34
+ set out i 0
35
+ i = i - 1
36
+ } {
37
+ set out i ((itemAt out i) + 1)
38
+ return
39
+ }
40
+ }
41
+ }
42
+
43
+ fn put:void (prob:int bit:int) {
44
+ def split:int (1 + (bit_shr ((range - 1) * prob) 8))
45
+ if (bit == 1) {
46
+ bottom = bottom + (to_double split)
47
+ range = range - split
48
+ } {
49
+ range = split
50
+ }
51
+ while (range < 128) {
52
+ range = range * 2
53
+ if (bottom >= 2147483648.0) {
54
+ this.addOne()
55
+ bottom = bottom - 2147483648.0
56
+ }
57
+ bottom = bottom * 2.0
58
+ bitCount = bitCount - 1
59
+ if (bitCount == 0) {
60
+ def byte:int (floor (bottom / 16777216.0))
61
+ push out byte
62
+ bottom = bottom - ((to_double byte) * 16777216.0)
63
+ bitCount = 8
64
+ }
65
+ }
66
+ }
67
+
68
+ fn putValue:void (v:int n:int) {
69
+ def k:int n
70
+ while (k > 0) {
71
+ k = k - 1
72
+ this.put(128 (bit_and (bit_shr v k) 1))
73
+ }
74
+ }
75
+
76
+ sfn pow2:double (n:int) {
77
+ def v:double 1.0
78
+ def i:int 0
79
+ while (i < n) {
80
+ v = v * 2.0
81
+ i = i + 1
82
+ }
83
+ return v
84
+ }
85
+
86
+ fn flush:void () {
87
+ def c:int bitCount
88
+ def v:double bottom
89
+ def bitAt:int (floor (v / (BoolEncoderT.pow2((32 - c)))))
90
+ if ((bit_and bitAt 1) == 1) {
91
+ this.addOne()
92
+ }
93
+ v = v * (BoolEncoderT.pow2((bit_and c 7)))
94
+ c = (bit_shr c 3)
95
+ while (c > 0) {
96
+ v = v * 256.0
97
+ c = c - 1
98
+ }
99
+ v = v - (4294967296.0 * (to_double (floor (v / 4294967296.0))))
100
+ c = 0
101
+ while (c < 4) {
102
+ def byte:int (floor (v / 16777216.0))
103
+ push out byte
104
+ v = (v - ((to_double byte) * 16777216.0)) * 256.0
105
+ c = c + 1
106
+ }
107
+ }
108
+
109
+ fn toBuffer:buffer () {
110
+ def n:int (array_length out)
111
+ def b:buffer (buffer_alloc n)
112
+ def i:int 0
113
+ while (i < n) {
114
+ buffer_set b i (itemAt out i)
115
+ i = i + 1
116
+ }
117
+ return b
118
+ }
119
+ }
120
+
121
+ ; least significant bit first, like the VP8L bit reader
122
+ class BitWriterT {
123
+ def bytes:[int]
124
+ def cur:int 0
125
+ def count:int 0
126
+
127
+ fn put:void (v:int n:int) {
128
+ def i:int 0
129
+ while (i < n) {
130
+ cur = (bit_or cur (bit_shl (bit_and (bit_shr v i) 1) count))
131
+ count = count + 1
132
+ if (count == 8) {
133
+ push bytes cur
134
+ cur = 0
135
+ count = 0
136
+ }
137
+ i = i + 1
138
+ }
139
+ }
140
+
141
+ ; a prefix code, most significant bit first
142
+ fn putCode:void (code:int len:int) {
143
+ def i:int (len - 1)
144
+ while (i >= 0) {
145
+ this.put((bit_and (bit_shr code i) 1) 1)
146
+ i = i - 1
147
+ }
148
+ }
149
+
150
+ fn toBuffer:buffer () {
151
+ if (count > 0) {
152
+ push bytes cur
153
+ cur = 0
154
+ count = 0
155
+ }
156
+ def n:int (array_length bytes)
157
+ def b:buffer (buffer_alloc (n + 4))
158
+ def i:int 0
159
+ while (i < n) {
160
+ buffer_set b i (itemAt bytes i)
161
+ i = i + 1
162
+ }
163
+ return b
164
+ }
165
+ }
166
+
167
+ class RngT {
168
+ def x:int 2463534242
169
+ fn next:int () {
170
+ x = (bit_xor x (bit_shl (bit_and x 524287) 13))
171
+ x = (bit_xor x (bit_ushr x 17))
172
+ x = (bit_xor x (bit_shl (bit_and x 134217727) 5))
173
+ return (bit_and x 2147483647)
174
+ }
175
+ fn below:int (n:int) {
176
+ return ((this.next()) % n)
177
+ }
178
+ }
179
+
180
+ class WebPDecoderTest {
181
+ def passed:int 0
182
+ def failed:int 0
183
+ def dir:string "lib/image/testdata/webp/"
184
+ def rng:RngT (new RngT())
185
+
186
+ fn check:void (cond:boolean name:string) {
187
+ if cond {
188
+ passed = passed + 1
189
+ } {
190
+ failed = failed + 1
191
+ print ("FAIL " + name)
192
+ }
193
+ }
194
+
195
+ sfn hex8:string (hi:int lo:int) {
196
+ def digits:string "0123456789abcdef"
197
+ def s:string ""
198
+ def v:int (bit_or (bit_shl hi 16) lo)
199
+ def k:int 28
200
+ while (k >= 0) {
201
+ def d:int (bit_and (bit_ushr v k) 15)
202
+ s = s + (substring digits d (d + 1))
203
+ k = k - 4
204
+ }
205
+ return s
206
+ }
207
+
208
+ sfn adler32:string (b:buffer) {
209
+ def a:int 1
210
+ def s:int 0
211
+ def n:int (buffer_length b)
212
+ def i:int 0
213
+ while (i < n) {
214
+ a = (a + (buffer_get b i)) % 65521
215
+ s = (s + a) % 65521
216
+ i = i + 1
217
+ }
218
+ return (WebPDecoderTest.hex8(s a))
219
+ }
220
+
221
+ fn readFile:buffer (name:string) {
222
+ ; a local: the es6 template of buffer_read_file cannot see `this`
223
+ def folder:string dir
224
+ return (buffer_read_file folder name)
225
+ }
226
+
227
+ sfn copyBytes:buffer (src:buffer n:int) {
228
+ def b:buffer (buffer_alloc n)
229
+ buffer_copy b 0 src 0 n
230
+ return b
231
+ }
232
+
233
+ ; ======================================================================
234
+ ; 1. fixtures against libwebp
235
+ ; ======================================================================
236
+
237
+ fn testFixtures:void () {
238
+ print "-- fixtures (checksums from libwebp)"
239
+ def folder:string dir
240
+ def listing@(optional):string (read_file folder "fixtures.txt")
241
+ if (null? listing) {
242
+ this.check(false ("cannot read " + dir + "fixtures.txt"))
243
+ return
244
+ }
245
+ def text:string (unwrap listing)
246
+ def lines:[string] (strsplit text "\n")
247
+ def count:int 0
248
+ ; coverage over all fixtures
249
+ def transforms:int 0
250
+ def predModes:int 0
251
+ def bundles:int 0
252
+ def maxCache:int 0
253
+ def maxGroups:int 0
254
+ def simpleCodes:int 0
255
+ def normalCodes:int 0
256
+ def backRefs:int 0
257
+ def cacheHits:int 0
258
+ def i4Modes:int 0
259
+ def i16Modes:int 0
260
+ def uvModes:int 0
261
+ def filterTypes:int 0
262
+ def maxParts:int 0
263
+ def skipped:int 0
264
+ def segments:int 0
265
+ def lfDelta:int 0
266
+ def sharp:int 0
267
+ def alphaMethods:int 0
268
+ def alphaFilters:int 0
269
+ def alphaPre:int 0
270
+ def animations:int 0
271
+ for lines line:string li {
272
+ def t:string (trim line)
273
+ if ((strlen t) == 0) {
274
+ continue
275
+ }
276
+ if ((substring t 0 1) == "#") {
277
+ continue
278
+ }
279
+ def parts:[string] (strsplit t " ")
280
+ if ((array_length parts) < 4) {
281
+ continue
282
+ }
283
+ def name:string (itemAt parts 0)
284
+ def ew:int (unwrap (to_int (itemAt parts 1)))
285
+ def eh:int (unwrap (to_int (itemAt parts 2)))
286
+ def sum:string (itemAt parts 3)
287
+ def dec (new WebPDecoder())
288
+ def img:ImageBuffer (dec.decodeBytes((this.readFile(name))))
289
+ this.check(dec.ok (name + " decodes: " + dec.error))
290
+ this.check(((img.width == ew) && (img.height == eh)) (name + " size " + (to_string img.width) + "x" + (to_string img.height)))
291
+ def got:string (WebPDecoderTest.adler32(img.pixels))
292
+ this.check((got == sum) (name + " RGBA checksum " + got + " expected " + sum))
293
+ count = count + 1
294
+ def ll:VP8LDecoder dec.lossless
295
+ def ly:VP8Decoder dec.lossy
296
+ if dec.isLossless {
297
+ transforms = (bit_or transforms ll.statTransforms)
298
+ predModes = (bit_or predModes ll.statPredModes)
299
+ if (ll.statBundleBits >= 0) {
300
+ bundles = (bit_or bundles (bit_shl 1 ll.statBundleBits))
301
+ }
302
+ if (ll.statCacheBits > maxCache) {
303
+ maxCache = ll.statCacheBits
304
+ }
305
+ if (ll.statGroups > maxGroups) {
306
+ maxGroups = ll.statGroups
307
+ }
308
+ simpleCodes = simpleCodes + ll.statSimpleCodes
309
+ normalCodes = normalCodes + ll.statNormalCodes
310
+ backRefs = backRefs + ll.statBackRefs
311
+ cacheHits = cacheHits + ll.statCacheHits
312
+ } {
313
+ i4Modes = (bit_or i4Modes ly.statI4Modes)
314
+ i16Modes = (bit_or i16Modes ly.statI16Modes)
315
+ uvModes = (bit_or uvModes ly.statUvModes)
316
+ filterTypes = (bit_or filterTypes (bit_shl 1 ly.filterType))
317
+ if (ly.numParts > maxParts) {
318
+ maxParts = ly.numParts
319
+ }
320
+ skipped = skipped + ly.statSkipped
321
+ segments = (bit_or segments ly.statSegments)
322
+ lfDelta = (bit_or lfDelta ly.useLfDelta)
323
+ if (ly.sharpness > 0) {
324
+ sharp = 1
325
+ }
326
+ if (dec.alphaMethod >= 0) {
327
+ alphaMethods = (bit_or alphaMethods (bit_shl 1 dec.alphaMethod))
328
+ alphaFilters = (bit_or alphaFilters (bit_shl 1 dec.alphaFilter))
329
+ alphaPre = (bit_or alphaPre (bit_shl 1 dec.alphaPreprocessing))
330
+ ; the ALPH stream is VP8L too
331
+ transforms = (bit_or transforms ll.statTransforms)
332
+ predModes = (bit_or predModes ll.statPredModes)
333
+ }
334
+ }
335
+ if dec.isAnimated {
336
+ animations = animations + 1
337
+ }
338
+ }
339
+ this.check((count >= 30) ("fixture count " + (to_string count)))
340
+ print (" " + (to_string count) + " fixtures")
341
+ ; what the fixtures exercise
342
+ this.check((transforms == 15) ("all four VP8L transforms, got mask " + (to_string transforms)))
343
+ this.check((predModes == 16383) ("all 14 predictor modes, got mask " + (to_string predModes)))
344
+ this.check((bundles == 15) ("color indexing with 1, 2, 4 and 8 pixels a byte, got mask " + (to_string bundles)))
345
+ this.check((maxCache > 0) "color cache")
346
+ this.check((cacheHits > 0) "color cache hits")
347
+ this.check((maxGroups > 1) "meta prefix codes")
348
+ this.check(((simpleCodes > 0) && (normalCodes > 0)) "simple and normal prefix codes")
349
+ this.check((backRefs > 0) "backward references")
350
+ this.check((i4Modes == 1023) ("all ten 4x4 modes, got mask " + (to_string i4Modes)))
351
+ this.check((i16Modes == 15) ("all four 16x16 modes, got mask " + (to_string i16Modes)))
352
+ this.check((uvModes == 15) ("all four chroma modes, got mask " + (to_string uvModes)))
353
+ this.check((filterTypes == 7) ("no, simple and normal loop filter, got mask " + (to_string filterTypes)))
354
+ this.check((maxParts == 8) ("eight token partitions, got " + (to_string maxParts)))
355
+ this.check((skipped > 0) "skipped macroblocks")
356
+ this.check((segments == 15) ("four segments, got mask " + (to_string segments)))
357
+ this.check((lfDelta == 1) "loop filter deltas")
358
+ this.check((sharp == 1) "filter sharpness")
359
+ this.check((alphaMethods == 3) "raw and VP8L-compressed alpha")
360
+ this.check((alphaFilters == 15) ("all four alpha filters, got mask " + (to_string alphaFilters)))
361
+ this.check((alphaPre == 3) "alpha pre-processing flag 0 and 1")
362
+ this.check((animations > 0) "animation (first frame)")
363
+ }
364
+
365
+ ; ======================================================================
366
+ ; 2. broken input
367
+ ; ======================================================================
368
+
369
+ fn expectFail:void (b:buffer name:string) {
370
+ def dec (new WebPDecoder())
371
+ def img:ImageBuffer (dec.decodeBytes(b))
372
+ this.check((dec.ok == false) (name + " is rejected"))
373
+ this.check(((strlen dec.error) > 0) (name + " has an error message"))
374
+ this.check(((img.width == 1) && (img.height == 1)) (name + " gives the 1x1 placeholder"))
375
+ }
376
+
377
+ fn testErrors:void () {
378
+ print "-- broken input"
379
+ this.expectFail((buffer_alloc 0) "empty buffer")
380
+ this.expectFail((buffer_alloc 11) "11 zero bytes")
381
+ this.expectFail((buffer_alloc 64) "64 zero bytes")
382
+ this.check(((WebPDecoder.isWebP((this.readFile("ly_1x1.webp")))) == true) "isWebP on a WebP file")
383
+ this.check(((WebPDecoder.isWebP((buffer_alloc 20))) == false) "isWebP on zeros")
384
+
385
+ def lossy:buffer (this.readFile("ly_odd_17x9.webp"))
386
+ def lossless:buffer (this.readFile("ll_noise_17x9.webp"))
387
+ def alpha:buffer (this.readFile("ly_alph_vp8l_f3_21x13.webp"))
388
+ def anim:buffer (this.readFile("anim_2f_24x16.webp"))
389
+
390
+ ; wrong magic
391
+ def b1:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
392
+ buffer_set b1 3 88
393
+ this.expectFail(b1 "RIFX magic")
394
+ def b2:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
395
+ buffer_set b2 11 81
396
+ this.expectFail(b2 "WEBQ form type")
397
+ def b3:buffer (WebPDecoderTest.copyBytes(lossless (buffer_length lossless)))
398
+ buffer_set b3 20 48
399
+ this.expectFail(b3 "bad VP8L signature")
400
+ def b4:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
401
+ buffer_set b4 23 0
402
+ this.expectFail(b4 "bad VP8 start code")
403
+
404
+ ; zero and oversized dimensions
405
+ def z:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
406
+ buffer_set z 26 0
407
+ buffer_set z 27 0
408
+ this.expectFail(z "VP8 width 0")
409
+ def big:buffer (WebPDecoderTest.copyBytes(alpha (buffer_length alpha)))
410
+ buffer_set big 24 255
411
+ buffer_set big 25 255
412
+ buffer_set big 26 0
413
+ this.expectFail(big "VP8X canvas of 65536 pixels a side")
414
+ def mism:buffer (WebPDecoderTest.copyBytes(alpha (buffer_length alpha)))
415
+ buffer_set mism 24 30
416
+ this.expectFail(mism "VP8X canvas that does not match the frame")
417
+ def cap (new WebPDecoder())
418
+ cap.maxDimension = 16
419
+ cap.decodeBytes(lossy)
420
+ this.check((cap.ok == false) "maxDimension rejects a 17 pixel wide image")
421
+ def capOk (new WebPDecoder())
422
+ capOk.maxDimension = 17
423
+ capOk.decodeBytes(lossy)
424
+ this.check(capOk.ok "maxDimension 17 accepts it")
425
+
426
+ ; chunk and RIFF sizes
427
+ def rs:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
428
+ buffer_set rs 7 127
429
+ this.expectFail(rs "RIFF size past the end")
430
+ def cs:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
431
+ buffer_set cs 19 1
432
+ this.expectFail(cs "chunk size past the RIFF end")
433
+ def cn:buffer (WebPDecoderTest.copyBytes(lossy (buffer_length lossy)))
434
+ buffer_set cn 19 128
435
+ this.expectFail(cn "chunk size of 2^31")
436
+ def ah:buffer (WebPDecoderTest.copyBytes(alpha (buffer_length alpha)))
437
+ buffer_set ah 38 (bit_or (buffer_get ah 38) 192)
438
+ this.expectFail(ah "ALPH header with reserved bits")
439
+ def am:buffer (WebPDecoderTest.copyBytes(alpha (buffer_length alpha)))
440
+ buffer_set am 38 (bit_or (buffer_get am 38) 3)
441
+ this.expectFail(am "ALPH compression method 3")
442
+
443
+ ; truncation anywhere
444
+ def files:[buffer] ([] _:buffer (lossy lossless alpha anim))
445
+ def names:[string] ([] _:string ("lossy" "lossless" "lossy+alpha" "animation"))
446
+ for files f:buffer fi {
447
+ def n:int (buffer_length f)
448
+ def rejected:int 0
449
+ def cut:int 0
450
+ while (cut < n) {
451
+ def tb:buffer (WebPDecoderTest.copyBytes(f cut))
452
+ def dec (new WebPDecoder())
453
+ dec.decodeBytes(tb)
454
+ if (dec.ok == false) {
455
+ rejected = rejected + 1
456
+ }
457
+ cut = cut + 1
458
+ }
459
+ this.check((rejected == n) ((itemAt names fi) + " truncated at every length is rejected (" + (to_string rejected) + "/" + (to_string n) + ")"))
460
+ }
461
+ ; a truncated payload with the sizes patched to match must fail too
462
+ def pl:buffer (this.patchedTruncation(lossless 60))
463
+ this.expectFail(pl "VP8L payload cut short, sizes consistent")
464
+ def py:buffer (this.patchedTruncation(lossy 50))
465
+ this.expectFail(py "VP8 payload cut short, sizes consistent")
466
+
467
+ ; corrupted bytes: never crash, always a definite answer
468
+ def all:[string] ([] _:string ("ll_meta_32x32.webp" "ll_predictors_64x32.webp" "ly_vpx_parts8_37x45.webp" "ly_alpha_33x17.webp" "anim_2f_24x16.webp" "ll_pal2_19x7.webp"))
469
+ def decoded:int 0
470
+ def refused:int 0
471
+ for all name:string ni {
472
+ def orig:buffer (this.readFile(name))
473
+ def n:int (buffer_length orig)
474
+ def it:int 0
475
+ while (it < 150) {
476
+ def b:buffer (WebPDecoderTest.copyBytes(orig n))
477
+ def flips:int (1 + (rng.below(6)))
478
+ def k:int 0
479
+ while (k < flips) {
480
+ def p:int (12 + (rng.below((n - 12))))
481
+ buffer_set b p (rng.below(256))
482
+ k = k + 1
483
+ }
484
+ def dec (new WebPDecoder())
485
+ def img:ImageBuffer (dec.decodeBytes(b))
486
+ if dec.ok {
487
+ decoded = decoded + 1
488
+ if ((buffer_length img.pixels) != ((img.width * img.height) * 4)) {
489
+ this.check(false (name + " corrupted: pixel buffer size"))
490
+ }
491
+ } {
492
+ refused = refused + 1
493
+ }
494
+ it = it + 1
495
+ }
496
+ }
497
+ this.check(((decoded + refused) == 900) "900 corrupted files decoded or refused without a crash")
498
+ print (" corrupted: " + (to_string decoded) + " decoded, " + (to_string refused) + " refused")
499
+ }
500
+
501
+ ; the first `keep` payload bytes of the image chunk of a simple-format file,
502
+ ; with the RIFF and chunk sizes rewritten to match
503
+ fn patchedTruncation:buffer (src:buffer keep:int) {
504
+ def total:int (20 + keep)
505
+ def b:buffer (WebPDecoderTest.copyBytes(src total))
506
+ def riff:int (total - 8)
507
+ buffer_set b 4 (bit_and riff 255)
508
+ buffer_set b 5 (bit_and (bit_shr riff 8) 255)
509
+ buffer_set b 6 0
510
+ buffer_set b 7 0
511
+ buffer_set b 16 (bit_and keep 255)
512
+ buffer_set b 17 (bit_and (bit_shr keep 8) 255)
513
+ buffer_set b 18 0
514
+ buffer_set b 19 0
515
+ return b
516
+ }
517
+
518
+ ; ======================================================================
519
+ ; 3. pieces
520
+ ; ======================================================================
521
+
522
+ fn testBoolDecoder:void () {
523
+ print "-- boolean decoder"
524
+ def enc (new BoolEncoderT())
525
+ def probs:[int]
526
+ def bits:[int]
527
+ def n:int 4000
528
+ def i:int 0
529
+ while (i < n) {
530
+ def p:int (1 + (rng.below(255)))
531
+ ; skewed bits so both likely and unlikely symbols occur
532
+ def bit:int 0
533
+ if ((rng.below(256)) >= p) {
534
+ bit = 1
535
+ }
536
+ push probs p
537
+ push bits bit
538
+ enc.put(p bit)
539
+ i = i + 1
540
+ }
541
+ enc.putValue(1234 11)
542
+ enc.putValue(5 4)
543
+ enc.putValue(77 7)
544
+ enc.put(128 1)
545
+ ; signs as the coefficient reader takes them
546
+ enc.put(128 1)
547
+ enc.put(128 0)
548
+ enc.flush()
549
+ def data:buffer (enc.toBuffer())
550
+ def dec (new VP8BoolDecoder())
551
+ dec.init(data 0 (buffer_length data))
552
+ def bad:int 0
553
+ i = 0
554
+ while (i < n) {
555
+ if ((dec.getBit((itemAt probs i))) != (itemAt bits i)) {
556
+ bad = bad + 1
557
+ }
558
+ i = i + 1
559
+ }
560
+ this.check((bad == 0) ("4000 bits at random probabilities round trip (" + (to_string bad) + " wrong)"))
561
+ this.check(((dec.getValue(11)) == 1234) "getValue(11)")
562
+ this.check(((dec.getValue(4)) == 5) "getValue(4)")
563
+ this.check(((dec.getSignedValue(7)) == -77) "getSignedValue: magnitude then sign")
564
+ this.check(((dec.getSigned(9)) == -9) "getSigned with a 1 sign bit")
565
+ this.check(((dec.getSigned(9)) == 9) "getSigned with a 0 sign bit")
566
+ this.check((dec.eof == false) "no end of data inside the stream")
567
+ ; reading on past the end sets eof and keeps returning bits
568
+ def k:int 0
569
+ while (k < 200) {
570
+ dec.getBit(128)
571
+ k = k + 1
572
+ }
573
+ this.check(dec.eof "eof after reading past the end")
574
+ ; an empty stream
575
+ def empty (new VP8BoolDecoder())
576
+ empty.init((buffer_alloc 0) 0 0)
577
+ empty.getValue(16)
578
+ this.check(empty.eof "empty stream reports eof")
579
+ ; a range outside the source is clipped, not read
580
+ def clipped (new VP8BoolDecoder())
581
+ clipped.init(data 5 1000000)
582
+ clipped.getValue(8)
583
+ this.check((clipped.bufEnd == ((buffer_length data) - 5)) "range clipped to the source")
584
+ }
585
+
586
+ fn testPrefixCodes:void () {
587
+ print "-- VP8L prefix codes"
588
+ def d (new VP8LDecoder())
589
+ ; a small complete code: lengths 2 2 2 3 3 -> 00 01 10 110 111
590
+ def l1:int_buffer (int_buffer_alloc 5)
591
+ int_buffer_set l1 0 2
592
+ int_buffer_set l1 1 2
593
+ int_buffer_set l1 2 2
594
+ int_buffer_set l1 3 3
595
+ int_buffer_set l1 4 3
596
+ def c1:int (d.buildCode(l1 5))
597
+ this.check((c1 >= 0) "complete code builds")
598
+ def w (new BitWriterT())
599
+ def seq:[int] ([] _:int (0 4 3 1 2 4 4 0 3))
600
+ def codes:[int] ([] _:int (0 1 2 6 7))
601
+ def lens:[int] ([] _:int (2 2 2 3 3))
602
+ for seq s:int si {
603
+ w.putCode((itemAt codes s) (itemAt lens s))
604
+ }
605
+ w.put(5 3)
606
+ def buf:buffer (w.toBuffer())
607
+ d.initBits(buf 0 (buffer_length buf))
608
+ def ok:boolean true
609
+ for seq s:int sj {
610
+ if ((d.readSymbol(c1)) != s) {
611
+ ok = false
612
+ }
613
+ }
614
+ this.check(ok "symbols read back through the table")
615
+ this.check(((d.readBits(3)) == 5) "bit position after the codes")
616
+
617
+ ; long codes use second-level tables: lengths 1..12 and 12
618
+ def n2:int 13
619
+ def l2:int_buffer (int_buffer_alloc n2)
620
+ def s:int 0
621
+ while (s < 12) {
622
+ int_buffer_set l2 s (s + 1)
623
+ s = s + 1
624
+ }
625
+ int_buffer_set l2 12 12
626
+ def c2:int (d.buildCode(l2 n2))
627
+ this.check((c2 >= 0) "code with 12-bit lengths builds")
628
+ ; canonical codes: symbol k (k < 12) is k ones then a zero; 12 is twelve ones
629
+ def w2 (new BitWriterT())
630
+ def order:[int] ([] _:int (11 12 0 9 5 12 1 10 3 11))
631
+ for order sym:int oi {
632
+ if (sym == 12) {
633
+ w2.putCode(4095 12)
634
+ } {
635
+ def len:int (sym + 1)
636
+ w2.putCode((((bit_shl 1 len) - 1) - 1) len)
637
+ }
638
+ }
639
+ def buf2:buffer (w2.toBuffer())
640
+ d.initBits(buf2 0 (buffer_length buf2))
641
+ def ok2:boolean true
642
+ for order sym2:int oj {
643
+ if ((d.readSymbol(c2)) != sym2) {
644
+ ok2 = false
645
+ }
646
+ }
647
+ this.check(ok2 "long codes read back")
648
+
649
+ ; one used symbol reads no bits
650
+ def l3:int_buffer (int_buffer_alloc 40)
651
+ int_buffer_set l3 17 1
652
+ def c3:int (d.buildCode(l3 40))
653
+ def w3 (new BitWriterT())
654
+ w3.put(201 8)
655
+ def buf3:buffer (w3.toBuffer())
656
+ d.initBits(buf3 0 (buffer_length buf3))
657
+ this.check(((d.readSymbol(c3)) == 17) "single-symbol code")
658
+ this.check(((d.readBits(8)) == 201) "single-symbol code consumes no bits")
659
+
660
+ ; invalid codes
661
+ def inc:int_buffer (int_buffer_alloc 2)
662
+ int_buffer_set inc 0 1
663
+ int_buffer_set inc 1 2
664
+ this.check(((d.buildCode(inc 2)) < 0) "incomplete code is rejected")
665
+ def over:int_buffer (int_buffer_alloc 3)
666
+ int_buffer_fill over 1 0 3
667
+ this.check(((d.buildCode(over 3)) < 0) "over-subscribed code is rejected")
668
+ def zero:int_buffer (int_buffer_alloc 8)
669
+ this.check(((d.buildCode(zero 8)) < 0) "all-zero lengths are rejected")
670
+ def tooLong:int_buffer (int_buffer_alloc 2)
671
+ int_buffer_set tooLong 0 16
672
+ int_buffer_set tooLong 1 1
673
+ this.check(((d.buildCode(tooLong 2)) < 0) "a length above 15 is rejected")
674
+
675
+ ; a simple code as the stream writes it: two 8-bit symbols
676
+ def w4 (new BitWriterT())
677
+ w4.put(1 1)
678
+ w4.put(1 1)
679
+ w4.put(1 1)
680
+ w4.put(200 8)
681
+ w4.put(33 8)
682
+ w4.put(0 1)
683
+ w4.put(1 1)
684
+ w4.put(1 1)
685
+ def buf4:buffer (w4.toBuffer())
686
+ d.initBits(buf4 0 (buffer_length buf4))
687
+ def c4:int (d.readCode(256))
688
+ this.check((c4 >= 0) "simple code reads")
689
+ this.check(((d.readSymbol(c4)) == 33) "simple code: 0 is the smaller symbol")
690
+ this.check(((d.readSymbol(c4)) == 200) "simple code: 1 is the larger symbol")
691
+ this.check(((d.readSymbol(c4)) == 200) "simple code: again")
692
+ ; a simple code whose symbol is outside a 40-symbol alphabet
693
+ def w5 (new BitWriterT())
694
+ w5.put(1 1)
695
+ w5.put(0 1)
696
+ w5.put(1 1)
697
+ w5.put(41 8)
698
+ def buf5:buffer (w5.toBuffer())
699
+ d.error = ""
700
+ d.initBits(buf5 0 (buffer_length buf5))
701
+ this.check(((d.readCode(40)) < 0) "simple code symbol outside the alphabet is rejected")
702
+ ; distance map and prefix coding of lengths
703
+ this.check(((VP8LDecoder.planeCodeToDistance(100 1)) == 100) "distance code 1 is the pixel above")
704
+ this.check(((VP8LDecoder.planeCodeToDistance(100 2)) == 1) "distance code 2 is the pixel to the left")
705
+ this.check(((VP8LDecoder.planeCodeToDistance(100 121)) == 1) "distance code 121 is distance 1")
706
+ this.check(((VP8LDecoder.planeCodeToDistance(1 4)) == 1) "a distance below 1 becomes 1")
707
+ this.check(((VP8LDecoder.planeCodeToDistance(100 120)) == 708) "distance code 120 is 7 rows up, 8 to the right")
708
+ }
709
+
710
+ sfn ch:int (p:int sh:int) {
711
+ return (bit_and (bit_shr p sh) 255)
712
+ }
713
+
714
+ sfn clampT:int (v:int) {
715
+ if (v < 0) {
716
+ return 0
717
+ }
718
+ if (v > 255) {
719
+ return 255
720
+ }
721
+ return v
722
+ }
723
+
724
+ sfn absT:int (v:int) {
725
+ if (v < 0) {
726
+ return (0 - v)
727
+ }
728
+ return v
729
+ }
730
+
731
+ ; the predictors of RFC 9649 section 4.1, one channel at a time
732
+ sfn referencePredict:int (mode:int l:int t:int tl:int tr:int) {
733
+ def out:int 0
734
+ def sh:int 0
735
+ def pl:int 0
736
+ def pt:int 0
737
+ while (sh < 32) {
738
+ def cl:int (WebPDecoderTest.ch(l sh))
739
+ def ct:int (WebPDecoderTest.ch(t sh))
740
+ def ctl:int (WebPDecoderTest.ch(tl sh))
741
+ pl = pl + (WebPDecoderTest.absT(((cl + ct) - ctl) - cl))
742
+ pt = pt + (WebPDecoderTest.absT(((cl + ct) - ctl) - ct))
743
+ sh = sh + 8
744
+ }
745
+ sh = 0
746
+ while (sh < 32) {
747
+ def cl:int (WebPDecoderTest.ch(l sh))
748
+ def ct:int (WebPDecoderTest.ch(t sh))
749
+ def ctl:int (WebPDecoderTest.ch(tl sh))
750
+ def ctr:int (WebPDecoderTest.ch(tr sh))
751
+ def v:int 0
752
+ if (mode == 0) {
753
+ v = 0
754
+ if (sh == 24) {
755
+ v = 255
756
+ }
757
+ }
758
+ if (mode == 1) {
759
+ v = cl
760
+ }
761
+ if (mode == 2) {
762
+ v = ct
763
+ }
764
+ if (mode == 3) {
765
+ v = ctr
766
+ }
767
+ if (mode == 4) {
768
+ v = ctl
769
+ }
770
+ if (mode == 5) {
771
+ v = (bit_shr ((bit_shr (cl + ctr) 1) + ct) 1)
772
+ }
773
+ if (mode == 6) {
774
+ v = (bit_shr (cl + ctl) 1)
775
+ }
776
+ if (mode == 7) {
777
+ v = (bit_shr (cl + ct) 1)
778
+ }
779
+ if (mode == 8) {
780
+ v = (bit_shr (ctl + ct) 1)
781
+ }
782
+ if (mode == 9) {
783
+ v = (bit_shr (ct + ctr) 1)
784
+ }
785
+ if (mode == 10) {
786
+ v = (bit_shr ((bit_shr (cl + ctl) 1) + (bit_shr (ct + ctr) 1)) 1)
787
+ }
788
+ if (mode == 11) {
789
+ if (pl < pt) {
790
+ v = cl
791
+ } {
792
+ v = ct
793
+ }
794
+ }
795
+ if (mode == 12) {
796
+ v = (WebPDecoderTest.clampT(((cl + ct) - ctl)))
797
+ }
798
+ if (mode == 13) {
799
+ def a:int (bit_shr (cl + ct) 1)
800
+ v = (WebPDecoderTest.clampT((a + (idiv (a - ctl) 2))))
801
+ }
802
+ out = (bit_or out (bit_shl v sh))
803
+ sh = sh + 8
804
+ }
805
+ return out
806
+ }
807
+
808
+ fn randomPixel:int () {
809
+ ; mostly nearby values, so the clamping and select cases both happen
810
+ def base:int (rng.below(256))
811
+ def p:int 0
812
+ def sh:int 0
813
+ while (sh < 32) {
814
+ def v:int base
815
+ if ((rng.below(3)) == 0) {
816
+ v = (rng.below(256))
817
+ } {
818
+ v = (WebPDecoderTest.clampT(((base + (rng.below(41))) - 20)))
819
+ }
820
+ p = (bit_or p (bit_shl v sh))
821
+ sh = sh + 8
822
+ }
823
+ return p
824
+ }
825
+
826
+ fn testPredictors:void () {
827
+ print "-- VP8L predictors and transforms"
828
+ def mode:int 0
829
+ while (mode < 14) {
830
+ def bad:int 0
831
+ def k:int 0
832
+ while (k < 400) {
833
+ def l:int (this.randomPixel())
834
+ def t:int (this.randomPixel())
835
+ def tl:int (this.randomPixel())
836
+ def tr:int (this.randomPixel())
837
+ if ((VP8LDecoder.predict(mode l t tl tr)) != (WebPDecoderTest.referencePredict(mode l t tl tr))) {
838
+ bad = bad + 1
839
+ }
840
+ k = k + 1
841
+ }
842
+ this.check((bad == 0) ("predictor mode " + (to_string mode) + " (" + (to_string bad) + " wrong)"))
843
+ mode = mode + 1
844
+ }
845
+ ; per-channel addition wraps at 256
846
+ def a:int (VP8LDecoder.pack(200 100 255 1))
847
+ def b:int (VP8LDecoder.pack(100 200 1 255))
848
+ this.check(((VP8LDecoder.addPixels(a b)) == (VP8LDecoder.pack(44 44 0 0))) "addPixels wraps per channel")
849
+ ; color cache hash, (0x1e35a7bd * argb) >> (32 - bits) on 32 bits
850
+ this.check(((VP8LDecoder.hashPixel(1 11)) == 241) "hash of 1")
851
+ this.check(((VP8LDecoder.hashPixel(-16777216 8)) == 67) "hash of 0xff000000")
852
+ this.check(((VP8LDecoder.hashPixel(305419896 11)) == 1119) "hash of 0x12345678")
853
+ this.check(((VP8LDecoder.hashPixel(-559038737 4)) == 4) "hash of 0xdeadbeef")
854
+ this.check(((VP8LDecoder.hashPixel(-1 11)) == 1806) "hash of 0xffffffff")
855
+ this.check(((VP8LDecoder.hashPixel(2147483647 8)) == 97) "hash of 0x7fffffff")
856
+ ; cross-color: green_to_red 0x10, green_to_blue 0xf0 (-16), red_to_blue 0x08
857
+ def d (new VP8LDecoder())
858
+ def px:int_buffer (int_buffer_alloc 1)
859
+ int_buffer_set px 0 (VP8LDecoder.pack(255 10 100 20))
860
+ def m:int_buffer (int_buffer_alloc 1)
861
+ int_buffer_set m 0 (VP8LDecoder.pack(0 8 240 16))
862
+ d.inverseCrossColor(px 1 1 2 m)
863
+ ; red = 10 + (16 * 100 >> 5) = 60; blue = 20 + (-16 * 100 >> 5) + (8 * 60 >> 5) = 20 - 50 + 15
864
+ this.check(((int_buffer_get px 0) == (VP8LDecoder.pack(255 60 100 241))) "cross-color transform")
865
+ int_buffer_set px 0 (VP8LDecoder.pack(7 250 20 240))
866
+ d.inverseSubtractGreen(px 1)
867
+ this.check(((int_buffer_get px 0) == (VP8LDecoder.pack(7 14 20 4))) "subtract-green transform")
868
+ ; color indexing, 2 colors packed 8 to a byte
869
+ def pal:int_buffer (int_buffer_alloc 256)
870
+ int_buffer_set pal 0 (VP8LDecoder.pack(255 1 2 3))
871
+ int_buffer_set pal 1 (VP8LDecoder.pack(255 9 8 7))
872
+ def packed:int_buffer (int_buffer_alloc 2)
873
+ int_buffer_set packed 0 (bit_shl 178 8)
874
+ int_buffer_set packed 1 (bit_shl 1 8)
875
+ def unpacked:int_buffer (d.inverseColorIndex(packed 9 1 3 pal))
876
+ ; 178 = 0b10110010, least significant bit first
877
+ def want:[int] ([] _:int (0 1 0 0 1 1 0 1 1))
878
+ def okIdx:boolean true
879
+ for want wi:int wk {
880
+ if ((int_buffer_get unpacked wk) != (int_buffer_get pal wi)) {
881
+ okIdx = false
882
+ }
883
+ }
884
+ this.check(okIdx "color indexing unpacks 8 pixels a byte")
885
+ }
886
+
887
+ ; RFC 6386 section 14.3, vp8_short_idct4x4llm_c
888
+ sfn referenceIDCT:int_buffer (input:int_buffer) {
889
+ def tmp:int_buffer (int_buffer_alloc 16)
890
+ def out:int_buffer (int_buffer_alloc 16)
891
+ def i:int 0
892
+ while (i < 4) {
893
+ def ip0:int (int_buffer_get input i)
894
+ def ip4:int (int_buffer_get input (i + 4))
895
+ def ip8:int (int_buffer_get input (i + 8))
896
+ def ip12:int (int_buffer_get input (i + 12))
897
+ def a1:int (ip0 + ip8)
898
+ def b1:int (ip0 - ip8)
899
+ def c1:int ((bit_shr (ip4 * 35468) 16) - (ip12 + (bit_shr (ip12 * 20091) 16)))
900
+ def d1:int ((ip4 + (bit_shr (ip4 * 20091) 16)) + (bit_shr (ip12 * 35468) 16))
901
+ int_buffer_set tmp i (a1 + d1)
902
+ int_buffer_set tmp (i + 12) (a1 - d1)
903
+ int_buffer_set tmp (i + 4) (b1 + c1)
904
+ int_buffer_set tmp (i + 8) (b1 - c1)
905
+ i = i + 1
906
+ }
907
+ i = 0
908
+ while (i < 4) {
909
+ def r:int (i * 4)
910
+ def ip0:int (int_buffer_get tmp r)
911
+ def ip1:int (int_buffer_get tmp (r + 1))
912
+ def ip2:int (int_buffer_get tmp (r + 2))
913
+ def ip3:int (int_buffer_get tmp (r + 3))
914
+ def a1:int (ip0 + ip2)
915
+ def b1:int (ip0 - ip2)
916
+ def c1:int ((bit_shr (ip1 * 35468) 16) - (ip3 + (bit_shr (ip3 * 20091) 16)))
917
+ def d1:int ((ip1 + (bit_shr (ip1 * 20091) 16)) + (bit_shr (ip3 * 35468) 16))
918
+ int_buffer_set out r (bit_shr ((a1 + d1) + 4) 3)
919
+ int_buffer_set out (r + 3) (bit_shr ((a1 - d1) + 4) 3)
920
+ int_buffer_set out (r + 1) (bit_shr ((b1 + c1) + 4) 3)
921
+ int_buffer_set out (r + 2) (bit_shr ((b1 - c1) + 4) 3)
922
+ i = i + 1
923
+ }
924
+ return out
925
+ }
926
+
927
+ ; RFC 6386 section 14.3, vp8_short_inv_walsh4x4_c
928
+ sfn referenceWHT:int_buffer (input:int_buffer) {
929
+ def tmp:int_buffer (int_buffer_alloc 16)
930
+ def out:int_buffer (int_buffer_alloc 16)
931
+ def i:int 0
932
+ while (i < 4) {
933
+ def a1:int ((int_buffer_get input i) + (int_buffer_get input (i + 12)))
934
+ def b1:int ((int_buffer_get input (i + 4)) + (int_buffer_get input (i + 8)))
935
+ def c1:int ((int_buffer_get input (i + 4)) - (int_buffer_get input (i + 8)))
936
+ def d1:int ((int_buffer_get input i) - (int_buffer_get input (i + 12)))
937
+ int_buffer_set tmp i (a1 + b1)
938
+ int_buffer_set tmp (i + 4) (c1 + d1)
939
+ int_buffer_set tmp (i + 8) (a1 - b1)
940
+ int_buffer_set tmp (i + 12) (d1 - c1)
941
+ i = i + 1
942
+ }
943
+ i = 0
944
+ while (i < 4) {
945
+ def r:int (i * 4)
946
+ def a1:int ((int_buffer_get tmp r) + (int_buffer_get tmp (r + 3)))
947
+ def b1:int ((int_buffer_get tmp (r + 1)) + (int_buffer_get tmp (r + 2)))
948
+ def c1:int ((int_buffer_get tmp (r + 1)) - (int_buffer_get tmp (r + 2)))
949
+ def d1:int ((int_buffer_get tmp r) - (int_buffer_get tmp (r + 3)))
950
+ int_buffer_set out r (bit_shr ((a1 + b1) + 3) 3)
951
+ int_buffer_set out (r + 1) (bit_shr ((c1 + d1) + 3) 3)
952
+ int_buffer_set out (r + 2) (bit_shr ((a1 - b1) + 3) 3)
953
+ int_buffer_set out (r + 3) (bit_shr ((d1 - c1) + 3) 3)
954
+ i = i + 1
955
+ }
956
+ return out
957
+ }
958
+
959
+ ; runs one of the decoder's 4x4 transforms on a block predicted as 128
960
+ fn runTransform:int_buffer (v:VP8Decoder kind:int input:int_buffer) {
961
+ def i:int 0
962
+ while (i < 16) {
963
+ int_buffer_set v.coeffs i (int_buffer_get input i)
964
+ i = i + 1
965
+ }
966
+ buffer_fill v.yuvB 128 0 832
967
+ if (kind == 0) {
968
+ v.transformOne(0 40)
969
+ }
970
+ if (kind == 1) {
971
+ v.transformAC3(0 40)
972
+ }
973
+ if (kind == 2) {
974
+ v.transformDC(0 40)
975
+ }
976
+ def out:int_buffer (int_buffer_alloc 16)
977
+ i = 0
978
+ while (i < 16) {
979
+ int_buffer_set out i ((buffer_get v.yuvB ((40 + ((bit_shr i 2) * 32)) + (bit_and i 3))) - 128)
980
+ i = i + 1
981
+ }
982
+ return out
983
+ }
984
+
985
+ fn testTransforms:void () {
986
+ print "-- VP8 inverse transforms"
987
+ def v (new VP8Decoder())
988
+ def badIdct:int 0
989
+ def badAc3:int 0
990
+ def badDc:int 0
991
+ def badWht:int 0
992
+ def k:int 0
993
+ while (k < 300) {
994
+ def input:int_buffer (int_buffer_alloc 16)
995
+ def i:int 0
996
+ while (i < 16) {
997
+ if ((rng.below(3)) != 0) {
998
+ int_buffer_set input i ((rng.below(401)) - 200)
999
+ }
1000
+ i = i + 1
1001
+ }
1002
+ def got:int_buffer (this.runTransform(v 0 input))
1003
+ def ref:int_buffer (WebPDecoderTest.referenceIDCT(input))
1004
+ i = 0
1005
+ while (i < 16) {
1006
+ if ((int_buffer_get got i) != (WebPDecoderTest.clampT(((int_buffer_get ref i) + 128)) - 128)) {
1007
+ badIdct = badIdct + 1
1008
+ }
1009
+ i = i + 1
1010
+ }
1011
+ ; the shortcut for blocks with coefficients 0, 1 and 4 only
1012
+ def ac3:int_buffer (int_buffer_alloc 16)
1013
+ int_buffer_set ac3 0 (int_buffer_get input 0)
1014
+ int_buffer_set ac3 1 (int_buffer_get input 1)
1015
+ int_buffer_set ac3 4 (int_buffer_get input 4)
1016
+ def g3:int_buffer (this.runTransform(v 1 ac3))
1017
+ def f3:int_buffer (this.runTransform(v 0 ac3))
1018
+ def dcOnly:int_buffer (int_buffer_alloc 16)
1019
+ int_buffer_set dcOnly 0 (int_buffer_get input 0)
1020
+ def gd:int_buffer (this.runTransform(v 2 dcOnly))
1021
+ def fd:int_buffer (this.runTransform(v 0 dcOnly))
1022
+ i = 0
1023
+ while (i < 16) {
1024
+ if ((int_buffer_get g3 i) != (int_buffer_get f3 i)) {
1025
+ badAc3 = badAc3 + 1
1026
+ }
1027
+ if ((int_buffer_get gd i) != (int_buffer_get fd i)) {
1028
+ badDc = badDc + 1
1029
+ }
1030
+ i = i + 1
1031
+ }
1032
+ ; the Walsh-Hadamard transform of the 16 DC values
1033
+ i = 0
1034
+ while (i < 16) {
1035
+ int_buffer_set v.dcBuf i ((rng.below(4001)) - 2000)
1036
+ i = i + 1
1037
+ }
1038
+ def wref:int_buffer (WebPDecoderTest.referenceWHT(v.dcBuf))
1039
+ v.transformWHT()
1040
+ i = 0
1041
+ while (i < 16) {
1042
+ if ((int_buffer_get v.coeffs (i * 16)) != (int_buffer_get wref i)) {
1043
+ badWht = badWht + 1
1044
+ }
1045
+ i = i + 1
1046
+ }
1047
+ k = k + 1
1048
+ }
1049
+ this.check((badIdct == 0) ("inverse DCT matches RFC 6386 (" + (to_string badIdct) + " wrong)"))
1050
+ this.check((badAc3 == 0) "AC3 shortcut equals the full transform")
1051
+ this.check((badDc == 0) "DC shortcut equals the full transform")
1052
+ this.check((badWht == 0) ("inverse WHT matches RFC 6386 (" + (to_string badWht) + " wrong)"))
1053
+ ; the 16x16 / chroma edge modes
1054
+ this.check(((VP8Decoder.checkMode(0 0 0)) == 6) "DC without top and left at the corner")
1055
+ this.check(((VP8Decoder.checkMode(3 0 0)) == 4) "DC without top on the first row")
1056
+ this.check(((VP8Decoder.checkMode(0 3 0)) == 5) "DC without left on the first column")
1057
+ this.check(((VP8Decoder.checkMode(0 0 1)) == 1) "other modes unchanged")
1058
+ ; 4x4 prediction: vertical, horizontal and DC on a known neighbourhood
1059
+ buffer_fill v.yuvB 0 0 832
1060
+ def t:int 0
1061
+ while (t < 8) {
1062
+ buffer_set v.yuvB ((40 - 32) + t) (10 + (t * 10))
1063
+ t = t + 1
1064
+ }
1065
+ buffer_set v.yuvB (40 - 33) 5
1066
+ t = 0
1067
+ while (t < 4) {
1068
+ buffer_set v.yuvB ((40 + (t * 32)) - 1) (100 + t)
1069
+ t = t + 1
1070
+ }
1071
+ v.predLuma4(2 40)
1072
+ ; VE4: avg3 of top-left/top/top-right neighbours
1073
+ this.check(((buffer_get v.yuvB 40) == (VP8Decoder.avg3(5 10 20))) "VE4 first column")
1074
+ this.check(((buffer_get v.yuvB (40 + 99)) == (VP8Decoder.avg3(30 40 50))) "VE4 last column uses the top-right sample")
1075
+ v.predLuma4(3 40)
1076
+ this.check(((buffer_get v.yuvB (40 + 96)) == (VP8Decoder.avg3(102 103 103))) "HE4 last row")
1077
+ v.predLuma4(0 40)
1078
+ this.check(((buffer_get v.yuvB 40) == (bit_shr ((((10 + 20) + (30 + 40)) + (((100 + 101) + 102) + 103)) + 4) 3)) "DC4")
1079
+ v.predLuma4(1 40)
1080
+ this.check(((buffer_get v.yuvB 40) == (VP8Decoder.clip(((10 + 100) - 5) 255))) "TM4")
1081
+ }
1082
+
1083
+ fn testAlphaFilters:void () {
1084
+ print "-- alpha filters"
1085
+ def w:int 13
1086
+ def h:int 7
1087
+ def f:int 1
1088
+ while (f <= 3) {
1089
+ def orig:buffer (buffer_alloc (w * h))
1090
+ def i:int 0
1091
+ while (i < (w * h)) {
1092
+ buffer_set orig i (rng.below(256))
1093
+ i = i + 1
1094
+ }
1095
+ ; forward filter: residual = value - prediction from the originals
1096
+ def filt:buffer (buffer_alloc (w * h))
1097
+ def y:int 0
1098
+ while (y < h) {
1099
+ def x:int 0
1100
+ while (x < w) {
1101
+ def j:int ((y * w) + x)
1102
+ def pred:int 0
1103
+ if (y == 0) {
1104
+ if (x > 0) {
1105
+ pred = (buffer_get orig (j - 1))
1106
+ }
1107
+ } {
1108
+ if (x == 0) {
1109
+ pred = (buffer_get orig (j - w))
1110
+ } {
1111
+ if (f == 1) {
1112
+ pred = (buffer_get orig (j - 1))
1113
+ }
1114
+ if (f == 2) {
1115
+ pred = (buffer_get orig (j - w))
1116
+ }
1117
+ if (f == 3) {
1118
+ pred = (WebPDecoderTest.clampT((((buffer_get orig (j - 1)) + (buffer_get orig (j - w))) - (buffer_get orig ((j - w) - 1)))))
1119
+ }
1120
+ }
1121
+ }
1122
+ buffer_set filt j (bit_and ((buffer_get orig j) - pred) 255)
1123
+ x = x + 1
1124
+ }
1125
+ y = y + 1
1126
+ }
1127
+ WebPDecoder.unfilterAlpha(filt w h f)
1128
+ def same:boolean true
1129
+ i = 0
1130
+ while (i < (w * h)) {
1131
+ if ((buffer_get filt i) != (buffer_get orig i)) {
1132
+ same = false
1133
+ }
1134
+ i = i + 1
1135
+ }
1136
+ this.check(same ("alpha filter " + (to_string f) + " round trip"))
1137
+ f = f + 1
1138
+ }
1139
+ }
1140
+
1141
+ fn run:void () {
1142
+ if ((shell_arg_cnt) > 0) {
1143
+ dir = (shell_arg 0)
1144
+ }
1145
+ this.testBoolDecoder()
1146
+ this.testPrefixCodes()
1147
+ this.testPredictors()
1148
+ this.testTransforms()
1149
+ this.testAlphaFilters()
1150
+ this.testFixtures()
1151
+ this.testErrors()
1152
+ print ("webp tests: " + (to_string passed) + " passed, " + (to_string failed) + " failed")
1153
+ if (failed == 0) {
1154
+ print "ALL PASS"
1155
+ }
1156
+ }
1157
+
1158
+ sfn m@(main):void () {
1159
+ def t (new WebPDecoderTest())
1160
+ t.run()
1161
+ }
1162
+ }