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,728 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EVGTransition — the stylesheet's values, arrived at over time
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; `transition: background-color 150ms` means: when this property's value
|
|
8
|
+
; changes, do not jump to the new one — leave from where you are and get there
|
|
9
|
+
; in 150ms. That is the whole feature, and it is worth being precise about the
|
|
10
|
+
; three things it needs, because a hand-rolled version usually gets the third
|
|
11
|
+
; one wrong:
|
|
12
|
+
;
|
|
13
|
+
; 1. the value the sheet WANTS. That is what `applyTree` already writes.
|
|
14
|
+
; 2. the value the element is SHOWING. That is what the painter reads, and
|
|
15
|
+
; while a flight is in the air it is neither end.
|
|
16
|
+
; 3. where a REVERSAL starts. Not the original value — where the flight had
|
|
17
|
+
; actually got to. A hover that leaves half way through must fade back
|
|
18
|
+
; from half way, and starting from the target is the flicker every naive
|
|
19
|
+
; implementation has.
|
|
20
|
+
;
|
|
21
|
+
; So the caller does two things per frame, and they are separate on purpose:
|
|
22
|
+
;
|
|
23
|
+
; reconcile(el) after applying the stylesheet: notice what changed, start
|
|
24
|
+
; or retarget a flight, and put the SHOWING value back.
|
|
25
|
+
; advance(el dt) move the clock and write the new showing value.
|
|
26
|
+
;
|
|
27
|
+
; It reads no clock of its own. A frame is however long the host says it is,
|
|
28
|
+
; which is what makes every one of these testable to the millisecond and what
|
|
29
|
+
; lets a PDF backend render frame 7 of an animation without a browser.
|
|
30
|
+
; ==============================================================================
|
|
31
|
+
|
|
32
|
+
Import "EVGElement.rgr"
|
|
33
|
+
Import "EVGColor.rgr"
|
|
34
|
+
Import "EVGEasing.rgr"
|
|
35
|
+
|
|
36
|
+
; One entry of the shorthand, resolved for one property.
|
|
37
|
+
class EVGTimingSpec {
|
|
38
|
+
; False when the property is not mentioned at all — which is a different
|
|
39
|
+
; answer from "mentioned with a duration of zero", and the two have to stay
|
|
40
|
+
; distinguishable or `transition: all 200ms, opacity 0s` cannot work.
|
|
41
|
+
def found:boolean false
|
|
42
|
+
def durationMs:double 0.0
|
|
43
|
+
def delayMs:double 0.0
|
|
44
|
+
; The default really is linear here: an unset `EVGEasing` is
|
|
45
|
+
; cubic-bezier(0, 0, 1, 1). CSS's own default is `ease`, but that applies
|
|
46
|
+
; to the shorthand's missing value, not to a missing shorthand.
|
|
47
|
+
def easing:EVGEasing (new EVGEasing())
|
|
48
|
+
def ok:boolean true
|
|
49
|
+
|
|
50
|
+
Constructor () {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class EVGTransition {
|
|
55
|
+
|
|
56
|
+
Constructor () {
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
; --- what the sheet asked for ------------------------------------------------
|
|
60
|
+
|
|
61
|
+
; The full shorthand, per property:
|
|
62
|
+
;
|
|
63
|
+
; transition: background-color 140ms ease-out 40ms, transform 200ms
|
|
64
|
+
;
|
|
65
|
+
; Order is the CSS one and it is only half positional: the property name
|
|
66
|
+
; and the timing function can sit anywhere in an entry, but the two TIMES
|
|
67
|
+
; are told apart by position — the first is the duration, the second the
|
|
68
|
+
; delay. There is no other way to distinguish them, which is why
|
|
69
|
+
; `transition: opacity 200ms` and `transition: opacity 0s 200ms` mean
|
|
70
|
+
; completely different things.
|
|
71
|
+
;
|
|
72
|
+
; The list is scanned to the END rather than returning on the first hit, so
|
|
73
|
+
; a later entry overrides an earlier one. That is what makes
|
|
74
|
+
; `transition: all 200ms, opacity 0s` mean "everything but opacity", which
|
|
75
|
+
; is a real and useful thing to write.
|
|
76
|
+
sfn specFor:EVGTimingSpec (spec:string property:string) {
|
|
77
|
+
def out (new EVGTimingSpec())
|
|
78
|
+
if ((strlen spec) == 0) {
|
|
79
|
+
return out
|
|
80
|
+
}
|
|
81
|
+
; Splitting on commas has to respect parentheses: `cubic-bezier(0.25,
|
|
82
|
+
; 0.1, 0.25, 1)` is one token with three commas inside it.
|
|
83
|
+
def parts:[string] (EVGEasing.splitTop(spec 44))
|
|
84
|
+
def i:int 0
|
|
85
|
+
while (i < (array_length parts)) {
|
|
86
|
+
def one:string (trim (itemAt parts i))
|
|
87
|
+
def words:[string] (EVGEasing.splitWordsTop(one))
|
|
88
|
+
def name:string ""
|
|
89
|
+
def fnText:string ""
|
|
90
|
+
def times:[double]
|
|
91
|
+
def w:int 0
|
|
92
|
+
while (w < (array_length words)) {
|
|
93
|
+
def word:string (itemAt words w)
|
|
94
|
+
if (EVGEasing.looksLikeFunction(word)) {
|
|
95
|
+
fnText = word
|
|
96
|
+
} {
|
|
97
|
+
if (EVGTransition.isTime(word)) {
|
|
98
|
+
push times (EVGTransition.parseMs(word))
|
|
99
|
+
} {
|
|
100
|
+
if ((strlen name) == 0) {
|
|
101
|
+
name = word
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
w = (w + 1)
|
|
106
|
+
}
|
|
107
|
+
if ((name == property) || (name == "all")) {
|
|
108
|
+
out.found = true
|
|
109
|
+
out.durationMs = 0.0
|
|
110
|
+
out.delayMs = 0.0
|
|
111
|
+
if ((array_length times) > 0) {
|
|
112
|
+
out.durationMs = (itemAt times 0)
|
|
113
|
+
}
|
|
114
|
+
if ((array_length times) > 1) {
|
|
115
|
+
out.delayMs = (itemAt times 1)
|
|
116
|
+
}
|
|
117
|
+
out.easing = (EVGEasing.parse(fnText))
|
|
118
|
+
out.ok = out.easing.ok
|
|
119
|
+
}
|
|
120
|
+
i = (i + 1)
|
|
121
|
+
}
|
|
122
|
+
return out
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
; Kept because a great deal of code and several tests ask only "how long":
|
|
126
|
+
; -1 means the property is not transitioned at all, which is a different
|
|
127
|
+
; answer from 0.
|
|
128
|
+
sfn durationFor:double (spec:string property:string) {
|
|
129
|
+
def s:EVGTimingSpec (EVGTransition.specFor(spec property))
|
|
130
|
+
if (s.found == false) {
|
|
131
|
+
return (0.0 - 1.0)
|
|
132
|
+
}
|
|
133
|
+
return s.durationMs
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
; A duration, or a property name? `200ms`, `0.15s` and a bare `0` are
|
|
137
|
+
; times; `opacity` and `background-color` are not. Requiring the numeric
|
|
138
|
+
; part to parse is what stops a property whose name happens to end in `s`
|
|
139
|
+
; from being read as a duration.
|
|
140
|
+
sfn isTime:boolean (word:string) {
|
|
141
|
+
def t:string (trim word)
|
|
142
|
+
def n:int (strlen t)
|
|
143
|
+
if (n == 0) {
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
if (n > 2) {
|
|
147
|
+
if ((substring t (n - 2) n) == "ms") {
|
|
148
|
+
def a@(optional):double (to_double (substring t 0 (n - 2)))
|
|
149
|
+
if a { return true }
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (n > 1) {
|
|
154
|
+
if ((substring t (n - 1) n) == "s") {
|
|
155
|
+
def b@(optional):double (to_double (substring t 0 (n - 1)))
|
|
156
|
+
if b { return true }
|
|
157
|
+
return false
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
def c@(optional):double (to_double t)
|
|
161
|
+
if c { return true }
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
; "150ms" or "0.15s". A bare number is milliseconds, which is the reading
|
|
166
|
+
; that cannot silently be a thousand times wrong.
|
|
167
|
+
sfn parseMs:double (text:string) {
|
|
168
|
+
def t:string (trim text)
|
|
169
|
+
def n:int (strlen t)
|
|
170
|
+
if (n == 0) {
|
|
171
|
+
return 0.0
|
|
172
|
+
}
|
|
173
|
+
if (n > 2) {
|
|
174
|
+
if ((substring t (n - 2) n) == "ms") {
|
|
175
|
+
def v@(optional):double (to_double (substring t 0 (n - 2)))
|
|
176
|
+
if v {
|
|
177
|
+
return (unwrap v)
|
|
178
|
+
}
|
|
179
|
+
return 0.0
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (n > 1) {
|
|
183
|
+
if ((substring t (n - 1) n) == "s") {
|
|
184
|
+
def v2@(optional):double (to_double (substring t 0 (n - 1)))
|
|
185
|
+
if v2 {
|
|
186
|
+
return ((unwrap v2) * 1000.0)
|
|
187
|
+
}
|
|
188
|
+
return 0.0
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
def v3@(optional):double (to_double t)
|
|
192
|
+
if v3 {
|
|
193
|
+
return (unwrap v3)
|
|
194
|
+
}
|
|
195
|
+
return 0.0
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
; --- the flights on an element -------------------------------------------------
|
|
199
|
+
|
|
200
|
+
fn flightFor@(optional):EVGFlight (el:EVGElement property:string) {
|
|
201
|
+
def i:int 0
|
|
202
|
+
while (i < (array_length el.transitions)) {
|
|
203
|
+
def f:EVGFlight (itemAt el.transitions i)
|
|
204
|
+
if (f.property == property) {
|
|
205
|
+
def hit@(optional):EVGFlight f
|
|
206
|
+
return hit
|
|
207
|
+
}
|
|
208
|
+
i = (i + 1)
|
|
209
|
+
}
|
|
210
|
+
def miss@(optional):EVGFlight
|
|
211
|
+
return miss
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
sfn sameColor:boolean (a:EVGColor b:EVGColor) {
|
|
215
|
+
if ((to_int a.r) != (to_int b.r)) { return false }
|
|
216
|
+
if ((to_int a.g) != (to_int b.g)) { return false }
|
|
217
|
+
if ((to_int a.b) != (to_int b.b)) { return false }
|
|
218
|
+
if ((to_int (a.a * 255.0)) != (to_int (b.a * 255.0))) { return false }
|
|
219
|
+
return true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
; Colour interpolation, in PREMULTIPLIED alpha — which is what CSS does and
|
|
223
|
+
; is not a detail anyone gets to skip.
|
|
224
|
+
;
|
|
225
|
+
; `transparent` is rgba(0, 0, 0, 0): a BLACK with no alpha. Mix the four
|
|
226
|
+
; channels independently and every fade-in from no background at all drags
|
|
227
|
+
; through a dark grey on its way to the colour — the classic "fade through
|
|
228
|
+
; black", and it looks like dirt on the screen rather than like a bug.
|
|
229
|
+
;
|
|
230
|
+
; Multiplying by alpha first makes the invisible end carry no colour of its
|
|
231
|
+
; own, so the mix travels along the visible colour and only its opacity
|
|
232
|
+
; changes. Measured: Chromium fading `transparent` to rgb(244, 241, 254)
|
|
233
|
+
; reports rgba(244, 241, 254, 0.25) a quarter of the way, not a grey.
|
|
234
|
+
;
|
|
235
|
+
; Where both ends are opaque the premultiplication is the identity, so
|
|
236
|
+
; nothing about the ordinary case changes.
|
|
237
|
+
sfn mixColor:EVGColor (from:EVGColor to:EVGColor t:double) {
|
|
238
|
+
def c (new EVGColor())
|
|
239
|
+
def fa:double from.a
|
|
240
|
+
def ta:double to.a
|
|
241
|
+
def a:double (fa + ((ta - fa) * t))
|
|
242
|
+
def pr:double ((from.r * fa) + (((to.r * ta) - (from.r * fa)) * t))
|
|
243
|
+
def pg:double ((from.g * fa) + (((to.g * ta) - (from.g * fa)) * t))
|
|
244
|
+
def pb:double ((from.b * fa) + (((to.b * ta) - (from.b * fa)) * t))
|
|
245
|
+
if (a > 0.0001) {
|
|
246
|
+
c.r = (pr / a)
|
|
247
|
+
c.g = (pg / a)
|
|
248
|
+
c.b = (pb / a)
|
|
249
|
+
} {
|
|
250
|
+
; Fully invisible, so there is nothing to divide out. The
|
|
251
|
+
; premultiplied value is what is left, and it is also what the
|
|
252
|
+
; browser reports: `transparent` at the very start of a fade comes
|
|
253
|
+
; back as rgba(0, 0, 0, 0) and not as the destination at zero alpha.
|
|
254
|
+
; Nothing is painted either way — this is about agreeing on the
|
|
255
|
+
; number rather than about the picture.
|
|
256
|
+
c.r = pr
|
|
257
|
+
c.g = pg
|
|
258
|
+
c.b = pb
|
|
259
|
+
}
|
|
260
|
+
c.a = a
|
|
261
|
+
c.isSet = true
|
|
262
|
+
return c
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
; The value the element is SHOWING for a flight at its current progress.
|
|
266
|
+
fn showColor:EVGColor (f:EVGFlight) {
|
|
267
|
+
return (EVGTransition.mixColor((unwrap f.fromColor) (unwrap f.toColor) (f.eased())))
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
fn showNumber:double (f:EVGFlight) {
|
|
271
|
+
return (f.fromNumber + ((f.toNumber - f.fromNumber) * (f.eased())))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
; --- reconcile ------------------------------------------------------------------
|
|
275
|
+
; Called after the stylesheet has written what it wants. The element's field
|
|
276
|
+
; holds the TARGET; a flight, if there is one, holds where it is actually at.
|
|
277
|
+
|
|
278
|
+
fn reconcile:void (el:EVGElement) {
|
|
279
|
+
if el.backgroundColor {
|
|
280
|
+
this.reconcileColor(el "background-color" (unwrap el.backgroundColor))
|
|
281
|
+
}
|
|
282
|
+
if el.color {
|
|
283
|
+
this.reconcileColor(el "color" (unwrap el.color))
|
|
284
|
+
}
|
|
285
|
+
this.reconcileNumber(el "opacity" el.opacity)
|
|
286
|
+
; `transform` is one CSS property and four interpolable numbers. They
|
|
287
|
+
; are kept as separate flights under separate keys but all look the
|
|
288
|
+
; DECLARED duration up under the name the sheet used, so
|
|
289
|
+
; `transition: transform 200ms` drives all four and they stay in step.
|
|
290
|
+
;
|
|
291
|
+
; Interpolating the composed similarity rather than the function list is
|
|
292
|
+
; what makes `rotate(0deg) scale(1)` to `rotate(15deg) scale(1.1)` work
|
|
293
|
+
; without matching the two lists up term by term — which is the part of
|
|
294
|
+
; CSS transform interpolation that carries all the special cases.
|
|
295
|
+
this.reconcileNumberAs(el "transform.rotate" "transform" el.rotate)
|
|
296
|
+
this.reconcileNumberAs(el "transform.scale" "transform" el.scale)
|
|
297
|
+
this.reconcileNumberAs(el "transform.tx" "transform" el.translateX)
|
|
298
|
+
this.reconcileNumberAs(el "transform.ty" "transform" el.translateY)
|
|
299
|
+
; `transform-origin` is its own CSS property with its own entry in the
|
|
300
|
+
; shorthand, and it does animate — measured: 0% 0% to 100% 100% passes
|
|
301
|
+
; through 25px 10px on a 100x40 box at a quarter of the way.
|
|
302
|
+
this.reconcileOriginAxis(el "transform-origin.x" el.transformOriginX)
|
|
303
|
+
this.reconcileOriginAxis(el "transform-origin.y" el.transformOriginY)
|
|
304
|
+
; Put the showing values back, so the painter draws the flight and not
|
|
305
|
+
; the destination.
|
|
306
|
+
this.writeBack(el)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
fn reconcileColor:void (el:EVGElement property:string target:EVGColor) {
|
|
310
|
+
def spec:EVGTimingSpec (EVGTransition.specFor(el.transitionSpec property))
|
|
311
|
+
if ((spec.found == false) || (spec.durationMs <= 0.0)) {
|
|
312
|
+
; Not transitioned: the target IS what shows, and any flight for it
|
|
313
|
+
; is abandoned rather than left to land on a value nobody asked for.
|
|
314
|
+
this.drop(el property)
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
if (target.isSet == false) {
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
def existing@(optional):EVGFlight (this.flightFor(el property))
|
|
321
|
+
if existing {
|
|
322
|
+
def f:EVGFlight (unwrap existing)
|
|
323
|
+
if (EVGTransition.sameColor((unwrap f.toColor) target)) {
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
; The element still holds what this flight last wrote there, so
|
|
327
|
+
; nobody has re-declared anything and there is nothing to react to.
|
|
328
|
+
; See `hasWrote` on EVGFlight for why reading one's own output back
|
|
329
|
+
; would otherwise stop the animation dead.
|
|
330
|
+
if f.hasWrote {
|
|
331
|
+
if (EVGTransition.sameColor((unwrap f.wroteColor) target)) {
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
; Where the flight has actually got to, which is where anything new
|
|
336
|
+
; has to leave from. Using the declared start instead is the flicker
|
|
337
|
+
; every naive implementation has.
|
|
338
|
+
def here:EVGColor (this.showColor(f))
|
|
339
|
+
if (EVGTransition.sameColor(here target)) {
|
|
340
|
+
; Already there. Landing it now rather than flying a
|
|
341
|
+
; zero-distance flight matters to the host: `busy()` would
|
|
342
|
+
; otherwise keep asking for frames to animate nothing.
|
|
343
|
+
f.fromColor = target
|
|
344
|
+
f.toColor = target
|
|
345
|
+
f.elapsedMs = f.durationMs
|
|
346
|
+
return
|
|
347
|
+
}
|
|
348
|
+
if (EVGTransition.sameColor((unwrap f.reversingStartColor) target)) {
|
|
349
|
+
this.reverse(f spec)
|
|
350
|
+
; The value being turned back towards becomes the thing a
|
|
351
|
+
; further reversal is measured against.
|
|
352
|
+
f.reversingStartColor = (unwrap f.toColor)
|
|
353
|
+
} {
|
|
354
|
+
f.reversingStartColor = here
|
|
355
|
+
f.reversingFactor = 1.0
|
|
356
|
+
f.durationMs = spec.durationMs
|
|
357
|
+
}
|
|
358
|
+
f.fromColor = here
|
|
359
|
+
f.toColor = target
|
|
360
|
+
f.elapsedMs = 0.0
|
|
361
|
+
f.delayMs = spec.delayMs
|
|
362
|
+
f.easing = spec.easing
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
; The first apply on a fresh element establishes the value rather than
|
|
366
|
+
; animating to it from black — nothing was on screen to leave from.
|
|
367
|
+
def created (new EVGFlight())
|
|
368
|
+
created.property = property
|
|
369
|
+
created.isColor = true
|
|
370
|
+
created.fromColor = target
|
|
371
|
+
created.toColor = target
|
|
372
|
+
created.reversingStartColor = target
|
|
373
|
+
created.durationMs = spec.durationMs
|
|
374
|
+
created.delayMs = spec.delayMs
|
|
375
|
+
created.easing = spec.easing
|
|
376
|
+
created.elapsedMs = (spec.durationMs + spec.delayMs)
|
|
377
|
+
push el.transitions created
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
; CSS's rule for turning a transition round, and it is more particular than
|
|
381
|
+
; "halve what is left".
|
|
382
|
+
;
|
|
383
|
+
; The shortening factor is the flight's OUTPUT progress — after the timing
|
|
384
|
+
; function — not the fraction of the clock that has run. On `ease-in` at the
|
|
385
|
+
; midpoint those differ by a factor of nearly two: the clock says 0.5 and
|
|
386
|
+
; the eye says 0.315, and the eye is right, because the eye is what has to
|
|
387
|
+
; travel back. Measured against Chromium: a 200ms `ease-in` reversed at
|
|
388
|
+
; 100ms comes back in 63ms, not 100ms.
|
|
389
|
+
;
|
|
390
|
+
; And the factor COMPOUNDS rather than replacing. Reversing a reversal makes
|
|
391
|
+
; the leg longer again, not shorter: 200ms reversed at half way gives 100ms,
|
|
392
|
+
; and reversing that at a quarter gives 125ms, because the value is now
|
|
393
|
+
; further from the target than it was. `f * p + (1 - f)` is that arithmetic,
|
|
394
|
+
; and a fresh flight has f = 1 so the first reversal is simply p.
|
|
395
|
+
;
|
|
396
|
+
; The DELAY is not scaled. That is measured too, and it is not obvious:
|
|
397
|
+
; a reversed `200ms linear 100ms` waits the full 100ms again and then runs
|
|
398
|
+
; for the shortened 100ms.
|
|
399
|
+
fn reverse:void (f:EVGFlight spec:EVGTimingSpec) {
|
|
400
|
+
def p:double (f.eased())
|
|
401
|
+
def nf:double (fabs ((p * f.reversingFactor) + (1.0 - f.reversingFactor)))
|
|
402
|
+
if (nf < 0.0) { nf = 0.0 }
|
|
403
|
+
if (nf > 1.0) { nf = 1.0 }
|
|
404
|
+
f.reversingFactor = nf
|
|
405
|
+
f.durationMs = (spec.durationMs * nf)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
fn reconcileNumber:void (el:EVGElement property:string target:double) {
|
|
409
|
+
this.reconcileNumberAs(el property property target)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
; `key` names the flight; `cssName` is what the shorthand is searched for.
|
|
413
|
+
; They differ only where one CSS property animates several numbers.
|
|
414
|
+
fn reconcileNumberAs:void (el:EVGElement key:string cssName:string target:double) {
|
|
415
|
+
def property:string key
|
|
416
|
+
def spec:EVGTimingSpec (EVGTransition.specFor(el.transitionSpec cssName))
|
|
417
|
+
if ((spec.found == false) || (spec.durationMs <= 0.0)) {
|
|
418
|
+
this.drop(el property)
|
|
419
|
+
return
|
|
420
|
+
}
|
|
421
|
+
def existing@(optional):EVGFlight (this.flightFor(el property))
|
|
422
|
+
if existing {
|
|
423
|
+
def f:EVGFlight (unwrap existing)
|
|
424
|
+
if (EVGTransition.sameNumber(f.toNumber target)) {
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
; As above: this is our own showing value coming back, not a new
|
|
428
|
+
; declaration.
|
|
429
|
+
if f.hasWrote {
|
|
430
|
+
if (EVGTransition.sameNumber(f.wroteNumber target)) {
|
|
431
|
+
return
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
def hereN:double (this.showNumber(f))
|
|
435
|
+
if (EVGTransition.sameNumber(hereN target)) {
|
|
436
|
+
f.fromNumber = target
|
|
437
|
+
f.toNumber = target
|
|
438
|
+
f.elapsedMs = f.durationMs
|
|
439
|
+
return
|
|
440
|
+
}
|
|
441
|
+
if (EVGTransition.sameNumber(f.reversingStartNumber target)) {
|
|
442
|
+
this.reverse(f spec)
|
|
443
|
+
f.reversingStartNumber = f.toNumber
|
|
444
|
+
} {
|
|
445
|
+
f.reversingStartNumber = hereN
|
|
446
|
+
f.reversingFactor = 1.0
|
|
447
|
+
f.durationMs = spec.durationMs
|
|
448
|
+
}
|
|
449
|
+
f.fromNumber = hereN
|
|
450
|
+
f.toNumber = target
|
|
451
|
+
f.elapsedMs = 0.0
|
|
452
|
+
f.delayMs = spec.delayMs
|
|
453
|
+
f.easing = spec.easing
|
|
454
|
+
return
|
|
455
|
+
}
|
|
456
|
+
def created (new EVGFlight())
|
|
457
|
+
created.property = property
|
|
458
|
+
created.isColor = false
|
|
459
|
+
created.fromNumber = target
|
|
460
|
+
created.toNumber = target
|
|
461
|
+
created.reversingStartNumber = target
|
|
462
|
+
created.durationMs = spec.durationMs
|
|
463
|
+
created.delayMs = spec.delayMs
|
|
464
|
+
created.easing = spec.easing
|
|
465
|
+
created.elapsedMs = (spec.durationMs + spec.delayMs)
|
|
466
|
+
push el.transitions created
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
sfn unitOf:EVGUnit (code:int value:double) {
|
|
470
|
+
def u (new EVGUnit())
|
|
471
|
+
u.unitType = code
|
|
472
|
+
u.value = value
|
|
473
|
+
u.pixels = value
|
|
474
|
+
u.isSet = true
|
|
475
|
+
return u
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
; A thousandth is the resolution everything numeric here is compared at:
|
|
479
|
+
; finer and floating point noise reads as a change worth animating.
|
|
480
|
+
sfn sameNumber:boolean (a:double b:double) {
|
|
481
|
+
return ((fabs (a - b)) < 0.001)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
; One axis of `transform-origin`.
|
|
485
|
+
;
|
|
486
|
+
; Separate from the plain number path because of the unit. The value is
|
|
487
|
+
; kept as WRITTEN — a percentage stays a percentage — since the box it
|
|
488
|
+
; resolves against is not known until the display list is built, and
|
|
489
|
+
; resolving a frame early would use the previous layout's size. Two
|
|
490
|
+
; percentages interpolate as percentages, two lengths as lengths, and both
|
|
491
|
+
; give what the browser gives.
|
|
492
|
+
;
|
|
493
|
+
; A change of unit mid-flight is the case that cannot be interpolated
|
|
494
|
+
; meaningfully, and it JUMPS rather than sliding through numbers that mean
|
|
495
|
+
; nothing. CSS blends the resolved lengths there; nobody writes it, and
|
|
496
|
+
; guessing quietly would be worse than the jump.
|
|
497
|
+
fn reconcileOriginAxis:void (el:EVGElement key:string u:EVGUnit) {
|
|
498
|
+
; Unset is 50%, the same default the display list resolves — so an
|
|
499
|
+
; element moving from no origin to `0%` travels from the centre, which
|
|
500
|
+
; is where it visibly was.
|
|
501
|
+
def code:int 1
|
|
502
|
+
def target:double 50.0
|
|
503
|
+
if u.isSet {
|
|
504
|
+
code = u.unitType
|
|
505
|
+
target = u.value
|
|
506
|
+
}
|
|
507
|
+
def existing@(optional):EVGFlight (this.flightFor(el key))
|
|
508
|
+
if existing {
|
|
509
|
+
def f:EVGFlight (unwrap existing)
|
|
510
|
+
if (f.unitCode != code) {
|
|
511
|
+
this.drop(el key)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
this.reconcileNumberAs(el key "transform-origin" target)
|
|
515
|
+
def now@(optional):EVGFlight (this.flightFor(el key))
|
|
516
|
+
if now {
|
|
517
|
+
def f2:EVGFlight (unwrap now)
|
|
518
|
+
f2.unitCode = code
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
; Remove the flight for one property, if there is one.
|
|
523
|
+
;
|
|
524
|
+
; The EARLY RETURN is the whole of this. `reconcileTree` calls `drop` for
|
|
525
|
+
; every animatable property of every element on the way past, and almost
|
|
526
|
+
; none of them has a flight in progress: the list is empty or holds
|
|
527
|
+
; something else. Rebuilding it regardless allocated one array per call,
|
|
528
|
+
; which put this among the most expensive functions in a scroll frame of
|
|
529
|
+
; `gallery/realtrainer` — 5.8% of it, to remove nothing from nothing.
|
|
530
|
+
fn drop:void (el:EVGElement property:string) {
|
|
531
|
+
def found:boolean false
|
|
532
|
+
def n:int 0
|
|
533
|
+
while (n < (array_length el.transitions)) {
|
|
534
|
+
def fn0:EVGFlight (itemAt el.transitions n)
|
|
535
|
+
if (fn0.property == property) {
|
|
536
|
+
found = true
|
|
537
|
+
}
|
|
538
|
+
n = (n + 1)
|
|
539
|
+
}
|
|
540
|
+
if (found == false) {
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
def kept:[EVGFlight]
|
|
544
|
+
def i:int 0
|
|
545
|
+
while (i < (array_length el.transitions)) {
|
|
546
|
+
def f:EVGFlight (itemAt el.transitions i)
|
|
547
|
+
if (f.property != property) {
|
|
548
|
+
push kept f
|
|
549
|
+
}
|
|
550
|
+
i = (i + 1)
|
|
551
|
+
}
|
|
552
|
+
clear el.transitions
|
|
553
|
+
def j:int 0
|
|
554
|
+
while (j < (array_length kept)) {
|
|
555
|
+
push el.transitions (itemAt kept j)
|
|
556
|
+
j = (j + 1)
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
; --- advance ---------------------------------------------------------------------
|
|
561
|
+
|
|
562
|
+
fn advance:void (el:EVGElement dtMs:double) {
|
|
563
|
+
def i:int 0
|
|
564
|
+
while (i < (array_length el.transitions)) {
|
|
565
|
+
def f:EVGFlight (itemAt el.transitions i)
|
|
566
|
+
if ((f.done()) == false) {
|
|
567
|
+
f.elapsedMs = (f.elapsedMs + dtMs)
|
|
568
|
+
def endsAt:double (f.delayMs + f.durationMs)
|
|
569
|
+
if (f.elapsedMs > endsAt) {
|
|
570
|
+
f.elapsedMs = endsAt
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
i = (i + 1)
|
|
574
|
+
}
|
|
575
|
+
this.writeBack(el)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
; The showing values, into the fields the painter reads. This is the one
|
|
579
|
+
; place a flight touches the element, and it happens after both reconcile
|
|
580
|
+
; and advance so the two cannot disagree about what is on screen.
|
|
581
|
+
fn writeBack:void (el:EVGElement) {
|
|
582
|
+
; An element with a flight in it no longer holds what the sheet
|
|
583
|
+
; declared — it holds where the flight has got to — so the sheet is
|
|
584
|
+
; told to re-declare rather than skip it next frame.
|
|
585
|
+
;
|
|
586
|
+
; ONLY when there is a flight. The first version said it
|
|
587
|
+
; unconditionally, and `reconcile` calls this for every element in the
|
|
588
|
+
; tree, so every element was invalidated every frame and the skip never
|
|
589
|
+
; fired at all on any page that uses transitions — which is every page
|
|
590
|
+
; here. The benchmark did not notice, because it runs no transitions;
|
|
591
|
+
; `testSkipSurvivesTransitions` is what notices.
|
|
592
|
+
;
|
|
593
|
+
; Strictly this is belt and braces: `EVGFlight.hasWrote` already lets
|
|
594
|
+
; `reconcile` recognise its own output and carry on. Kept because the
|
|
595
|
+
; elements with flights are few and reasoning about that guard is not
|
|
596
|
+
; something the next reader should have to redo.
|
|
597
|
+
def moving:boolean false
|
|
598
|
+
def i:int 0
|
|
599
|
+
while (i < (array_length el.transitions)) {
|
|
600
|
+
def f:EVGFlight (itemAt el.transitions i)
|
|
601
|
+
if ((f.done()) == false) {
|
|
602
|
+
moving = true
|
|
603
|
+
}
|
|
604
|
+
if (f.isColor) {
|
|
605
|
+
def c:EVGColor (this.showColor(f))
|
|
606
|
+
f.wroteColor = c
|
|
607
|
+
f.hasWrote = true
|
|
608
|
+
if (f.property == "background-color") {
|
|
609
|
+
el.backgroundColor = c
|
|
610
|
+
}
|
|
611
|
+
if (f.property == "color") {
|
|
612
|
+
el.color = c
|
|
613
|
+
}
|
|
614
|
+
} {
|
|
615
|
+
def n:double (this.showNumber(f))
|
|
616
|
+
f.wroteNumber = n
|
|
617
|
+
f.hasWrote = true
|
|
618
|
+
if (f.property == "opacity") {
|
|
619
|
+
el.opacity = n
|
|
620
|
+
}
|
|
621
|
+
if (f.property == "transform.rotate") {
|
|
622
|
+
el.rotate = n
|
|
623
|
+
}
|
|
624
|
+
if (f.property == "transform.scale") {
|
|
625
|
+
el.scale = n
|
|
626
|
+
}
|
|
627
|
+
if (f.property == "transform.tx") {
|
|
628
|
+
el.translateX = n
|
|
629
|
+
}
|
|
630
|
+
if (f.property == "transform.ty") {
|
|
631
|
+
el.translateY = n
|
|
632
|
+
}
|
|
633
|
+
if (f.property == "transform-origin.x") {
|
|
634
|
+
el.transformOriginX = (EVGTransition.unitOf(f.unitCode n))
|
|
635
|
+
}
|
|
636
|
+
if (f.property == "transform-origin.y") {
|
|
637
|
+
el.transformOriginY = (EVGTransition.unitOf(f.unitCode n))
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
i = (i + 1)
|
|
641
|
+
}
|
|
642
|
+
; An element with a flight STILL IN THE AIR no longer holds what the
|
|
643
|
+
; sheet declared — it holds where the flight has got to — so the sheet
|
|
644
|
+
; is told to re-declare rather than skip it next frame.
|
|
645
|
+
;
|
|
646
|
+
; Only while it is MOVING. Two earlier versions were wrong in the same
|
|
647
|
+
; direction: unconditional, so `reconcile` (which runs on every element)
|
|
648
|
+
; made the whole tree stale every frame and nothing was ever skipped;
|
|
649
|
+
; then "has any flight", which kept every element that has ever
|
|
650
|
+
; transitioned stale forever, because a finished flight stays in the
|
|
651
|
+
; list. A benchmark could see neither, because it runs no transitions —
|
|
652
|
+
; `testSkipSurvivesTransitions` is what does.
|
|
653
|
+
;
|
|
654
|
+
; On the frame a flight LANDS this correctly does nothing: `writeBack`
|
|
655
|
+
; has just written the target, which is what the sheet would write.
|
|
656
|
+
;
|
|
657
|
+
; And it is belt and braces rather than load-bearing. Removing it
|
|
658
|
+
; entirely passes every test, because `EVGFlight.hasWrote` already lets
|
|
659
|
+
; `reconcile` recognise its own output and carry on — that mutation was
|
|
660
|
+
; run and survived. It stays because the elements it touches are the few
|
|
661
|
+
; that are moving, and because the next person to change `hasWrote`
|
|
662
|
+
; should not have to rediscover that it is holding this up.
|
|
663
|
+
if moving {
|
|
664
|
+
el.styleGen = (0 - 1)
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
; --- whole trees -------------------------------------------------------------------
|
|
669
|
+
|
|
670
|
+
fn reconcileTree:void (root:EVGElement) {
|
|
671
|
+
this.reconcile(root)
|
|
672
|
+
def i:int 0
|
|
673
|
+
while (i < (array_length root.children)) {
|
|
674
|
+
this.reconcileTree((itemAt root.children i))
|
|
675
|
+
i = (i + 1)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
; …and says whether anything under `root` is in flight. A subtree with
|
|
680
|
+
; a flight in it is being painted differently every frame, and its
|
|
681
|
+
; `paintStamp` is moved on to say so: a display list keeping what it
|
|
682
|
+
; drew for the subtree (`EVGDisplayList.emitFragment`) then draws it
|
|
683
|
+
; afresh, and every subtree with no flight in it keeps what it had.
|
|
684
|
+
fn advanceTree:boolean (root:EVGElement dtMs:double) {
|
|
685
|
+
this.advance(root dtMs)
|
|
686
|
+
def any@(mutable):boolean false
|
|
687
|
+
def f:int 0
|
|
688
|
+
while (f < (array_length root.transitions)) {
|
|
689
|
+
def flight:EVGFlight (itemAt root.transitions f)
|
|
690
|
+
if ((flight.done()) == false) {
|
|
691
|
+
any = true
|
|
692
|
+
}
|
|
693
|
+
f = (f + 1)
|
|
694
|
+
}
|
|
695
|
+
def i:int 0
|
|
696
|
+
while (i < (array_length root.children)) {
|
|
697
|
+
if (this.advanceTree((itemAt root.children i) dtMs)) {
|
|
698
|
+
any = true
|
|
699
|
+
}
|
|
700
|
+
i = (i + 1)
|
|
701
|
+
}
|
|
702
|
+
if any {
|
|
703
|
+
root.paintStamp = (root.paintStamp + 1)
|
|
704
|
+
}
|
|
705
|
+
return any
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
; Is anything still moving? A host that repaints on demand asks this to
|
|
709
|
+
; know whether it needs another frame.
|
|
710
|
+
fn busy:boolean (root:EVGElement) {
|
|
711
|
+
def i:int 0
|
|
712
|
+
while (i < (array_length root.transitions)) {
|
|
713
|
+
def f:EVGFlight (itemAt root.transitions i)
|
|
714
|
+
if ((f.done()) == false) {
|
|
715
|
+
return true
|
|
716
|
+
}
|
|
717
|
+
i = (i + 1)
|
|
718
|
+
}
|
|
719
|
+
def j:int 0
|
|
720
|
+
while (j < (array_length root.children)) {
|
|
721
|
+
if (this.busy((itemAt root.children j))) {
|
|
722
|
+
return true
|
|
723
|
+
}
|
|
724
|
+
j = (j + 1)
|
|
725
|
+
}
|
|
726
|
+
return false
|
|
727
|
+
}
|
|
728
|
+
}
|