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,30 @@
|
|
|
1
|
+
// Compile-time stub. See AndroidStubs.kt.
|
|
2
|
+
package android.os
|
|
3
|
+
|
|
4
|
+
class Bundle
|
|
5
|
+
|
|
6
|
+
interface IBinder
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enough of `Build` for an API check. The hosts gate on `SDK_INT` where a
|
|
10
|
+
* platform feature is newer than `minSdk`, and a stub that did not have it
|
|
11
|
+
* would make those branches unverifiable — which is the one thing this
|
|
12
|
+
* directory exists to prevent.
|
|
13
|
+
*/
|
|
14
|
+
object Build {
|
|
15
|
+
// What `DashboardView.onEmulator` reads to keep a software GPU from being
|
|
16
|
+
// asked to run a full-screen shader.
|
|
17
|
+
@JvmField val FINGERPRINT: String = "stub"
|
|
18
|
+
@JvmField val HARDWARE: String = "stub"
|
|
19
|
+
@JvmField val MODEL: String = "stub"
|
|
20
|
+
|
|
21
|
+
object VERSION {
|
|
22
|
+
@JvmField val SDK_INT: Int = 34
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
object VERSION_CODES {
|
|
26
|
+
const val LOLLIPOP = 21
|
|
27
|
+
const val S = 31
|
|
28
|
+
const val TIRAMISU = 33
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Compile-time stub. See AndroidStubs.kt.
|
|
2
|
+
package android.util
|
|
3
|
+
|
|
4
|
+
class DisplayMetrics {
|
|
5
|
+
@JvmField var density: Float = 1f
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface AttributeSet
|
|
9
|
+
|
|
10
|
+
@Suppress("UNUSED_PARAMETER")
|
|
11
|
+
object Log {
|
|
12
|
+
fun d(tag: String, msg: String): Int = 0
|
|
13
|
+
fun w(tag: String, msg: String): Int = 0
|
|
14
|
+
fun e(tag: String, msg: String): Int = 0
|
|
15
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Compile-time stub. See AndroidStubs.kt.
|
|
2
|
+
@file:Suppress("UNUSED_PARAMETER", "unused")
|
|
3
|
+
|
|
4
|
+
package android.view
|
|
5
|
+
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.graphics.Canvas
|
|
8
|
+
import android.util.AttributeSet
|
|
9
|
+
|
|
10
|
+
open class View(context: Context, attrs: AttributeSet? = null) {
|
|
11
|
+
val context: Context = context
|
|
12
|
+
companion object {
|
|
13
|
+
const val LAYER_TYPE_NONE = 0
|
|
14
|
+
const val LAYER_TYPE_SOFTWARE = 1
|
|
15
|
+
const val LAYER_TYPE_HARDWARE = 2
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
val width: Int = 0
|
|
19
|
+
val height: Int = 0
|
|
20
|
+
val resources: android.content.res.Resources = context.resources
|
|
21
|
+
|
|
22
|
+
var isFocusable: Boolean = false
|
|
23
|
+
var isFocusableInTouchMode: Boolean = false
|
|
24
|
+
|
|
25
|
+
fun setLayerType(layerType: Int, paint: android.graphics.Paint?) {}
|
|
26
|
+
open fun invalidate() {}
|
|
27
|
+
open fun requestFocus(): Boolean = false
|
|
28
|
+
open fun setRenderEffect(effect: android.graphics.RenderEffect?) {}
|
|
29
|
+
open fun postOnAnimation(action: Runnable) {}
|
|
30
|
+
open fun onDetachedFromWindow() {}
|
|
31
|
+
open fun post(action: Runnable): Boolean = true
|
|
32
|
+
open fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean = false
|
|
33
|
+
open fun postInvalidateOnAnimation() {}
|
|
34
|
+
protected open fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {}
|
|
35
|
+
protected open fun onDraw(canvas: Canvas) {}
|
|
36
|
+
open fun onTouchEvent(event: MotionEvent): Boolean = false
|
|
37
|
+
val windowToken: android.os.IBinder? = null
|
|
38
|
+
open fun onCheckIsTextEditor(): Boolean = false
|
|
39
|
+
open fun onCreateInputConnection(outAttrs: android.view.inputmethod.EditorInfo): android.view.inputmethod.InputConnection? = null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class MotionEvent {
|
|
43
|
+
companion object {
|
|
44
|
+
const val ACTION_DOWN = 0
|
|
45
|
+
const val ACTION_UP = 1
|
|
46
|
+
const val ACTION_MOVE = 2
|
|
47
|
+
const val ACTION_CANCEL = 3
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
val x: Float = 0f
|
|
51
|
+
val y: Float = 0f
|
|
52
|
+
val actionMasked: Int = 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class KeyEvent {
|
|
56
|
+
companion object {
|
|
57
|
+
const val KEYCODE_DPAD_UP = 19
|
|
58
|
+
const val KEYCODE_DPAD_DOWN = 20
|
|
59
|
+
const val KEYCODE_DPAD_LEFT = 21
|
|
60
|
+
const val KEYCODE_DPAD_RIGHT = 22
|
|
61
|
+
const val KEYCODE_PAGE_UP = 92
|
|
62
|
+
const val KEYCODE_PAGE_DOWN = 93
|
|
63
|
+
const val KEYCODE_MOVE_HOME = 122
|
|
64
|
+
const val KEYCODE_MOVE_END = 123
|
|
65
|
+
const val KEYCODE_ENTER = 66
|
|
66
|
+
const val KEYCODE_SPACE = 62
|
|
67
|
+
const val KEYCODE_DEL = 67
|
|
68
|
+
const val KEYCODE_FORWARD_DEL = 112
|
|
69
|
+
const val KEYCODE_TAB = 61
|
|
70
|
+
const val KEYCODE_ESCAPE = 111
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
val keyCode: Int = 0
|
|
74
|
+
val unicodeChar: Int = 0
|
|
75
|
+
val isShiftPressed: Boolean = false
|
|
76
|
+
val isCtrlPressed: Boolean = false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
class GestureDetector(context: Context, listener: OnGestureListener) {
|
|
80
|
+
interface OnGestureListener
|
|
81
|
+
|
|
82
|
+
open class SimpleOnGestureListener : OnGestureListener {
|
|
83
|
+
open fun onDown(e: MotionEvent): Boolean = false
|
|
84
|
+
open fun onSingleTapUp(e: MotionEvent): Boolean = false
|
|
85
|
+
open fun onDoubleTap(e: MotionEvent): Boolean = false
|
|
86
|
+
open fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean = false
|
|
87
|
+
open fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean = false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fun onTouchEvent(event: MotionEvent): Boolean = false
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class ScaleGestureDetector(context: Context, listener: OnScaleGestureListener) {
|
|
94
|
+
interface OnScaleGestureListener
|
|
95
|
+
|
|
96
|
+
open class SimpleOnScaleGestureListener : OnScaleGestureListener {
|
|
97
|
+
open fun onScale(detector: ScaleGestureDetector): Boolean = false
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
val scaleFactor: Float = 1f
|
|
101
|
+
val focusX: Float = 0f
|
|
102
|
+
val focusY: Float = 0f
|
|
103
|
+
var isQuickScaleEnabled: Boolean = true
|
|
104
|
+
fun onTouchEvent(event: MotionEvent): Boolean = false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface Menu {
|
|
108
|
+
fun add(groupId: Int, itemId: Int, order: Int, title: CharSequence): MenuItem
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface MenuItem {
|
|
112
|
+
val itemId: Int
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Compile-time stub. See AndroidStubs.kt.
|
|
2
|
+
@file:Suppress("UNUSED_PARAMETER", "unused")
|
|
3
|
+
|
|
4
|
+
package android.widget
|
|
5
|
+
|
|
6
|
+
import android.content.Context
|
|
7
|
+
|
|
8
|
+
class Toast {
|
|
9
|
+
companion object {
|
|
10
|
+
const val LENGTH_SHORT = 0
|
|
11
|
+
const val LENGTH_LONG = 1
|
|
12
|
+
fun makeText(context: Context, text: CharSequence, duration: Int): Toast = Toast()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fun show() {}
|
|
16
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
package fi.ranger.evg
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.graphics.BitmapFactory
|
|
5
|
+
import android.graphics.BlurMaskFilter
|
|
6
|
+
import android.graphics.Canvas
|
|
7
|
+
import android.graphics.Color
|
|
8
|
+
import android.graphics.LinearGradient
|
|
9
|
+
import android.graphics.Matrix
|
|
10
|
+
import android.graphics.Paint
|
|
11
|
+
import android.graphics.Path
|
|
12
|
+
import android.graphics.RectF
|
|
13
|
+
import android.graphics.Shader
|
|
14
|
+
import android.graphics.Typeface
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The display list, painted with `android.graphics.Canvas`.
|
|
18
|
+
*
|
|
19
|
+
* This is the whole of the platform-specific half of the port: every command
|
|
20
|
+
* kind maps onto something Skia already does — a rounded rect, a shader, a
|
|
21
|
+
* path with a fill type, a run of text at a baseline — so there is no
|
|
22
|
+
* rasteriser here, no atlas, no shader, and nothing that has to agree with the
|
|
23
|
+
* layout engine about anything but coordinates.
|
|
24
|
+
*
|
|
25
|
+
* Text is drawn rather than blitted. EVG measured each run with its own
|
|
26
|
+
* TrueType reader against the same `.ttf` the [FaceSet] loads, and the command
|
|
27
|
+
* carries the run's origin, so Skia only has to put the same glyphs at the same
|
|
28
|
+
* place at whatever size the canvas is currently scaled to. That is why a
|
|
29
|
+
* pinch-zoom stays sharp: nothing was ever rasterised at a fixed size.
|
|
30
|
+
*/
|
|
31
|
+
class AndroidEvgSurface(
|
|
32
|
+
private val canvas: Canvas,
|
|
33
|
+
/** Decoded pictures by package part, from [ImageStore]. */
|
|
34
|
+
private val images: ImageStore,
|
|
35
|
+
private val faces: FaceSet,
|
|
36
|
+
) : EvgSurface {
|
|
37
|
+
|
|
38
|
+
private val fill = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
39
|
+
private val stroke = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
|
|
40
|
+
private val text = Paint(Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG)
|
|
41
|
+
private val shadowPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
42
|
+
private val rect = RectF()
|
|
43
|
+
private val path = Path()
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A `BlurMaskFilter` is exact and cheap — and is **ignored** on a
|
|
47
|
+
* hardware-accelerated canvas, which is the canvas this app wants. So it is
|
|
48
|
+
* used only when the canvas is a software one (a `LAYER_TYPE_SOFTWARE`
|
|
49
|
+
* view, a bitmap-backed canvas, a screenshot); on the GPU the falloff is
|
|
50
|
+
* built out of ordinary draw calls instead. See [drawShadow].
|
|
51
|
+
*
|
|
52
|
+
* The canvas is asked rather than the view, so this is right whichever one
|
|
53
|
+
* we are handed.
|
|
54
|
+
*/
|
|
55
|
+
private val canBlur = !canvas.isHardwareAccelerated
|
|
56
|
+
|
|
57
|
+
override fun save() {
|
|
58
|
+
canvas.save()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override fun restore() {
|
|
62
|
+
canvas.restore()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override fun clipRect(x: Float, y: Float, w: Float, h: Float) {
|
|
66
|
+
canvas.clipRect(x, y, x + w, y + h)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override fun rotate(degrees: Float, px: Float, py: Float) {
|
|
70
|
+
canvas.rotate(degrees, px, py)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
override fun fillRect(
|
|
74
|
+
x: Float, y: Float, w: Float, h: Float,
|
|
75
|
+
radius: Float, color: Int, gradient: EvgGradient?, shadow: EvgShadow?,
|
|
76
|
+
) {
|
|
77
|
+
if (w <= 0f || h <= 0f) return
|
|
78
|
+
rect.set(x, y, x + w, y + h)
|
|
79
|
+
val r = radius.coerceAtMost(minOf(w, h) / 2f)
|
|
80
|
+
shadow?.let { drawShadowRect(rect, r, it) }
|
|
81
|
+
fill.shader = gradient?.let {
|
|
82
|
+
if (it.vertical) {
|
|
83
|
+
LinearGradient(x, y, x, y + h, it.color1, it.color2, Shader.TileMode.CLAMP)
|
|
84
|
+
} else {
|
|
85
|
+
LinearGradient(x, y, x + w, y, it.color1, it.color2, Shader.TileMode.CLAMP)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
fill.color = color
|
|
89
|
+
if (gradient == null && Color.alpha(color) == 0) return
|
|
90
|
+
if (r > 0.5f) canvas.drawRoundRect(rect, r, r, fill) else canvas.drawRect(rect, fill)
|
|
91
|
+
fill.shader = null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override fun strokeRect(
|
|
95
|
+
x: Float, y: Float, w: Float, h: Float,
|
|
96
|
+
radius: Float, thickness: Float, color: Int,
|
|
97
|
+
) {
|
|
98
|
+
if (w <= 0f || h <= 0f) return
|
|
99
|
+
// EVG keeps a border's band INSIDE the box; Skia centres a stroke on
|
|
100
|
+
// the path, so the rectangle moves in by half the thickness.
|
|
101
|
+
val half = thickness / 2f
|
|
102
|
+
rect.set(x + half, y + half, x + w - half, y + h - half)
|
|
103
|
+
stroke.color = color
|
|
104
|
+
stroke.strokeWidth = thickness
|
|
105
|
+
val r = (radius - half).coerceAtLeast(0f)
|
|
106
|
+
if (r > 0.5f) canvas.drawRoundRect(rect, r, r, stroke) else canvas.drawRect(rect, stroke)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
override fun fillPath(
|
|
110
|
+
pts: List<Double>, ringEnds: List<Int>, evenOdd: Boolean,
|
|
111
|
+
color: Int, shadow: EvgShadow?,
|
|
112
|
+
) {
|
|
113
|
+
if (!buildPath(pts, ringEnds, close = true)) return
|
|
114
|
+
path.fillType = if (evenOdd) Path.FillType.EVEN_ODD else Path.FillType.WINDING
|
|
115
|
+
shadow?.let { drawShadowPath(it) }
|
|
116
|
+
fill.shader = null
|
|
117
|
+
fill.color = color
|
|
118
|
+
canvas.drawPath(path, fill)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
override fun strokePath(pts: List<Double>, ringEnds: List<Int>, thickness: Float, color: Int) {
|
|
122
|
+
if (!buildPath(pts, ringEnds, close = false)) return
|
|
123
|
+
stroke.color = color
|
|
124
|
+
stroke.strokeWidth = thickness
|
|
125
|
+
stroke.strokeJoin = Paint.Join.ROUND
|
|
126
|
+
stroke.strokeCap = Paint.Cap.ROUND
|
|
127
|
+
canvas.drawPath(path, stroke)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
override fun drawImage(
|
|
131
|
+
src: String, x: Float, y: Float, w: Float, h: Float,
|
|
132
|
+
radius: Float, flipH: Boolean, flipV: Boolean,
|
|
133
|
+
) {
|
|
134
|
+
if (w <= 0f || h <= 0f) return
|
|
135
|
+
val bmp = images.bitmap(src)
|
|
136
|
+
if (bmp == null) {
|
|
137
|
+
// A picture the package did not carry must look different from an
|
|
138
|
+
// empty slide, or a decoding bug reads as a design choice.
|
|
139
|
+
rect.set(x, y, x + w, y + h)
|
|
140
|
+
fill.shader = null
|
|
141
|
+
fill.color = Color.rgb(180, 198, 230)
|
|
142
|
+
canvas.drawRect(rect, fill)
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
val saved = canvas.save()
|
|
146
|
+
if (radius > 0.5f) {
|
|
147
|
+
rect.set(x, y, x + w, y + h)
|
|
148
|
+
path.reset()
|
|
149
|
+
path.addRoundRect(rect, radius, radius, Path.Direction.CW)
|
|
150
|
+
canvas.clipPath(path)
|
|
151
|
+
}
|
|
152
|
+
val m = Matrix()
|
|
153
|
+
m.setScale(w / bmp.width, h / bmp.height)
|
|
154
|
+
m.postTranslate(x, y)
|
|
155
|
+
if (flipH || flipV) {
|
|
156
|
+
// Mirroring is the texture read backwards, about the box's own
|
|
157
|
+
// centre — the quad stays where the layout put it.
|
|
158
|
+
val mm = Matrix()
|
|
159
|
+
mm.setScale(if (flipH) -1f else 1f, if (flipV) -1f else 1f, x + w / 2f, y + h / 2f)
|
|
160
|
+
m.postConcat(mm)
|
|
161
|
+
}
|
|
162
|
+
canvas.drawBitmap(bmp, m, fill.also { it.shader = null; it.color = Color.WHITE })
|
|
163
|
+
canvas.restoreToCount(saved)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
override fun drawTextRun(
|
|
167
|
+
txt: String, x: Float, top: Float, sizePx: Float,
|
|
168
|
+
family: String, bold: Boolean, italic: Boolean, color: Int,
|
|
169
|
+
) {
|
|
170
|
+
if (sizePx <= 0f) return
|
|
171
|
+
text.typeface = faces.typeface(family, bold, italic)
|
|
172
|
+
text.textSize = sizePx
|
|
173
|
+
text.color = color
|
|
174
|
+
// `top` is the top of the line box; `ascent` is negative and is the
|
|
175
|
+
// distance from the baseline up to it. Same rule as the WebGL atlas.
|
|
176
|
+
canvas.drawText(txt, x, top - text.fontMetrics.ascent, text)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// --- the parts that are only arithmetic ----------------------------------
|
|
180
|
+
|
|
181
|
+
private fun buildPath(pts: List<Double>, ringEnds: List<Int>, close: Boolean): Boolean {
|
|
182
|
+
if (pts.size < 4) return false
|
|
183
|
+
path.reset()
|
|
184
|
+
var start = 0
|
|
185
|
+
var any = false
|
|
186
|
+
for (end in ringEnds) {
|
|
187
|
+
val stop = if (end > pts.size) pts.size else end
|
|
188
|
+
if (stop - start < 4) { start = stop; continue }
|
|
189
|
+
path.moveTo(pts[start].toFloat(), pts[start + 1].toFloat())
|
|
190
|
+
var i = start + 2
|
|
191
|
+
while (i + 1 < stop) {
|
|
192
|
+
path.lineTo(pts[i].toFloat(), pts[i + 1].toFloat())
|
|
193
|
+
i += 2
|
|
194
|
+
}
|
|
195
|
+
if (close) path.close()
|
|
196
|
+
any = true
|
|
197
|
+
start = stop
|
|
198
|
+
}
|
|
199
|
+
return any
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private fun drawShadowRect(box: RectF, radius: Float, shadow: EvgShadow) {
|
|
203
|
+
val moved = RectF(box)
|
|
204
|
+
moved.offset(shadow.dx, shadow.dy)
|
|
205
|
+
drawShadow(shadow) {
|
|
206
|
+
if (radius > 0.5f) {
|
|
207
|
+
canvas.drawRoundRect(moved, radius, radius, shadowPaint)
|
|
208
|
+
} else {
|
|
209
|
+
canvas.drawRect(moved, shadowPaint)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private fun drawShadowPath(shadow: EvgShadow) {
|
|
215
|
+
val saved = canvas.save()
|
|
216
|
+
canvas.translate(shadow.dx, shadow.dy)
|
|
217
|
+
drawShadow(shadow) { canvas.drawPath(path, shadowPaint) }
|
|
218
|
+
canvas.restoreToCount(saved)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* The silhouette, softened, without asking the GPU for something it will
|
|
223
|
+
* quietly refuse.
|
|
224
|
+
*
|
|
225
|
+
* `BlurMaskFilter` is the right answer and Skia ignores it on a
|
|
226
|
+
* hardware-accelerated canvas — it does not fail, it draws a hard-edged
|
|
227
|
+
* grey shape, which is worse than no shadow at all. Forcing the whole view
|
|
228
|
+
* onto a software layer to get it back would trade the GPU for one effect,
|
|
229
|
+
* on a page whose other few hundred commands want the GPU.
|
|
230
|
+
*
|
|
231
|
+
* So on the GPU the falloff is drawn instead of filtered: the silhouette a
|
|
232
|
+
* few times, each pass grown by a stroke of increasing width and drawn at a
|
|
233
|
+
* decreasing alpha. It is a handful of ordinary draw calls, it batches like
|
|
234
|
+
* any other geometry, and at the blur radii a deck actually asks for
|
|
235
|
+
* (`outerShdw` is usually a few points) the difference from a true Gaussian
|
|
236
|
+
* is not something you can see on a slide.
|
|
237
|
+
*
|
|
238
|
+
* `RenderEffect.createBlurEffect` would be exact and is API 31+ and needs
|
|
239
|
+
* its own `RenderNode` per shape; that is the upgrade path if a deck ever
|
|
240
|
+
* turns up whose design depends on the exact falloff.
|
|
241
|
+
*/
|
|
242
|
+
private inline fun drawShadow(shadow: EvgShadow, silhouette: () -> Unit) {
|
|
243
|
+
shadowPaint.style = Paint.Style.FILL
|
|
244
|
+
shadowPaint.maskFilter = null
|
|
245
|
+
if (canBlur && shadow.blur > 0.5f) {
|
|
246
|
+
shadowPaint.color = shadow.color
|
|
247
|
+
shadowPaint.maskFilter = BlurMaskFilter(shadow.blur, BlurMaskFilter.Blur.NORMAL)
|
|
248
|
+
silhouette()
|
|
249
|
+
shadowPaint.maskFilter = null
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
if (shadow.blur <= 0.5f) {
|
|
253
|
+
shadowPaint.color = shadow.color
|
|
254
|
+
silhouette()
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
val alpha = Color.alpha(shadow.color)
|
|
258
|
+
val rgb = shadow.color and 0x00FFFFFF
|
|
259
|
+
var pass = SHADOW_PASSES - 1
|
|
260
|
+
while (pass >= 0) {
|
|
261
|
+
// Outermost pass first and faintest, so the passes accumulate
|
|
262
|
+
// towards the middle the way a blur does.
|
|
263
|
+
val t = (pass + 1).toFloat() / SHADOW_PASSES
|
|
264
|
+
val grow = shadow.blur * t
|
|
265
|
+
val a = (alpha * (1f - t) / SHADOW_PASSES * 2f).toInt().coerceIn(0, 255)
|
|
266
|
+
shadowPaint.color = (a shl 24) or rgb
|
|
267
|
+
if (grow > 0.01f) {
|
|
268
|
+
shadowPaint.style = Paint.Style.FILL_AND_STROKE
|
|
269
|
+
shadowPaint.strokeWidth = grow * 2f
|
|
270
|
+
shadowPaint.strokeJoin = Paint.Join.ROUND
|
|
271
|
+
shadowPaint.strokeCap = Paint.Cap.ROUND
|
|
272
|
+
} else {
|
|
273
|
+
shadowPaint.style = Paint.Style.FILL
|
|
274
|
+
}
|
|
275
|
+
silhouette()
|
|
276
|
+
pass--
|
|
277
|
+
}
|
|
278
|
+
shadowPaint.style = Paint.Style.FILL
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private companion object {
|
|
282
|
+
/** Enough for a slide's shadow to read as soft; more is not visible. */
|
|
283
|
+
const val SHADOW_PASSES = 4
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* The four faces the deck is measured and drawn in.
|
|
289
|
+
*
|
|
290
|
+
* EVG measured every run against these exact `.ttf` bytes, so the same files
|
|
291
|
+
* have to be what Skia draws with — a substituted face would put the same
|
|
292
|
+
* glyphs at widths the layout never agreed to.
|
|
293
|
+
*/
|
|
294
|
+
class FaceSet(
|
|
295
|
+
private val regular: Typeface,
|
|
296
|
+
private val bold: Typeface,
|
|
297
|
+
private val italic: Typeface,
|
|
298
|
+
private val boldItalic: Typeface,
|
|
299
|
+
) {
|
|
300
|
+
fun typeface(@Suppress("UNUSED_PARAMETER") family: String, bold: Boolean, italic: Boolean): Typeface = when {
|
|
301
|
+
bold && italic -> boldItalic
|
|
302
|
+
bold -> this.bold
|
|
303
|
+
italic -> this.italic
|
|
304
|
+
else -> regular
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** The deck's own pictures, decoded once and kept until another deck is opened. */
|
|
309
|
+
class ImageStore {
|
|
310
|
+
private val bytes = HashMap<String, ByteArray>()
|
|
311
|
+
private val decoded = HashMap<String, Bitmap?>()
|
|
312
|
+
|
|
313
|
+
fun reset(parts: Map<String, ByteArray>) {
|
|
314
|
+
bytes.clear()
|
|
315
|
+
decoded.clear()
|
|
316
|
+
bytes.putAll(parts)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
fun bitmap(part: String): Bitmap? = decoded.getOrPut(part) {
|
|
320
|
+
val raw = bytes[part] ?: return@getOrPut null
|
|
321
|
+
runCatching { BitmapFactory.decodeByteArray(raw, 0, raw.size) }.getOrNull()
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
package fi.ranger.evg
|
|
3
|
+
|
|
4
|
+
import android.graphics.Paint
|
|
5
|
+
import fi.ranger.rgr.EVGDefaultMeasurer
|
|
6
|
+
import fi.ranger.rgr.EVGHostTextMeasurer
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Skia measures, EVG breaks the lines.
|
|
10
|
+
*
|
|
11
|
+
* PLAN_NATIVE_HOSTS.md S0, the Android half. `EVGHostTextMeasurer` (Ranger,
|
|
12
|
+
* in the app's generated Kotlin) takes ONE function from the platform — a
|
|
13
|
+
* run's width, and a face's ascent, descent and leading — and every layout
|
|
14
|
+
* the app builds then measures with it. Before this the layout measured with
|
|
15
|
+
* the advance table, a snapshot of one browser's sans, and
|
|
16
|
+
* [AndroidEvgSurface] drew with whatever the [FaceSet] handed it: two faces,
|
|
17
|
+
* and every box sized from the wrong one.
|
|
18
|
+
*
|
|
19
|
+
* The face is the SAME `Typeface` the surface draws with — the [FaceSet] is
|
|
20
|
+
* asked with the same three arguments `drawTextRun` asks it with — so the
|
|
21
|
+
* width the layout measured is the width `Canvas.drawText` puts on the
|
|
22
|
+
* screen, at the size the layout named. The canvas is scaled for density and
|
|
23
|
+
* zoom AFTER that, which is why a pinch stays sharp and why the measurement
|
|
24
|
+
* is in the layout's own pixels rather than the panel's.
|
|
25
|
+
*
|
|
26
|
+
* Install once, before the app's `start`. The `Paint` is used from whatever
|
|
27
|
+
* thread lays out — `gallery/ui/android` starts the page on a worker — and
|
|
28
|
+
* from no other, and is guarded in case a host ever measures from two.
|
|
29
|
+
*/
|
|
30
|
+
object AndroidTextMeasurer {
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Make the measurer, attach the platform to it and make it the default
|
|
34
|
+
* every `EVGLayout` and `EVGTextEngine` in the process starts from.
|
|
35
|
+
*/
|
|
36
|
+
fun install(faces: FaceSet): EVGHostTextMeasurer {
|
|
37
|
+
val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG)
|
|
38
|
+
val measurer = EVGHostTextMeasurer()
|
|
39
|
+
measurer.attach({ kind, text, family, size, bold, italic ->
|
|
40
|
+
synchronized(paint) {
|
|
41
|
+
paint.typeface = faces.typeface(family, bold, italic)
|
|
42
|
+
paint.textSize = size.toFloat()
|
|
43
|
+
when (kind) {
|
|
44
|
+
0 -> if (text.isEmpty()) 0.0 else paint.measureText(text).toDouble()
|
|
45
|
+
// `ascent` is negative on Android — the distance from
|
|
46
|
+
// the baseline UP to the top — and EVG wants it positive.
|
|
47
|
+
1 -> (-paint.fontMetrics.ascent).toDouble()
|
|
48
|
+
2 -> paint.fontMetrics.descent.toDouble()
|
|
49
|
+
else -> paint.fontMetrics.leading.toDouble()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}, "android")
|
|
53
|
+
EVGDefaultMeasurer.install(measurer)
|
|
54
|
+
return measurer
|
|
55
|
+
}
|
|
56
|
+
}
|