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,375 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EVGRelayoutTest — the same tree laid out again at a new page size
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; A retained tree is laid out many times, and when the window changes size it
|
|
8
|
+
; is laid out at a size it has never had. What comes out must be what a FRESH
|
|
9
|
+
; copy of the tree laid out once at that size would give: nothing computed at
|
|
10
|
+
; the old size may be read back as an input at the new one.
|
|
11
|
+
;
|
|
12
|
+
; Found in the EVGUI Separator demo, whose page is this shape:
|
|
13
|
+
;
|
|
14
|
+
; .pg { display:flex; flex-wrap:wrap; gap:16px } cards in a wrapping row
|
|
15
|
+
; .card { flex-direction:column; width:418px; height:248px }
|
|
16
|
+
; .stage { flex-grow:1 } grown to the card
|
|
17
|
+
; .menu { flex-direction:row; align-items:stretch } columns + 1px rules
|
|
18
|
+
; @media (max-width:600px) { .card { width:100%; height:auto } … }
|
|
19
|
+
;
|
|
20
|
+
; (The demo's columns are `width: 30%` only under the media rule. Here they
|
|
21
|
+
; always are: a property a media rule set is not put back by the sheet when
|
|
22
|
+
; the rule stops matching, which is the sheet's business and not what this
|
|
23
|
+
; file tests.)
|
|
24
|
+
;
|
|
25
|
+
; Laid out at 900 and then at 332, two answers from the first pass came back:
|
|
26
|
+
;
|
|
27
|
+
; 1. `.stage` kept the height the column's flex-grow gave it
|
|
28
|
+
; (`calculatedFlexHeight`), so every card stayed 248px tall after the
|
|
29
|
+
; phone rules made it `height: auto`.
|
|
30
|
+
; 2. `.menu`, auto-height, read its old `calculatedInnerHeight` as the
|
|
31
|
+
; height to stretch its items to, so the columns whose text now wrapped
|
|
32
|
+
; onto three lines kept their one-line height and the rules with them.
|
|
33
|
+
;
|
|
34
|
+
; The demo worked around it by clearing those fields itself before every
|
|
35
|
+
; fresh layout. This holds the engine to doing it.
|
|
36
|
+
;
|
|
37
|
+
; --- WHAT IS ASSERTED ---------------------------------------------------------
|
|
38
|
+
;
|
|
39
|
+
; * 900 → 332 → 900: after each pass every element's rectangle equals the
|
|
40
|
+
; one a fresh identical tree gets at that size.
|
|
41
|
+
; * In each pass the menu's rules and columns are as tall as the menu row
|
|
42
|
+
; (align-items: stretch in an auto-height row, which on a FIRST layout
|
|
43
|
+
; used to leave a 1px rule 0px tall — it only came right on later
|
|
44
|
+
; passes, from the stale inner height in 2. above).
|
|
45
|
+
; * The same with the cards kept (`keepLayout`).
|
|
46
|
+
; * A column that shrinks declared heights gives the same answer on every
|
|
47
|
+
; pass. It used to by accident: the shrink cleared `height.isSet` and the
|
|
48
|
+
; next pass reused the stale flex height, so clearing that height (the
|
|
49
|
+
; fix above) needs the shrink to keep the declaration.
|
|
50
|
+
; * A kept box with no stylesheet whose child is sized in `vw` is laid out
|
|
51
|
+
; again at a new page size, though nothing the flow hands the box changed.
|
|
52
|
+
; * And the cache still does its job: the same size twice, nothing changed,
|
|
53
|
+
; and the kept boxes are answered from what they hold.
|
|
54
|
+
; ==============================================================================
|
|
55
|
+
|
|
56
|
+
Import "EVGElement.rgr"
|
|
57
|
+
Import "EVGUnit.rgr"
|
|
58
|
+
Import "EVGLayout.rgr"
|
|
59
|
+
Import "EVGStyleSheet.rgr"
|
|
60
|
+
|
|
61
|
+
class RelayoutCheck {
|
|
62
|
+
def passed:int 0
|
|
63
|
+
def failed:int 0
|
|
64
|
+
def shown:int 0
|
|
65
|
+
|
|
66
|
+
Constructor () {
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn ok:void (name:string cond:boolean) {
|
|
70
|
+
if cond {
|
|
71
|
+
passed = (passed + 1)
|
|
72
|
+
print (" PASS " + name)
|
|
73
|
+
} {
|
|
74
|
+
failed = (failed + 1)
|
|
75
|
+
print (" FAIL " + name)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fn css:string () {
|
|
80
|
+
def s:string ""
|
|
81
|
+
s = (s + ".pg { display: flex; flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 16px; padding: 24px; width: 100%; }\n")
|
|
82
|
+
s = (s + ".card { display: flex; flex-direction: column; flex-wrap: nowrap; width: 418px; height: 248px; border: 1px solid #e4e4e7; }\n")
|
|
83
|
+
s = (s + ".cap { height: 40px; line-height: 40px; padding: 0 16px; font-size: 12px; }\n")
|
|
84
|
+
s = (s + ".stage { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: center; justify-content: center; flex-grow: 1; padding: 16px 24px; }\n")
|
|
85
|
+
s = (s + ".menu { display: flex; flex-direction: row; flex-wrap: nowrap; align-items: stretch; gap: 16px; }\n")
|
|
86
|
+
s = (s + ".mcol { display: flex; flex-direction: column; flex-wrap: nowrap; gap: 2px; width: 30%; }\n")
|
|
87
|
+
s = (s + ".txt { font-size: 14px; line-height: 20px; }\n")
|
|
88
|
+
s = (s + ".rule { width: 1px; flex-shrink: 0; align-self: stretch; background-color: #e4e4e7; }\n")
|
|
89
|
+
s = (s + ".vwbox { display: flex; flex-direction: column; width: 300px; }\n")
|
|
90
|
+
s = (s + ".vwkid { width: 10vw; height: 5vw; }\n")
|
|
91
|
+
s = (s + "@media (max-width: 600px) {\n")
|
|
92
|
+
s = (s + " .pg { padding: 12px; gap: 12px; }\n")
|
|
93
|
+
s = (s + " .card { width: 100%; height: auto; }\n")
|
|
94
|
+
s = (s + " .stage { padding: 20px 16px; }\n")
|
|
95
|
+
s = (s + " .menu { gap: 10px; width: 100%; }\n")
|
|
96
|
+
s = (s + "}\n")
|
|
97
|
+
return s
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fn div:EVGElement (cls:string) {
|
|
101
|
+
def d (EVGElement.createDiv())
|
|
102
|
+
d.className = cls
|
|
103
|
+
return d
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fn text:EVGElement (t:string) {
|
|
107
|
+
def d (this.div("txt"))
|
|
108
|
+
d.textContent = t
|
|
109
|
+
return d
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn menuCol:EVGElement (a:string b:string) {
|
|
113
|
+
def c (this.div("mcol"))
|
|
114
|
+
c.addChild((this.text(a)))
|
|
115
|
+
c.addChild((this.text(b)))
|
|
116
|
+
return c
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fn card:EVGElement (caption:string withMenu:boolean) {
|
|
120
|
+
def c (this.div("card"))
|
|
121
|
+
def cap (this.div("cap"))
|
|
122
|
+
cap.textContent = caption
|
|
123
|
+
c.addChild(cap)
|
|
124
|
+
def stage (this.div("stage"))
|
|
125
|
+
if withMenu {
|
|
126
|
+
def menu (this.div("menu"))
|
|
127
|
+
menu.addChild((this.menuCol("Blog" "Latest posts and updates from the team")))
|
|
128
|
+
menu.addChild((this.div("rule")))
|
|
129
|
+
menu.addChild((this.menuCol("Docs" "Guides and reference for every component")))
|
|
130
|
+
menu.addChild((this.div("rule")))
|
|
131
|
+
menu.addChild((this.menuCol("Source" "The code on GitHub")))
|
|
132
|
+
stage.addChild(menu)
|
|
133
|
+
} {
|
|
134
|
+
stage.addChild((this.text("A short line")))
|
|
135
|
+
}
|
|
136
|
+
c.addChild(stage)
|
|
137
|
+
return c
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
; No width of its own in the sheet: the page gives it one.
|
|
141
|
+
fn build:EVGElement (keep:boolean) {
|
|
142
|
+
def pg (this.div("pg"))
|
|
143
|
+
def c1 (this.card("Horizontal" false))
|
|
144
|
+
def c2 (this.card("Vertical" true))
|
|
145
|
+
def c3 (this.card("Menu" true))
|
|
146
|
+
def vb (this.div("vwbox"))
|
|
147
|
+
vb.addChild((this.div("vwkid")))
|
|
148
|
+
vb.addChild((this.div("vwkid")))
|
|
149
|
+
if keep {
|
|
150
|
+
c1.keepLayout = true
|
|
151
|
+
c2.keepLayout = true
|
|
152
|
+
c3.keepLayout = true
|
|
153
|
+
vb.keepLayout = true
|
|
154
|
+
}
|
|
155
|
+
pg.addChild(c1)
|
|
156
|
+
pg.addChild(c2)
|
|
157
|
+
pg.addChild(c3)
|
|
158
|
+
pg.addChild(vb)
|
|
159
|
+
return pg
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fn layoutAt:void (root:EVGElement sheet:EVGStyleSheet w:double) {
|
|
163
|
+
sheet.applyTreeIn(root "" w 640.0 false)
|
|
164
|
+
def lay (new EVGLayout())
|
|
165
|
+
lay.setPageSize(w 640.0)
|
|
166
|
+
lay.layout(root)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
fn freshAt:EVGElement (keep:boolean w:double) {
|
|
170
|
+
def root (this.build(keep))
|
|
171
|
+
def sheet (new EVGStyleSheet())
|
|
172
|
+
sheet.parse((this.css()))
|
|
173
|
+
this.layoutAt(root sheet w)
|
|
174
|
+
return root
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fn near:boolean (a:double b:double) {
|
|
178
|
+
def d:double (a - b)
|
|
179
|
+
if (d < 0.0) {
|
|
180
|
+
d = (0.0 - d)
|
|
181
|
+
}
|
|
182
|
+
return (d < 0.01)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
fn rect:string (e:EVGElement) {
|
|
186
|
+
def s:string ((to_string e.calculatedX) + "," + (to_string e.calculatedY))
|
|
187
|
+
s = (s + " " + (to_string e.calculatedWidth) + "x" + (to_string e.calculatedHeight))
|
|
188
|
+
return s
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
; Mismatches under `a` against `b`, walked in step; the first few named.
|
|
192
|
+
fn diff:int (a:EVGElement b:EVGElement path:string) {
|
|
193
|
+
def bad:int 0
|
|
194
|
+
def same:boolean (((this.near(a.calculatedX b.calculatedX)) && (this.near(a.calculatedY b.calculatedY)))
|
|
195
|
+
&& ((this.near(a.calculatedWidth b.calculatedWidth)) && (this.near(a.calculatedHeight b.calculatedHeight))))
|
|
196
|
+
if (same == false) {
|
|
197
|
+
bad = 1
|
|
198
|
+
if (shown < 12) {
|
|
199
|
+
shown = (shown + 1)
|
|
200
|
+
def got:string (this.rect(a))
|
|
201
|
+
def want:string (this.rect(b))
|
|
202
|
+
print (" " + path + " " + a.className + " got " + got + " want " + want)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
def i:int 0
|
|
206
|
+
while (i < (a.getChildCount())) {
|
|
207
|
+
bad = (bad + (this.diff((a.getChild(i)) (b.getChild(i)) ((path + "/") + (to_string i)))))
|
|
208
|
+
i = (i + 1)
|
|
209
|
+
}
|
|
210
|
+
return bad
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
; Every item of each `.menu` row as tall as the row: align-items:
|
|
214
|
+
; stretch, which in an auto-height row can only be answered once the
|
|
215
|
+
; row has measured its line.
|
|
216
|
+
fn spans:boolean (root:EVGElement) {
|
|
217
|
+
def good:boolean true
|
|
218
|
+
def c:int 1
|
|
219
|
+
while (c <= 2) {
|
|
220
|
+
def card:EVGElement (root.getChild(c))
|
|
221
|
+
def stage:EVGElement (card.getChild(1))
|
|
222
|
+
def menu:EVGElement (stage.getChild(0))
|
|
223
|
+
def k:int 0
|
|
224
|
+
while (k < (menu.getChildCount())) {
|
|
225
|
+
def it:EVGElement (menu.getChild(k))
|
|
226
|
+
if ((this.near(it.calculatedHeight menu.calculatedInnerHeight)) == false) {
|
|
227
|
+
good = false
|
|
228
|
+
print (" " + it.className + " is " + (to_string it.calculatedHeight) + " in a " + (to_string menu.calculatedInnerHeight) + "px row")
|
|
229
|
+
}
|
|
230
|
+
k = (k + 1)
|
|
231
|
+
}
|
|
232
|
+
c = (c + 1)
|
|
233
|
+
}
|
|
234
|
+
return good
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
fn sweep:void (keep:boolean label:string) {
|
|
238
|
+
def root (this.build(keep))
|
|
239
|
+
def sheet (new EVGStyleSheet())
|
|
240
|
+
sheet.parse((this.css()))
|
|
241
|
+
def widths:[double] ([] _:double (900.0 332.0 900.0 332.0))
|
|
242
|
+
def i:int 0
|
|
243
|
+
while (i < (array_length widths)) {
|
|
244
|
+
def w:double (itemAt widths i)
|
|
245
|
+
this.layoutAt(root sheet w)
|
|
246
|
+
shown = 0
|
|
247
|
+
def bad:int (this.diff(root (this.freshAt(keep w)) "root"))
|
|
248
|
+
def name:string (label + " pass " + (to_string (i + 1)) + " at " + (to_string w) + " matches a fresh tree")
|
|
249
|
+
this.ok(name (bad == 0))
|
|
250
|
+
this.ok((label + " pass " + (to_string (i + 1)) + ": the rules and columns span the menu row")
|
|
251
|
+
(this.spans(root)))
|
|
252
|
+
i = (i + 1)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fn run:void () {
|
|
257
|
+
print "EVGRelayoutTest"
|
|
258
|
+
|
|
259
|
+
this.sweep(false "plain tree:")
|
|
260
|
+
this.sweep(true "kept cards:")
|
|
261
|
+
|
|
262
|
+
; The cache still answers a relayout at the same size.
|
|
263
|
+
def root (this.build(true))
|
|
264
|
+
def sheet (new EVGStyleSheet())
|
|
265
|
+
sheet.parse((this.css()))
|
|
266
|
+
this.layoutAt(root sheet 900.0)
|
|
267
|
+
this.layoutAt(root sheet 900.0)
|
|
268
|
+
def allSkipped:boolean true
|
|
269
|
+
def k:int 0
|
|
270
|
+
while (k < (root.getChildCount())) {
|
|
271
|
+
def kid:EVGElement (root.getChild(k))
|
|
272
|
+
if (kid.layoutSkipped == false) {
|
|
273
|
+
allSkipped = false
|
|
274
|
+
}
|
|
275
|
+
k = (k + 1)
|
|
276
|
+
}
|
|
277
|
+
this.ok("same size twice: every kept box is answered from its last layout" allSkipped)
|
|
278
|
+
shown = 0
|
|
279
|
+
this.ok("…and the answer is the fresh one"
|
|
280
|
+
((this.diff(root (this.freshAt(true 900.0)) "root")) == 0))
|
|
281
|
+
|
|
282
|
+
this.shrunkTwice()
|
|
283
|
+
this.keptInViewport()
|
|
284
|
+
|
|
285
|
+
print ""
|
|
286
|
+
print ((("passed=" + (to_string passed)) + " failed=") + (to_string failed))
|
|
287
|
+
if (failed > 0) {
|
|
288
|
+
print "FAILURES"
|
|
289
|
+
} {
|
|
290
|
+
print "ALL PASS"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
; A column that shrinks declared heights to fit. The shrink is the
|
|
295
|
+
; column's answer this pass, not a new declaration: laid out a second
|
|
296
|
+
; time the children are still `height: 80px` and are shrunk again.
|
|
297
|
+
fn shrinkTree:EVGElement () {
|
|
298
|
+
def col (EVGElement.createDiv())
|
|
299
|
+
col.setAttribute("display" "flex")
|
|
300
|
+
col.setAttribute("flex-direction" "column")
|
|
301
|
+
col.setAttribute("flex-wrap" "nowrap")
|
|
302
|
+
col.setAttribute("height" "100px")
|
|
303
|
+
def a (EVGElement.createDiv())
|
|
304
|
+
a.setAttribute("height" "80px")
|
|
305
|
+
def b (EVGElement.createDiv())
|
|
306
|
+
b.setAttribute("height" "80px")
|
|
307
|
+
col.addChild(a)
|
|
308
|
+
col.addChild(b)
|
|
309
|
+
def pg (EVGElement.createDiv())
|
|
310
|
+
pg.setAttribute("width" "100%")
|
|
311
|
+
pg.addChild(col)
|
|
312
|
+
return pg
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
fn plainAt:void (root:EVGElement w:double) {
|
|
316
|
+
def lay (new EVGLayout())
|
|
317
|
+
lay.setPageSize(w 640.0)
|
|
318
|
+
lay.layout(root)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fn shrunkTwice:void () {
|
|
322
|
+
def t (this.shrinkTree())
|
|
323
|
+
this.plainAt(t 900.0)
|
|
324
|
+
def first:int (this.diff(t (this.freshShrink(900.0)) "root"))
|
|
325
|
+
this.plainAt(t 900.0)
|
|
326
|
+
shown = 0
|
|
327
|
+
def second:int (this.diff(t (this.freshShrink(900.0)) "root"))
|
|
328
|
+
this.plainAt(t 332.0)
|
|
329
|
+
shown = 0
|
|
330
|
+
def third:int (this.diff(t (this.freshShrink(332.0)) "root"))
|
|
331
|
+
this.ok("a column that shrinks its children: the same on every pass"
|
|
332
|
+
(((first + second) + third) == 0))
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
fn freshShrink:EVGElement (w:double) {
|
|
336
|
+
def t (this.shrinkTree())
|
|
337
|
+
this.plainAt(t w)
|
|
338
|
+
return t
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
; A kept box with no stylesheet to mark it dirty: nothing the flow hands
|
|
342
|
+
; it depends on the page, but its children are sized in `vw`, so a new
|
|
343
|
+
; page size is a new layout for it however clean it says it is.
|
|
344
|
+
fn keptInViewport:void () {
|
|
345
|
+
def pg (EVGElement.createDiv())
|
|
346
|
+
def box (EVGElement.createDiv())
|
|
347
|
+
box.setAttribute("width" "300px")
|
|
348
|
+
box.setAttribute("height" "100px")
|
|
349
|
+
def kid (EVGElement.createDiv())
|
|
350
|
+
kid.setAttribute("width" "10vw")
|
|
351
|
+
kid.setAttribute("height" "20px")
|
|
352
|
+
box.addChild(kid)
|
|
353
|
+
pg.addChild(box)
|
|
354
|
+
box.keepLayout = true
|
|
355
|
+
this.plainAt(pg 900.0)
|
|
356
|
+
box.layoutClean = true
|
|
357
|
+
kid.layoutClean = true
|
|
358
|
+
this.plainAt(pg 900.0)
|
|
359
|
+
this.ok("a clean kept box at the same page size is answered from its last layout"
|
|
360
|
+
box.layoutSkipped)
|
|
361
|
+
this.plainAt(pg 332.0)
|
|
362
|
+
this.ok("…and at a new page size is laid out again (10vw of 332)"
|
|
363
|
+
(this.near(kid.calculatedWidth 33.2)))
|
|
364
|
+
box.layoutClean = true
|
|
365
|
+
kid.layoutClean = true
|
|
366
|
+
this.plainAt(pg 332.0)
|
|
367
|
+
this.ok("…after which the same size is answered from it again"
|
|
368
|
+
box.layoutSkipped)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
sfn m@(main):void () {
|
|
372
|
+
def c (new RelayoutCheck())
|
|
373
|
+
c.run()
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EVGRtlLayoutTest — one switch, and the whole interface turns around
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; Mirroring a user interface for Arabic and Hebrew is not a job for the three
|
|
8
|
+
; editors. They all draw through the same layout engine, so the direction
|
|
9
|
+
; belongs in that engine, once, as the property CSS already has for it — and
|
|
10
|
+
; then every panel, strip, toolbar and grid built on it turns around together
|
|
11
|
+
; and anything built later turns around the day it lands.
|
|
12
|
+
;
|
|
13
|
+
; It is done by reflecting each container's children about its content box
|
|
14
|
+
; after they have been placed. That choice is the reason this is thirty lines
|
|
15
|
+
; rather than a rewrite of two engines, and it is worth stating why it is not
|
|
16
|
+
; a shortcut: every way a container can place a child horizontally — flex row,
|
|
17
|
+
; row-reverse, wrapping, every value of justify-content, gap, grid tracks,
|
|
18
|
+
; named grid lines, dense packing — ends with children at x positions inside a
|
|
19
|
+
; content box. Reflect those and all of it is right at once.
|
|
20
|
+
;
|
|
21
|
+
; The cases below are the ones that separate that from something that merely
|
|
22
|
+
; reverses a list:
|
|
23
|
+
;
|
|
24
|
+
; * the ORDER reverses and the packing end changes with it
|
|
25
|
+
; * a nested container turns around too, because the property inherits —
|
|
26
|
+
; that is what makes it one switch rather than one per panel
|
|
27
|
+
; * an island can opt back out, which is what a left-to-right code block or
|
|
28
|
+
; a phone number inside an Arabic page needs
|
|
29
|
+
; * grid column 1 becomes the RIGHTMOST column
|
|
30
|
+
; * absolutely positioned children do NOT move: `left: 0` is the left edge
|
|
31
|
+
; in any direction
|
|
32
|
+
; * `margin-left` stays physically on the left, which is CSS's rule and the
|
|
33
|
+
; one of the two readings that is easy to get wrong
|
|
34
|
+
; * and the older `direction: row` still means the flow axis, because two
|
|
35
|
+
; properties share that name and only the VALUE tells them apart
|
|
36
|
+
;
|
|
37
|
+
; npm run evg:rtl:test
|
|
38
|
+
; ==============================================================================
|
|
39
|
+
|
|
40
|
+
Import "EVGLayout.rgr"
|
|
41
|
+
|
|
42
|
+
class RtlCheck {
|
|
43
|
+
def passed:int 0
|
|
44
|
+
def failed:int 0
|
|
45
|
+
|
|
46
|
+
fn ok:void (name:string cond:boolean) {
|
|
47
|
+
if cond {
|
|
48
|
+
passed = (passed + 1)
|
|
49
|
+
print (" PASS " + name)
|
|
50
|
+
} {
|
|
51
|
+
failed = (failed + 1)
|
|
52
|
+
print (" FAIL " + name)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fn eqNum:void (name:string got:double want:double) {
|
|
57
|
+
def d:double (got - want)
|
|
58
|
+
if (d < 0.0) {
|
|
59
|
+
d = (0.0 - d)
|
|
60
|
+
}
|
|
61
|
+
this.ok(((((name + " (got ") + (to_string got)) + " want ") + ((to_string want) + ")")) (d < 0.5))
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class EVGRtlLayoutTest {
|
|
66
|
+
def c:RtlCheck (new RtlCheck)
|
|
67
|
+
|
|
68
|
+
sfn main:void () {
|
|
69
|
+
def t (new EVGRtlLayoutTest())
|
|
70
|
+
t.run()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
; A fixed-size box with an id, which is all these cases need.
|
|
74
|
+
sfn box:EVGElement (id:string w:double h:double) {
|
|
75
|
+
def e (new EVGElement())
|
|
76
|
+
e.id = id
|
|
77
|
+
e.width = (EVGUnit.px(w))
|
|
78
|
+
e.height = (EVGUnit.px(h))
|
|
79
|
+
return e
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
; A 300-wide row with no padding, holding three boxes of 40, 60 and 20.
|
|
83
|
+
; Their widths differ on purpose: equal boxes would look mirrored even if
|
|
84
|
+
; the reflection were wrong by a constant.
|
|
85
|
+
sfn strip:EVGElement (rtl:boolean) {
|
|
86
|
+
def root (new EVGElement())
|
|
87
|
+
root.id = "root"
|
|
88
|
+
root.width = (EVGUnit.px(300.0))
|
|
89
|
+
root.height = (EVGUnit.px(50.0))
|
|
90
|
+
root.display = "flex"
|
|
91
|
+
root.flexDirection = "row"
|
|
92
|
+
if rtl {
|
|
93
|
+
root.setAttribute("direction" "rtl")
|
|
94
|
+
}
|
|
95
|
+
root.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
|
|
96
|
+
root.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
|
|
97
|
+
root.addChild((EVGRtlLayoutTest.box("c" 20.0 20.0)))
|
|
98
|
+
return root
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
sfn childX:double (parent:EVGElement i:int) {
|
|
102
|
+
def ch:EVGElement (parent.getChild(i))
|
|
103
|
+
return ch.calculatedX
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fn laidOut:EVGElement (root:EVGElement) {
|
|
107
|
+
def lay (new EVGLayout())
|
|
108
|
+
lay.setPageSize(300.0 200.0)
|
|
109
|
+
lay.layout(root)
|
|
110
|
+
return root
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fn run:void () {
|
|
114
|
+
print "=== EVGRtlLayoutTest ==="
|
|
115
|
+
this.testOrder()
|
|
116
|
+
this.testGrid()
|
|
117
|
+
this.testInheritance()
|
|
118
|
+
this.testIsland()
|
|
119
|
+
this.testAbsolute()
|
|
120
|
+
this.testMargins()
|
|
121
|
+
this.testLegacyDirection()
|
|
122
|
+
print ""
|
|
123
|
+
print (("passed = " + (to_string c.passed)) + (" failed = " + (to_string c.failed)))
|
|
124
|
+
if (c.failed == 0) {
|
|
125
|
+
print "ALL PASS"
|
|
126
|
+
} {
|
|
127
|
+
print "SOME FAILED"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn testOrder:void () {
|
|
132
|
+
print "--- the order, and which end it packs against ---"
|
|
133
|
+
def ltr:EVGElement (this.laidOut((EVGRtlLayoutTest.strip(false))))
|
|
134
|
+
c.eqNum("a starts at the left edge" (EVGRtlLayoutTest.childX(ltr 0)) 0.0)
|
|
135
|
+
c.eqNum("b follows it" (EVGRtlLayoutTest.childX(ltr 1)) 40.0)
|
|
136
|
+
c.eqNum("and c follows b" (EVGRtlLayoutTest.childX(ltr 2)) 100.0)
|
|
137
|
+
|
|
138
|
+
; Reflected about a 300-wide box: a's right edge was at 40, so its
|
|
139
|
+
; left edge is now at 260; b spanned 40..100 and now spans 200..260;
|
|
140
|
+
; c spanned 100..120 and now spans 180..200.
|
|
141
|
+
def rtl:EVGElement (this.laidOut((EVGRtlLayoutTest.strip(true))))
|
|
142
|
+
c.eqNum("a is now against the RIGHT edge" (EVGRtlLayoutTest.childX(rtl 0)) 260.0)
|
|
143
|
+
c.eqNum("b sits to its left" (EVGRtlLayoutTest.childX(rtl 1)) 200.0)
|
|
144
|
+
c.eqNum("and c to the left of b" (EVGRtlLayoutTest.childX(rtl 2)) 180.0)
|
|
145
|
+
; The children are still in their authored order in the tree — only
|
|
146
|
+
; where they are DRAWN changed. Anything that walks the tree to read a
|
|
147
|
+
; document, an accessibility tree included, still reads it in the
|
|
148
|
+
; order it was written.
|
|
149
|
+
c.ok("the tree order is untouched" (((ltr.getChild(0)).id) == "a"))
|
|
150
|
+
c.ok("in the mirrored one too" (((rtl.getChild(0)).id) == "a"))
|
|
151
|
+
; And nothing left the box.
|
|
152
|
+
c.ok("nothing was pushed off the left edge" ((EVGRtlLayoutTest.childX(rtl 2)) >= 0.0))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
fn testGrid:void () {
|
|
156
|
+
print "--- and the grid turns with it ---"
|
|
157
|
+
; A grid is placed by a different engine entirely — tracks, spans,
|
|
158
|
+
; named lines, dense packing — and none of it had to be touched. The
|
|
159
|
+
; children still end up at x positions inside a content box, and
|
|
160
|
+
; reflecting those makes column 1 the RIGHTMOST column, which is what
|
|
161
|
+
; a grid in a right-to-left page is.
|
|
162
|
+
def g (new EVGElement())
|
|
163
|
+
g.id = "grid"
|
|
164
|
+
g.width = (EVGUnit.px(300.0))
|
|
165
|
+
g.height = (EVGUnit.px(60.0))
|
|
166
|
+
g.display = "grid"
|
|
167
|
+
g.setAttribute("grid-template-columns" "100px 200px")
|
|
168
|
+
g.setAttribute("direction" "rtl")
|
|
169
|
+
def one:EVGElement (EVGRtlLayoutTest.box("one" 100.0 20.0))
|
|
170
|
+
def two:EVGElement (EVGRtlLayoutTest.box("two" 200.0 20.0))
|
|
171
|
+
g.addChild(one)
|
|
172
|
+
g.addChild(two)
|
|
173
|
+
this.laidOut(g)
|
|
174
|
+
; Column 1 is 100 wide and spans 200..300 mirrored; column 2 is 200
|
|
175
|
+
; wide and spans 0..200.
|
|
176
|
+
c.eqNum("the first column is on the right" one.calculatedX 200.0)
|
|
177
|
+
c.eqNum("and the second beside it" two.calculatedX 0.0)
|
|
178
|
+
|
|
179
|
+
; The same grid the other way round, so the numbers above are read as
|
|
180
|
+
; a mirror rather than as whatever the engine happened to produce.
|
|
181
|
+
def g2 (new EVGElement())
|
|
182
|
+
g2.id = "grid2"
|
|
183
|
+
g2.width = (EVGUnit.px(300.0))
|
|
184
|
+
g2.height = (EVGUnit.px(60.0))
|
|
185
|
+
g2.display = "grid"
|
|
186
|
+
g2.setAttribute("grid-template-columns" "100px 200px")
|
|
187
|
+
def one2:EVGElement (EVGRtlLayoutTest.box("one" 100.0 20.0))
|
|
188
|
+
def two2:EVGElement (EVGRtlLayoutTest.box("two" 200.0 20.0))
|
|
189
|
+
g2.addChild(one2)
|
|
190
|
+
g2.addChild(two2)
|
|
191
|
+
this.laidOut(g2)
|
|
192
|
+
c.eqNum("left to right, the first column is on the left" one2.calculatedX 0.0)
|
|
193
|
+
c.eqNum("and the second follows it" two2.calculatedX 100.0)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
fn testInheritance:void () {
|
|
197
|
+
print "--- one switch, not one per panel ---"
|
|
198
|
+
; The direction is set ONCE, on the page. The strip inside it is never
|
|
199
|
+
; told anything, and turns around because `direction` inherits — which
|
|
200
|
+
; is the whole point: an interface is mirrored by saying so at the top,
|
|
201
|
+
; not by finding every container in it.
|
|
202
|
+
def page (new EVGElement())
|
|
203
|
+
page.id = "page"
|
|
204
|
+
page.width = (EVGUnit.px(300.0))
|
|
205
|
+
page.height = (EVGUnit.px(200.0))
|
|
206
|
+
page.display = "flex"
|
|
207
|
+
page.flexDirection = "column"
|
|
208
|
+
page.setAttribute("direction" "rtl")
|
|
209
|
+
def strip (new EVGElement())
|
|
210
|
+
strip.id = "strip"
|
|
211
|
+
strip.width = (EVGUnit.px(300.0))
|
|
212
|
+
strip.height = (EVGUnit.px(50.0))
|
|
213
|
+
strip.display = "flex"
|
|
214
|
+
strip.flexDirection = "row"
|
|
215
|
+
strip.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
|
|
216
|
+
strip.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
|
|
217
|
+
page.addChild(strip)
|
|
218
|
+
this.laidOut(page)
|
|
219
|
+
c.ok("the nested strip inherited the direction" strip.resolvedRtl)
|
|
220
|
+
c.eqNum("so its first button is on the right" (EVGRtlLayoutTest.childX(strip 0)) 260.0)
|
|
221
|
+
c.eqNum("and its second is beside it" (EVGRtlLayoutTest.childX(strip 1)) 200.0)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
fn testIsland:void () {
|
|
225
|
+
print "--- and an island can opt back out ---"
|
|
226
|
+
; A code block, a formula bar, a phone number: things that read left to
|
|
227
|
+
; right inside a page that does not. Without this, a switch at the top
|
|
228
|
+
; would be a blunt instrument nobody could use on a real document.
|
|
229
|
+
def page (new EVGElement())
|
|
230
|
+
page.id = "page"
|
|
231
|
+
page.width = (EVGUnit.px(300.0))
|
|
232
|
+
page.height = (EVGUnit.px(200.0))
|
|
233
|
+
page.display = "flex"
|
|
234
|
+
page.flexDirection = "column"
|
|
235
|
+
page.setAttribute("direction" "rtl")
|
|
236
|
+
def code (new EVGElement())
|
|
237
|
+
code.id = "code"
|
|
238
|
+
code.width = (EVGUnit.px(300.0))
|
|
239
|
+
code.height = (EVGUnit.px(50.0))
|
|
240
|
+
code.display = "flex"
|
|
241
|
+
code.flexDirection = "row"
|
|
242
|
+
code.setAttribute("direction" "ltr")
|
|
243
|
+
code.addChild((EVGRtlLayoutTest.box("a" 40.0 20.0)))
|
|
244
|
+
code.addChild((EVGRtlLayoutTest.box("b" 60.0 20.0)))
|
|
245
|
+
page.addChild(code)
|
|
246
|
+
this.laidOut(page)
|
|
247
|
+
c.ok("the island is left to right" ((code.resolvedRtl) == false))
|
|
248
|
+
c.eqNum("so its first box is on the left" (EVGRtlLayoutTest.childX(code 0)) 0.0)
|
|
249
|
+
c.eqNum("and the second follows it" (EVGRtlLayoutTest.childX(code 1)) 40.0)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
fn testAbsolute:void () {
|
|
253
|
+
print "--- what must NOT move ---"
|
|
254
|
+
; `left: 0` is the left edge in any direction. An absolutely
|
|
255
|
+
; positioned child was placed against the edge it named, and mirroring
|
|
256
|
+
; it would send a close button to the wrong corner.
|
|
257
|
+
def page (new EVGElement())
|
|
258
|
+
page.id = "page"
|
|
259
|
+
page.width = (EVGUnit.px(300.0))
|
|
260
|
+
page.height = (EVGUnit.px(200.0))
|
|
261
|
+
page.display = "flex"
|
|
262
|
+
page.flexDirection = "row"
|
|
263
|
+
page.setAttribute("direction" "rtl")
|
|
264
|
+
def pinned:EVGElement (EVGRtlLayoutTest.box("pinned" 30.0 30.0))
|
|
265
|
+
pinned.isAbsolute = true
|
|
266
|
+
pinned.left = (EVGUnit.px(0.0))
|
|
267
|
+
pinned.top = (EVGUnit.px(0.0))
|
|
268
|
+
page.addChild(pinned)
|
|
269
|
+
this.laidOut(page)
|
|
270
|
+
c.eqNum("an absolute child stays where it was pinned" pinned.calculatedX 0.0)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fn testMargins:void () {
|
|
274
|
+
print "--- margins stay physical ---"
|
|
275
|
+
; CSS's rule, and the half of it that is easy to get wrong. What a
|
|
276
|
+
; right-to-left container reverses is the ORDER of its children and
|
|
277
|
+
; the end they pack against — not which side of a child its own
|
|
278
|
+
; `margin-left` sits on. An author who wants the margin to follow the
|
|
279
|
+
; direction says `margin-inline-start`.
|
|
280
|
+
;
|
|
281
|
+
; With symmetric margins the two readings agree, which is why picking
|
|
282
|
+
; the wrong one would have survived a long time before anything looked
|
|
283
|
+
; a pixel out. So this uses a margin on ONE side only.
|
|
284
|
+
def root (new EVGElement())
|
|
285
|
+
root.id = "root"
|
|
286
|
+
root.width = (EVGUnit.px(300.0))
|
|
287
|
+
root.height = (EVGUnit.px(50.0))
|
|
288
|
+
root.display = "flex"
|
|
289
|
+
root.flexDirection = "row"
|
|
290
|
+
root.setAttribute("direction" "rtl")
|
|
291
|
+
def only:EVGElement (EVGRtlLayoutTest.box("only" 40.0 20.0))
|
|
292
|
+
only.box.marginLeft = (EVGUnit.px(10.0))
|
|
293
|
+
root.addChild(only)
|
|
294
|
+
this.laidOut(root)
|
|
295
|
+
; Its margin box spans 0..50 (10 of margin, then 40 of box). Mirrored
|
|
296
|
+
; about 0..300 that margin box lands at 250..300, and the border box
|
|
297
|
+
; sits at its own margin-left inside it: 260.
|
|
298
|
+
c.eqNum("the left margin is still on the left of the box" only.calculatedX 260.0)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
fn testLegacyDirection:void () {
|
|
302
|
+
print "--- and the property that already had the name ---"
|
|
303
|
+
; `direction` here has always meant the flow AXIS, and still does for
|
|
304
|
+
; those values. Two properties cannot share a name, so the VALUE
|
|
305
|
+
; decides — and a page that says `direction: row` must not quietly
|
|
306
|
+
; become a right-to-left one.
|
|
307
|
+
def e (new EVGElement())
|
|
308
|
+
e.setAttribute("direction" "row")
|
|
309
|
+
c.ok("row is still the axis" (e.direction == "row"))
|
|
310
|
+
c.ok("and says nothing about handedness" (e.textDir == ""))
|
|
311
|
+
def e2 (new EVGElement())
|
|
312
|
+
e2.setAttribute("direction" "column")
|
|
313
|
+
c.ok("so is column" (e2.direction == "column"))
|
|
314
|
+
def e3 (new EVGElement())
|
|
315
|
+
e3.setAttribute("direction" "rtl")
|
|
316
|
+
c.ok("rtl is the handedness" (e3.textDir == "rtl"))
|
|
317
|
+
c.ok("and leaves the axis alone" (e3.direction == "row"))
|
|
318
|
+
}
|
|
319
|
+
}
|