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.
- package/CHANGELOG.md +1160 -19
- package/LICENSE +3 -1
- package/README.md +124 -29
- package/dist/Lang.rgr +1188 -290
- package/dist/api.d.ts +2343 -879
- package/dist/api.js +79924 -56922
- 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,21 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "evgr"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"ranger",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[[package]]
|
|
13
|
+
name = "ranger"
|
|
14
|
+
version = "0.1.0"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"ranger-macros",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[[package]]
|
|
20
|
+
name = "ranger-macros"
|
|
21
|
+
version = "0.1.0"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
#
|
|
3
|
+
# EVGr: EVG's layout as a strict Rust module (see src/lib.rs). The same
|
|
4
|
+
# source builds here with cargo and with `rgrc` for the other targets.
|
|
5
|
+
|
|
6
|
+
[package]
|
|
7
|
+
name = "evgr"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
edition = "2021"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
publish = false
|
|
12
|
+
|
|
13
|
+
[dependencies]
|
|
14
|
+
ranger = { path = "../../runtime/rust/ranger" }
|
|
15
|
+
|
|
16
|
+
[profile.release]
|
|
17
|
+
overflow-checks = false
|
|
18
|
+
|
|
19
|
+
[workspace]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# EVGr — EVG's layout as a strict Rust module
|
|
2
|
+
|
|
3
|
+
An experiment beside [`lib/evg`](../evg), which it does not replace: the layout
|
|
4
|
+
of an EVG document — boxes styled with CSS declarations, laid out as flexbox
|
|
5
|
+
and grid with EVG's box model and initial values — written once in Rust
|
|
6
|
+
(`src/`, 2,300 lines) and built two ways:
|
|
7
|
+
|
|
8
|
+
- by **cargo** into native code (`cargo run --release --bin bench`);
|
|
9
|
+
- by **`rgrc`** into every Ranger target, the way any `.rs` module is
|
|
10
|
+
(`docs/plans/PLAN_RUST_SYNTAX.md`): `npm run evgr:build` writes
|
|
11
|
+
`bin/Evgr.cjs`, and `bench/NativeBench.rgr` — a Ranger program that imports
|
|
12
|
+
`src/lib.rs` beside `lib/evg` — builds for C++ and Go.
|
|
13
|
+
|
|
14
|
+
The questions were how it does on the layout cases EVG is measured with, and
|
|
15
|
+
how its speed compares with the Ranger engine.
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm run evgr:compare # the layout cases: EVGr, EVG and Chromium
|
|
19
|
+
npm run evgr:speed # the layout-bench fixtures at 1k / 10k / 100k
|
|
20
|
+
npx vitest run --config tests/vitest.config.ts evgr.test.ts
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## What it lays out
|
|
24
|
+
|
|
25
|
+
`display` block / flex / grid / none, `flex-direction` (and the reverse
|
|
26
|
+
forms), `flex-wrap`, width / height and their min / max (px, %, `calc()` of
|
|
27
|
+
px and %), padding (a percentage of the containing block's width), margin,
|
|
28
|
+
gap, `flex-grow` / `-shrink` / `-basis` / `flex`, `justify-content`,
|
|
29
|
+
`align-items` / `-self` / `-content` (with `baseline`), `aspect-ratio`,
|
|
30
|
+
`position: absolute` with top / right / bottom / left, grid templates (px, %,
|
|
31
|
+
fr, auto, `minmax()`, `fit-content()`, `repeat(n, …)`,
|
|
32
|
+
`repeat(auto-fit | auto-fill, …)`), placement by line numbers, `span`,
|
|
33
|
+
`grid-template-areas` / `grid-area`, auto placement with `dense`, and text
|
|
34
|
+
measured with EVG's default advance table, wrapped at spaces.
|
|
35
|
+
|
|
36
|
+
Not there: borders, images, overlays, connectors, the stylesheet, scrolling,
|
|
37
|
+
RTL — everything of EVG that is not the box layout. A property EVGr does not
|
|
38
|
+
know is reported (`unsupported_count` / `unsupported_at`).
|
|
39
|
+
|
|
40
|
+
The tree is an arena (a node is an index), and a subtree laid out at the same
|
|
41
|
+
width in the same pass is moved rather than laid out again, which is what
|
|
42
|
+
keeps a column of rows linear.
|
|
43
|
+
|
|
44
|
+
## The layout cases
|
|
45
|
+
|
|
46
|
+
`bench/compare.mjs` runs the 47 cases of `lib/evg/bench/layout-cases.mjs`
|
|
47
|
+
through the three engines; two agree on a case when every box is within half
|
|
48
|
+
a pixel.
|
|
49
|
+
|
|
50
|
+
| | agree |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| EVGr and Chromium | 42 of 47 |
|
|
53
|
+
| EVGr and EVG | 39 of 47 |
|
|
54
|
+
| EVG and Chromium | 34 of 47 |
|
|
55
|
+
|
|
56
|
+
Where EVGr and Chromium differ, EVGr keeps a choice EVG made on purpose:
|
|
57
|
+
the initial values of `flex-direction` (column), `flex-wrap` (wrap) and
|
|
58
|
+
`align-items` (flex-start: `defaults-*`, `nested-flex-in-flex`), and an
|
|
59
|
+
absolute box placed against the content box (`absolute-child`). EVGr also
|
|
60
|
+
keeps two of EVG's rules the cases do not reach: a root without a height is
|
|
61
|
+
as tall as the viewport, and a text leaf without a width fits its text even
|
|
62
|
+
where a column stretches its boxes.
|
|
63
|
+
|
|
64
|
+
Where EVGr and EVG differ, EVGr agrees with Chromium: `align-content:
|
|
65
|
+
stretch` over wrapped lines, `row-reverse`, a grid cell holding a flex row, a
|
|
66
|
+
grid template mixing px / % / fr / auto, `max-content` as a width,
|
|
67
|
+
`aspect-ratio`, `calc()`, and `repeat(auto-fit, …)`.
|
|
68
|
+
|
|
69
|
+
The three text cases hold on EVGr's boxes, and EVGr's text boxes are EVG's
|
|
70
|
+
(same advance table, same line height).
|
|
71
|
+
|
|
72
|
+
## Speed
|
|
73
|
+
|
|
74
|
+
`bench/speed.mjs` builds the three fixtures of
|
|
75
|
+
`lib/evg/bench/layout-bench.mjs` — nested flex (a column of cards, each a row
|
|
76
|
+
of a rail and a growing column), a four-column grid of small flex columns,
|
|
77
|
+
and the flex fixture with a line of text per card — and times a re-layout of
|
|
78
|
+
the built tree (median of five). Every engine's boxes are summed into a
|
|
79
|
+
checksum: on all nine fixture sizes EVG and EVGr lay the tree out the same,
|
|
80
|
+
in JavaScript, C++, Go and native Rust.
|
|
81
|
+
|
|
82
|
+
Re-layout, milliseconds, one run on the development container:
|
|
83
|
+
|
|
84
|
+
| fixture | nodes | EVG js | EVGr js | EVGr rustc | EVG / EVGr (js) | EVG js / EVGr rustc |
|
|
85
|
+
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
86
|
+
| flex | 1,002 | 3.7 | 2.9 | 0.24 | 1.3x | 16x |
|
|
87
|
+
| flex | 10,004 | 12.1 | 6.7 | 2.7 | 1.8x | 4.4x |
|
|
88
|
+
| flex | 100,003 | 284 | 105 | 49 | 2.7x | 5.8x |
|
|
89
|
+
| grid | 1,001 | 6.5 | 3.3 | 0.17 | 2.0x | 38x |
|
|
90
|
+
| grid | 10,001 | 20.6 | 7.0 | 1.8 | 3.0x | 11x |
|
|
91
|
+
| grid | 100,001 | 380 | 85 | 35 | 4.5x | 11x |
|
|
92
|
+
| text | 1,002 | 4.1 | 4.2 | 0.30 | 1.0x | 14x |
|
|
93
|
+
| text | 10,004 | 19.6 | 10.7 | 2.7 | 1.8x | 7.2x |
|
|
94
|
+
| text | 100,003 | 345 | 97 | 43 | 3.6x | 8.0x |
|
|
95
|
+
|
|
96
|
+
The same program through Ranger to C++ (`g++ -O2`) and Go:
|
|
97
|
+
|
|
98
|
+
| fixture | nodes | EVG C++ | EVGr C++ | EVG Go | EVGr Go |
|
|
99
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
100
|
+
| flex | 100,003 | 198 | 144 | 148 | 129 |
|
|
101
|
+
| grid | 100,001 | 329 | 125 | 285 | 73 |
|
|
102
|
+
| text | 100,003 | 397 | 152 | 180 | 200 |
|
|
103
|
+
|
|
104
|
+
What the numbers say:
|
|
105
|
+
|
|
106
|
+
- Written as Rust and compiled by Ranger, EVGr's layout is faster than EVG's
|
|
107
|
+
on every target at 10k boxes and above — 2–4x in JavaScript. EVGr does less
|
|
108
|
+
(no stylesheet, no overlays, no paint bookkeeping) and caches more (a
|
|
109
|
+
subtree laid out at the same width is moved), so this measures the two
|
|
110
|
+
engines, not the two source languages.
|
|
111
|
+
- The same Rust source built by rustc is 2–3x faster again than its
|
|
112
|
+
JavaScript build at 100k boxes, and 4–38x faster than EVG in JavaScript.
|
|
113
|
+
- Ranger's C++ output is not the fast path for this code: EVGr through C++ is
|
|
114
|
+
slower than EVGr through JavaScript (`shared_ptr` everywhere, and the
|
|
115
|
+
`children.clone()` the Rust source does per node becomes a vector copy).
|
|
116
|
+
Go sits between.
|
|
117
|
+
- Building the tree (parsing the CSS text) is where EVGr is slower than EVG
|
|
118
|
+
in JavaScript, 1–2x: its string handling is lowered from Rust's `split`,
|
|
119
|
+
`trim` and `find` one operation at a time.
|
|
120
|
+
|
|
121
|
+
## Found on the way
|
|
122
|
+
|
|
123
|
+
Writing a 2,300-line module in the subset found these, fixed in the
|
|
124
|
+
compiler or the runtime:
|
|
125
|
+
|
|
126
|
+
- `str::strip_prefix` / `strip_suffix` were not in the subset.
|
|
127
|
+
- An associated function named like a field of its struct (`Len::px` beside
|
|
128
|
+
`Len.px`) came out under one name, which C++ rejects; it is now written as
|
|
129
|
+
`px_m`.
|
|
130
|
+
- `f64::floor` / `ceil` lowered to Ranger's `floor` / `ceil`, which answer an
|
|
131
|
+
int: Go rejected it. They have their own templates now.
|
|
132
|
+
|
|
133
|
+
Two limits of Ranger itself, met in `NativeBench.rgr`, are fixed too:
|
|
134
|
+
|
|
135
|
+
- A static method named like an operator (`count`, `make`, `size`, `sort`,
|
|
136
|
+
…) was rewritten into the operator-method form and then looked up as an
|
|
137
|
+
instance method: `Util.count(3)` failed with "Class Util does not have
|
|
138
|
+
method count".
|
|
139
|
+
- `sort` took only a comparison callback. `(sort xs)` of a `[double]` or
|
|
140
|
+
`[int]` now gives a new array in ascending order on every target.
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; EVG and EVGr in one program, for a target the JavaScript harness cannot
|
|
4
|
+
; drive: the fixtures of lib/evg/bench/layout-bench.mjs built for both
|
|
5
|
+
; engines, laid out, and timed. One line per fixture, size and engine:
|
|
6
|
+
;
|
|
7
|
+
; <fixture> <size> <engine> <nodes> <layout ms> <checksum>
|
|
8
|
+
;
|
|
9
|
+
; `layout ms` is the median of five re-layouts after one warm-up; the
|
|
10
|
+
; checksum sums x + y + w + h over every box, so the two engines can be
|
|
11
|
+
; compared on the same tree. `bench/speed.mjs --targets cpp,go` builds this
|
|
12
|
+
; for C++ and Go and prints the table.
|
|
13
|
+
|
|
14
|
+
Import "../../evg/EVGElement.rgr"
|
|
15
|
+
Import "../../evg/EVGUnit.rgr"
|
|
16
|
+
Import "../../evg/EVGLayout.rgr"
|
|
17
|
+
Import "../src/lib.rs"
|
|
18
|
+
|
|
19
|
+
class NativeBench {
|
|
20
|
+
|
|
21
|
+
sfn setCss:void (el:EVGElement css:string) {
|
|
22
|
+
def decls:[string] (strsplit css ";")
|
|
23
|
+
for decls d:string i {
|
|
24
|
+
def t:string (trim d)
|
|
25
|
+
if ((strlen t) == 0) {
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
def c:int (indexOf t ":")
|
|
29
|
+
if (c < 0) {
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
el.setAttribute((trim (substring t 0 c)) (trim (substring t (c + 1) (strlen t))))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
sfn node:EVGElement (css:string) {
|
|
37
|
+
def el:EVGElement (new EVGElement())
|
|
38
|
+
NativeBench.setCss(el css)
|
|
39
|
+
return el
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
sfn css:string (name:string) {
|
|
43
|
+
if (name == "page") {
|
|
44
|
+
return "display:flex;flex-direction:column;flex-wrap:nowrap;width:1200px;gap:8px;align-items:stretch"
|
|
45
|
+
}
|
|
46
|
+
if (name == "card") {
|
|
47
|
+
return "display:flex;flex-direction:row;flex-wrap:nowrap;gap:12px;padding:8px;align-items:stretch"
|
|
48
|
+
}
|
|
49
|
+
if (name == "rail") {
|
|
50
|
+
return "width:48px;height:56px;background-color:#e4e4e7"
|
|
51
|
+
}
|
|
52
|
+
if (name == "body") {
|
|
53
|
+
return "display:flex;flex-direction:column;flex-wrap:nowrap;flex-grow:1;gap:4px;align-items:stretch"
|
|
54
|
+
}
|
|
55
|
+
if (name == "line") {
|
|
56
|
+
return "height:16px;background-color:#f4f4f5"
|
|
57
|
+
}
|
|
58
|
+
if (name == "gridc") {
|
|
59
|
+
return "display:grid;grid-template-columns:repeat(4, 1fr);gap:10px;width:1200px"
|
|
60
|
+
}
|
|
61
|
+
if (name == "cell") {
|
|
62
|
+
return "display:flex;flex-direction:column;flex-wrap:nowrap;gap:4px;padding:6px;align-items:stretch"
|
|
63
|
+
}
|
|
64
|
+
return "font-size:14px"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
sfn word:string (i:int) {
|
|
68
|
+
def words:[string] ([] _:string ("Ada Lovelace" "Grace Hopper" "Alan Turing" "Edsger Dijkstra" "Barbara McClintock"))
|
|
69
|
+
return (itemAt words (i % 5))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
sfn count:int (n:int per:int) {
|
|
73
|
+
def c:int (to_int ((to_double n) / (to_double per) + 0.5))
|
|
74
|
+
if (c < 1) {
|
|
75
|
+
return 1
|
|
76
|
+
}
|
|
77
|
+
return c
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
; --- EVG
|
|
81
|
+
|
|
82
|
+
sfn evgTree:EVGElement (fixture:string n:int) {
|
|
83
|
+
if (fixture == "grid") {
|
|
84
|
+
def g:EVGElement (NativeBench.node((NativeBench.css("gridc"))))
|
|
85
|
+
def cells:int (NativeBench.count(n 5))
|
|
86
|
+
def i:int 0
|
|
87
|
+
while (i < cells) {
|
|
88
|
+
def cell:EVGElement (NativeBench.node((NativeBench.css("cell"))))
|
|
89
|
+
def j:int 0
|
|
90
|
+
while (j < 4) {
|
|
91
|
+
cell.addChild((NativeBench.node((NativeBench.css("line")))))
|
|
92
|
+
j = j + 1
|
|
93
|
+
}
|
|
94
|
+
g.addChild(cell)
|
|
95
|
+
i = i + 1
|
|
96
|
+
}
|
|
97
|
+
return g
|
|
98
|
+
}
|
|
99
|
+
def page:EVGElement (NativeBench.node((NativeBench.css("page"))))
|
|
100
|
+
def cards:int (NativeBench.count(n 7))
|
|
101
|
+
def k:int 0
|
|
102
|
+
while (k < cards) {
|
|
103
|
+
def card:EVGElement (NativeBench.node((NativeBench.css("card"))))
|
|
104
|
+
card.addChild((NativeBench.node((NativeBench.css("rail")))))
|
|
105
|
+
def body:EVGElement (NativeBench.node((NativeBench.css("body"))))
|
|
106
|
+
def q:int 0
|
|
107
|
+
while (q < 4) {
|
|
108
|
+
if ((fixture == "text") && (q == 0)) {
|
|
109
|
+
def tx:EVGElement (NativeBench.node((NativeBench.css("text"))))
|
|
110
|
+
tx.elementType = 1
|
|
111
|
+
tx.textContent = (NativeBench.word(k))
|
|
112
|
+
body.addChild(tx)
|
|
113
|
+
} {
|
|
114
|
+
body.addChild((NativeBench.node((NativeBench.css("line")))))
|
|
115
|
+
}
|
|
116
|
+
q = q + 1
|
|
117
|
+
}
|
|
118
|
+
card.addChild(body)
|
|
119
|
+
page.addChild(card)
|
|
120
|
+
k = k + 1
|
|
121
|
+
}
|
|
122
|
+
return page
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
sfn evgSum:double (el:EVGElement) {
|
|
126
|
+
def s:double (((el.calculatedX + el.calculatedY) + el.calculatedWidth) + el.calculatedHeight)
|
|
127
|
+
for el.children k:EVGElement i {
|
|
128
|
+
s = s + (NativeBench.evgSum(k))
|
|
129
|
+
}
|
|
130
|
+
return s
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
sfn evgCount:int (el:EVGElement) {
|
|
134
|
+
def c:int 1
|
|
135
|
+
for el.children k:EVGElement i {
|
|
136
|
+
c = c + (NativeBench.evgCount(k))
|
|
137
|
+
}
|
|
138
|
+
return c
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
; --- EVGr
|
|
142
|
+
|
|
143
|
+
sfn evgrTree:EvgrTree (fixture:string n:int) {
|
|
144
|
+
def t:EvgrTree (EvgrTree.new_())
|
|
145
|
+
if (fixture == "grid") {
|
|
146
|
+
def g:int (t.add(-1 (NativeBench.css("gridc"))))
|
|
147
|
+
def cells:int (NativeBench.count(n 5))
|
|
148
|
+
def i:int 0
|
|
149
|
+
while (i < cells) {
|
|
150
|
+
def cell:int (t.add(g (NativeBench.css("cell"))))
|
|
151
|
+
def j:int 0
|
|
152
|
+
while (j < 4) {
|
|
153
|
+
t.add(cell (NativeBench.css("line")))
|
|
154
|
+
j = j + 1
|
|
155
|
+
}
|
|
156
|
+
i = i + 1
|
|
157
|
+
}
|
|
158
|
+
return t
|
|
159
|
+
}
|
|
160
|
+
def page:int (t.add(-1 (NativeBench.css("page"))))
|
|
161
|
+
def cards:int (NativeBench.count(n 7))
|
|
162
|
+
def k:int 0
|
|
163
|
+
while (k < cards) {
|
|
164
|
+
def card:int (t.add(page (NativeBench.css("card"))))
|
|
165
|
+
t.add(card (NativeBench.css("rail")))
|
|
166
|
+
def body:int (t.add(card (NativeBench.css("body"))))
|
|
167
|
+
def q:int 0
|
|
168
|
+
while (q < 4) {
|
|
169
|
+
if ((fixture == "text") && (q == 0)) {
|
|
170
|
+
t.add_text(body (NativeBench.css("text")) (NativeBench.word(k)))
|
|
171
|
+
} {
|
|
172
|
+
t.add(body (NativeBench.css("line")))
|
|
173
|
+
}
|
|
174
|
+
q = q + 1
|
|
175
|
+
}
|
|
176
|
+
k = k + 1
|
|
177
|
+
}
|
|
178
|
+
return t
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
sfn evgrSum:double (t:EvgrTree) {
|
|
182
|
+
def s:double 0.0
|
|
183
|
+
def i:int 0
|
|
184
|
+
def n:int (t.count())
|
|
185
|
+
while (i < n) {
|
|
186
|
+
s = s + (((t.x(i) + t.y(i)) + t.w(i)) + t.h(i))
|
|
187
|
+
i = i + 1
|
|
188
|
+
}
|
|
189
|
+
return s
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
sfn median:double (xs:[double]) {
|
|
193
|
+
def s:[double] (sort xs)
|
|
194
|
+
return (itemAt s (idiv (array_length s) 2))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
sfn fmt:string (v:double) {
|
|
198
|
+
def whole:int (to_int (v * 1000.0))
|
|
199
|
+
return (to_string ((to_double whole) / 1000.0))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
sfn report:void (fx:string n:int engine:string nodes:int ms:double sum:double) {
|
|
203
|
+
def line:string ((fx + " ") + (to_string n))
|
|
204
|
+
line = ((line + " ") + engine)
|
|
205
|
+
line = ((line + " ") + (to_string nodes))
|
|
206
|
+
line = ((line + " ") + (NativeBench.fmt(ms)))
|
|
207
|
+
; the checksum in hundreds, which an int of every target holds
|
|
208
|
+
line = ((line + " ") + (to_string (to_int (sum / 100.0))))
|
|
209
|
+
print line
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
sfn main:void () {
|
|
213
|
+
def fixtures:[string] ([] _:string ("flex" "grid" "text"))
|
|
214
|
+
def sizes:[int] ([] _:int (1000 10000 100000))
|
|
215
|
+
for fixtures fx:string fi {
|
|
216
|
+
for sizes n:int si {
|
|
217
|
+
; EVG
|
|
218
|
+
def root:EVGElement (NativeBench.evgTree(fx n))
|
|
219
|
+
def lay:EVGLayout (new EVGLayout())
|
|
220
|
+
lay.setPageSize(1200.0 900.0)
|
|
221
|
+
lay.layout(root)
|
|
222
|
+
def times:[double]
|
|
223
|
+
def r:int 0
|
|
224
|
+
while (r < 5) {
|
|
225
|
+
def a:double (wall_clock_ms)
|
|
226
|
+
lay.layout(root)
|
|
227
|
+
push times ((wall_clock_ms) - a)
|
|
228
|
+
r = r + 1
|
|
229
|
+
}
|
|
230
|
+
NativeBench.report(fx n "evg" (NativeBench.evgCount(root)) (NativeBench.median(times)) (NativeBench.evgSum(root)))
|
|
231
|
+
; EVGr
|
|
232
|
+
def t:EvgrTree (NativeBench.evgrTree(fx n))
|
|
233
|
+
t.layout(1200.0 900.0)
|
|
234
|
+
def times2:[double]
|
|
235
|
+
def r2:int 0
|
|
236
|
+
while (r2 < 5) {
|
|
237
|
+
def b:double (wall_clock_ms)
|
|
238
|
+
t.layout(1200.0 900.0)
|
|
239
|
+
push times2 ((wall_clock_ms) - b)
|
|
240
|
+
r2 = r2 + 1
|
|
241
|
+
}
|
|
242
|
+
NativeBench.report(fx n "evgr" (t.count()) (NativeBench.median(times2)) (NativeBench.evgrSum(t)))
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
//
|
|
4
|
+
// The layout cases of lib/evg/bench/layout-cases.mjs, laid out by three
|
|
5
|
+
// engines: EVG (Ranger, compiled to JavaScript), EVGr (the strict Rust module
|
|
6
|
+
// lib/evgr/src, compiled to JavaScript by rgrc) and Chromium.
|
|
7
|
+
//
|
|
8
|
+
// npm run evgr:compare [-- --only <id>] [--verbose] [--json] [--no-browser]
|
|
9
|
+
//
|
|
10
|
+
// Every case is CSS text, split into declarations for EVG and EVGr and put in
|
|
11
|
+
// a `style=` attribute for Chromium, exactly as layout-conformance.mjs does.
|
|
12
|
+
// A pair of engines AGREES on a case when every box is within half a pixel.
|
|
13
|
+
// Chromium is the reference for what the CSS says; EVG is the engine EVGr
|
|
14
|
+
// sits beside, so both comparisons are reported.
|
|
15
|
+
|
|
16
|
+
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { createRequire } from "node:module";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import { CASES, TEXT_CASES } from "../../evg/bench/layout-cases.mjs";
|
|
21
|
+
|
|
22
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const ROOT = path.resolve(HERE, "..", "..", "..");
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const EVG = require(path.join(ROOT, "lib/evg/bin/EvgLayoutBench.cjs"));
|
|
26
|
+
const R = require(path.join(ROOT, "lib/evgr/bin/Evgr.cjs"));
|
|
27
|
+
|
|
28
|
+
const argv = process.argv.slice(2);
|
|
29
|
+
const AS_JSON = argv.includes("--json");
|
|
30
|
+
const VERBOSE = argv.includes("--verbose");
|
|
31
|
+
const NO_BROWSER = argv.includes("--no-browser");
|
|
32
|
+
const ONLY = argv.includes("--only") ? argv[argv.indexOf("--only") + 1] : null;
|
|
33
|
+
const EPS = 0.5;
|
|
34
|
+
|
|
35
|
+
// --- EVG ---------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
function evgBuild(node) {
|
|
38
|
+
const el = new EVG.EVGElement();
|
|
39
|
+
for (const decl of (node.s || "").split(";")) {
|
|
40
|
+
const t = decl.trim();
|
|
41
|
+
if (!t) continue;
|
|
42
|
+
const i = t.indexOf(":");
|
|
43
|
+
if (i < 0) continue;
|
|
44
|
+
el.setAttribute(t.slice(0, i).trim(), t.slice(i + 1).trim());
|
|
45
|
+
}
|
|
46
|
+
if (node.text !== undefined) {
|
|
47
|
+
el.elementType = 1;
|
|
48
|
+
el.textContent = node.text;
|
|
49
|
+
}
|
|
50
|
+
for (const k of node.kids || []) el.addChild(evgBuild(k));
|
|
51
|
+
return el;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function evgBoxes(spec) {
|
|
55
|
+
EVG.EVGReject.clearNotes();
|
|
56
|
+
const root = evgBuild(spec);
|
|
57
|
+
const lay = new EVG.EVGLayout();
|
|
58
|
+
lay.setPageSize(1200, 900);
|
|
59
|
+
lay.layout(root);
|
|
60
|
+
const flat = [];
|
|
61
|
+
(function collect(el) {
|
|
62
|
+
flat.push({ x: el.calculatedX, y: el.calculatedY, w: el.calculatedWidth, h: el.calculatedHeight });
|
|
63
|
+
for (const k of el.children) collect(k);
|
|
64
|
+
})(root);
|
|
65
|
+
return flat;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --- EVGr --------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
function evgrBuild(t, node, parent) {
|
|
71
|
+
const i = node.text !== undefined ? t.add_text(parent, node.s || "", node.text) : t.add(parent, node.s || "");
|
|
72
|
+
for (const k of node.kids || []) evgrBuild(t, k, i);
|
|
73
|
+
return i;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function evgrBoxes(spec) {
|
|
77
|
+
const t = R.EvgrTree.new_();
|
|
78
|
+
evgrBuild(t, spec, -1);
|
|
79
|
+
t.layout(1200, 900);
|
|
80
|
+
const flat = [];
|
|
81
|
+
for (let i = 0; i < t.count(); i++) flat.push({ x: t.x(i), y: t.y(i), w: t.w(i), h: t.h(i) });
|
|
82
|
+
const unsupported = [];
|
|
83
|
+
for (let k = 0; k < t.unsupported_count(); k++) unsupported.push(t.unsupported_at(k));
|
|
84
|
+
return { flat, unsupported };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Chromium ----------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
function html(spec) {
|
|
90
|
+
const render = (n) =>
|
|
91
|
+
`<div style="${(n.s || "").replace(/"/g, """)}">` +
|
|
92
|
+
(n.text !== undefined ? n.text.replace(/[<&]/g, (c) => (c === "<" ? "<" : "&")) : "") +
|
|
93
|
+
(n.kids || []).map(render).join("") +
|
|
94
|
+
`</div>`;
|
|
95
|
+
return (
|
|
96
|
+
`<!doctype html><meta charset="utf-8"><style>` +
|
|
97
|
+
`*{box-sizing:border-box;margin:0;padding:0;border:0 solid #000}` +
|
|
98
|
+
`html,body{margin:0;padding:0;font:16px/1.2 monospace}` +
|
|
99
|
+
`#host{position:absolute;left:0;top:0}` +
|
|
100
|
+
`</style><div id="host">${render(spec)}</div>`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function browserBoxes(page, spec) {
|
|
105
|
+
await page.setContent(html(spec));
|
|
106
|
+
return page.evaluate(() => {
|
|
107
|
+
const out = [];
|
|
108
|
+
const host = document.getElementById("host");
|
|
109
|
+
const origin = host.firstElementChild.getBoundingClientRect();
|
|
110
|
+
(function collect(el) {
|
|
111
|
+
const r = el.getBoundingClientRect();
|
|
112
|
+
out.push({ x: r.left - origin.left, y: r.top - origin.top, w: r.width, h: r.height });
|
|
113
|
+
for (const c of el.children) collect(c);
|
|
114
|
+
})(host.firstElementChild);
|
|
115
|
+
return out;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Whatever Chromium is on disk: this container's, a playwright cache's, or
|
|
120
|
+
// the user's own Chrome.
|
|
121
|
+
function chromiumPath() {
|
|
122
|
+
const roots = [process.env.PLAYWRIGHT_BROWSERS_PATH, "/opt/pw-browsers", path.join(process.env.HOME || "", "Library/Caches/ms-playwright"), path.join(process.env.HOME || "", ".cache/ms-playwright")];
|
|
123
|
+
for (const root of roots) {
|
|
124
|
+
if (!root || !fs.existsSync(root)) continue;
|
|
125
|
+
for (const dir of fs.readdirSync(root).filter((d) => d.startsWith("chromium-")).sort().reverse()) {
|
|
126
|
+
for (const rel of [
|
|
127
|
+
"chrome-linux/chrome",
|
|
128
|
+
"chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing",
|
|
129
|
+
"chrome-mac/Chromium.app/Contents/MacOS/Chromium",
|
|
130
|
+
]) {
|
|
131
|
+
const p = path.join(root, dir, rel);
|
|
132
|
+
if (fs.existsSync(p)) return p;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- compare -----------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
function agree(a, b) {
|
|
142
|
+
if (!a || !b) return null;
|
|
143
|
+
if (a.length !== b.length) return [{ id: "count", miss: true }];
|
|
144
|
+
const rows = [];
|
|
145
|
+
for (let i = 0; i < a.length; i++) {
|
|
146
|
+
const d = ["x", "y", "w", "h"].filter((k) => Math.abs(a[i][k] - b[i][k]) > EPS);
|
|
147
|
+
if (d.length) rows.push({ id: "n" + i, fields: d, a: a[i], b: b[i] });
|
|
148
|
+
}
|
|
149
|
+
return rows;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let page = null;
|
|
153
|
+
let browser = null;
|
|
154
|
+
if (!NO_BROWSER) {
|
|
155
|
+
const { chromium } = require("playwright-core");
|
|
156
|
+
const exe = chromiumPath();
|
|
157
|
+
browser = await chromium.launch(exe ? { executablePath: exe } : { channel: "chrome" });
|
|
158
|
+
page = await browser.newPage({ viewport: { width: 1200, height: 900 } });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const results = [];
|
|
162
|
+
for (const c of CASES) {
|
|
163
|
+
if (ONLY && c.id !== ONLY) continue;
|
|
164
|
+
const evg = evgBoxes(c.root);
|
|
165
|
+
const r = evgrBoxes(c.root);
|
|
166
|
+
const css = page ? await browserBoxes(page, c.root) : null;
|
|
167
|
+
results.push({
|
|
168
|
+
id: c.id,
|
|
169
|
+
group: c.group,
|
|
170
|
+
why: c.why,
|
|
171
|
+
nodes: evg.length,
|
|
172
|
+
unsupported: r.unsupported,
|
|
173
|
+
evg,
|
|
174
|
+
evgr: r.flat,
|
|
175
|
+
css,
|
|
176
|
+
rCss: agree(r.flat, css),
|
|
177
|
+
rEvg: agree(r.flat, evg),
|
|
178
|
+
eCss: agree(evg, css),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Text cases: EVG's own assertions, run on EVGr's boxes, and the boxes of
|
|
183
|
+
// both engines side by side (they share the measurer's advance table).
|
|
184
|
+
const textResults = [];
|
|
185
|
+
for (const c of TEXT_CASES) {
|
|
186
|
+
if (ONLY && c.id !== ONLY) continue;
|
|
187
|
+
const evg = evgBoxes(c.root);
|
|
188
|
+
const r = evgrBoxes(c.root);
|
|
189
|
+
let ok = false;
|
|
190
|
+
try {
|
|
191
|
+
ok = !!c.assert(r.flat);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
ok = false;
|
|
194
|
+
}
|
|
195
|
+
textResults.push({ id: c.id, why: c.why, ok, rEvg: agree(r.flat, evg), evg, evgr: r.flat });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (browser) await browser.close();
|
|
199
|
+
|
|
200
|
+
if (AS_JSON) {
|
|
201
|
+
// no process.exit: it would cut a piped stdout short
|
|
202
|
+
process.stdout.write(JSON.stringify({ results, textResults }, null, 2) + "\n");
|
|
203
|
+
} else {
|
|
204
|
+
report();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function report() {
|
|
208
|
+
|
|
209
|
+
// --- report ------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
const mark = (rows) => (rows === null ? " - " : rows.length ? "DIFF" : " ok ");
|
|
212
|
+
const pad = (s, n) => String(s).padEnd(n);
|
|
213
|
+
const r2 = (v) => Math.round(v * 100) / 100;
|
|
214
|
+
const f = (o) => `x=${r2(o.x)} y=${r2(o.y)} w=${r2(o.w)} h=${r2(o.h)}`;
|
|
215
|
+
|
|
216
|
+
console.log("\nEVGr (Rust, via rgrc to JS) beside EVG and Chromium — the same CSS\n");
|
|
217
|
+
console.log(` ${pad("case", 28)} EVGr=CSS EVGr=EVG EVG=CSS`);
|
|
218
|
+
let lastGroup = null;
|
|
219
|
+
const count = { rCss: 0, rEvg: 0, eCss: 0 };
|
|
220
|
+
for (const r of results) {
|
|
221
|
+
if (r.group !== lastGroup) {
|
|
222
|
+
console.log(` ── ${r.group}`);
|
|
223
|
+
lastGroup = r.group;
|
|
224
|
+
}
|
|
225
|
+
for (const k of Object.keys(count)) if (r[k] && r[k].length === 0) count[k]++;
|
|
226
|
+
const note = r.unsupported.length ? ` (not laid out: ${r.unsupported.slice(0, 2).join("; ")}${r.unsupported.length > 2 ? "; …" : ""})` : "";
|
|
227
|
+
console.log(` ${pad(r.id, 28)} ${mark(r.rCss)} ${mark(r.rEvg)} ${mark(r.eCss)}${note}`);
|
|
228
|
+
}
|
|
229
|
+
const n = results.length;
|
|
230
|
+
console.log(`\n EVGr agrees with Chromium on ${count.rCss} of ${n}, with EVG on ${count.rEvg} of ${n}; EVG agrees with Chromium on ${count.eCss} of ${n}.`);
|
|
231
|
+
|
|
232
|
+
console.log("\n Text (EVG's assertions on EVGr's boxes; boxes against EVG's)");
|
|
233
|
+
for (const t of textResults) {
|
|
234
|
+
console.log(` ${t.ok ? " ok " : "FAIL"} ${mark(t.rEvg)} ${pad(t.id, 26)} ${t.why}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (VERBOSE) {
|
|
238
|
+
for (const r of results) {
|
|
239
|
+
const rows = r.rCss && r.rCss.length ? r.rCss : [];
|
|
240
|
+
if (!rows.length) continue;
|
|
241
|
+
console.log(`\n ${r.id} — ${r.why}`);
|
|
242
|
+
for (const d of rows.slice(0, 6)) {
|
|
243
|
+
if (d.miss) {
|
|
244
|
+
console.log(` box count differs`);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
console.log(` ${d.id} [${d.fields.join(",")}] EVGr ${f(d.a)} CSS ${f(d.b)} EVG ${f(r.evg[Number(d.id.slice(1))])}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
console.log("");
|
|
252
|
+
}
|