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,531 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EvgResponsiveDemo — one page, laid out by EVG, at whatever width the window is
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; Every other EVG page in this repository is laid out ONCE, at a size somebody
|
|
8
|
+
; typed: a sheet of A4 for the PDF, 420×320 for the conformance playground,
|
|
9
|
+
; `boxmodel.json` at whatever it was exported at. That is a fair test of the
|
|
10
|
+
; layout, and no test at all of the part CSS calls responsive — `@media`, `vw`,
|
|
11
|
+
; percentages, a grid that changes how many columns it has.
|
|
12
|
+
;
|
|
13
|
+
; So this one is laid out on every frame, at the width of the browser window,
|
|
14
|
+
; and NOTHING about it is precomputed. Drag the window and the whole pipeline
|
|
15
|
+
; runs again:
|
|
16
|
+
;
|
|
17
|
+
; 1. build the tree (this file, `build()`)
|
|
18
|
+
; 2. state the viewport `EVGStyleSheet.setViewport(w, h, coarse)`
|
|
19
|
+
; 3. resolve the cascade `applyTree` — the `@media` blocks that match
|
|
20
|
+
; this width contribute, the others do not
|
|
21
|
+
; 4. lay out `EVGLayout.layout` with `setPageSize(w, h)`,
|
|
22
|
+
; which is also what `vw` / `vh` resolve to
|
|
23
|
+
; 5. flatten to draw commands `EVGDisplayList.build`
|
|
24
|
+
;
|
|
25
|
+
; The page is then painted by `lib/evg/html/evg-html.js` — the SVG backend,
|
|
26
|
+
; 500 lines, which knows about rectangles, glyph runs and clips and nothing at
|
|
27
|
+
; all about CSS. The browser never lays anything out. It is handed absolute
|
|
28
|
+
; pixels that EVG computed.
|
|
29
|
+
;
|
|
30
|
+
; --- WHAT IS ACTUALLY BEING DEMONSTRATED --------------------------------------
|
|
31
|
+
;
|
|
32
|
+
; The tree below has no width, no colour and no size anywhere in it. It is a
|
|
33
|
+
; list of names. Every number on the screen comes from `defaultCss()`, and the
|
|
34
|
+
; three `@media` blocks in it are the entire difference between the wide layout
|
|
35
|
+
; and the phone one:
|
|
36
|
+
;
|
|
37
|
+
; > 1080px sidebar beside the content, cards four across
|
|
38
|
+
; ≤ 1080px cards three across
|
|
39
|
+
; ≤ 820px sidebar above the content, cards two across
|
|
40
|
+
; ≤ 560px one card per row, smaller type, tighter padding
|
|
41
|
+
;
|
|
42
|
+
; The badge in the top bar is the one thing this file computes rather than
|
|
43
|
+
; declares, because it is reporting the input: it says what the host told the
|
|
44
|
+
; stylesheet the viewport was. Everything else is the cascade's answer.
|
|
45
|
+
; ==============================================================================
|
|
46
|
+
|
|
47
|
+
Import "../../EVGElement.rgr"
|
|
48
|
+
Import "../../EVGUnit.rgr"
|
|
49
|
+
Import "../../EVGBox.rgr"
|
|
50
|
+
Import "../../EVGLayout.rgr"
|
|
51
|
+
Import "../../EVGHostTree.rgr"
|
|
52
|
+
Import "../../EVGStyleSheet.rgr"
|
|
53
|
+
Import "../../EVGDisplayList.rgr"
|
|
54
|
+
|
|
55
|
+
; The tags this page is built from. Names only — a tag carries a class and,
|
|
56
|
+
; for the text nodes, `elementType 1`, and never a visual attribute.
|
|
57
|
+
treefactory Rp {
|
|
58
|
+
child addChild
|
|
59
|
+
text textContent
|
|
60
|
+
|
|
61
|
+
tag Page EVGElement (props (className "page"))
|
|
62
|
+
|
|
63
|
+
tag Bar EVGElement (props (className "bar"))
|
|
64
|
+
tag Brand EVGElement (props (className "brand") (elementType 1))
|
|
65
|
+
tag BarTitle EVGElement (props (className "bar-title") (elementType 1))
|
|
66
|
+
tag Spacer EVGElement (props (className "spacer"))
|
|
67
|
+
tag Badge EVGElement (props (className "badge") (elementType 1))
|
|
68
|
+
|
|
69
|
+
tag Hero EVGElement (props (className "hero"))
|
|
70
|
+
tag HeroH EVGElement (props (className "hero-h") (elementType 1))
|
|
71
|
+
tag HeroP EVGElement (props (className "hero-p") (elementType 1))
|
|
72
|
+
|
|
73
|
+
tag Chips EVGElement (props (className "chips"))
|
|
74
|
+
tag ChipW EVGElement (props (className "chip chip-wide") (elementType 1))
|
|
75
|
+
tag ChipL EVGElement (props (className "chip chip-lap") (elementType 1))
|
|
76
|
+
tag ChipT EVGElement (props (className "chip chip-tab") (elementType 1))
|
|
77
|
+
tag ChipP EVGElement (props (className "chip chip-phone") (elementType 1))
|
|
78
|
+
|
|
79
|
+
tag Body EVGElement (props (className "body"))
|
|
80
|
+
tag Side EVGElement (props (className "side"))
|
|
81
|
+
tag SideH EVGElement (props (className "side-h") (elementType 1))
|
|
82
|
+
tag NavList EVGElement (props (className "nav"))
|
|
83
|
+
tag NavItem EVGElement (props (className "nav-item") (elementType 1))
|
|
84
|
+
tag Main EVGElement (props (className "main"))
|
|
85
|
+
|
|
86
|
+
tag SecH EVGElement (props (className "sec-h") (elementType 1))
|
|
87
|
+
tag Cards EVGElement (props (className "cards"))
|
|
88
|
+
tag Card EVGElement (props (className "card"))
|
|
89
|
+
tag CardTag EVGElement (props (className "card-tag") (elementType 1))
|
|
90
|
+
tag CardH EVGElement (props (className "card-h") (elementType 1))
|
|
91
|
+
tag CardP EVGElement (props (className "card-p") (elementType 1))
|
|
92
|
+
|
|
93
|
+
tag Stats EVGElement (props (className "stats"))
|
|
94
|
+
tag Stat EVGElement (props (className "stat"))
|
|
95
|
+
tag StatN EVGElement (props (className "stat-n") (elementType 1))
|
|
96
|
+
tag StatL EVGElement (props (className "stat-l") (elementType 1))
|
|
97
|
+
|
|
98
|
+
tag Foot EVGElement (props (className "foot"))
|
|
99
|
+
tag FootT EVGElement (props (className "foot-t") (elementType 1))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
class EvgResponsiveDemo {
|
|
103
|
+
|
|
104
|
+
; The surface, as the host reports it. `vw` / `vh` and every `@media` bound
|
|
105
|
+
; are resolved against exactly these two numbers — a Ranger program has no
|
|
106
|
+
; window to ask, so the host has to say.
|
|
107
|
+
def pageW:double 1200.0
|
|
108
|
+
def pageH:double 800.0
|
|
109
|
+
; A finger rather than a mouse, for `@media (pointer: coarse)`.
|
|
110
|
+
def coarse:boolean false
|
|
111
|
+
|
|
112
|
+
def css:string ""
|
|
113
|
+
|
|
114
|
+
; What the last render worked out, so a caller can report it without
|
|
115
|
+
; parsing the JSON back.
|
|
116
|
+
def lastHeight:double 0.0
|
|
117
|
+
def lastCommands:int 0
|
|
118
|
+
def lastErrors:int 0
|
|
119
|
+
|
|
120
|
+
; The host tree (`EVGHostTree`), kept across renders: `renderHost` says
|
|
121
|
+
; what changed since the last one, keyed by the inspector's path, so a
|
|
122
|
+
; host that keeps DOM nodes patches them. The tree literal builds every
|
|
123
|
+
; element anew each render and the ops still come out empty for a page
|
|
124
|
+
; that did not change — identity is the PATH, not the object.
|
|
125
|
+
def host:EVGHostTree (new EVGHostTree())
|
|
126
|
+
|
|
127
|
+
Constructor () {
|
|
128
|
+
css = (EvgResponsiveDemo.defaultCss())
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn setViewport:void (w:double h:double c:boolean) {
|
|
132
|
+
pageW = w
|
|
133
|
+
pageH = h
|
|
134
|
+
coarse = c
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
; The page's own stylesheet, so the demo can show it and let it be edited.
|
|
138
|
+
fn stylesheet:string () {
|
|
139
|
+
return css
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
fn setStylesheet:void (text:string) {
|
|
143
|
+
css = text
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fn contentHeight:double () {
|
|
147
|
+
return lastHeight
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fn commandCount:int () {
|
|
151
|
+
return lastCommands
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fn cssErrorCount:int () {
|
|
155
|
+
return lastErrors
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
; ------------------------------------------------------------------------
|
|
159
|
+
; The stylesheet. Every number on the page is in here.
|
|
160
|
+
; ------------------------------------------------------------------------
|
|
161
|
+
sfn defaultCss:string () {
|
|
162
|
+
def s:string ""
|
|
163
|
+
|
|
164
|
+
; --- the page ---------------------------------------------------------
|
|
165
|
+
; `font-family` is declared once and inherits from here. It is a
|
|
166
|
+
; GENERIC on purpose: `SimpleTextMeasurer`'s advances were measured off
|
|
167
|
+
; a browser's sans fallback, so naming that same fallback is what makes
|
|
168
|
+
; the width EVG computed and the width the browser paints the same
|
|
169
|
+
; number. A named face nobody has installed would silently be measured
|
|
170
|
+
; as one thing and drawn as another.
|
|
171
|
+
s = s + ".page { display: flex; flex-direction: column; width: 100vw;"
|
|
172
|
+
s = s + " font-family: sans-serif;"
|
|
173
|
+
s = s + " background-color: #f6f7fb; padding-bottom: 28px }\n"
|
|
174
|
+
|
|
175
|
+
; --- top bar ----------------------------------------------------------
|
|
176
|
+
s = s + ".bar { display: flex; flex-direction: row; align-items: center;"
|
|
177
|
+
s = s + " gap: 12px; padding: 18px 32px; background-color: #10162b }\n"
|
|
178
|
+
s = s + ".brand { font-size: 15px; font-weight: 700; color: #ffffff }\n"
|
|
179
|
+
s = s + ".bar-title { font-size: 13px; color: #8ea0c8 }\n"
|
|
180
|
+
s = s + ".spacer { flex: 1 }\n"
|
|
181
|
+
s = s + ".badge { font-size: 12px; font-weight: 600; color: #06122e;"
|
|
182
|
+
s = s + " background-color: #7cc4ff; border-radius: 999px;"
|
|
183
|
+
s = s + " padding: 6px 14px }\n"
|
|
184
|
+
|
|
185
|
+
; --- hero -------------------------------------------------------------
|
|
186
|
+
; `padding-left: 4vw` is the viewport unit doing the work a percentage
|
|
187
|
+
; cannot: it is a share of the PAGE, not of this element's parent.
|
|
188
|
+
s = s + ".hero { display: flex; flex-direction: column; gap: 10px;"
|
|
189
|
+
s = s + " padding-top: 30px; padding-bottom: 26px;"
|
|
190
|
+
s = s + " padding-left: 4vw; padding-right: 4vw;"
|
|
191
|
+
s = s + " background-color: #ffffff }\n"
|
|
192
|
+
s = s + ".hero-h { font-size: 30px; font-weight: 700; color: #10162b;"
|
|
193
|
+
s = s + " line-height: 1.2 }\n"
|
|
194
|
+
s = s + ".hero-p { font-size: 14px; color: #55617e; line-height: 1.5 }\n"
|
|
195
|
+
|
|
196
|
+
; --- the breakpoint chips --------------------------------------------
|
|
197
|
+
; Four chips, one per band. They are grey here, and each `@media` block
|
|
198
|
+
; below lights its own one up — so the page says which rules are firing
|
|
199
|
+
; without anything in the tree knowing how wide the window is.
|
|
200
|
+
s = s + ".chips { display: flex; flex-direction: row; flex-wrap: wrap;"
|
|
201
|
+
s = s + " gap: 8px; padding-top: 6px }\n"
|
|
202
|
+
s = s + ".chip { font-size: 12px; color: #7a869f;"
|
|
203
|
+
s = s + " background-color: #eef0f6; border-radius: 6px;"
|
|
204
|
+
s = s + " padding: 6px 10px }\n"
|
|
205
|
+
s = s + ".chip-wide { color: #06122e; background-color: #b9e2ff }\n"
|
|
206
|
+
|
|
207
|
+
; --- the body split ---------------------------------------------------
|
|
208
|
+
s = s + ".body { display: flex; flex-direction: row; gap: 24px;"
|
|
209
|
+
s = s + " padding-top: 26px;"
|
|
210
|
+
s = s + " padding-left: 4vw; padding-right: 4vw }\n"
|
|
211
|
+
s = s + ".side { display: flex; flex-direction: column; gap: 8px;"
|
|
212
|
+
s = s + " width: 240px; padding: 16px; background-color: #ffffff;"
|
|
213
|
+
s = s + " border-radius: 12px }\n"
|
|
214
|
+
s = s + ".side-h { font-size: 11px; font-weight: 700; color: #8b95ad;"
|
|
215
|
+
s = s + " padding-bottom: 4px }\n"
|
|
216
|
+
; `width: 100%` rather than nothing. EVG's `align-items` default on a
|
|
217
|
+
; column is `flex-start`, not `stretch`, so an auto cross size here is
|
|
218
|
+
; fit-content — which is not what a list of rows in a fixed-width
|
|
219
|
+
; sidebar means. Saying the percentage says it.
|
|
220
|
+
s = s + ".nav { display: flex; flex-direction: column; gap: 6px;"
|
|
221
|
+
s = s + " width: 100% }\n"
|
|
222
|
+
; `min-width` so the rows are a consistent size — and so that no label
|
|
223
|
+
; sits on the wrap threshold. A shrink-to-fit box comes out at exactly
|
|
224
|
+
; its own text's width, and the content width is that number minus the
|
|
225
|
+
; padding it was added to, which for some strings loses a ulp and wraps
|
|
226
|
+
; a label that fits. See lib/evg/ISSUES.md, "shrink-to-fit text".
|
|
227
|
+
s = s + ".nav-item { font-size: 13px; color: #26314c;"
|
|
228
|
+
s = s + " background-color: #f2f4fa; border-radius: 8px;"
|
|
229
|
+
s = s + " min-width: 104px; padding: 9px 12px }\n"
|
|
230
|
+
s = s + ".main { display: flex; flex-direction: column; gap: 18px;"
|
|
231
|
+
s = s + " flex: 1 }\n"
|
|
232
|
+
s = s + ".sec-h { font-size: 16px; font-weight: 700; color: #10162b }\n"
|
|
233
|
+
|
|
234
|
+
; --- the card grid ----------------------------------------------------
|
|
235
|
+
s = s + ".cards { display: grid;"
|
|
236
|
+
s = s + " grid-template-columns: repeat(4, 1fr); gap: 16px }\n"
|
|
237
|
+
s = s + ".card { display: flex; flex-direction: column; gap: 8px;"
|
|
238
|
+
s = s + " padding: 16px; background-color: #ffffff;"
|
|
239
|
+
s = s + " border-radius: 12px; border-width: 1px; border-color: #e3e7f1 }\n"
|
|
240
|
+
s = s + ".card-tag { font-size: 11px; font-weight: 700; color: #2f7fd0 }\n"
|
|
241
|
+
s = s + ".card-h { font-size: 15px; font-weight: 700; color: #10162b }\n"
|
|
242
|
+
s = s + ".card-p { font-size: 13px; color: #55617e; line-height: 1.45 }\n"
|
|
243
|
+
|
|
244
|
+
; --- the stat strip ---------------------------------------------------
|
|
245
|
+
; `flex-wrap: wrap` with a minimum width is the other way a layout
|
|
246
|
+
; answers a narrow window: no rule fires, the line simply runs out.
|
|
247
|
+
s = s + ".stats { display: flex; flex-direction: row; flex-wrap: wrap;"
|
|
248
|
+
s = s + " gap: 12px }\n"
|
|
249
|
+
s = s + ".stat { display: flex; flex-direction: column; gap: 4px;"
|
|
250
|
+
s = s + " flex: 1; min-width: 150px; padding: 14px 16px;"
|
|
251
|
+
s = s + " background-color: #10162b; border-radius: 12px }\n"
|
|
252
|
+
s = s + ".stat-n { font-size: 22px; font-weight: 700; color: #ffffff }\n"
|
|
253
|
+
s = s + ".stat-l { font-size: 12px; color: #8ea0c8 }\n"
|
|
254
|
+
|
|
255
|
+
; --- footer -----------------------------------------------------------
|
|
256
|
+
s = s + ".foot { display: flex; flex-direction: row;"
|
|
257
|
+
s = s + " padding-top: 22px;"
|
|
258
|
+
s = s + " padding-left: 4vw; padding-right: 4vw }\n"
|
|
259
|
+
s = s + ".foot-t { font-size: 12px; color: #8b95ad; line-height: 1.5 }\n"
|
|
260
|
+
|
|
261
|
+
; ======================================================================
|
|
262
|
+
; The breakpoints. This is the whole responsive behaviour of the page.
|
|
263
|
+
; ======================================================================
|
|
264
|
+
|
|
265
|
+
; Laptop: one column out of the card grid.
|
|
266
|
+
s = s + "@media (max-width: 1080px) {\n"
|
|
267
|
+
s = s + " .cards { grid-template-columns: repeat(3, 1fr) }\n"
|
|
268
|
+
s = s + " .hero-h { font-size: 26px }\n"
|
|
269
|
+
s = s + " .chip-wide { color: #7a869f; background-color: #eef0f6 }\n"
|
|
270
|
+
s = s + " .chip-lap { color: #06122e; background-color: #b9e2ff }\n"
|
|
271
|
+
s = s + "}\n"
|
|
272
|
+
|
|
273
|
+
; Tablet: the sidebar stops being a sidebar. One declaration —
|
|
274
|
+
; `flex-direction: column` on the split — moves it above the content,
|
|
275
|
+
; and `width: auto` lets it fill the line it now has to itself.
|
|
276
|
+
s = s + "@media (max-width: 820px) {\n"
|
|
277
|
+
s = s + " .body { flex-direction: column; gap: 18px }\n"
|
|
278
|
+
s = s + " .side { width: auto }\n"
|
|
279
|
+
s = s + " .nav { flex-direction: row; flex-wrap: wrap }\n"
|
|
280
|
+
s = s + " .cards { grid-template-columns: repeat(2, 1fr) }\n"
|
|
281
|
+
s = s + " .chip-lap { color: #7a869f; background-color: #eef0f6 }\n"
|
|
282
|
+
s = s + " .chip-tab { color: #06122e; background-color: #b9e2ff }\n"
|
|
283
|
+
s = s + "}\n"
|
|
284
|
+
|
|
285
|
+
; Phone: one card per row, and the type and padding come down with it.
|
|
286
|
+
s = s + "@media (max-width: 560px) {\n"
|
|
287
|
+
s = s + " .bar { padding-left: 18px; padding-right: 18px }\n"
|
|
288
|
+
s = s + " .bar-title { font-size: 12px }\n"
|
|
289
|
+
s = s + " .hero { padding-top: 22px; padding-bottom: 20px }\n"
|
|
290
|
+
s = s + " .hero-h { font-size: 21px }\n"
|
|
291
|
+
s = s + " .hero-p { font-size: 13px }\n"
|
|
292
|
+
s = s + " .cards { grid-template-columns: repeat(1, 1fr); gap: 12px }\n"
|
|
293
|
+
s = s + " .stat { min-width: 120px }\n"
|
|
294
|
+
s = s + " .chip-tab { color: #7a869f; background-color: #eef0f6 }\n"
|
|
295
|
+
s = s + " .chip-phone { color: #06122e; background-color: #b9e2ff }\n"
|
|
296
|
+
s = s + "}\n"
|
|
297
|
+
|
|
298
|
+
; A finger needs a bigger target than a mouse does. Nothing on this page
|
|
299
|
+
; is clickable, but the rule is here because it is the third thing a
|
|
300
|
+
; media query can ask about and it costs one block to prove it works.
|
|
301
|
+
s = s + "@media (pointer: coarse) {\n"
|
|
302
|
+
s = s + " .nav-item { padding-top: 13px; padding-bottom: 13px }\n"
|
|
303
|
+
s = s + "}\n"
|
|
304
|
+
|
|
305
|
+
return s
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
; ------------------------------------------------------------------------
|
|
309
|
+
; The tree. Names, and not one number.
|
|
310
|
+
; ------------------------------------------------------------------------
|
|
311
|
+
|
|
312
|
+
fn card:EVGElement (tag:string title:string body:string) {
|
|
313
|
+
def c (tree Rp (Card))
|
|
314
|
+
c.addChild((tree Rp (CardTag tag)))
|
|
315
|
+
c.addChild((tree Rp (CardH title)))
|
|
316
|
+
c.addChild((tree Rp (CardP body)))
|
|
317
|
+
return c
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
fn stat:EVGElement (value:string label:string) {
|
|
321
|
+
def s (tree Rp (Stat))
|
|
322
|
+
s.addChild((tree Rp (StatN value)))
|
|
323
|
+
s.addChild((tree Rp (StatL label)))
|
|
324
|
+
return s
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
fn navItem:EVGElement (label:string) {
|
|
328
|
+
return (tree Rp (NavItem label))
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
; What the badge says. This is the ONE thing the tree is told about the
|
|
332
|
+
; window, and it is reporting the input rather than reacting to it.
|
|
333
|
+
fn badgeText:string () {
|
|
334
|
+
def w:int (to_int pageW)
|
|
335
|
+
def h:int (to_int pageH)
|
|
336
|
+
def band:string "wide"
|
|
337
|
+
if (pageW <= 1080.0) { band = "laptop" }
|
|
338
|
+
if (pageW <= 820.0) { band = "tablet" }
|
|
339
|
+
if (pageW <= 560.0) { band = "phone" }
|
|
340
|
+
return (((((to_string w) + " × ") + (to_string h)) + " px · ") + band)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
fn build:EVGElement () {
|
|
344
|
+
def page (tree Rp (Page))
|
|
345
|
+
|
|
346
|
+
; --- bar --------------------------------------------------------------
|
|
347
|
+
def bar (tree Rp (Bar))
|
|
348
|
+
bar.addChild((tree Rp (Brand "EVG")))
|
|
349
|
+
bar.addChild((tree Rp (BarTitle "responsive layout, laid out on every frame")))
|
|
350
|
+
bar.addChild((tree Rp (Spacer)))
|
|
351
|
+
bar.addChild((tree Rp (Badge (this.badgeText()))))
|
|
352
|
+
page.addChild(bar)
|
|
353
|
+
|
|
354
|
+
; --- hero -------------------------------------------------------------
|
|
355
|
+
def hero (tree Rp (Hero))
|
|
356
|
+
hero.addChild((tree Rp (HeroH "Sama puu, sama tyylitiedosto, mikä tahansa leveys")))
|
|
357
|
+
hero.addChild((tree Rp (HeroP ("Selain ei aseta tällä sivulla mitään. EVG saa ikkunan koon, "
|
|
358
|
+
+ "ratkaisee @media-säännöt sitä vasten, laskee laatikot ja antaa SVG-piirtäjälle "
|
|
359
|
+
+ "valmiit pikselit. Muuta ikkunan kokoa — koko putki ajetaan uudelleen."))))
|
|
360
|
+
|
|
361
|
+
def chips (tree Rp (Chips))
|
|
362
|
+
chips.addChild((tree Rp (ChipW "> 1080px · 4 saraketta")))
|
|
363
|
+
chips.addChild((tree Rp (ChipL "≤ 1080px · 3 saraketta")))
|
|
364
|
+
chips.addChild((tree Rp (ChipT "≤ 820px · sivupalkki ylös")))
|
|
365
|
+
chips.addChild((tree Rp (ChipP "≤ 560px · 1 sarake")))
|
|
366
|
+
hero.addChild(chips)
|
|
367
|
+
page.addChild(hero)
|
|
368
|
+
|
|
369
|
+
; --- body -------------------------------------------------------------
|
|
370
|
+
def body (tree Rp (Body))
|
|
371
|
+
|
|
372
|
+
def side (tree Rp (Side))
|
|
373
|
+
side.addChild((tree Rp (SideH "MOOTTORI")))
|
|
374
|
+
def nav (tree Rp (NavList))
|
|
375
|
+
nav.addChild((this.navItem("Layout")))
|
|
376
|
+
nav.addChild((this.navItem("Stylesheet")))
|
|
377
|
+
nav.addChild((this.navItem("Text engine")))
|
|
378
|
+
nav.addChild((this.navItem("Display list")))
|
|
379
|
+
nav.addChild((this.navItem("Hit test")))
|
|
380
|
+
nav.addChild((this.navItem("A11y tree")))
|
|
381
|
+
side.addChild(nav)
|
|
382
|
+
body.addChild(side)
|
|
383
|
+
|
|
384
|
+
def main (tree Rp (Main))
|
|
385
|
+
main.addChild((tree Rp (SecH "Mitä leveys muuttaa")))
|
|
386
|
+
|
|
387
|
+
def cards (tree Rp (Cards))
|
|
388
|
+
cards.addChild((this.card("GRID" "Sarakkeet"
|
|
389
|
+
"grid-template-columns vaihtuu neljästä yhteen. Sama solulista, eri raidat.")))
|
|
390
|
+
cards.addChild((this.card("FLEX" "Suunta"
|
|
391
|
+
"Sivupalkin ja sisällön jako on flex-rivi, joka kääntyy sarakkeeksi 820 pikselissä.")))
|
|
392
|
+
cards.addChild((this.card("VW" "Marginaali"
|
|
393
|
+
"Reunojen padding on 4vw eli osuus sivusta, ei vanhemmasta. Se kapenee ikkunan mukana.")))
|
|
394
|
+
cards.addChild((this.card("WRAP" "Rivitys"
|
|
395
|
+
"Tilastorivi ei kysy leveyttä keneltäkään: min-width ja flex-wrap katkaisevat rivin itse.")))
|
|
396
|
+
cards.addChild((this.card("TEXT" "Katkot"
|
|
397
|
+
"Teksti mitataan samalla moottorilla joka sen piirtää, joten rivitys on se mikä näkyy.")))
|
|
398
|
+
cards.addChild((this.card("MEDIA" "Ehdot"
|
|
399
|
+
"@media on ehto säännöille, ei uusi valitsin: spesifisyys säilyy ennallaan.")))
|
|
400
|
+
cards.addChild((this.card("POINTER" "Osoitin"
|
|
401
|
+
"(pointer: coarse) kasvattaa navin kohteet sormelle. Isäntä kertoo kumpi on käytössä.")))
|
|
402
|
+
cards.addChild((this.card("SAMA" "Yksi puu"
|
|
403
|
+
"Tämä sivu kelpaa sellaisenaan PDF:ksi ja PNG:ksi. Vain sivun koko on eri.")))
|
|
404
|
+
main.addChild(cards)
|
|
405
|
+
|
|
406
|
+
def stats (tree Rp (Stats))
|
|
407
|
+
stats.addChild((this.stat("3" "@media-lohkoa")))
|
|
408
|
+
stats.addChild((this.stat("0" "kovaa pikseliä puussa")))
|
|
409
|
+
stats.addChild((this.stat("1" "tyylitiedosto")))
|
|
410
|
+
stats.addChild((this.stat("6" "piirtokohdetta")))
|
|
411
|
+
main.addChild(stats)
|
|
412
|
+
|
|
413
|
+
body.addChild(main)
|
|
414
|
+
page.addChild(body)
|
|
415
|
+
|
|
416
|
+
; --- foot -------------------------------------------------------------
|
|
417
|
+
def foot (tree Rp (Foot))
|
|
418
|
+
foot.addChild((tree Rp (FootT ("lib/evg/web/responsive — puu rakennetaan, tyylit "
|
|
419
|
+
+ "ratkaistaan ja laatikot lasketaan uudelleen jokaisella koon muutoksella."))))
|
|
420
|
+
page.addChild(foot)
|
|
421
|
+
|
|
422
|
+
return page
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
; How tall the page turned out.
|
|
426
|
+
;
|
|
427
|
+
; NOT `root.calculatedHeight`: `EVGLayout` gives a root with no stated
|
|
428
|
+
; height the page height, because a document's root IS the page — which is
|
|
429
|
+
; right for paper and wrong for a window, where the content is free to be
|
|
430
|
+
; taller than the viewport and scroll. So the answer is the lowest edge any
|
|
431
|
+
; child reached, plus the root's own bottom padding, and the caller sizes
|
|
432
|
+
; the surface to that.
|
|
433
|
+
fn measuredHeight:double (root:EVGElement) {
|
|
434
|
+
def bottom:double 0.0
|
|
435
|
+
def i:int 0
|
|
436
|
+
def n:int (root.getChildCount())
|
|
437
|
+
while (i < n) {
|
|
438
|
+
def c:EVGElement (root.getChild(i))
|
|
439
|
+
def b:double (c.calculatedY + c.calculatedHeight)
|
|
440
|
+
if (b > bottom) {
|
|
441
|
+
bottom = b
|
|
442
|
+
}
|
|
443
|
+
i = (i + 1)
|
|
444
|
+
}
|
|
445
|
+
; The RESOLVED box, not the declared unit: `paddingBottom` is still the
|
|
446
|
+
; `28px` the sheet wrote, and `box` is what layout made of it.
|
|
447
|
+
def box:EVGBox root.box
|
|
448
|
+
bottom = (bottom + box.paddingBottomPx)
|
|
449
|
+
if (bottom < pageH) {
|
|
450
|
+
bottom = pageH
|
|
451
|
+
}
|
|
452
|
+
return bottom
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
; ------------------------------------------------------------------------
|
|
456
|
+
; One frame: tree, cascade, layout, draw commands, JSON.
|
|
457
|
+
; ------------------------------------------------------------------------
|
|
458
|
+
fn render:string () {
|
|
459
|
+
def root:EVGElement (this.build())
|
|
460
|
+
|
|
461
|
+
def sheet (new EVGStyleSheet())
|
|
462
|
+
sheet.parse(css)
|
|
463
|
+
lastErrors = (array_length sheet.errors)
|
|
464
|
+
; The viewport is stated, not guessed: with none, a conditional rule
|
|
465
|
+
; does not apply at all.
|
|
466
|
+
sheet.setViewport(pageW pageH coarse)
|
|
467
|
+
sheet.applyTree(root "")
|
|
468
|
+
|
|
469
|
+
def lay (new EVGLayout())
|
|
470
|
+
lay.setPageSize(pageW pageH)
|
|
471
|
+
lay.layout(root)
|
|
472
|
+
|
|
473
|
+
; A second pass, and only when the content came out taller than the
|
|
474
|
+
; window. `EVGLayout` gives an unstated root the PAGE height, so the
|
|
475
|
+
; first pass leaves the page background 900px tall under 1800px of
|
|
476
|
+
; cards; stating the measured height and laying out again paints it to
|
|
477
|
+
; the bottom. The page SIZE is not touched, so `vw`, `vh` and every
|
|
478
|
+
; `@media` bound still mean the window and not the document.
|
|
479
|
+
def tall:double (this.measuredHeight(root))
|
|
480
|
+
if (tall > pageH) {
|
|
481
|
+
root.height = (EVGUnit.px(tall))
|
|
482
|
+
lay.layout(root)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
def dl (new EVGDisplayList())
|
|
486
|
+
; The list must break paragraphs exactly where layout broke them.
|
|
487
|
+
dl.setTextEngine((lay.getTextEngine()))
|
|
488
|
+
dl.build(root)
|
|
489
|
+
|
|
490
|
+
lastHeight = (this.measuredHeight(root))
|
|
491
|
+
lastCommands = (dl.count())
|
|
492
|
+
|
|
493
|
+
def json:string "{\"width\":"
|
|
494
|
+
json = json + (EVGDisplayList.num(pageW))
|
|
495
|
+
json = json + ",\"height\":" + (EVGDisplayList.num(lastHeight))
|
|
496
|
+
json = json + ",\"cssErrors\":" + (to_string lastErrors)
|
|
497
|
+
json = json + ",\"list\":" + (dl.toJson()) + "}"
|
|
498
|
+
return json
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
; The same frame, as the ops a host that keeps nodes applies — the
|
|
502
|
+
; retained DOM painter (`html/evg-dom.js`) reads this. Same tree, same
|
|
503
|
+
; cascade, same layout; the display list is not built, because nothing
|
|
504
|
+
; below the seam is asked for.
|
|
505
|
+
fn renderHost:string () {
|
|
506
|
+
def root:EVGElement (this.build())
|
|
507
|
+
def sheet (new EVGStyleSheet())
|
|
508
|
+
sheet.parse(css)
|
|
509
|
+
lastErrors = (array_length sheet.errors)
|
|
510
|
+
sheet.setViewport(pageW pageH coarse)
|
|
511
|
+
sheet.applyTree(root "")
|
|
512
|
+
def lay (new EVGLayout())
|
|
513
|
+
lay.setPageSize(pageW pageH)
|
|
514
|
+
lay.layout(root)
|
|
515
|
+
def tall:double (this.measuredHeight(root))
|
|
516
|
+
if (tall > pageH) {
|
|
517
|
+
root.height = (EVGUnit.px(tall))
|
|
518
|
+
lay.layout(root)
|
|
519
|
+
}
|
|
520
|
+
host.setTextEngine((lay.getTextEngine()))
|
|
521
|
+
host.build(root)
|
|
522
|
+
lastHeight = (this.measuredHeight(root))
|
|
523
|
+
lastCommands = host.count
|
|
524
|
+
def json:string "{\"width\":"
|
|
525
|
+
json = json + (EVGDisplayList.num(pageW))
|
|
526
|
+
json = json + ",\"height\":" + (EVGDisplayList.num(lastHeight))
|
|
527
|
+
json = json + ",\"cssErrors\":" + (to_string lastErrors)
|
|
528
|
+
json = json + ",\"host\":" + (host.toJson()) + "}"
|
|
529
|
+
return json
|
|
530
|
+
}
|
|
531
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Responsive layout, live
|
|
2
|
+
|
|
3
|
+
A page as wide as the browser window, laid out **again on every resize** by the
|
|
4
|
+
EVG engine compiled into the browser. The browser lays out nothing: it is handed
|
|
5
|
+
an `<svg>` full of absolute coordinates that EVG computed.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm run evg:responsive:web:serve # build and serve on http://localhost:8007/
|
|
9
|
+
npm run evg:responsive:check # the same layout at four widths, no browser
|
|
10
|
+
npm run evg:responsive:web:smoke # the built page, driven in Chromium
|
|
11
|
+
npm run evg:dom:check # the same page painted as retained DOM (?painter=dom), checked
|
|
12
|
+
npm run evg:responsive:web # build only -> dist/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The showcase build ships the same files to `/evg/responsive/` on Pages.
|
|
16
|
+
|
|
17
|
+
## Why it exists
|
|
18
|
+
|
|
19
|
+
Every other EVG page in this repository is laid out **once**, at a size somebody
|
|
20
|
+
typed: a sheet of A4 for the PDF, 420×320 for the conformance playground,
|
|
21
|
+
`boxmodel.json` at whatever it was exported at. That is a fair test of the
|
|
22
|
+
layout and no test at all of the part CSS calls responsive — `@media`, `vw`,
|
|
23
|
+
percentages, a grid that changes how many columns it has.
|
|
24
|
+
|
|
25
|
+
Here every frame runs the whole pipeline:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
build the tree EvgResponsiveDemo.build()
|
|
29
|
+
state the viewport EVGStyleSheet.setViewport(w, h, coarse)
|
|
30
|
+
resolve the cascade applyTree — matching @media blocks contribute
|
|
31
|
+
lay out EVGLayout.layout, setPageSize(w, h) ← also vw / vh
|
|
32
|
+
flatten EVGDisplayList.build
|
|
33
|
+
paint ../../html/evg-html.js, the SVG backend
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
About a millisecond of layout per frame at 1400px, reported in the strip at the
|
|
37
|
+
bottom of the page along with the width EVG was given and how many draw commands
|
|
38
|
+
came out.
|
|
39
|
+
|
|
40
|
+
## What is being demonstrated
|
|
41
|
+
|
|
42
|
+
The tree in [`EvgResponsiveDemo.rgr`](EvgResponsiveDemo.rgr) has no width, no
|
|
43
|
+
colour and no size anywhere in it — it is a list of names. Every number on the
|
|
44
|
+
screen comes from `defaultCss()`, and its three `@media` blocks are the entire
|
|
45
|
+
difference between the wide layout and the phone one:
|
|
46
|
+
|
|
47
|
+
| Width | |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `> 1080px` | sidebar beside the content, cards four across |
|
|
50
|
+
| `≤ 1080px` | cards three across |
|
|
51
|
+
| `≤ 820px` | sidebar above the content, cards two across |
|
|
52
|
+
| `≤ 560px` | one card per row, smaller type, tighter padding |
|
|
53
|
+
|
|
54
|
+
Plus two things no breakpoint decides: the page margins are `4vw`, a share of
|
|
55
|
+
the window rather than of the parent, and the stat strip wraps on its own
|
|
56
|
+
because its tiles state a `min-width` and the line runs out.
|
|
57
|
+
|
|
58
|
+
`@media (pointer: coarse)` is in there too — the *pointer: coarse* button in the
|
|
59
|
+
strip toggles what the host reports, and the sidebar's rows grow for a finger.
|
|
60
|
+
|
|
61
|
+
## The files
|
|
62
|
+
|
|
63
|
+
| | |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `EvgResponsiveDemo.rgr` | the page: the tree, the stylesheet, and one `render()` that returns a display list as JSON |
|
|
66
|
+
| `EvgResponsiveCheck.rgr` | the same layout at four widths, asserted in Node |
|
|
67
|
+
| `index.html` | the stage, the resize observer and the controls |
|
|
68
|
+
| `build.mjs` | compiles the demo to a browser IIFE and copies the painter beside it |
|
|
69
|
+
| `smoke.mjs` | serves `dist/` and drives it in Chromium |
|
|
70
|
+
| `dom-check.mjs` | the same page through `html/evg-dom.js` — a DOM node per element, patched from `EVGHostTree`'s ops — asked whether every node is where the engine put it and whether a resize kept them |
|
|
71
|
+
|
|
72
|
+
## What it found
|
|
73
|
+
|
|
74
|
+
The page did what a demo is for. Dragging the window edge flickered: the content
|
|
75
|
+
dropped below the sidebar and came back up a pixel later, over and over.
|
|
76
|
+
|
|
77
|
+
`.side` and `.main` are a flex row and `.main` is `flex: 1`, so its width is
|
|
78
|
+
computed by the layout out of the same line it is then measured against — and
|
|
79
|
+
`(a - b - c) + b + c` can land one ulp above `a`, at which point the row is too
|
|
80
|
+
wide for itself and wraps. It failed at **127 of the 680 integer widths between
|
|
81
|
+
821 and 1500**, scattered rather than in a band, which is why it read as a
|
|
82
|
+
flicker rather than as a breakpoint.
|
|
83
|
+
|
|
84
|
+
Fixed in `EVGLayout` by allowing a hundredth of a pixel of overflow before the
|
|
85
|
+
row wraps (`ISSUES.md` #8). Guarded in three places: `EVGFlexWrapTest.rgr` in
|
|
86
|
+
the engine, the width sweep in `EvgResponsiveCheck` here, and a sweep in
|
|
87
|
+
`smoke.mjs` that reads it off the painted boxes in Chromium.
|
|
88
|
+
|
|
89
|
+
## The checks
|
|
90
|
+
|
|
91
|
+
`EvgResponsiveCheck` counts card columns by **grouping the laid-out cards by
|
|
92
|
+
their `y`** rather than by reading the stylesheet back: however the grid decided
|
|
93
|
+
to place them, the cards sharing the top row are the columns. The sidebar's move
|
|
94
|
+
is checked the same way — where its box ended up, not what rule put it there.
|
|
95
|
+
It also checks the rule that a stylesheet with **no viewport stated** applies no
|
|
96
|
+
conditional rule at all, because a media query that cannot be evaluated has no
|
|
97
|
+
truth value.
|