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,975 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; EVGGrid.rgr - Track lists and item placement for EVG's CSS Grid subset
|
|
4
|
+
;
|
|
5
|
+
; Targets photo-book pages, not CSS Grid Level 2. What is supported:
|
|
6
|
+
;
|
|
7
|
+
; grid-template-columns: 120px 1fr 40% | repeat(3, 1fr) | minmax(40px, 1fr)
|
|
8
|
+
; grid-template-rows: 1fr 1fr
|
|
9
|
+
; grid-template-areas: "hero hero" "a b"
|
|
10
|
+
; grid-auto-flow: row | row dense
|
|
11
|
+
; grid-template-columns: subgrid | grid-template-rows: subgrid
|
|
12
|
+
; grid-column: span 2 | 2 | 2 / 4 | 2 / span 3
|
|
13
|
+
; grid-row: (same forms)
|
|
14
|
+
;
|
|
15
|
+
; grid-template-columns: [full-start] 1fr [main] 2fr [main-end]
|
|
16
|
+
; grid-column: main / main-end (named lines, resolved by EVGLayout)
|
|
17
|
+
;
|
|
18
|
+
; A track list this subset cannot honour sets `hadError` with a message, which
|
|
19
|
+
; EVGLayout collects and the tools print — an unsupported declaration changes
|
|
20
|
+
; the layout, so it must not be dropped in silence.
|
|
21
|
+
;
|
|
22
|
+
; `auto` and `fit-content(limit)` size to the content of the items placed in
|
|
23
|
+
; the track: EVGLayout measures each item's min- and max-content width and
|
|
24
|
+
; hands the per-track maxima to resolveWithContent(). `auto` takes the
|
|
25
|
+
; max-content size; `fit-content(limit)` clamps that to the limit but never
|
|
26
|
+
; below min-content, so an item that cannot be made narrower still fits.
|
|
27
|
+
; Leftover space then goes to the `fr` tracks as before.
|
|
28
|
+
|
|
29
|
+
Import "EVGUnit.rgr"
|
|
30
|
+
|
|
31
|
+
; One column or row track.
|
|
32
|
+
; kind 0 = fixed pixels, 1 = percentage of the container, 2 = fr,
|
|
33
|
+
; 3 = intrinsic (`auto`, or `fit-content(limit)` when hasFitLimit)
|
|
34
|
+
class EVGGridTrack {
|
|
35
|
+
def kind:int 0
|
|
36
|
+
def value:double 0.0
|
|
37
|
+
; fit-content(limit): the ceiling on the max-content side. Without it an
|
|
38
|
+
; intrinsic track is a plain `auto`.
|
|
39
|
+
def hasFitLimit:boolean false
|
|
40
|
+
def fitLimit:EVGUnit
|
|
41
|
+
; Resolved extent in pixels, filled in by EVGGridTemplate.resolve.
|
|
42
|
+
def sizePx:double 0.0
|
|
43
|
+
; minmax(min, max) bounds in pixels. Percentages are resolved against the
|
|
44
|
+
; container when the template is resolved. `hasMin`/`hasMax` distinguish an
|
|
45
|
+
; absent bound from a zero one.
|
|
46
|
+
def hasMin:boolean false
|
|
47
|
+
def hasMax:boolean false
|
|
48
|
+
def minUnit:EVGUnit
|
|
49
|
+
def maxUnit:EVGUnit
|
|
50
|
+
; Set while the redistribution loop has already pinned this track.
|
|
51
|
+
def frozen:boolean false
|
|
52
|
+
|
|
53
|
+
Constructor () {
|
|
54
|
+
kind = 0
|
|
55
|
+
value = 0.0
|
|
56
|
+
sizePx = 0.0
|
|
57
|
+
hasMin = false
|
|
58
|
+
hasMax = false
|
|
59
|
+
frozen = false
|
|
60
|
+
hasFitLimit = false
|
|
61
|
+
minUnit = (EVGUnit.unset())
|
|
62
|
+
maxUnit = (EVGUnit.unset())
|
|
63
|
+
fitLimit = (EVGUnit.unset())
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class EVGGridTemplate {
|
|
68
|
+
def tracks:[EVGGridTrack]
|
|
69
|
+
; Named grid lines: "[full-start] 1fr [main] 2fr [main-end]". Parallel
|
|
70
|
+
; arrays of name and the 1-based line number it labels. One line may carry
|
|
71
|
+
; several names ("[a b]") and one name may not label two lines — the first
|
|
72
|
+
; wins, which is what CSS does for a duplicate custom-ident.
|
|
73
|
+
def lineNames:[string]
|
|
74
|
+
def lineNumbers:[int]
|
|
75
|
+
; Set when the spec named a track type this subset does not implement.
|
|
76
|
+
def hadError:boolean false
|
|
77
|
+
def errorText:string ""
|
|
78
|
+
|
|
79
|
+
Constructor () {
|
|
80
|
+
hadError = false
|
|
81
|
+
errorText = ""
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
; The 1-based line a name labels, or 0 when the template does not have it.
|
|
85
|
+
fn lineNumberNamed:int (name:string) {
|
|
86
|
+
def i:int 0
|
|
87
|
+
while (i < (array_length lineNames)) {
|
|
88
|
+
if ((itemAt lineNames i) == name) {
|
|
89
|
+
return (itemAt lineNumbers i)
|
|
90
|
+
}
|
|
91
|
+
i = (i + 1)
|
|
92
|
+
}
|
|
93
|
+
return 0
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
; A "[a b]" token labels the line that comes next — line 1 before the first
|
|
97
|
+
; track, and one past the last track when it trails the list.
|
|
98
|
+
fn addLineNames:void (tok:string) {
|
|
99
|
+
def inner:string (trim (substring tok 1 ((strlen tok) - 1)))
|
|
100
|
+
def line:int ((array_length tracks) + 1)
|
|
101
|
+
def parts:[string] (EVGGridTemplate.tokenize(inner))
|
|
102
|
+
def i:int 0
|
|
103
|
+
while (i < (array_length parts)) {
|
|
104
|
+
def nm:string (itemAt parts i)
|
|
105
|
+
if ((strlen nm) > 0) {
|
|
106
|
+
if ((this.lineNumberNamed(nm)) == 0) {
|
|
107
|
+
push lineNames nm
|
|
108
|
+
push lineNumbers line
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
i = (i + 1)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
sfn isLineNameToken:boolean (tok:string) {
|
|
116
|
+
def len:int (strlen tok)
|
|
117
|
+
if (len < 2) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
if ((charAt tok 0) != 91) {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
return ((charAt tok (len - 1)) == 93)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fn count:int () {
|
|
127
|
+
return (array_length tracks)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fn trackAt:EVGGridTrack (i:int) {
|
|
131
|
+
return (itemAt tracks i)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
; "1fr 1fr", "repeat(3, 1fr)", "120px 40% 1fr"
|
|
135
|
+
sfn parse:EVGGridTemplate (spec:string) {
|
|
136
|
+
def tpl (new EVGGridTemplate())
|
|
137
|
+
def tokens:[string] (EVGGridTemplate.tokenize(spec))
|
|
138
|
+
def i:int 0
|
|
139
|
+
while (i < (array_length tokens)) {
|
|
140
|
+
def tok:string (itemAt tokens i)
|
|
141
|
+
if (EVGGridTemplate.isLineNameToken(tok)) {
|
|
142
|
+
tpl.addLineNames(tok)
|
|
143
|
+
} {
|
|
144
|
+
if (EVGGridTemplate.isRepeat(tok)) {
|
|
145
|
+
tpl.expandRepeat(tok)
|
|
146
|
+
} {
|
|
147
|
+
if (EVGGridTemplate.isMinmax(tok)) {
|
|
148
|
+
tpl.addMinmax(tok)
|
|
149
|
+
} {
|
|
150
|
+
tpl.addTrack(tok)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
i = (i + 1)
|
|
155
|
+
}
|
|
156
|
+
return tpl
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
; Split on whitespace, but only at paren depth 0 so "repeat(3, 1fr)"
|
|
160
|
+
; survives as a single token despite the space after its comma.
|
|
161
|
+
sfn tokenize:[string] (spec:string) {
|
|
162
|
+
def out:[string]
|
|
163
|
+
def len:int (strlen spec)
|
|
164
|
+
def depth:int 0
|
|
165
|
+
def start:int 0
|
|
166
|
+
def inTok:boolean false
|
|
167
|
+
def i:int 0
|
|
168
|
+
while (i < len) {
|
|
169
|
+
def c:int (charAt spec i)
|
|
170
|
+
if ((c == 40) || (c == 91)) {
|
|
171
|
+
depth = (depth + 1)
|
|
172
|
+
}
|
|
173
|
+
if ((c == 41) || (c == 93)) {
|
|
174
|
+
depth = (depth - 1)
|
|
175
|
+
}
|
|
176
|
+
def isSpace:boolean (((c == 32) || (c == 9)) || ((c == 10) || (c == 13)))
|
|
177
|
+
if (isSpace && (depth == 0)) {
|
|
178
|
+
if inTok {
|
|
179
|
+
push out (substring spec start i)
|
|
180
|
+
inTok = false
|
|
181
|
+
}
|
|
182
|
+
} {
|
|
183
|
+
if (inTok == false) {
|
|
184
|
+
start = i
|
|
185
|
+
inTok = true
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
i = (i + 1)
|
|
189
|
+
}
|
|
190
|
+
if inTok {
|
|
191
|
+
push out (substring spec start len)
|
|
192
|
+
}
|
|
193
|
+
return out
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
sfn isRepeat:boolean (tok:string) {
|
|
197
|
+
if ((strlen tok) < 8) {
|
|
198
|
+
return false
|
|
199
|
+
}
|
|
200
|
+
return ((substring tok 0 7) == "repeat(")
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
; repeat(N, <track list>) -> the track list N times.
|
|
204
|
+
fn expandRepeat:void (tok:string) {
|
|
205
|
+
def len:int (strlen tok)
|
|
206
|
+
def close:int (len - 1)
|
|
207
|
+
if ((charAt tok close) != 41) {
|
|
208
|
+
hadError = true
|
|
209
|
+
errorText = ("Malformed repeat(): " + tok)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
def inner:string (substring tok 7 close)
|
|
213
|
+
def comma:int 0 - 1
|
|
214
|
+
def j:int 0
|
|
215
|
+
while (j < (strlen inner)) {
|
|
216
|
+
if ((charAt inner j) == 44) {
|
|
217
|
+
comma = j
|
|
218
|
+
j = (strlen inner)
|
|
219
|
+
} {
|
|
220
|
+
j = (j + 1)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (comma < 0) {
|
|
224
|
+
hadError = true
|
|
225
|
+
errorText = ("repeat() needs a count and a track list: " + tok)
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
def countStr:string (trim (substring inner 0 comma))
|
|
229
|
+
def listStr:string (trim (substring inner (comma + 1) (strlen inner)))
|
|
230
|
+
def countVal@(optional):double (to_double countStr)
|
|
231
|
+
def n:int 0
|
|
232
|
+
if countVal {
|
|
233
|
+
n = (to_int (unwrap countVal))
|
|
234
|
+
} {
|
|
235
|
+
hadError = true
|
|
236
|
+
errorText = ("repeat() count is not a number: " + tok)
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
if (n < 1) {
|
|
240
|
+
hadError = true
|
|
241
|
+
errorText = ("repeat() count must be at least 1: " + tok)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
def inner2:[string] (EVGGridTemplate.tokenize(listStr))
|
|
245
|
+
def r:int 0
|
|
246
|
+
while (r < n) {
|
|
247
|
+
def k:int 0
|
|
248
|
+
while (k < (array_length inner2)) {
|
|
249
|
+
; Nested repeat() is out of scope, but minmax() inside repeat()
|
|
250
|
+
; is the ordinary way to write a responsive album grid.
|
|
251
|
+
def innerTok:string (itemAt inner2 k)
|
|
252
|
+
if (EVGGridTemplate.isMinmax(innerTok)) {
|
|
253
|
+
this.addMinmax(innerTok)
|
|
254
|
+
} {
|
|
255
|
+
this.addTrack(innerTok)
|
|
256
|
+
}
|
|
257
|
+
k = (k + 1)
|
|
258
|
+
}
|
|
259
|
+
r = (r + 1)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
sfn isMinmax:boolean (tok:string) {
|
|
264
|
+
if ((strlen tok) < 8) {
|
|
265
|
+
return false
|
|
266
|
+
}
|
|
267
|
+
return ((substring tok 0 7) == "minmax(")
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
; minmax(<min>, <max>): the track sizes as its max but is clamped into the
|
|
271
|
+
; range once the fr share is known. A fixed min with an fr max is the common
|
|
272
|
+
; photo-grid case — "at least 120px, otherwise share what is left".
|
|
273
|
+
fn addMinmax:void (tok:string) {
|
|
274
|
+
def len:int (strlen tok)
|
|
275
|
+
def close:int (len - 1)
|
|
276
|
+
if ((charAt tok close) != 41) {
|
|
277
|
+
hadError = true
|
|
278
|
+
errorText = ("Malformed minmax(): " + tok)
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
def inner:string (substring tok 7 close)
|
|
282
|
+
def comma:int 0 - 1
|
|
283
|
+
def j:int 0
|
|
284
|
+
while (j < (strlen inner)) {
|
|
285
|
+
if ((charAt inner j) == 44) {
|
|
286
|
+
comma = j
|
|
287
|
+
j = (strlen inner)
|
|
288
|
+
} {
|
|
289
|
+
j = (j + 1)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (comma < 0) {
|
|
293
|
+
hadError = true
|
|
294
|
+
errorText = ("minmax() needs two values: " + tok)
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
def minStr:string (trim (substring inner 0 comma))
|
|
298
|
+
def maxStr:string (trim (substring inner (comma + 1) (strlen inner)))
|
|
299
|
+
|
|
300
|
+
; The max decides how the track grows; the min is a floor applied after.
|
|
301
|
+
def before:int (array_length tracks)
|
|
302
|
+
this.addTrack(maxStr)
|
|
303
|
+
if ((array_length tracks) == before) {
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
def track:EVGGridTrack (itemAt tracks ((array_length tracks) - 1))
|
|
307
|
+
if ((EVGGridTemplate.isFrToken(minStr)) == false) {
|
|
308
|
+
track.minUnit = (EVGUnit.parse(minStr))
|
|
309
|
+
track.hasMin = track.minUnit.isSet
|
|
310
|
+
}
|
|
311
|
+
if ((EVGGridTemplate.isFrToken(maxStr)) == false) {
|
|
312
|
+
track.maxUnit = (EVGUnit.parse(maxStr))
|
|
313
|
+
track.hasMax = track.maxUnit.isSet
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
sfn isFrToken:boolean (tok:string) {
|
|
318
|
+
def len:int (strlen tok)
|
|
319
|
+
if (len < 2) {
|
|
320
|
+
return false
|
|
321
|
+
}
|
|
322
|
+
return ((substring tok (len - 2) len) == "fr")
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
fn addTrack:void (tok:string) {
|
|
326
|
+
def t:string (trim tok)
|
|
327
|
+
def len:int (strlen t)
|
|
328
|
+
if (len == 0) {
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
def track (new EVGGridTrack())
|
|
332
|
+
|
|
333
|
+
; `auto` is an intrinsic track: sized to the content of whatever lands
|
|
334
|
+
; in it. It used to be 1fr, which is predictable but not what CSS does.
|
|
335
|
+
if (t == "auto") {
|
|
336
|
+
track.kind = 3
|
|
337
|
+
push tracks track
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
; fit-content(limit) — an intrinsic track with a ceiling.
|
|
342
|
+
if (EVGGridTemplate.isFitContent(t)) {
|
|
343
|
+
def inner:string (trim (substring t 12 (len - 1)))
|
|
344
|
+
def lim:EVGUnit (EVGUnit.parse(inner))
|
|
345
|
+
if (lim.isSet == false) {
|
|
346
|
+
hadError = true
|
|
347
|
+
errorText = ("Unsupported fit-content() limit: " + inner)
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
track.kind = 3
|
|
351
|
+
track.hasFitLimit = true
|
|
352
|
+
track.fitLimit = lim
|
|
353
|
+
push tracks track
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (len > 2) {
|
|
358
|
+
if ((substring t (len - 2) len) == "fr") {
|
|
359
|
+
def numStr:string (substring t 0 (len - 2))
|
|
360
|
+
def frVal@(optional):double (to_double numStr)
|
|
361
|
+
if frVal {
|
|
362
|
+
track.kind = 2
|
|
363
|
+
track.value = (unwrap frVal)
|
|
364
|
+
push tracks track
|
|
365
|
+
return
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (t == "fr") {
|
|
370
|
+
track.kind = 2
|
|
371
|
+
track.value = 1.0
|
|
372
|
+
push tracks track
|
|
373
|
+
return
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
def unit:EVGUnit (EVGUnit.parse(t))
|
|
377
|
+
if (unit.isSet == false) {
|
|
378
|
+
hadError = true
|
|
379
|
+
errorText = ("Unsupported track size: " + t)
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
if (unit.unitType == 1) {
|
|
383
|
+
track.kind = 1
|
|
384
|
+
track.value = unit.value
|
|
385
|
+
} {
|
|
386
|
+
track.kind = 0
|
|
387
|
+
track.value = unit.value
|
|
388
|
+
}
|
|
389
|
+
push tracks track
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
; Resolve every track to pixels inside `available`, which must already have
|
|
393
|
+
; the gaps subtracted. Fixed and percentage tracks take their size first;
|
|
394
|
+
; whatever is left is split between the fr tracks in proportion.
|
|
395
|
+
; Does any track need to know what is in it?
|
|
396
|
+
fn hasIntrinsicTrack:boolean () {
|
|
397
|
+
def i:int 0
|
|
398
|
+
while (i < (array_length tracks)) {
|
|
399
|
+
def t:EVGGridTrack (itemAt tracks i)
|
|
400
|
+
if (t.kind == 3) {
|
|
401
|
+
return true
|
|
402
|
+
}
|
|
403
|
+
i = (i + 1)
|
|
404
|
+
}
|
|
405
|
+
return false
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
sfn isFitContent:boolean (tok:string) {
|
|
409
|
+
if ((strlen tok) < 14) {
|
|
410
|
+
return false
|
|
411
|
+
}
|
|
412
|
+
if ((substring tok 0 12) != "fit-content(") {
|
|
413
|
+
return false
|
|
414
|
+
}
|
|
415
|
+
return ((charAt tok ((strlen tok) - 1)) == 41)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
; Size the tracks with no content information — every intrinsic track ends
|
|
419
|
+
; up at zero. Callers that know what is in the tracks use resolveWithContent.
|
|
420
|
+
fn resolve:void (available:double) {
|
|
421
|
+
def empty:[double]
|
|
422
|
+
def empty2:[double]
|
|
423
|
+
this.resolveWithContent(available empty empty2)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
; `content` and `minContent` give each track's max-content and min-content
|
|
427
|
+
; width by index — the widest item placed in it, and the narrowest that
|
|
428
|
+
; item can be squeezed to. Shorter than the track list (or empty) means the
|
|
429
|
+
; rest have no content.
|
|
430
|
+
fn resolveWithContent:void (available:double content:[double] minContent:[double]) {
|
|
431
|
+
def n:int (array_length tracks)
|
|
432
|
+
def used:double 0.0
|
|
433
|
+
def totalFr:double 0.0
|
|
434
|
+
def i:int 0
|
|
435
|
+
while (i < n) {
|
|
436
|
+
def t:EVGGridTrack (itemAt tracks i)
|
|
437
|
+
t.frozen = false
|
|
438
|
+
; Resolve any minmax() bounds against the container first, so the
|
|
439
|
+
; clamp below is in pixels like everything else.
|
|
440
|
+
if t.hasMin {
|
|
441
|
+
t.minUnit.resolve(available 16.0)
|
|
442
|
+
}
|
|
443
|
+
if t.hasMax {
|
|
444
|
+
t.maxUnit.resolve(available 16.0)
|
|
445
|
+
}
|
|
446
|
+
if (t.kind == 0) {
|
|
447
|
+
t.sizePx = t.value
|
|
448
|
+
used = (used + t.sizePx)
|
|
449
|
+
t.frozen = true
|
|
450
|
+
}
|
|
451
|
+
if (t.kind == 1) {
|
|
452
|
+
t.sizePx = ((available * t.value) / 100.0)
|
|
453
|
+
used = (used + t.sizePx)
|
|
454
|
+
t.frozen = true
|
|
455
|
+
}
|
|
456
|
+
if (t.kind == 2) {
|
|
457
|
+
totalFr = (totalFr + t.value)
|
|
458
|
+
}
|
|
459
|
+
if (t.kind == 3) {
|
|
460
|
+
; Intrinsic: the widest thing in the track, capped by a
|
|
461
|
+
; fit-content() limit if there is one. CSS floors that clamp at
|
|
462
|
+
; min-content, but an item that cannot wrap has min-content ==
|
|
463
|
+
; max-content, and this engine only measures items that cannot
|
|
464
|
+
; — so the floor is the measurement itself and clamping below
|
|
465
|
+
; it would make the item overflow its own track.
|
|
466
|
+
def c:double 0.0
|
|
467
|
+
if (i < (array_length content)) {
|
|
468
|
+
c = (itemAt content i)
|
|
469
|
+
}
|
|
470
|
+
if t.hasFitLimit {
|
|
471
|
+
t.fitLimit.resolve(available 16.0)
|
|
472
|
+
if (c > t.fitLimit.pixels) {
|
|
473
|
+
c = t.fitLimit.pixels
|
|
474
|
+
}
|
|
475
|
+
; The clamp is floored at min-content: an item that cannot
|
|
476
|
+
; be made narrower than the limit keeps its size and the
|
|
477
|
+
; track grows to hold it, rather than the item spilling out
|
|
478
|
+
; of its own cell. For an item with a definite width that
|
|
479
|
+
; floor IS its width, which is why fit-content(100px)
|
|
480
|
+
; around a 200px box measures 200 in a browser.
|
|
481
|
+
if (i < (array_length minContent)) {
|
|
482
|
+
def floorPx:double (itemAt minContent i)
|
|
483
|
+
if (c < floorPx) {
|
|
484
|
+
c = floorPx
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
t.sizePx = c
|
|
489
|
+
used = (used + c)
|
|
490
|
+
t.frozen = true
|
|
491
|
+
}
|
|
492
|
+
i = (i + 1)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
; Distribute the leftover across the fr tracks, then clamp against any
|
|
496
|
+
; minmax() bounds. A track that hits a bound is pinned there and the
|
|
497
|
+
; space it did not take is offered to the rest — the same freeze-and-
|
|
498
|
+
; redistribute the flex axis uses, and the reason `minmax(120px, 1fr)`
|
|
499
|
+
; can hold its floor without stealing from its neighbours silently.
|
|
500
|
+
def poolSpace:double (available - used)
|
|
501
|
+
if (poolSpace < 0.0) {
|
|
502
|
+
poolSpace = 0.0
|
|
503
|
+
}
|
|
504
|
+
def poolFr:double totalFr
|
|
505
|
+
def pass:int 0
|
|
506
|
+
def settled:boolean false
|
|
507
|
+
while ((pass <= n) && (settled == false)) {
|
|
508
|
+
settled = true
|
|
509
|
+
def j:int 0
|
|
510
|
+
while (j < n) {
|
|
511
|
+
def t2:EVGGridTrack (itemAt tracks j)
|
|
512
|
+
if ((t2.kind == 2) && (t2.frozen == false)) {
|
|
513
|
+
def size:double 0.0
|
|
514
|
+
if (poolFr > 0.0) {
|
|
515
|
+
size = ((poolSpace * t2.value) / poolFr)
|
|
516
|
+
}
|
|
517
|
+
def clamped:double size
|
|
518
|
+
if t2.hasMin {
|
|
519
|
+
if (clamped < t2.minUnit.pixels) {
|
|
520
|
+
clamped = t2.minUnit.pixels
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if t2.hasMax {
|
|
524
|
+
if (clamped > t2.maxUnit.pixels) {
|
|
525
|
+
clamped = t2.maxUnit.pixels
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
t2.sizePx = clamped
|
|
529
|
+
if (clamped != size) {
|
|
530
|
+
t2.frozen = true
|
|
531
|
+
poolSpace = (poolSpace - clamped)
|
|
532
|
+
poolFr = (poolFr - t2.value)
|
|
533
|
+
if (poolSpace < 0.0) {
|
|
534
|
+
poolSpace = 0.0
|
|
535
|
+
}
|
|
536
|
+
settled = false
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
j = (j + 1)
|
|
540
|
+
}
|
|
541
|
+
pass = (pass + 1)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
; A fixed or percentage track can still carry a minmax() floor.
|
|
545
|
+
def k:int 0
|
|
546
|
+
while (k < n) {
|
|
547
|
+
def t3:EVGGridTrack (itemAt tracks k)
|
|
548
|
+
if (t3.kind != 2) {
|
|
549
|
+
if t3.hasMin {
|
|
550
|
+
if (t3.sizePx < t3.minUnit.pixels) {
|
|
551
|
+
t3.sizePx = t3.minUnit.pixels
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if t3.hasMax {
|
|
555
|
+
if (t3.sizePx > t3.maxUnit.pixels) {
|
|
556
|
+
t3.sizePx = t3.maxUnit.pixels
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
k = (k + 1)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
; Extent of `span` tracks starting at index `from`, including the gaps
|
|
565
|
+
; between them (but not the gaps on either outer edge).
|
|
566
|
+
fn extentOf:double (from:int span:int gap:double) {
|
|
567
|
+
def total:double 0.0
|
|
568
|
+
def n:int (array_length tracks)
|
|
569
|
+
def i:int from
|
|
570
|
+
def placed:int 0
|
|
571
|
+
while ((i < n) && (placed < span)) {
|
|
572
|
+
def tk:EVGGridTrack (itemAt tracks i)
|
|
573
|
+
total = (total + tk.sizePx)
|
|
574
|
+
placed = (placed + 1)
|
|
575
|
+
i = (i + 1)
|
|
576
|
+
}
|
|
577
|
+
if (placed > 1) {
|
|
578
|
+
total = (total + ((to_double (placed - 1)) * gap))
|
|
579
|
+
}
|
|
580
|
+
return total
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
; Distance from the container's content edge to the start of track `index`.
|
|
584
|
+
fn offsetOf:double (index:int gap:double) {
|
|
585
|
+
def total:double 0.0
|
|
586
|
+
def i:int 0
|
|
587
|
+
while (i < index) {
|
|
588
|
+
def tk:EVGGridTrack (itemAt tracks i)
|
|
589
|
+
total = (total + tk.sizePx)
|
|
590
|
+
total = (total + gap)
|
|
591
|
+
i = (i + 1)
|
|
592
|
+
}
|
|
593
|
+
return total
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
; A `grid-column` / `grid-row` value.
|
|
598
|
+
; start: 1-based grid line, or 0 for "wherever auto-flow puts it"
|
|
599
|
+
; span : number of tracks covered, at least 1
|
|
600
|
+
; grid-template-areas — a picture of the page in names:
|
|
601
|
+
;
|
|
602
|
+
; grid-template-areas="'hero hero' 'left right'"
|
|
603
|
+
;
|
|
604
|
+
; Each quoted string is a row, each name a column. An item claims a region with
|
|
605
|
+
; grid-area="hero". A name repeated across adjacent cells forms one rectangle,
|
|
606
|
+
; which is the whole point: the layout reads as the shape it produces.
|
|
607
|
+
;
|
|
608
|
+
; "." is the CSS spelling for a deliberately empty cell.
|
|
609
|
+
class EVGGridAreas {
|
|
610
|
+
def names:[string]
|
|
611
|
+
def rowStart:[int]
|
|
612
|
+
def colStart:[int]
|
|
613
|
+
def rowSpan:[int]
|
|
614
|
+
def colSpan:[int]
|
|
615
|
+
def columns:int 0
|
|
616
|
+
def rows:int 0
|
|
617
|
+
def hadError:boolean false
|
|
618
|
+
def errorText:string ""
|
|
619
|
+
|
|
620
|
+
Constructor () {
|
|
621
|
+
columns = 0
|
|
622
|
+
rows = 0
|
|
623
|
+
hadError = false
|
|
624
|
+
errorText = ""
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
fn count:int () {
|
|
628
|
+
return (array_length names)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
fn indexOfName:int (name:string) {
|
|
632
|
+
def i:int 0
|
|
633
|
+
while (i < (array_length names)) {
|
|
634
|
+
if ((itemAt names i) == name) {
|
|
635
|
+
return i
|
|
636
|
+
}
|
|
637
|
+
i = (i + 1)
|
|
638
|
+
}
|
|
639
|
+
return 0 - 1
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
; Split the spec into rows. Both quote styles are accepted, and a row may
|
|
643
|
+
; also be separated by a newline so a stylesheet can lay it out readably.
|
|
644
|
+
sfn parse:EVGGridAreas (spec:string) {
|
|
645
|
+
def areas (new EVGGridAreas())
|
|
646
|
+
def rowsOut:[string]
|
|
647
|
+
def cur:string ""
|
|
648
|
+
def inQuote:boolean false
|
|
649
|
+
def quoteCh:int 0
|
|
650
|
+
def i:int 0
|
|
651
|
+
def len:int (strlen spec)
|
|
652
|
+
while (i < len) {
|
|
653
|
+
def c:int (charAt spec i)
|
|
654
|
+
if inQuote {
|
|
655
|
+
if (c == quoteCh) {
|
|
656
|
+
push rowsOut cur
|
|
657
|
+
cur = ""
|
|
658
|
+
inQuote = false
|
|
659
|
+
} {
|
|
660
|
+
cur = cur + (strfromcode c)
|
|
661
|
+
}
|
|
662
|
+
} {
|
|
663
|
+
if ((c == 34) || (c == 39)) {
|
|
664
|
+
inQuote = true
|
|
665
|
+
quoteCh = c
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
i = (i + 1)
|
|
669
|
+
}
|
|
670
|
+
if inQuote {
|
|
671
|
+
areas.hadError = true
|
|
672
|
+
areas.errorText = ("Unterminated row in grid-template-areas: " + spec)
|
|
673
|
+
return areas
|
|
674
|
+
}
|
|
675
|
+
if ((array_length rowsOut) == 0) {
|
|
676
|
+
areas.hadError = true
|
|
677
|
+
areas.errorText = ("grid-template-areas needs quoted rows: " + spec)
|
|
678
|
+
return areas
|
|
679
|
+
}
|
|
680
|
+
areas.build(rowsOut)
|
|
681
|
+
return areas
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
; Turn the grid of names into one rectangle per name. A name that appears in
|
|
685
|
+
; a non-rectangular pattern is reported rather than guessed at, because the
|
|
686
|
+
; result would silently overlap another area.
|
|
687
|
+
fn build:void (rowsOut:[string]) {
|
|
688
|
+
rows = (array_length rowsOut)
|
|
689
|
+
def cells:[string]
|
|
690
|
+
def r:int 0
|
|
691
|
+
while (r < rows) {
|
|
692
|
+
def toks:[string] (EVGGridTemplate.tokenize((itemAt rowsOut r)))
|
|
693
|
+
if (r == 0) {
|
|
694
|
+
columns = (array_length toks)
|
|
695
|
+
} {
|
|
696
|
+
if ((array_length toks) != columns) {
|
|
697
|
+
hadError = true
|
|
698
|
+
errorText = "grid-template-areas rows must all have the same number of columns"
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
def c:int 0
|
|
703
|
+
while (c < (array_length toks)) {
|
|
704
|
+
push cells (itemAt toks c)
|
|
705
|
+
c = (c + 1)
|
|
706
|
+
}
|
|
707
|
+
r = (r + 1)
|
|
708
|
+
}
|
|
709
|
+
if (columns == 0) {
|
|
710
|
+
hadError = true
|
|
711
|
+
errorText = "grid-template-areas has no columns"
|
|
712
|
+
return
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
def rr:int 0
|
|
716
|
+
while (rr < rows) {
|
|
717
|
+
def cc:int 0
|
|
718
|
+
while (cc < columns) {
|
|
719
|
+
def name:string (itemAt cells ((rr * columns) + cc))
|
|
720
|
+
if (name != ".") {
|
|
721
|
+
def at:int (this.indexOfName(name))
|
|
722
|
+
if (at < 0) {
|
|
723
|
+
push names name
|
|
724
|
+
push rowStart rr
|
|
725
|
+
push colStart cc
|
|
726
|
+
push rowSpan 1
|
|
727
|
+
push colSpan 1
|
|
728
|
+
} {
|
|
729
|
+
; Extend the existing rectangle to cover this cell.
|
|
730
|
+
def r0:int (itemAt rowStart at)
|
|
731
|
+
def c0:int (itemAt colStart at)
|
|
732
|
+
def rs:int (itemAt rowSpan at)
|
|
733
|
+
def cs:int (itemAt colSpan at)
|
|
734
|
+
if ((rr + 1) > (r0 + rs)) {
|
|
735
|
+
set rowSpan at ((rr + 1) - r0)
|
|
736
|
+
}
|
|
737
|
+
if ((cc + 1) > (c0 + cs)) {
|
|
738
|
+
set colSpan at ((cc + 1) - c0)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
cc = (cc + 1)
|
|
743
|
+
}
|
|
744
|
+
rr = (rr + 1)
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
; Every cell inside a name's rectangle must actually carry that name.
|
|
748
|
+
def n:int (array_length names)
|
|
749
|
+
def k:int 0
|
|
750
|
+
while (k < n) {
|
|
751
|
+
def nm:string (itemAt names k)
|
|
752
|
+
def r0:int (itemAt rowStart k)
|
|
753
|
+
def c0:int (itemAt colStart k)
|
|
754
|
+
def rs:int (itemAt rowSpan k)
|
|
755
|
+
def cs:int (itemAt colSpan k)
|
|
756
|
+
def a:int 0
|
|
757
|
+
while (a < rs) {
|
|
758
|
+
def b:int 0
|
|
759
|
+
while (b < cs) {
|
|
760
|
+
def idx:int (((r0 + a) * columns) + (c0 + b))
|
|
761
|
+
if ((itemAt cells idx) != nm) {
|
|
762
|
+
hadError = true
|
|
763
|
+
errorText = ("Area \"" + nm + "\" is not a rectangle in grid-template-areas")
|
|
764
|
+
return
|
|
765
|
+
}
|
|
766
|
+
b = (b + 1)
|
|
767
|
+
}
|
|
768
|
+
a = (a + 1)
|
|
769
|
+
}
|
|
770
|
+
k = (k + 1)
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
class EVGGridPlacement {
|
|
776
|
+
def start:int 0
|
|
777
|
+
def span:int 1
|
|
778
|
+
; A placement this parser cannot honour. Named lines ("grid-column:
|
|
779
|
+
; sidebar") are the case that matters: they used to fall through
|
|
780
|
+
; lineNumber's `to_double` and come back as 0, which is indistinguishable
|
|
781
|
+
; from auto-placement — the item quietly landed wherever the flow put it
|
|
782
|
+
; and nothing said the name had been ignored.
|
|
783
|
+
def hadError:boolean false
|
|
784
|
+
def errorText:string ""
|
|
785
|
+
; Line names, kept unresolved: a placement is parsed from the item, but the
|
|
786
|
+
; names live on the container's template, which only the layout can see.
|
|
787
|
+
; EVGLayout calls resolveNames() once it has both.
|
|
788
|
+
def startName:string ""
|
|
789
|
+
def endName:string ""
|
|
790
|
+
; A numeric end line, so span can be recomputed if the start moves when a
|
|
791
|
+
; name resolves. 0 = none.
|
|
792
|
+
def endLine:int 0
|
|
793
|
+
; True when the span came from an explicit "span N", which outranks any
|
|
794
|
+
; end line.
|
|
795
|
+
def spanExplicit:boolean false
|
|
796
|
+
|
|
797
|
+
Constructor () {
|
|
798
|
+
start = 0
|
|
799
|
+
span = 1
|
|
800
|
+
hadError = false
|
|
801
|
+
errorText = ""
|
|
802
|
+
startName = ""
|
|
803
|
+
endName = ""
|
|
804
|
+
endLine = 0
|
|
805
|
+
spanExplicit = false
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
; "span 2" | "2" | "2 / 4" | "2 / span 3" | "" (auto)
|
|
809
|
+
sfn parse:EVGGridPlacement (spec:string) {
|
|
810
|
+
def p (new EVGGridPlacement())
|
|
811
|
+
def s:string (trim spec)
|
|
812
|
+
if ((strlen s) == 0) {
|
|
813
|
+
return p
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
; Split on '/' into at most two sides.
|
|
817
|
+
def slash:int 0 - 1
|
|
818
|
+
def i:int 0
|
|
819
|
+
while (i < (strlen s)) {
|
|
820
|
+
if ((charAt s i) == 47) {
|
|
821
|
+
slash = i
|
|
822
|
+
i = (strlen s)
|
|
823
|
+
} {
|
|
824
|
+
i = (i + 1)
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (slash < 0) {
|
|
829
|
+
; One side: "span N", a line number, or a line name.
|
|
830
|
+
if (EVGGridPlacement.isSpan(s)) {
|
|
831
|
+
p.span = (EVGGridPlacement.spanCount(s))
|
|
832
|
+
p.spanExplicit = true
|
|
833
|
+
} {
|
|
834
|
+
p.takeStart(s)
|
|
835
|
+
}
|
|
836
|
+
return p
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
def lhs:string (trim (substring s 0 slash))
|
|
840
|
+
def rhs:string (trim (substring s (slash + 1) (strlen s)))
|
|
841
|
+
p.takeStart(lhs)
|
|
842
|
+
if (EVGGridPlacement.isSpan(rhs)) {
|
|
843
|
+
p.span = (EVGGridPlacement.spanCount(rhs))
|
|
844
|
+
p.spanExplicit = true
|
|
845
|
+
} {
|
|
846
|
+
p.takeEnd(rhs)
|
|
847
|
+
}
|
|
848
|
+
p.applyEndLine()
|
|
849
|
+
return p
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
; A side is a line number, a line name, or nothing this subset can use.
|
|
853
|
+
; Something that looks like a number but is not a usable one — 0, or a
|
|
854
|
+
; negative line, CSS's count-from-the-end form — is rejected outright
|
|
855
|
+
; rather than treated as a name it plainly is not.
|
|
856
|
+
fn takeStart:void (token:string) {
|
|
857
|
+
if (EVGGridPlacement.isNumericToken(token)) {
|
|
858
|
+
start = (EVGGridPlacement.lineNumber(token))
|
|
859
|
+
if (start == 0) {
|
|
860
|
+
this.reject(token)
|
|
861
|
+
}
|
|
862
|
+
} {
|
|
863
|
+
startName = token
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
fn takeEnd:void (token:string) {
|
|
868
|
+
if (EVGGridPlacement.isNumericToken(token)) {
|
|
869
|
+
endLine = (EVGGridPlacement.lineNumber(token))
|
|
870
|
+
if (endLine == 0) {
|
|
871
|
+
this.reject(token)
|
|
872
|
+
}
|
|
873
|
+
} {
|
|
874
|
+
endName = token
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
; "2 / 4" covers the tracks between lines 2 and 4, i.e. two tracks.
|
|
879
|
+
fn applyEndLine:void () {
|
|
880
|
+
if spanExplicit {
|
|
881
|
+
return
|
|
882
|
+
}
|
|
883
|
+
if (start < 1) {
|
|
884
|
+
return
|
|
885
|
+
}
|
|
886
|
+
if (endLine > start) {
|
|
887
|
+
span = (endLine - start)
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
; Point the named sides at real lines, now that the container's template is
|
|
892
|
+
; known. A name the template does not define leaves the item auto-placed
|
|
893
|
+
; and is reported, the same as any other declaration the engine cannot
|
|
894
|
+
; honour.
|
|
895
|
+
fn resolveNames:void (tpl:EVGGridTemplate) {
|
|
896
|
+
if ((strlen startName) > 0) {
|
|
897
|
+
def n:int (tpl.lineNumberNamed(startName))
|
|
898
|
+
if (n > 0) {
|
|
899
|
+
start = n
|
|
900
|
+
startName = ""
|
|
901
|
+
} {
|
|
902
|
+
this.rejectName(startName)
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if ((strlen endName) > 0) {
|
|
906
|
+
def e:int (tpl.lineNumberNamed(endName))
|
|
907
|
+
if (e > 0) {
|
|
908
|
+
endLine = e
|
|
909
|
+
endName = ""
|
|
910
|
+
} {
|
|
911
|
+
this.rejectName(endName)
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
this.applyEndLine()
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
sfn isNumericToken:boolean (s:string) {
|
|
918
|
+
if ((strlen s) == 0) {
|
|
919
|
+
return false
|
|
920
|
+
}
|
|
921
|
+
def c:int (charAt s 0)
|
|
922
|
+
if ((c >= 48) && (c <= 57)) {
|
|
923
|
+
return true
|
|
924
|
+
}
|
|
925
|
+
return ((c == 45) || (c == 43))
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
fn rejectName:void (name:string) {
|
|
929
|
+
if hadError {
|
|
930
|
+
return
|
|
931
|
+
}
|
|
932
|
+
hadError = true
|
|
933
|
+
errorText = ("no line named \"" + name + "\"; the item was auto-placed")
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
; A token that looks numeric but is not a line this engine can use: 0, or
|
|
937
|
+
; a negative line, which CSS counts from the end of the grid.
|
|
938
|
+
fn reject:void (token:string) {
|
|
939
|
+
if hadError {
|
|
940
|
+
return
|
|
941
|
+
}
|
|
942
|
+
hadError = true
|
|
943
|
+
errorText = ("unsupported line \"" + token + "\" (negative line numbers are not supported); the item was auto-placed")
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
sfn isSpan:boolean (s:string) {
|
|
947
|
+
if ((strlen s) < 4) {
|
|
948
|
+
return false
|
|
949
|
+
}
|
|
950
|
+
return ((substring s 0 4) == "span")
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
sfn spanCount:int (s:string) {
|
|
954
|
+
def rest:string (trim (substring s 4 (strlen s)))
|
|
955
|
+
def v@(optional):double (to_double rest)
|
|
956
|
+
if v {
|
|
957
|
+
def n:int (to_int (unwrap v))
|
|
958
|
+
if (n >= 1) {
|
|
959
|
+
return n
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return 1
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
sfn lineNumber:int (s:string) {
|
|
966
|
+
def v@(optional):double (to_double s)
|
|
967
|
+
if v {
|
|
968
|
+
def n:int (to_int (unwrap v))
|
|
969
|
+
if (n >= 1) {
|
|
970
|
+
return n
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return 0
|
|
974
|
+
}
|
|
975
|
+
}
|