ranger-compiler 3.5.1 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1064 -20
- package/LICENSE +3 -1
- package/README.md +123 -28
- package/dist/Lang.rgr +1188 -290
- package/dist/api.d.ts +2343 -879
- package/dist/api.js +79923 -56921
- package/dist/lib/JSON.rgr +102 -91
- package/dist/lib/Shell.rgr +4 -4
- package/dist/lib/apple/AppleToolchain.rgr +4 -4
- package/dist/lib/apple/README.md +5 -4
- package/dist/lib/apple/apple_test.rgr +1 -1
- package/dist/lib/core/README.md +1 -1
- package/dist/lib/evg/EVG.rgr +12 -0
- package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
- package/dist/lib/evg/EVGA11yTree.rgr +894 -0
- package/dist/lib/evg/EVGBox.rgr +267 -0
- package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
- package/dist/lib/evg/EVGCodepoint.rgr +316 -0
- package/dist/lib/evg/EVGColor.rgr +700 -0
- package/dist/lib/evg/EVGCommands.rgr +177 -0
- package/dist/lib/evg/EVGComponent.rgr +331 -0
- package/dist/lib/evg/EVGComponentTest.rgr +387 -0
- package/dist/lib/evg/EVGConnector.rgr +541 -0
- package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
- package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
- package/dist/lib/evg/EVGEasing.rgr +370 -0
- package/dist/lib/evg/EVGEffectTest.rgr +253 -0
- package/dist/lib/evg/EVGElement.rgr +4914 -0
- package/dist/lib/evg/EVGFixedTest.rgr +289 -0
- package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
- package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
- package/dist/lib/evg/EVGFling.rgr +244 -0
- package/dist/lib/evg/EVGFocus.rgr +400 -0
- package/dist/lib/evg/EVGFocusTest.rgr +399 -0
- package/dist/lib/evg/EVGGradient.rgr +322 -0
- package/dist/lib/evg/EVGGrapheme.rgr +190 -0
- package/dist/lib/evg/EVGGrid.rgr +975 -0
- package/dist/lib/evg/EVGHitTest.rgr +208 -0
- package/dist/lib/evg/EVGHoles.rgr +294 -0
- package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
- package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
- package/dist/lib/evg/EVGHostTree.rgr +834 -0
- package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
- package/dist/lib/evg/EVGImageDecode.rgr +117 -0
- package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
- package/dist/lib/evg/EVGInspect.rgr +883 -0
- package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
- package/dist/lib/evg/EVGJsonTest.rgr +535 -0
- package/dist/lib/evg/EVGLayout.rgr +4220 -0
- package/dist/lib/evg/EVGMeasure.rgr +1267 -0
- package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
- package/dist/lib/evg/EVGPatch.rgr +1721 -0
- package/dist/lib/evg/EVGPatchTest.rgr +692 -0
- package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
- package/dist/lib/evg/EVGReconcile.rgr +226 -0
- package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
- package/dist/lib/evg/EVGReject.rgr +126 -0
- package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
- package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
- package/dist/lib/evg/EVGRuler.rgr +232 -0
- package/dist/lib/evg/EVGRulerTest.rgr +172 -0
- package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
- package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
- package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
- package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
- package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
- package/dist/lib/evg/EVGText.rgr +105 -0
- package/dist/lib/evg/EVGTextEngine.rgr +536 -0
- package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
- package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
- package/dist/lib/evg/EVGToolbar.rgr +1369 -0
- package/dist/lib/evg/EVGTransition.rgr +728 -0
- package/dist/lib/evg/EVGTreeJson.rgr +721 -0
- package/dist/lib/evg/EVGUnit.rgr +554 -0
- package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
- package/dist/lib/evg/EvgApp.rgr +189 -0
- package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
- package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
- package/dist/lib/evg/EvgHost.rgr +451 -0
- package/dist/lib/evg/EvgTest.rgr +91 -0
- package/dist/lib/evg/EvgTraceColor.rgr +236 -0
- package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
- package/dist/lib/evg/EvgTraceFit.rgr +767 -0
- package/dist/lib/evg/EvgTracePath.rgr +435 -0
- package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
- package/dist/lib/evg/EvgViewport.rgr +313 -0
- package/dist/lib/evg/FxDemoDoc.rgr +185 -0
- package/dist/lib/evg/HOSTS.md +227 -0
- package/dist/lib/evg/ISSUES.md +835 -0
- package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
- package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
- package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
- package/dist/lib/evg/PLAN_EVG.md +518 -0
- package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
- package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
- package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
- package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
- package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
- package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
- package/dist/lib/evg/PathBuilder.rgr +333 -0
- package/dist/lib/evg/README.md +1236 -0
- package/dist/lib/evg/SPEC.md +1252 -0
- package/dist/lib/evg/SVGPathParser.rgr +1199 -0
- package/dist/lib/evg/SvgParser.rgr +1736 -0
- package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
- package/dist/lib/evg/VectorShapes.rgr +331 -0
- package/dist/lib/evg/VectorStroke.rgr +107 -0
- package/dist/lib/evg/VectorViewBox.rgr +380 -0
- package/dist/lib/evg/agent/README.md +290 -0
- package/dist/lib/evg/agent/evg_agent.rgr +899 -0
- package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
- package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
- package/dist/lib/evg/agent/fixtures/connector.css +63 -0
- package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
- package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
- package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
- package/dist/lib/evg/agent/fixtures/popover.css +99 -0
- package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
- package/dist/lib/evg/agent/roundtrip.sh +74 -0
- package/dist/lib/evg/agent/smoke.sh +230 -0
- package/dist/lib/evg/android/README.md +97 -0
- package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
- package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
- package/dist/lib/evg/android/androidstubs/App.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
- package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
- package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
- package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
- package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
- package/dist/lib/evg/android/androidstubs/View.kt +113 -0
- package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
- package/dist/lib/evg/apple/README.md +128 -0
- package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
- package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
- package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
- package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
- package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
- package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
- package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
- package/dist/lib/evg/bench/README.md +64 -0
- package/dist/lib/evg/bench/layout-bench.mjs +316 -0
- package/dist/lib/evg/bench/layout-cases.mjs +510 -0
- package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
- package/dist/lib/evg/bin/.gitignore +17 -0
- package/dist/lib/evg/evg_test.rgr +313 -0
- package/dist/lib/evg/gl/README.md +198 -0
- package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
- package/dist/lib/evg/gl/blur-check.mjs +399 -0
- package/dist/lib/evg/gl/boxmodel.json +1 -0
- package/dist/lib/evg/gl/demo.html +46 -0
- package/dist/lib/evg/gl/effect-presets.css +285 -0
- package/dist/lib/evg/gl/effect-presets.js +63 -0
- package/dist/lib/evg/gl/effect-shots.mjs +135 -0
- package/dist/lib/evg/gl/evg-a11y.js +566 -0
- package/dist/lib/evg/gl/evg-binary.js +160 -0
- package/dist/lib/evg/gl/evg-engine.js +296 -0
- package/dist/lib/evg/gl/evg-fx.js +237 -0
- package/dist/lib/evg/gl/evg-gestures.js +209 -0
- package/dist/lib/evg/gl/evg-list.js +167 -0
- package/dist/lib/evg/gl/evg-measure.js +186 -0
- package/dist/lib/evg/gl/evg-textinput.js +303 -0
- package/dist/lib/evg/gl/evg-view.js +144 -0
- package/dist/lib/evg/gl/evg-webgl.js +3942 -0
- package/dist/lib/evg/gl/fx-check.mjs +998 -0
- package/dist/lib/evg/gl/fx-demo.html +166 -0
- package/dist/lib/evg/gl/fx-demo.js +2 -0
- package/dist/lib/evg/gl/fx-serve.mjs +47 -0
- package/dist/lib/evg/gl/gestures-check.mjs +189 -0
- package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
- package/dist/lib/evg/gl/measure-check.mjs +135 -0
- package/dist/lib/evg/gl/rotation-check.mjs +207 -0
- package/dist/lib/evg/gl/shift-check.mjs +113 -0
- package/dist/lib/evg/gl/stroke-check.mjs +168 -0
- package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
- package/dist/lib/evg/gl/view-check.mjs +343 -0
- package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
- package/dist/lib/evg/html/evg-dom.js +318 -0
- package/dist/lib/evg/html/evg-html.js +600 -0
- package/dist/lib/evg/inspect/README.md +415 -0
- package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
- package/dist/lib/evg/inspect/evg-inspect.js +947 -0
- package/dist/lib/evg/inspect/shots/css.png +0 -0
- package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
- package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
- package/dist/lib/evg/inspect/shots/state.png +0 -0
- package/dist/lib/evg/inspect/shots.mjs +226 -0
- package/dist/lib/evg/oracle/css-blur.json +576 -0
- package/dist/lib/evg/oracle/css-box.json +157 -0
- package/dist/lib/evg/oracle/css-timing.json +709 -0
- package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
- package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
- package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
- package/dist/lib/evg/original/EVGColor.clj +310 -0
- package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
- package/dist/lib/evg/original/SVGPath.rgr +627 -0
- package/dist/lib/evg/original/Vec2.crgr +103 -0
- package/dist/lib/evg/ranger.json +9 -0
- package/dist/lib/evg/showcase/README.md +246 -0
- package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
- package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
- package/dist/lib/evg/showcase/build.mjs +651 -0
- package/dist/lib/evg/showcase/pages/album.tsx +30 -0
- package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
- package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
- package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
- package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
- package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
- package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
- package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
- package/dist/lib/evg/showcase/pages/more.tsx +332 -0
- package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
- package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
- package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
- package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
- package/dist/lib/evg/showcase/pages/units.tsx +35 -0
- package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
- package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
- package/dist/lib/evg/showcase/pages/views.tsx +223 -0
- package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
- package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
- package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
- package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
- package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
- package/dist/lib/evg/showcase/themes/more-default.css +128 -0
- package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
- package/dist/lib/evg/showcase/themes/showcase.css +508 -0
- package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
- package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
- package/dist/lib/evg/showcase/themes/views-default.css +15 -0
- package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
- package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
- package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
- package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
- package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
- package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
- package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
- package/dist/lib/evg/web/responsive/README.md +97 -0
- package/dist/lib/evg/web/responsive/build.mjs +90 -0
- package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
- package/dist/lib/evg/web/responsive/index.html +177 -0
- package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
- package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
- package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
- package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
- package/dist/lib/evg/web/tools/minify.mjs +60 -0
- package/dist/lib/evg/web/tracer/build.mjs +87 -0
- package/dist/lib/evg/web/tracer/index.html +2805 -0
- package/dist/lib/evg/web/tracer/sample.png +0 -0
- package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
- package/dist/lib/evgr/Cargo.lock +21 -0
- package/dist/lib/evgr/Cargo.toml +19 -0
- package/dist/lib/evgr/README.md +140 -0
- package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
- package/dist/lib/evgr/bench/compare.mjs +252 -0
- package/dist/lib/evgr/bench/speed.mjs +277 -0
- package/dist/lib/evgr/bin/.gitignore +3 -0
- package/dist/lib/evgr/src/bin/bench.rs +106 -0
- package/dist/lib/evgr/src/bin/smoke.rs +13 -0
- package/dist/lib/evgr/src/grid.rs +730 -0
- package/dist/lib/evgr/src/lib.rs +1003 -0
- package/dist/lib/evgr/src/style.rs +468 -0
- package/dist/lib/evgr/src/text.rs +83 -0
- package/dist/lib/image/BitReader.rgr +171 -0
- package/dist/lib/image/Buffer.rgr +173 -0
- package/dist/lib/image/DCT.rgr +283 -0
- package/dist/lib/image/Deflate.rgr +339 -0
- package/dist/lib/image/HuffmanDecoder.rgr +181 -0
- package/dist/lib/image/ImageBuffer.rgr +706 -0
- package/dist/lib/image/JPEGDecoder.rgr +808 -0
- package/dist/lib/image/PNGDecoder.rgr +544 -0
- package/dist/lib/image/PNGEncoder.rgr +388 -0
- package/dist/lib/image/PPMImage.rgr +224 -0
- package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
- package/dist/lib/image/README.md +33 -0
- package/dist/lib/image/RasterBuffer.rgr +294 -0
- package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
- package/dist/lib/image/WebPDecoder.rgr +433 -0
- package/dist/lib/image/WebPLossless.rgr +1035 -0
- package/dist/lib/image/WebPLossy.rgr +1929 -0
- package/dist/lib/image/ranger.json +9 -0
- package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
- package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
- package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
- package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
- package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
- package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
- package/dist/lib/image/tests/run_webp_tests.sh +39 -0
- package/dist/lib/rust/RsJson.rgr +468 -0
- package/dist/lib/rust/RsPrelude.rgr +1663 -0
- package/dist/lib/shell_test.rgr +7 -7
- package/dist/lib/stdlib.rgr +21 -5
- package/dist/lib/zip/ranger.json +6 -0
- package/dist/rgrc.js +87318 -67610
- package/package.json +1010 -1040
- package/dist/README.md +0 -117
- package/dist/package.json +0 -47
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// The walk: an `EVGDisplayList` in, calls on an `EvgSurface` out.
|
|
4
|
+
//
|
|
5
|
+
// Android and Apple differ in how they fill a rounded box, not in what a
|
|
6
|
+
// command *means*, so what a command means is decided exactly once — here —
|
|
7
|
+
// and this file is a transliteration of `lib/evg/android`'s `EvgPainter`
|
|
8
|
+
// rather than a second reading of the format. Where the two disagree, one of
|
|
9
|
+
// them is wrong.
|
|
10
|
+
//
|
|
11
|
+
// Two things this painter honours that a JSON-fed backend cannot:
|
|
12
|
+
//
|
|
13
|
+
// * **Gradients and shadows.** `EVGDisplayList.toJson` carries neither, so a
|
|
14
|
+
// browser host cannot draw them. Reading the objects directly — which is
|
|
15
|
+
// what a Swift host can do — brings both back.
|
|
16
|
+
// * **Clipping and multi-ring paths.** `save`/`clipRect`/`restore` and a real
|
|
17
|
+
// even-odd fill are one line each on CoreGraphics.
|
|
18
|
+
|
|
19
|
+
import CoreGraphics
|
|
20
|
+
|
|
21
|
+
enum EvgPainter {
|
|
22
|
+
|
|
23
|
+
private static let RECT = 0
|
|
24
|
+
private static let BORDER = 1
|
|
25
|
+
private static let IMAGE = 2
|
|
26
|
+
private static let TEXT = 3
|
|
27
|
+
private static let PUSH_CLIP = 4
|
|
28
|
+
private static let POP_CLIP = 5
|
|
29
|
+
private static let PATH = 6
|
|
30
|
+
private static let STROKE = 7
|
|
31
|
+
|
|
32
|
+
/// Anything below this is invisible; drawing it is work for nothing.
|
|
33
|
+
private static let MIN_ALPHA = 0.001
|
|
34
|
+
|
|
35
|
+
/// Paint every command in order. Answers how many were actually drawn,
|
|
36
|
+
/// which is what a host puts in a debug overlay — a frame that draws 0 of
|
|
37
|
+
/// 350 commands is a bug you want to see rather than a black screen.
|
|
38
|
+
@discardableResult
|
|
39
|
+
static func paint(_ list: EVGDisplayList, into surface: EvgSurface) -> Int {
|
|
40
|
+
var drawn = 0
|
|
41
|
+
// A list that pushes more clips than it pops must not leave the surface
|
|
42
|
+
// with a clip nobody asked for, and one that pops more than it pushes
|
|
43
|
+
// must not restore past the state the host handed us. The depth counter
|
|
44
|
+
// is the whole of both guarantees.
|
|
45
|
+
var clipDepth = 0
|
|
46
|
+
let n = list.count()
|
|
47
|
+
var i = 0
|
|
48
|
+
while i < n {
|
|
49
|
+
let c = list.at(i: i)
|
|
50
|
+
i += 1
|
|
51
|
+
|
|
52
|
+
if c.kind == PUSH_CLIP {
|
|
53
|
+
surface.save()
|
|
54
|
+
surface.clipRect(
|
|
55
|
+
x: CGFloat(c.x), y: CGFloat(c.y),
|
|
56
|
+
w: CGFloat(c.w), h: CGFloat(c.h)
|
|
57
|
+
)
|
|
58
|
+
clipDepth += 1
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
if c.kind == POP_CLIP {
|
|
62
|
+
if clipDepth > 0 {
|
|
63
|
+
surface.restore()
|
|
64
|
+
clipDepth -= 1
|
|
65
|
+
}
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// A rotation turns the command about the point the display list
|
|
70
|
+
// names, and about the command's own box centre only when it names
|
|
71
|
+
// none. `EVGDisplayList` resolves `transform-origin` into
|
|
72
|
+
// rotOriginX/Y and sets hasRotOrigin, exactly because the centre is
|
|
73
|
+
// "right for a lone rotated label and wrong for everything else: a
|
|
74
|
+
// box, its text and its children have to turn about ONE point or
|
|
75
|
+
// they come apart".
|
|
76
|
+
//
|
|
77
|
+
// Ignoring it is what made RealTrainer's loading spinner a single
|
|
78
|
+
// small bar. Its twelve blades are one 8x26 box each, fanned into a
|
|
79
|
+
// ring by `transform: rotate(Ndeg)` about `transform-origin: 4px
|
|
80
|
+
// 54px` -- a point 41px BELOW each blade's own centre. Turned about
|
|
81
|
+
// their centres they all spin in place and land on top of each
|
|
82
|
+
// other. Wrapping it in save/restore keeps the clip stack above
|
|
83
|
+
// untouched.
|
|
84
|
+
let turned = c.rotate > 0.001 || c.rotate < -0.001
|
|
85
|
+
if turned {
|
|
86
|
+
surface.save()
|
|
87
|
+
surface.rotate(
|
|
88
|
+
degrees: CGFloat(c.rotate),
|
|
89
|
+
px: c.hasRotOrigin ? CGFloat(c.rotOriginX) : CGFloat(c.x + c.w * 0.5),
|
|
90
|
+
py: c.hasRotOrigin ? CGFloat(c.rotOriginY) : CGFloat(c.y + c.h * 0.5)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if drawOne(c, surface) { drawn += 1 }
|
|
95
|
+
|
|
96
|
+
if turned { surface.restore() }
|
|
97
|
+
}
|
|
98
|
+
while clipDepth > 0 {
|
|
99
|
+
surface.restore()
|
|
100
|
+
clipDepth -= 1
|
|
101
|
+
}
|
|
102
|
+
return drawn
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private static func drawOne(_ c: EVGDrawCmd, _ surface: EvgSurface) -> Bool {
|
|
106
|
+
switch c.kind {
|
|
107
|
+
case RECT:
|
|
108
|
+
let shadow = shadowOf(c)
|
|
109
|
+
let gradient = gradientOf(c)
|
|
110
|
+
if c.a < MIN_ALPHA && gradient == nil && shadow == nil { return false }
|
|
111
|
+
surface.fillRect(
|
|
112
|
+
x: CGFloat(c.x), y: CGFloat(c.y), w: CGFloat(c.w), h: CGFloat(c.h),
|
|
113
|
+
radius: CGFloat(c.radius),
|
|
114
|
+
color: colorOf(c),
|
|
115
|
+
gradient: gradient,
|
|
116
|
+
shadow: shadow
|
|
117
|
+
)
|
|
118
|
+
return true
|
|
119
|
+
|
|
120
|
+
case BORDER:
|
|
121
|
+
if c.a < MIN_ALPHA { return false }
|
|
122
|
+
// A border with no thickness is still a border: the display list
|
|
123
|
+
// leaves the default at 0 for a hairline, and a stroke of width 0
|
|
124
|
+
// is invisible.
|
|
125
|
+
let t = c.thickness > 0.0 ? CGFloat(c.thickness) : 1.0
|
|
126
|
+
surface.strokeRect(
|
|
127
|
+
x: CGFloat(c.x), y: CGFloat(c.y), w: CGFloat(c.w), h: CGFloat(c.h),
|
|
128
|
+
radius: CGFloat(c.radius), thickness: t,
|
|
129
|
+
color: colorOf(c)
|
|
130
|
+
)
|
|
131
|
+
return true
|
|
132
|
+
|
|
133
|
+
case IMAGE:
|
|
134
|
+
if c.src.isEmpty { return false }
|
|
135
|
+
surface.drawImage(
|
|
136
|
+
src: c.src,
|
|
137
|
+
x: CGFloat(c.x), y: CGFloat(c.y), w: CGFloat(c.w), h: CGFloat(c.h),
|
|
138
|
+
radius: CGFloat(c.radius),
|
|
139
|
+
flipH: c.flipH, flipV: c.flipV
|
|
140
|
+
)
|
|
141
|
+
return true
|
|
142
|
+
|
|
143
|
+
case TEXT:
|
|
144
|
+
if c.text.isEmpty { return false }
|
|
145
|
+
if c.a < MIN_ALPHA { return false }
|
|
146
|
+
surface.drawTextRun(
|
|
147
|
+
text: c.text,
|
|
148
|
+
x: CGFloat(c.x), top: CGFloat(c.y),
|
|
149
|
+
sizePx: CGFloat(c.fontSize),
|
|
150
|
+
family: c.fontFamily,
|
|
151
|
+
bold: isBold(c.fontWeight),
|
|
152
|
+
// `addText` has nowhere else to record a slanted face, so it
|
|
153
|
+
// writes "italic" into textAlign and `toJson` reads it back out
|
|
154
|
+
// the same way. Not lovely, but it is the format.
|
|
155
|
+
italic: c.textAlign == "italic",
|
|
156
|
+
color: colorOf(c)
|
|
157
|
+
)
|
|
158
|
+
return true
|
|
159
|
+
|
|
160
|
+
case PATH:
|
|
161
|
+
if c.a < MIN_ALPHA { return false }
|
|
162
|
+
if c.pts.count < 6 { return false }
|
|
163
|
+
surface.fillPath(
|
|
164
|
+
pts: c.pts, ringEnds: ringsOf(c), evenOdd: c.evenOdd,
|
|
165
|
+
color: colorOf(c), shadow: shadowOf(c)
|
|
166
|
+
)
|
|
167
|
+
return true
|
|
168
|
+
|
|
169
|
+
case STROKE:
|
|
170
|
+
if c.a < MIN_ALPHA { return false }
|
|
171
|
+
if c.pts.count < 4 { return false }
|
|
172
|
+
let t = c.thickness > 0.0 ? CGFloat(c.thickness) : 1.0
|
|
173
|
+
surface.strokePath(
|
|
174
|
+
pts: c.pts, ringEnds: ringsOf(c), thickness: t, color: colorOf(c)
|
|
175
|
+
)
|
|
176
|
+
return true
|
|
177
|
+
|
|
178
|
+
default:
|
|
179
|
+
return false
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// A path emitted by the SVG walk carries its ring boundaries; one emitted
|
|
184
|
+
/// by `addPolygon` / `addPolyline` may not. A single implicit ring covering
|
|
185
|
+
/// every point is the right reading of an empty `ringEnds` — it is what the
|
|
186
|
+
/// polygon filler assumes.
|
|
187
|
+
private static func ringsOf(_ c: EVGDrawCmd) -> [Int] {
|
|
188
|
+
c.ringEnds.isEmpty ? [c.pts.count] : c.ringEnds
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private static func gradientOf(_ c: EVGDrawCmd) -> EvgGradient? {
|
|
192
|
+
if !c.hasGrad { return nil }
|
|
193
|
+
return EvgGradient(
|
|
194
|
+
color1: EvgColor(r: c.r, g: c.g, b: c.b, a: c.a),
|
|
195
|
+
color2: EvgColor(r: c.r2, g: c.g2, b: c.b2, a: c.a2),
|
|
196
|
+
// dir 0 = vertical (top to bottom), 1 = horizontal (left to right)
|
|
197
|
+
vertical: c.gradDir != 1
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private static func shadowOf(_ c: EVGDrawCmd) -> EvgShadow? {
|
|
202
|
+
if !c.hasShadow { return nil }
|
|
203
|
+
if c.shadowA < MIN_ALPHA { return nil }
|
|
204
|
+
return EvgShadow(
|
|
205
|
+
dx: CGFloat(c.shadowX),
|
|
206
|
+
dy: CGFloat(c.shadowY),
|
|
207
|
+
blur: CGFloat(c.shadowBlur),
|
|
208
|
+
color: EvgColor(r: c.shadowR, g: c.shadowG, b: c.shadowB, a: c.shadowA)
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private static func colorOf(_ c: EVGDrawCmd) -> EvgColor {
|
|
213
|
+
EvgColor(r: c.r, g: c.g, b: c.b, a: c.a)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/// The display list writes the word, not the number — `addText` only ever
|
|
217
|
+
/// says "bold" — but a stylesheet path could put a CSS weight here, so a
|
|
218
|
+
/// number is read as one.
|
|
219
|
+
static func isBold(_ weight: String) -> Bool {
|
|
220
|
+
if weight.isEmpty { return false }
|
|
221
|
+
if weight == "bold" || weight == "bolder" { return true }
|
|
222
|
+
guard let n = Int(weight) else { return false }
|
|
223
|
+
return n >= 600
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Everything a backend has to be able to draw, and nothing else.
|
|
4
|
+
//
|
|
5
|
+
// `EVGDisplayList` is eight command kinds of absolute pixels and resolved
|
|
6
|
+
// colours — no tree, no units, no fonts to resolve. That is small enough that a
|
|
7
|
+
// backend is a page of delegation rather than a renderer, which is the point:
|
|
8
|
+
// `CoreGraphicsEvgSurface` paints with a `CGContext` (so a `UIView` on iOS and
|
|
9
|
+
// a SwiftUI `Canvas` on watchOS share one implementation), `RecordingSurface`
|
|
10
|
+
// counts what was dispatched without drawing anything, and the walk that
|
|
11
|
+
// decides what each command *means* — `EvgPainter` — is written once.
|
|
12
|
+
//
|
|
13
|
+
// This is the Apple sibling of `lib/evg/android`, and the interface is
|
|
14
|
+
// deliberately the same one: a port that diverges here would make the two
|
|
15
|
+
// painters two programs to keep in step rather than one idea with two
|
|
16
|
+
// backends.
|
|
17
|
+
//
|
|
18
|
+
// Geometry is in the app's own points. A host that wants device pixels scales
|
|
19
|
+
// its context and leaves these numbers alone — text then rasterises at the
|
|
20
|
+
// panel's real resolution instead of being blown up from a bitmap made at some
|
|
21
|
+
// other size.
|
|
22
|
+
|
|
23
|
+
import CoreGraphics
|
|
24
|
+
|
|
25
|
+
/// A colour as the display list carries it: 0-255 channels and a 0-1 alpha.
|
|
26
|
+
struct EvgColor {
|
|
27
|
+
let r: Int
|
|
28
|
+
let g: Int
|
|
29
|
+
let b: Int
|
|
30
|
+
let a: Double
|
|
31
|
+
|
|
32
|
+
init(r: Int, g: Int, b: Int, a: Double) {
|
|
33
|
+
self.r = r
|
|
34
|
+
self.g = g
|
|
35
|
+
self.b = b
|
|
36
|
+
self.a = a
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private static func clamp255(_ v: Int) -> CGFloat {
|
|
40
|
+
if v < 0 { return 0 }
|
|
41
|
+
if v > 255 { return 1 }
|
|
42
|
+
return CGFloat(v) / 255.0
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var cgColor: CGColor {
|
|
46
|
+
let alpha = a < 0 ? 0 : (a > 1 ? 1 : a)
|
|
47
|
+
return CGColor(
|
|
48
|
+
srgbRed: EvgColor.clamp255(r),
|
|
49
|
+
green: EvgColor.clamp255(g),
|
|
50
|
+
blue: EvgColor.clamp255(b),
|
|
51
|
+
alpha: CGFloat(alpha)
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// The same colour with the alpha replaced, for a shadow that carries its
|
|
56
|
+
/// own.
|
|
57
|
+
func withAlpha(_ alpha: Double) -> EvgColor {
|
|
58
|
+
EvgColor(r: r, g: g, b: b, a: alpha)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// A two-stop linear gradient. `vertical` is EVG's `gradDir == 0`.
|
|
63
|
+
struct EvgGradient {
|
|
64
|
+
let color1: EvgColor
|
|
65
|
+
let color2: EvgColor
|
|
66
|
+
let vertical: Bool
|
|
67
|
+
|
|
68
|
+
init(color1: EvgColor, color2: EvgColor, vertical: Bool) {
|
|
69
|
+
self.color1 = color1
|
|
70
|
+
self.color2 = color2
|
|
71
|
+
self.vertical = vertical
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// An outer drop shadow: offset, blur radius, colour.
|
|
76
|
+
struct EvgShadow {
|
|
77
|
+
let dx: CGFloat
|
|
78
|
+
let dy: CGFloat
|
|
79
|
+
let blur: CGFloat
|
|
80
|
+
let color: EvgColor
|
|
81
|
+
|
|
82
|
+
init(dx: CGFloat, dy: CGFloat, blur: CGFloat, color: EvgColor) {
|
|
83
|
+
self.dx = dx
|
|
84
|
+
self.dy = dy
|
|
85
|
+
self.blur = blur
|
|
86
|
+
self.color = color
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protocol EvgSurface: AnyObject {
|
|
91
|
+
|
|
92
|
+
/// Push the clip/transform stack. Paired with `restore`.
|
|
93
|
+
func save()
|
|
94
|
+
|
|
95
|
+
/// Pop back to the state the matching `save` recorded.
|
|
96
|
+
func restore()
|
|
97
|
+
|
|
98
|
+
/// Intersect the clip with this rectangle. Only ever inside a `save`.
|
|
99
|
+
func clipRect(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat)
|
|
100
|
+
|
|
101
|
+
/// Turn the coordinate system `degrees` about (`px`, `py`).
|
|
102
|
+
func rotate(degrees: CGFloat, px: CGFloat, py: CGFloat)
|
|
103
|
+
|
|
104
|
+
/// A filled box, possibly rounded, possibly a two-stop gradient, possibly
|
|
105
|
+
/// under a drop shadow. The shadow is painted first and is the shape's own
|
|
106
|
+
/// silhouette — a rounded box casts a rounded shadow.
|
|
107
|
+
func fillRect(
|
|
108
|
+
x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
109
|
+
radius: CGFloat,
|
|
110
|
+
color: EvgColor,
|
|
111
|
+
gradient: EvgGradient?,
|
|
112
|
+
shadow: EvgShadow?
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
/// A stroked outline, drawn as a band of `thickness` INSIDE the box.
|
|
116
|
+
func strokeRect(
|
|
117
|
+
x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
118
|
+
radius: CGFloat, thickness: CGFloat,
|
|
119
|
+
color: EvgColor
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
/// A filled vector outline. The rings are already flattened and already in
|
|
123
|
+
/// page coordinates; `ringEnds` gives the index in `pts` one past each
|
|
124
|
+
/// ring's last coordinate, so a shape with a hole arrives as two rings.
|
|
125
|
+
func fillPath(
|
|
126
|
+
pts: [Double], ringEnds: [Int], evenOdd: Bool,
|
|
127
|
+
color: EvgColor,
|
|
128
|
+
shadow: EvgShadow?
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
/// The same rings, stroked rather than filled.
|
|
132
|
+
func strokePath(
|
|
133
|
+
pts: [Double], ringEnds: [Int],
|
|
134
|
+
thickness: CGFloat,
|
|
135
|
+
color: EvgColor
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
/// A picture, by the name the page gave it. A surface that has no bytes for
|
|
139
|
+
/// `src` should draw the placeholder rather than nothing — a missing
|
|
140
|
+
/// texture and a blank card look identical otherwise.
|
|
141
|
+
func drawImage(
|
|
142
|
+
src: String,
|
|
143
|
+
x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
144
|
+
radius: CGFloat,
|
|
145
|
+
flipH: Bool, flipV: Bool
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
/// One run, on one line, in one face.
|
|
149
|
+
///
|
|
150
|
+
/// `top` is the top of the LINE BOX, not the baseline: EVG measured the run
|
|
151
|
+
/// with its own width estimate and the baseline sits one face-ascent below.
|
|
152
|
+
/// Placing the ink at `top` instead lifts every run by the empty space
|
|
153
|
+
/// above its capitals — a couple of points on a caption, most of a line on
|
|
154
|
+
/// a heading. The surface owns that conversion because only it knows what
|
|
155
|
+
/// its own font metrics say.
|
|
156
|
+
func drawTextRun(
|
|
157
|
+
text: String,
|
|
158
|
+
x: CGFloat, top: CGFloat,
|
|
159
|
+
sizePx: CGFloat,
|
|
160
|
+
family: String, bold: Bool, italic: Bool,
|
|
161
|
+
color: EvgColor
|
|
162
|
+
)
|
|
163
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// A surface that draws nothing and counts everything.
|
|
4
|
+
//
|
|
5
|
+
// Wrap a real surface in one of these and the frame is painted exactly as it
|
|
6
|
+
// would be, with a tally of what was dispatched on the other side. "Some ink
|
|
7
|
+
// appeared" is a weak check — a painter that had quietly stopped drawing text
|
|
8
|
+
// would pass it — so a check asserts the counts instead: this page reaches
|
|
9
|
+
// text, filled boxes, borders, rounded corners, clipping, a filled path and
|
|
10
|
+
// stroked paths, and every `save` is matched by a `restore`.
|
|
11
|
+
//
|
|
12
|
+
// The Ranger side of this port counts the same things one step earlier, on the
|
|
13
|
+
// display list itself (`gallery/ui/ios/ranger/check_ios.rgr`), because that can
|
|
14
|
+
// run without a Mac. This is for the half that cannot: it says whether the
|
|
15
|
+
// PAINTER dispatched them, not merely whether the page produced them.
|
|
16
|
+
|
|
17
|
+
import CoreGraphics
|
|
18
|
+
|
|
19
|
+
final class RecordingSurface: EvgSurface {
|
|
20
|
+
|
|
21
|
+
private(set) var calls: [String: Int] = [:]
|
|
22
|
+
private let inner: EvgSurface?
|
|
23
|
+
|
|
24
|
+
init(wrapping inner: EvgSurface? = nil) {
|
|
25
|
+
self.inner = inner
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func count(_ kind: String) -> Int {
|
|
29
|
+
calls[kind] ?? 0
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private func note(_ kind: String) {
|
|
33
|
+
calls[kind, default: 0] += 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var summary: String {
|
|
37
|
+
calls.keys.sorted().map { "\($0)=\(calls[$0]!)" }.joined(separator: " ")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func save() {
|
|
41
|
+
note("save")
|
|
42
|
+
inner?.save()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func restore() {
|
|
46
|
+
note("restore")
|
|
47
|
+
inner?.restore()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func clipRect(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) {
|
|
51
|
+
note("clipRect")
|
|
52
|
+
inner?.clipRect(x: x, y: y, w: w, h: h)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func rotate(degrees: CGFloat, px: CGFloat, py: CGFloat) {
|
|
56
|
+
note("rotate")
|
|
57
|
+
inner?.rotate(degrees: degrees, px: px, py: py)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func fillRect(
|
|
61
|
+
x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
62
|
+
radius: CGFloat, color: EvgColor,
|
|
63
|
+
gradient: EvgGradient?, shadow: EvgShadow?
|
|
64
|
+
) {
|
|
65
|
+
note("fillRect")
|
|
66
|
+
if radius > 0 { note("roundedRect") }
|
|
67
|
+
if gradient != nil { note("gradient") }
|
|
68
|
+
if shadow != nil { note("shadow") }
|
|
69
|
+
inner?.fillRect(x: x, y: y, w: w, h: h, radius: radius, color: color, gradient: gradient, shadow: shadow)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func strokeRect(
|
|
73
|
+
x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
74
|
+
radius: CGFloat, thickness: CGFloat, color: EvgColor
|
|
75
|
+
) {
|
|
76
|
+
note("strokeRect")
|
|
77
|
+
inner?.strokeRect(x: x, y: y, w: w, h: h, radius: radius, thickness: thickness, color: color)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func fillPath(
|
|
81
|
+
pts: [Double], ringEnds: [Int], evenOdd: Bool,
|
|
82
|
+
color: EvgColor, shadow: EvgShadow?
|
|
83
|
+
) {
|
|
84
|
+
note("fillPath")
|
|
85
|
+
if shadow != nil { note("shadow") }
|
|
86
|
+
inner?.fillPath(pts: pts, ringEnds: ringEnds, evenOdd: evenOdd, color: color, shadow: shadow)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func strokePath(pts: [Double], ringEnds: [Int], thickness: CGFloat, color: EvgColor) {
|
|
90
|
+
note("strokePath")
|
|
91
|
+
inner?.strokePath(pts: pts, ringEnds: ringEnds, thickness: thickness, color: color)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func drawImage(
|
|
95
|
+
src: String, x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat,
|
|
96
|
+
radius: CGFloat, flipH: Bool, flipV: Bool
|
|
97
|
+
) {
|
|
98
|
+
note("drawImage")
|
|
99
|
+
inner?.drawImage(src: src, x: x, y: y, w: w, h: h, radius: radius, flipH: flipH, flipV: flipV)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func drawTextRun(
|
|
103
|
+
text: String, x: CGFloat, top: CGFloat, sizePx: CGFloat,
|
|
104
|
+
family: String, bold: Bool, italic: Bool, color: EvgColor
|
|
105
|
+
) {
|
|
106
|
+
note("drawTextRun")
|
|
107
|
+
if italic { note("italicText") }
|
|
108
|
+
inner?.drawTextRun(text: text, x: x, top: top, sizePx: sizePx, family: family, bold: bold, italic: italic, color: color)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EvgLayoutBench — the layout engine, exported so a harness can drive it
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
; The benchmark and the conformance probe beside this file are JavaScript,
|
|
7
|
+
; because the other side of both comparisons is a browser and the case list has
|
|
8
|
+
; to be written once. This module exists only so `-nodemodule` publishes the
|
|
9
|
+
; engine's classes: the harness builds `EVGElement` trees itself, calls
|
|
10
|
+
; `setAttribute` with CSS property names, and reads `calculated*` back.
|
|
11
|
+
;
|
|
12
|
+
; Nothing here is part of the engine. The one function is the count a harness
|
|
13
|
+
; would otherwise have to re-derive, and it is here rather than in JS so the
|
|
14
|
+
; tree walk is the engine's own.
|
|
15
|
+
; ==============================================================================
|
|
16
|
+
|
|
17
|
+
Import "../EVGElement.rgr"
|
|
18
|
+
Import "../EVGUnit.rgr"
|
|
19
|
+
Import "../EVGLayout.rgr"
|
|
20
|
+
Import "../EVGDisplayList.rgr"
|
|
21
|
+
|
|
22
|
+
class EvgLayoutBench {
|
|
23
|
+
|
|
24
|
+
sfn countElements:int (el:EVGElement) {
|
|
25
|
+
def n:int 1
|
|
26
|
+
def i:int 0
|
|
27
|
+
while (i < (array_length el.children)) {
|
|
28
|
+
def kid:EVGElement (itemAt el.children i)
|
|
29
|
+
n = (n + (EvgLayoutBench.countElements(kid)))
|
|
30
|
+
i = (i + 1)
|
|
31
|
+
}
|
|
32
|
+
return n
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# `bench/` — the same CSS, two engines
|
|
2
|
+
|
|
3
|
+
Two harnesses. Both drive the compiled engine from JavaScript, which is worth
|
|
4
|
+
saying on its own: `-nodemodule` publishes `EVGElement`, `EVGLayout` and the
|
|
5
|
+
rest, so a tree is `new EVGElement()`, `setAttribute` with CSS property names,
|
|
6
|
+
`addChild`, `layout()` — no Ranger, no JSX, no stylesheet in the way.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm run evg:layout:conformance # box for box against Chromium
|
|
10
|
+
npm run evg:layout:bench # 1k / 10k / 100k, three fixtures
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## `layout-conformance.mjs` — where an EVG document and its CSS disagree
|
|
14
|
+
|
|
15
|
+
The cases in `layout-cases.mjs` are written ONCE, as CSS text. The runner
|
|
16
|
+
splits that text into `setAttribute` calls for EVG and drops it verbatim into a
|
|
17
|
+
`style=` attribute for Chromium, so a differing box is a difference between the
|
|
18
|
+
engines and not between two transcriptions of the same intent.
|
|
19
|
+
|
|
20
|
+
This is a measurement, not a test suite: Chromium is the definition of what the
|
|
21
|
+
CSS says, and a case that differs names a place where a document written as CSS
|
|
22
|
+
does not lay out as CSS. The report separates the deliberate divergences —
|
|
23
|
+
EVG's initial values for `flex-direction`, `flex-wrap` and `align-items`, which
|
|
24
|
+
are documented choices — from the rest, and says for each whether **the engine
|
|
25
|
+
said anything about it**. That last column is the one that mattered: of the
|
|
26
|
+
nineteen divergences the first run found, eighteen were silent.
|
|
27
|
+
|
|
28
|
+
The three text cases are not compared pixel for pixel. EVG's default measurer
|
|
29
|
+
is a heuristic and the browser's is a real face, so a diff there would measure
|
|
30
|
+
the fixture; what is asserted instead is that text participates in layout at
|
|
31
|
+
all. Font parity has its own suite (`evg:measure:web`, the textbox oracle).
|
|
32
|
+
|
|
33
|
+
## `layout-bench.mjs` — what it costs at size
|
|
34
|
+
|
|
35
|
+
Three fixtures, because "layout" is not one cost: nested flex (an application
|
|
36
|
+
UI's shape, four levels), a wide flat grid (track sizing at size), and the flex
|
|
37
|
+
fixture with text in it. Sizes 1k / 10k / 100k. `layout` is a RE-layout of a
|
|
38
|
+
tree that already exists — what a resize costs, not what a first paint does.
|
|
39
|
+
|
|
40
|
+
Chromium is timed on the same tree with a forced reflow. Read it as an
|
|
41
|
+
order-of-magnitude reference for a production C++ layout engine on the same
|
|
42
|
+
boxes, not a like-for-like race: the browser is doing line layout and paint
|
|
43
|
+
invalidation that this pass is not, and it is not paying for a heuristic text
|
|
44
|
+
measurer either.
|
|
45
|
+
|
|
46
|
+
`--ab` builds a second copy of the engine from the pre-change sources
|
|
47
|
+
(`EvgLayoutBenchBase.cjs`, compiled from a `git archive` of the tree you are
|
|
48
|
+
comparing against) and alternates the two inside one process, best-of-runs with
|
|
49
|
+
`--min`. A laptop's noise floor on these fixtures is a few per cent and two runs
|
|
50
|
+
taken minutes apart cannot see through it; alternating can.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
git archive HEAD lib/evg | tar -x -C /tmp/base
|
|
54
|
+
cp lib/evg/bench/EvgLayoutBench.rgr /tmp/base/lib/evg/bench/
|
|
55
|
+
RANGER_LIB=./compiler/Lang.rgr:./lib/stdops.rgr node dist/rgrc.js -es6 -nodemodule \
|
|
56
|
+
/tmp/base/lib/evg/bench/EvgLayoutBench.rgr -d=./lib/evg/bin -o=EvgLayoutBenchBase.cjs
|
|
57
|
+
node --expose-gc lib/evg/bench/layout-bench.mjs --ab --min --no-browser
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What it needs
|
|
61
|
+
|
|
62
|
+
`playwright-core` and a Chromium on disk. The harness takes whatever revision is
|
|
63
|
+
actually installed rather than the one `playwright-core` was built against,
|
|
64
|
+
because those drift; `--no-browser` skips the browser half entirely.
|