ranger-compiler 3.5.1 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1064 -20
- package/LICENSE +3 -1
- package/README.md +123 -28
- package/dist/Lang.rgr +1188 -290
- package/dist/api.d.ts +2343 -879
- package/dist/api.js +79923 -56921
- package/dist/lib/JSON.rgr +102 -91
- package/dist/lib/Shell.rgr +4 -4
- package/dist/lib/apple/AppleToolchain.rgr +4 -4
- package/dist/lib/apple/README.md +5 -4
- package/dist/lib/apple/apple_test.rgr +1 -1
- package/dist/lib/core/README.md +1 -1
- package/dist/lib/evg/EVG.rgr +12 -0
- package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
- package/dist/lib/evg/EVGA11yTree.rgr +894 -0
- package/dist/lib/evg/EVGBox.rgr +267 -0
- package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
- package/dist/lib/evg/EVGCodepoint.rgr +316 -0
- package/dist/lib/evg/EVGColor.rgr +700 -0
- package/dist/lib/evg/EVGCommands.rgr +177 -0
- package/dist/lib/evg/EVGComponent.rgr +331 -0
- package/dist/lib/evg/EVGComponentTest.rgr +387 -0
- package/dist/lib/evg/EVGConnector.rgr +541 -0
- package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
- package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
- package/dist/lib/evg/EVGEasing.rgr +370 -0
- package/dist/lib/evg/EVGEffectTest.rgr +253 -0
- package/dist/lib/evg/EVGElement.rgr +4914 -0
- package/dist/lib/evg/EVGFixedTest.rgr +289 -0
- package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
- package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
- package/dist/lib/evg/EVGFling.rgr +244 -0
- package/dist/lib/evg/EVGFocus.rgr +400 -0
- package/dist/lib/evg/EVGFocusTest.rgr +399 -0
- package/dist/lib/evg/EVGGradient.rgr +322 -0
- package/dist/lib/evg/EVGGrapheme.rgr +190 -0
- package/dist/lib/evg/EVGGrid.rgr +975 -0
- package/dist/lib/evg/EVGHitTest.rgr +208 -0
- package/dist/lib/evg/EVGHoles.rgr +294 -0
- package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
- package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
- package/dist/lib/evg/EVGHostTree.rgr +834 -0
- package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
- package/dist/lib/evg/EVGImageDecode.rgr +117 -0
- package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
- package/dist/lib/evg/EVGInspect.rgr +883 -0
- package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
- package/dist/lib/evg/EVGJsonTest.rgr +535 -0
- package/dist/lib/evg/EVGLayout.rgr +4220 -0
- package/dist/lib/evg/EVGMeasure.rgr +1267 -0
- package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
- package/dist/lib/evg/EVGPatch.rgr +1721 -0
- package/dist/lib/evg/EVGPatchTest.rgr +692 -0
- package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
- package/dist/lib/evg/EVGReconcile.rgr +226 -0
- package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
- package/dist/lib/evg/EVGReject.rgr +126 -0
- package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
- package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
- package/dist/lib/evg/EVGRuler.rgr +232 -0
- package/dist/lib/evg/EVGRulerTest.rgr +172 -0
- package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
- package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
- package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
- package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
- package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
- package/dist/lib/evg/EVGText.rgr +105 -0
- package/dist/lib/evg/EVGTextEngine.rgr +536 -0
- package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
- package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
- package/dist/lib/evg/EVGToolbar.rgr +1369 -0
- package/dist/lib/evg/EVGTransition.rgr +728 -0
- package/dist/lib/evg/EVGTreeJson.rgr +721 -0
- package/dist/lib/evg/EVGUnit.rgr +554 -0
- package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
- package/dist/lib/evg/EvgApp.rgr +189 -0
- package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
- package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
- package/dist/lib/evg/EvgHost.rgr +451 -0
- package/dist/lib/evg/EvgTest.rgr +91 -0
- package/dist/lib/evg/EvgTraceColor.rgr +236 -0
- package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
- package/dist/lib/evg/EvgTraceFit.rgr +767 -0
- package/dist/lib/evg/EvgTracePath.rgr +435 -0
- package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
- package/dist/lib/evg/EvgViewport.rgr +313 -0
- package/dist/lib/evg/FxDemoDoc.rgr +185 -0
- package/dist/lib/evg/HOSTS.md +227 -0
- package/dist/lib/evg/ISSUES.md +835 -0
- package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
- package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
- package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
- package/dist/lib/evg/PLAN_EVG.md +518 -0
- package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
- package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
- package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
- package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
- package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
- package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
- package/dist/lib/evg/PathBuilder.rgr +333 -0
- package/dist/lib/evg/README.md +1236 -0
- package/dist/lib/evg/SPEC.md +1252 -0
- package/dist/lib/evg/SVGPathParser.rgr +1199 -0
- package/dist/lib/evg/SvgParser.rgr +1736 -0
- package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
- package/dist/lib/evg/VectorShapes.rgr +331 -0
- package/dist/lib/evg/VectorStroke.rgr +107 -0
- package/dist/lib/evg/VectorViewBox.rgr +380 -0
- package/dist/lib/evg/agent/README.md +290 -0
- package/dist/lib/evg/agent/evg_agent.rgr +899 -0
- package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
- package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
- package/dist/lib/evg/agent/fixtures/connector.css +63 -0
- package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
- package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
- package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
- package/dist/lib/evg/agent/fixtures/popover.css +99 -0
- package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
- package/dist/lib/evg/agent/roundtrip.sh +74 -0
- package/dist/lib/evg/agent/smoke.sh +230 -0
- package/dist/lib/evg/android/README.md +97 -0
- package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
- package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
- package/dist/lib/evg/android/androidstubs/App.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
- package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
- package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
- package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
- package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
- package/dist/lib/evg/android/androidstubs/View.kt +113 -0
- package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
- package/dist/lib/evg/apple/README.md +128 -0
- package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
- package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
- package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
- package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
- package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
- package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
- package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
- package/dist/lib/evg/bench/README.md +64 -0
- package/dist/lib/evg/bench/layout-bench.mjs +316 -0
- package/dist/lib/evg/bench/layout-cases.mjs +510 -0
- package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
- package/dist/lib/evg/bin/.gitignore +17 -0
- package/dist/lib/evg/evg_test.rgr +313 -0
- package/dist/lib/evg/gl/README.md +198 -0
- package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
- package/dist/lib/evg/gl/blur-check.mjs +399 -0
- package/dist/lib/evg/gl/boxmodel.json +1 -0
- package/dist/lib/evg/gl/demo.html +46 -0
- package/dist/lib/evg/gl/effect-presets.css +285 -0
- package/dist/lib/evg/gl/effect-presets.js +63 -0
- package/dist/lib/evg/gl/effect-shots.mjs +135 -0
- package/dist/lib/evg/gl/evg-a11y.js +566 -0
- package/dist/lib/evg/gl/evg-binary.js +160 -0
- package/dist/lib/evg/gl/evg-engine.js +296 -0
- package/dist/lib/evg/gl/evg-fx.js +237 -0
- package/dist/lib/evg/gl/evg-gestures.js +209 -0
- package/dist/lib/evg/gl/evg-list.js +167 -0
- package/dist/lib/evg/gl/evg-measure.js +186 -0
- package/dist/lib/evg/gl/evg-textinput.js +303 -0
- package/dist/lib/evg/gl/evg-view.js +144 -0
- package/dist/lib/evg/gl/evg-webgl.js +3942 -0
- package/dist/lib/evg/gl/fx-check.mjs +998 -0
- package/dist/lib/evg/gl/fx-demo.html +166 -0
- package/dist/lib/evg/gl/fx-demo.js +2 -0
- package/dist/lib/evg/gl/fx-serve.mjs +47 -0
- package/dist/lib/evg/gl/gestures-check.mjs +189 -0
- package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
- package/dist/lib/evg/gl/measure-check.mjs +135 -0
- package/dist/lib/evg/gl/rotation-check.mjs +207 -0
- package/dist/lib/evg/gl/shift-check.mjs +113 -0
- package/dist/lib/evg/gl/stroke-check.mjs +168 -0
- package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
- package/dist/lib/evg/gl/view-check.mjs +343 -0
- package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
- package/dist/lib/evg/html/evg-dom.js +318 -0
- package/dist/lib/evg/html/evg-html.js +600 -0
- package/dist/lib/evg/inspect/README.md +415 -0
- package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
- package/dist/lib/evg/inspect/evg-inspect.js +947 -0
- package/dist/lib/evg/inspect/shots/css.png +0 -0
- package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
- package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
- package/dist/lib/evg/inspect/shots/state.png +0 -0
- package/dist/lib/evg/inspect/shots.mjs +226 -0
- package/dist/lib/evg/oracle/css-blur.json +576 -0
- package/dist/lib/evg/oracle/css-box.json +157 -0
- package/dist/lib/evg/oracle/css-timing.json +709 -0
- package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
- package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
- package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
- package/dist/lib/evg/original/EVGColor.clj +310 -0
- package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
- package/dist/lib/evg/original/SVGPath.rgr +627 -0
- package/dist/lib/evg/original/Vec2.crgr +103 -0
- package/dist/lib/evg/ranger.json +9 -0
- package/dist/lib/evg/showcase/README.md +246 -0
- package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
- package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
- package/dist/lib/evg/showcase/build.mjs +651 -0
- package/dist/lib/evg/showcase/pages/album.tsx +30 -0
- package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
- package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
- package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
- package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
- package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
- package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
- package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
- package/dist/lib/evg/showcase/pages/more.tsx +332 -0
- package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
- package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
- package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
- package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
- package/dist/lib/evg/showcase/pages/units.tsx +35 -0
- package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
- package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
- package/dist/lib/evg/showcase/pages/views.tsx +223 -0
- package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
- package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
- package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
- package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
- package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
- package/dist/lib/evg/showcase/themes/more-default.css +128 -0
- package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
- package/dist/lib/evg/showcase/themes/showcase.css +508 -0
- package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
- package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
- package/dist/lib/evg/showcase/themes/views-default.css +15 -0
- package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
- package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
- package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
- package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
- package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
- package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
- package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
- package/dist/lib/evg/web/responsive/README.md +97 -0
- package/dist/lib/evg/web/responsive/build.mjs +90 -0
- package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
- package/dist/lib/evg/web/responsive/index.html +177 -0
- package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
- package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
- package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
- package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
- package/dist/lib/evg/web/tools/minify.mjs +60 -0
- package/dist/lib/evg/web/tracer/build.mjs +87 -0
- package/dist/lib/evg/web/tracer/index.html +2805 -0
- package/dist/lib/evg/web/tracer/sample.png +0 -0
- package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
- package/dist/lib/evgr/Cargo.lock +21 -0
- package/dist/lib/evgr/Cargo.toml +19 -0
- package/dist/lib/evgr/README.md +140 -0
- package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
- package/dist/lib/evgr/bench/compare.mjs +252 -0
- package/dist/lib/evgr/bench/speed.mjs +277 -0
- package/dist/lib/evgr/bin/.gitignore +3 -0
- package/dist/lib/evgr/src/bin/bench.rs +106 -0
- package/dist/lib/evgr/src/bin/smoke.rs +13 -0
- package/dist/lib/evgr/src/grid.rs +730 -0
- package/dist/lib/evgr/src/lib.rs +1003 -0
- package/dist/lib/evgr/src/style.rs +468 -0
- package/dist/lib/evgr/src/text.rs +83 -0
- package/dist/lib/image/BitReader.rgr +171 -0
- package/dist/lib/image/Buffer.rgr +173 -0
- package/dist/lib/image/DCT.rgr +283 -0
- package/dist/lib/image/Deflate.rgr +339 -0
- package/dist/lib/image/HuffmanDecoder.rgr +181 -0
- package/dist/lib/image/ImageBuffer.rgr +706 -0
- package/dist/lib/image/JPEGDecoder.rgr +808 -0
- package/dist/lib/image/PNGDecoder.rgr +544 -0
- package/dist/lib/image/PNGEncoder.rgr +388 -0
- package/dist/lib/image/PPMImage.rgr +224 -0
- package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
- package/dist/lib/image/README.md +33 -0
- package/dist/lib/image/RasterBuffer.rgr +294 -0
- package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
- package/dist/lib/image/WebPDecoder.rgr +433 -0
- package/dist/lib/image/WebPLossless.rgr +1035 -0
- package/dist/lib/image/WebPLossy.rgr +1929 -0
- package/dist/lib/image/ranger.json +9 -0
- package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
- package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
- package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
- package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
- package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
- package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
- package/dist/lib/image/tests/run_webp_tests.sh +39 -0
- package/dist/lib/rust/RsJson.rgr +468 -0
- package/dist/lib/rust/RsPrelude.rgr +1663 -0
- package/dist/lib/shell_test.rgr +7 -7
- package/dist/lib/stdlib.rgr +21 -5
- package/dist/lib/zip/ranger.json +6 -0
- package/dist/rgrc.js +87318 -67610
- package/package.json +1010 -1040
- package/dist/README.md +0 -117
- package/dist/package.json +0 -47
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EVGHostMeasurerTest — does a platform's one function reach every layout?
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; `EVGHostTextMeasurer` is the seam PLAN_NATIVE_HOSTS.md S0 adds: a platform
|
|
8
|
+
; hands over one function and every layout in the process measures with it.
|
|
9
|
+
; This drives the Ranger half with a made-up platform — widths and vertical
|
|
10
|
+
; metrics nothing like the table's, so a layout that still used the table
|
|
11
|
+
; is caught by the numbers — and asks:
|
|
12
|
+
;
|
|
13
|
+
; * does a layout built after `EVGDefaultMeasurer.install` measure with it,
|
|
14
|
+
; with no call on the layout itself, and one built after `clear` not;
|
|
15
|
+
; * does the `-Bold` suffix `effectiveFontFamily` writes reach the host as
|
|
16
|
+
; a flag, with the family stripped;
|
|
17
|
+
; * is the platform asked for a face's vertical metrics ONCE per face and
|
|
18
|
+
; never per run, and for a width once per distinct run through the
|
|
19
|
+
; engine's cache;
|
|
20
|
+
; * does `line-height: normal` become the face's own line box;
|
|
21
|
+
; * does an unattached measurer fall back to the table, and does attaching
|
|
22
|
+
; later move `measureKey` so an engine re-measures;
|
|
23
|
+
; * does a text node in a real layout wrap where the host's widths say.
|
|
24
|
+
;
|
|
25
|
+
; npm run evg:hostmeasurer:test
|
|
26
|
+
; ==============================================================================
|
|
27
|
+
|
|
28
|
+
Import "EVGHostTextMeasurer.rgr"
|
|
29
|
+
Import "EVGTextEngine.rgr"
|
|
30
|
+
Import "EVGLayout.rgr"
|
|
31
|
+
Import "EVGElement.rgr"
|
|
32
|
+
Import "EVGUnit.rgr"
|
|
33
|
+
|
|
34
|
+
class EVGHostMeasurerTest {
|
|
35
|
+
def passed:int 0
|
|
36
|
+
def failed:int 0
|
|
37
|
+
; What the fake platform was asked, for the assertions on call counts
|
|
38
|
+
; and on what reached it.
|
|
39
|
+
def lastFamily:string ""
|
|
40
|
+
def lastBold:boolean false
|
|
41
|
+
def lastText:string ""
|
|
42
|
+
|
|
43
|
+
sfn m@(main):void () {
|
|
44
|
+
def t (new EVGHostMeasurerTest())
|
|
45
|
+
t.run()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn ok:void (what:string cond:boolean) {
|
|
49
|
+
if cond {
|
|
50
|
+
passed = (passed + 1)
|
|
51
|
+
print (" PASS " + what)
|
|
52
|
+
} {
|
|
53
|
+
failed = (failed + 1)
|
|
54
|
+
print (" FAIL " + what)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fn near:void (what:string a:double b:double) {
|
|
59
|
+
def d:double (a - b)
|
|
60
|
+
if (d < 0.0) {
|
|
61
|
+
d = (0.0 - d)
|
|
62
|
+
}
|
|
63
|
+
this.ok((what + " (" + (to_string a) + " vs " + (to_string b) + ")") (d < 0.001))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
; The made-up platform: every glyph is 0.7em wide (0.9em bold), the
|
|
67
|
+
; ascent 1.0em, the descent 0.3em, the gap 0.2em — so the normal line box
|
|
68
|
+
; is 1.5em where the table says 1.15, and no width agrees with the table.
|
|
69
|
+
fn fakePlatform:EVGHostTextMeasurer () {
|
|
70
|
+
def hm (new EVGHostTextMeasurer())
|
|
71
|
+
hm.attach((fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean) {
|
|
72
|
+
lastFamily = family
|
|
73
|
+
lastBold = bold
|
|
74
|
+
lastText = text
|
|
75
|
+
if (kind == 0) {
|
|
76
|
+
def per:double 0.7
|
|
77
|
+
if bold {
|
|
78
|
+
per = 0.9
|
|
79
|
+
}
|
|
80
|
+
return ((to_double (strlen text)) * size * per)
|
|
81
|
+
}
|
|
82
|
+
if (kind == 1) {
|
|
83
|
+
return (size * 1.0)
|
|
84
|
+
}
|
|
85
|
+
if (kind == 2) {
|
|
86
|
+
return (size * 0.3)
|
|
87
|
+
}
|
|
88
|
+
return (size * 0.2)
|
|
89
|
+
}) "fake")
|
|
90
|
+
return hm
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn run:void () {
|
|
94
|
+
print "=== EVGHostTextMeasurer ==="
|
|
95
|
+
this.testDefaultReachesFreshLayouts()
|
|
96
|
+
this.testBoldSuffix()
|
|
97
|
+
this.testFaceCacheAndRunCache()
|
|
98
|
+
this.testLineHeight()
|
|
99
|
+
this.testUnattachedFallsBackThenAttaches()
|
|
100
|
+
this.testWrapInRealLayout()
|
|
101
|
+
this.testHasFace()
|
|
102
|
+
EVGDefaultMeasurer.uninstall()
|
|
103
|
+
print ""
|
|
104
|
+
print ("passed = " + (to_string passed) + " failed = " + (to_string failed))
|
|
105
|
+
if (failed > 0) {
|
|
106
|
+
print "FAILURES"
|
|
107
|
+
} {
|
|
108
|
+
print "ALL PASS"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn testDefaultReachesFreshLayouts:void () {
|
|
113
|
+
print "-- the default reaches a layout that never heard of it"
|
|
114
|
+
EVGDefaultMeasurer.uninstall()
|
|
115
|
+
def before (new EVGLayout())
|
|
116
|
+
def te0:EVGTextEngine (before.getTextEngine())
|
|
117
|
+
def m0:EVGTextMetrics (te0.measureRun("abcd" "sans-serif" 10.0))
|
|
118
|
+
this.ok("without an install a layout measures with the table" (m0.width < 28.0))
|
|
119
|
+
|
|
120
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
121
|
+
EVGDefaultMeasurer.install(hm)
|
|
122
|
+
this.ok("isInstalled" (EVGDefaultMeasurer.isInstalled()))
|
|
123
|
+
def lay (new EVGLayout())
|
|
124
|
+
def te:EVGTextEngine (lay.getTextEngine())
|
|
125
|
+
def m:EVGTextMetrics (te.measureRun("abcd" "sans-serif" 10.0))
|
|
126
|
+
this.near("a fresh layout measures with the host" m.width 28.0)
|
|
127
|
+
this.ok("and reports itself font-accurate" (te.measurer.isFontAccurate()))
|
|
128
|
+
|
|
129
|
+
def eng (new EVGTextEngine())
|
|
130
|
+
def m2:EVGTextMetrics (eng.measureRun("ab" "sans-serif" 10.0))
|
|
131
|
+
this.near("a fresh engine too" m2.width 14.0)
|
|
132
|
+
|
|
133
|
+
EVGDefaultMeasurer.uninstall()
|
|
134
|
+
def after (new EVGLayout())
|
|
135
|
+
def te2:EVGTextEngine (after.getTextEngine())
|
|
136
|
+
def m3:EVGTextMetrics (te2.measureRun("abcd" "sans-serif" 10.0))
|
|
137
|
+
this.ok("after clear a new layout is back on the table" (m3.width < 28.0))
|
|
138
|
+
this.near("and the old one keeps the host it was built with" ((te.measureRun("abcd" "sans-serif" 10.0)).width) 28.0)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fn testBoldSuffix:void () {
|
|
142
|
+
print "-- the -Bold suffix reaches the host as a flag"
|
|
143
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
144
|
+
def m:EVGTextMetrics (hm.measureText("ab" "Inter-Bold" 10.0))
|
|
145
|
+
this.ok("family stripped" (lastFamily == "Inter"))
|
|
146
|
+
this.ok("bold set" lastBold)
|
|
147
|
+
this.near("bold width" m.width 18.0)
|
|
148
|
+
def m2:EVGTextMetrics (hm.measureText("ab" "Inter" 10.0))
|
|
149
|
+
this.ok("plain family unchanged" (lastFamily == "Inter"))
|
|
150
|
+
this.ok("bold clear" (lastBold == false))
|
|
151
|
+
this.near("plain width" m2.width 14.0)
|
|
152
|
+
this.ok("a family that merely ends in Bold is not stripped twice" ((EVGHostTextMeasurer.baseFamily("Bold")) == "Bold"))
|
|
153
|
+
def el (EVGElement.createSpan())
|
|
154
|
+
el.setAttribute("font-family" "Inter")
|
|
155
|
+
el.setAttribute("font-weight" "bold")
|
|
156
|
+
this.ok("effectiveFontFamily is Family-Bold" ((el.effectiveFontFamily()) == "Inter-Bold"))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
fn testFaceCacheAndRunCache:void () {
|
|
160
|
+
print "-- the platform is asked per face and per distinct run, not per call"
|
|
161
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
162
|
+
def eng (new EVGTextEngine())
|
|
163
|
+
eng.setMeasurer(hm)
|
|
164
|
+
def i:int 0
|
|
165
|
+
while (i < 50) {
|
|
166
|
+
eng.measureRun("hello" "sans-serif" 12.0)
|
|
167
|
+
eng.measureRun("hello world" "sans-serif" 12.0)
|
|
168
|
+
i = (i + 1)
|
|
169
|
+
}
|
|
170
|
+
this.ok("three vertical calls for one face" (hm.faceCalls == 3))
|
|
171
|
+
this.ok("two width calls for two runs through the engine" (hm.widthCalls == 2))
|
|
172
|
+
eng.measureRun("hello" "sans-serif-Bold" 12.0)
|
|
173
|
+
this.ok("a bold face is a second face" (hm.faceCalls == 6))
|
|
174
|
+
eng.measureRun("hello" "sans-serif" 13.0)
|
|
175
|
+
this.ok("a size is a third" (hm.faceCalls == 9))
|
|
176
|
+
this.ok("the empty run costs no width call" (((hm.measureText("" "sans-serif" 12.0)).width) == 0.0))
|
|
177
|
+
this.ok("and asked the host for nothing" (hm.widthCalls == 4))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn testLineHeight:void () {
|
|
181
|
+
print "-- line-height: normal is the face's line box"
|
|
182
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
183
|
+
this.near("ascent + descent + gap" (hm.getLineHeight("sans-serif" 10.0)) 15.0)
|
|
184
|
+
def m:EVGTextMetrics (hm.measureText("x" "sans-serif" 10.0))
|
|
185
|
+
this.near("ascent" m.ascent 10.0)
|
|
186
|
+
this.near("descent" m.descent 3.0)
|
|
187
|
+
this.near("the run carries the same line height" m.lineHeight 15.0)
|
|
188
|
+
; A host that does not know the gap says so with a negative number.
|
|
189
|
+
def noGap (new EVGHostTextMeasurer())
|
|
190
|
+
noGap.attach((fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean) {
|
|
191
|
+
if (kind == 3) {
|
|
192
|
+
return (0.0 - 1.0)
|
|
193
|
+
}
|
|
194
|
+
if (kind == 0) {
|
|
195
|
+
return (size * (to_double (strlen text)))
|
|
196
|
+
}
|
|
197
|
+
return (size * 0.5)
|
|
198
|
+
}) "nogap")
|
|
199
|
+
this.near("an unknown gap is zero, not negative" (noGap.getLineHeight("sans-serif" 10.0)) 10.0)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
fn testUnattachedFallsBackThenAttaches:void () {
|
|
203
|
+
print "-- unattached measures like the table; attaching moves the key"
|
|
204
|
+
def hm (new EVGHostTextMeasurer())
|
|
205
|
+
def table (new SimpleTextMeasurer())
|
|
206
|
+
def a:EVGTextMetrics (hm.measureText("Päiväkirja" "sans-serif" 14.0))
|
|
207
|
+
def b:EVGTextMetrics (table.measureText("Päiväkirja" "sans-serif" 14.0))
|
|
208
|
+
this.near("width as the table" a.width b.width)
|
|
209
|
+
this.near("line height as the table" (hm.getLineHeight("sans-serif" 14.0)) (table.getLineHeight("sans-serif" 14.0)))
|
|
210
|
+
this.ok("not font-accurate before attach" ((hm.isFontAccurate()) == false))
|
|
211
|
+
this.ok("no face before attach" ((hm.hasFace("sans-serif")) == false))
|
|
212
|
+
def k0:string (hm.measureKey())
|
|
213
|
+
def eng (new EVGTextEngine())
|
|
214
|
+
eng.setMeasurer(hm)
|
|
215
|
+
def w0:double ((eng.measureRun("hello" "sans-serif" 10.0)).width)
|
|
216
|
+
hm.attach((fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean) {
|
|
217
|
+
if (kind == 0) {
|
|
218
|
+
return (size * 2.0 * (to_double (strlen text)))
|
|
219
|
+
}
|
|
220
|
+
return (size * 0.5)
|
|
221
|
+
}) "late")
|
|
222
|
+
def k1:string (hm.measureKey())
|
|
223
|
+
this.ok("the key moved" (k0 != k1))
|
|
224
|
+
this.ok("the key names the host" ((indexOf k1 "late") >= 0))
|
|
225
|
+
def w1:double ((eng.measureRun("hello" "sans-serif" 10.0)).width)
|
|
226
|
+
this.ok("the engine measured again without clearCache" (w1 != w0))
|
|
227
|
+
this.near("with the host's width" w1 100.0)
|
|
228
|
+
hm.invalidate()
|
|
229
|
+
this.ok("invalidate moves the key again" ((hm.measureKey()) != k1))
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
fn testWrapInRealLayout:void () {
|
|
233
|
+
print "-- a text node wraps where the host's widths say"
|
|
234
|
+
; 0.7em a glyph at 10px is 7px; "aaaa bbbb cccc" is 14 glyphs = 98px.
|
|
235
|
+
; In a 60px box the host wraps it into three lines; the table
|
|
236
|
+
; (0.556em) fits "aaaa bbbb" in 50px and makes two.
|
|
237
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
238
|
+
EVGDefaultMeasurer.install(hm)
|
|
239
|
+
def root (EVGElement.createDiv())
|
|
240
|
+
root.setAttribute("width" "60px")
|
|
241
|
+
root.setAttribute("height" "200px")
|
|
242
|
+
def span (EVGElement.createSpan())
|
|
243
|
+
span.setAttribute("width" "60px")
|
|
244
|
+
span.setAttribute("font-size" "10px")
|
|
245
|
+
span.setAttribute("font-family" "sans-serif")
|
|
246
|
+
span.textContent = "aaaa bbbb cccc"
|
|
247
|
+
root.addChild(span)
|
|
248
|
+
def lay (new EVGLayout())
|
|
249
|
+
lay.setPageSize(60.0 200.0)
|
|
250
|
+
lay.layout(root)
|
|
251
|
+
; Three lines of the face's 15px line box.
|
|
252
|
+
this.near("three lines at the host's line height" span.calculatedHeight 45.0)
|
|
253
|
+
def te:EVGTextEngine (lay.getTextEngine())
|
|
254
|
+
this.ok("the engine counts three" ((te.lineCount("aaaa bbbb cccc" "sans-serif" 10.0 60.0)) == 3))
|
|
255
|
+
EVGDefaultMeasurer.uninstall()
|
|
256
|
+
def lay2 (new EVGLayout())
|
|
257
|
+
def root2 (EVGElement.createDiv())
|
|
258
|
+
root2.setAttribute("width" "60px")
|
|
259
|
+
root2.setAttribute("height" "200px")
|
|
260
|
+
def span2 (EVGElement.createSpan())
|
|
261
|
+
span2.setAttribute("width" "60px")
|
|
262
|
+
span2.setAttribute("font-size" "10px")
|
|
263
|
+
span2.setAttribute("font-family" "sans-serif")
|
|
264
|
+
span2.textContent = "aaaa bbbb cccc"
|
|
265
|
+
root2.addChild(span2)
|
|
266
|
+
lay2.setPageSize(60.0 200.0)
|
|
267
|
+
lay2.layout(root2)
|
|
268
|
+
this.ok("the table makes fewer" (span2.calculatedHeight < 45.0))
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fn testHasFace:void () {
|
|
272
|
+
print "-- hasFace: a substituting host has every face, a strict one names them"
|
|
273
|
+
def hm:EVGHostTextMeasurer (this.fakePlatform())
|
|
274
|
+
this.ok("resolvesAll by default" (hm.hasFace("Whatever")))
|
|
275
|
+
hm.setResolvesAll(false)
|
|
276
|
+
this.ok("strict: unknown family has no face" ((hm.hasFace("Whatever")) == false))
|
|
277
|
+
hm.addKnownFamily("Inter")
|
|
278
|
+
this.ok("strict: a known family has one" (hm.hasFace("Inter")))
|
|
279
|
+
this.ok("strict: and its bold" (hm.hasFace("Inter-Bold")))
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
; SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
; ==============================================================================
|
|
4
|
+
; EVGHostTextMeasurer — the platform measures, EVG breaks the lines
|
|
5
|
+
; ==============================================================================
|
|
6
|
+
;
|
|
7
|
+
; PLAN_NATIVE_HOSTS.md, decision D3 and stage S0. Every painter below the
|
|
8
|
+
; display list draws text with a face the PLATFORM chose — a browser's font
|
|
9
|
+
; stack, CoreText on Apple, a `Typeface` on Android — while the layout above
|
|
10
|
+
; it measured the run with `SimpleTextMeasurer`'s advance table, a snapshot of
|
|
11
|
+
; one browser's sans fallback taken once. Where the two faces differ, a run
|
|
12
|
+
; is drawn wider or narrower than the box that was sized for it: a label
|
|
13
|
+
; clips, a caret lands beside its glyphs, a line wraps that paint would not
|
|
14
|
+
; have wrapped.
|
|
15
|
+
;
|
|
16
|
+
; This measurer closes that gap the way `EVGContextMeasurer` closes it for
|
|
17
|
+
; the software canvas: the host that will paint is the host that measures.
|
|
18
|
+
; It is GENERIC on purpose — one measurer, every platform, every app — and
|
|
19
|
+
; the whole of what a platform has to provide is ONE FUNCTION:
|
|
20
|
+
;
|
|
21
|
+
; metric(kind text family size bold italic) -> double
|
|
22
|
+
;
|
|
23
|
+
; kind 0 the advance width of `text` set in that face at that size
|
|
24
|
+
; kind 1 the face's ascent, in pixels, at that size (text ignored)
|
|
25
|
+
; kind 2 the face's descent (text ignored)
|
|
26
|
+
; kind 3 the face's line gap, or a negative number for "unknown"
|
|
27
|
+
;
|
|
28
|
+
; The host writes it in its own language against its own text API — canvas
|
|
29
|
+
; `measureText`, `CTLineGetTypographicBounds`, `Paint.measureText` — and
|
|
30
|
+
; hands it over with `attach`. Everything else is here, written once:
|
|
31
|
+
; the per-face cache of the vertical metrics (three host calls per face,
|
|
32
|
+
; not three per run), the `-Bold` convention `EVGElement.effectiveFontFamily`
|
|
33
|
+
; encodes the weight in, the cache key the text engine needs, and the
|
|
34
|
+
; fallback to the table when no host has attached yet, so an app can install
|
|
35
|
+
; this at start-up and attach the platform later — a browser after
|
|
36
|
+
; `document.fonts.ready` — without ever measuring nothing.
|
|
37
|
+
;
|
|
38
|
+
; WHY A FUNCTION AND NOT A SUBCLASS. A host could extend this class in its own
|
|
39
|
+
; language and override `measureText`; JavaScript, Swift and Kotlin all
|
|
40
|
+
; allow it. But then each of the three hosts owns a copy of the face cache,
|
|
41
|
+
; the weight convention and the key — the three things that were wrong in
|
|
42
|
+
; three different ways when five painters each walked the tree. A closure
|
|
43
|
+
; keeps the platform's contribution to the one thing only the platform
|
|
44
|
+
; knows, and Ranger's lambda fields compile to a settable property of
|
|
45
|
+
; function type on every target (`(Int, String, …) -> Double` in Kotlin, an
|
|
46
|
+
; `@escaping` closure in Swift, a plain property in ES6).
|
|
47
|
+
;
|
|
48
|
+
; WHAT IT MEANS FOR PRINT PARITY. Nothing. The lines are still broken here,
|
|
49
|
+
; by `EVGTextEngine`, one run per line; a PDF laid out with the TTF measurer
|
|
50
|
+
; and a screen laid out with this one agree wherever they share a face, and
|
|
51
|
+
; where they do not, the screen is now honest about its own face rather
|
|
52
|
+
; than pretending to be the table.
|
|
53
|
+
;
|
|
54
|
+
; See `EVGHostMeasurerTest.rgr` (`npm run evg:hostmeasurer:test`) and the
|
|
55
|
+
; three hosts: `gl/evg-measure.js`, `apple/Sources/CoreTextMeasurer.swift`,
|
|
56
|
+
; `android/src/…/AndroidTextMeasurer.kt` (with its Java2D twin).
|
|
57
|
+
; ==============================================================================
|
|
58
|
+
|
|
59
|
+
Import "EVGTextMeasurer.rgr"
|
|
60
|
+
|
|
61
|
+
class EVGHostTextMeasurer {
|
|
62
|
+
Extends(EVGTextMeasurer)
|
|
63
|
+
|
|
64
|
+
; The one function. Unset until the host attaches; every question is then
|
|
65
|
+
; answered by `fallback` below, so a measurer that was installed before
|
|
66
|
+
; its platform arrived measures like the table did, not like nothing.
|
|
67
|
+
def metricFn@(optional):(fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean))
|
|
68
|
+
def attached:boolean false
|
|
69
|
+
; Which platform is on the other end — "canvas", "coretext", "android",
|
|
70
|
+
; "awt", or whatever the host calls itself. It goes into `measureKey`, so
|
|
71
|
+
; a text engine that outlives a host swap cannot hand back the old host's
|
|
72
|
+
; widths.
|
|
73
|
+
def hostName:string ""
|
|
74
|
+
; Bumped by `attach`, `detach` and `invalidate`. Same reason: the engine
|
|
75
|
+
; caches by `measureKey`, and a face that finished loading is a different
|
|
76
|
+
; answer to the same question.
|
|
77
|
+
def generation:int 0
|
|
78
|
+
|
|
79
|
+
; Does the platform draw SOMETHING for every family it is asked for? A
|
|
80
|
+
; browser's font stack and CoreText both substitute, so every family
|
|
81
|
+
; "has a face" — the face the painter will use — and warning about it
|
|
82
|
+
; would warn about every label on the page. A host that bundles exact
|
|
83
|
+
; TTFs and wants a missing one reported sets this false and names what
|
|
84
|
+
; it has through `addKnownFamily`.
|
|
85
|
+
def resolvesAll:boolean true
|
|
86
|
+
def known:[string]
|
|
87
|
+
|
|
88
|
+
; The face cache: key -> ascent, descent, line gap, in pixels. A face is
|
|
89
|
+
; a family, a size, a weight and a slant; a page asks for a handful of
|
|
90
|
+
; them and thousands of runs in each, so the three vertical questions
|
|
91
|
+
; are asked once per face and never per run.
|
|
92
|
+
def faceKeys:[string]
|
|
93
|
+
def faceAsc:[double]
|
|
94
|
+
def faceDesc:[double]
|
|
95
|
+
def faceGap:[double]
|
|
96
|
+
; The last face looked up, because a wrap asks the same face for every
|
|
97
|
+
; candidate line and a linear search over a dozen keys per call adds up.
|
|
98
|
+
def lastKey:string ""
|
|
99
|
+
def lastIdx:int (0 - 1)
|
|
100
|
+
|
|
101
|
+
; How many times the host has been called, by kind. For the test and for
|
|
102
|
+
; a bench: a measurer that calls the platform per character instead of
|
|
103
|
+
; per run would pass every width check and cost a frame.
|
|
104
|
+
def widthCalls:int 0
|
|
105
|
+
def faceCalls:int 0
|
|
106
|
+
|
|
107
|
+
; Answers everything while no host is attached.
|
|
108
|
+
def fallback:SimpleTextMeasurer (new SimpleTextMeasurer())
|
|
109
|
+
|
|
110
|
+
Constructor () {
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
; --- the kinds, by name -------------------------------------------------
|
|
114
|
+
|
|
115
|
+
sfn KIND_WIDTH:int () {
|
|
116
|
+
return 0
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
sfn KIND_ASCENT:int () {
|
|
120
|
+
return 1
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
sfn KIND_DESCENT:int () {
|
|
124
|
+
return 2
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
sfn KIND_GAP:int () {
|
|
128
|
+
return 3
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
; --- attaching the platform ---------------------------------------------
|
|
132
|
+
|
|
133
|
+
fn attach:void (f:(fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean)) name:string) {
|
|
134
|
+
metricFn = f
|
|
135
|
+
hostName = name
|
|
136
|
+
attached = true
|
|
137
|
+
this.invalidate()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn detach:void () {
|
|
141
|
+
attached = false
|
|
142
|
+
this.invalidate()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
; The host's answers changed — a face finished loading, the device's
|
|
146
|
+
; font settings moved. The cache is dropped and the key moves on, so
|
|
147
|
+
; every engine holding this measurer measures again.
|
|
148
|
+
fn invalidate:void () {
|
|
149
|
+
generation = (generation + 1)
|
|
150
|
+
def fk:[string]
|
|
151
|
+
faceKeys = fk
|
|
152
|
+
def fa:[double]
|
|
153
|
+
faceAsc = fa
|
|
154
|
+
def fd:[double]
|
|
155
|
+
faceDesc = fd
|
|
156
|
+
def fg:[double]
|
|
157
|
+
faceGap = fg
|
|
158
|
+
lastKey = ""
|
|
159
|
+
lastIdx = (0 - 1)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fn setResolvesAll:void (b:boolean) {
|
|
163
|
+
resolvesAll = b
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fn addKnownFamily:void (name:string) {
|
|
167
|
+
if ((strlen name) == 0) {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
def i:int 0
|
|
171
|
+
while (i < (array_length known)) {
|
|
172
|
+
if ((itemAt known i) == name) {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
i = (i + 1)
|
|
176
|
+
}
|
|
177
|
+
push known name
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn isAttached:boolean () {
|
|
181
|
+
return attached
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
; --- the EVGTextMeasurer contract ---------------------------------------
|
|
185
|
+
|
|
186
|
+
fn isFontAccurate:boolean () {
|
|
187
|
+
return attached
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
fn hasFace:boolean (fontFamily:string) {
|
|
191
|
+
if (attached == false) {
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
if resolvesAll {
|
|
195
|
+
return true
|
|
196
|
+
}
|
|
197
|
+
def base:string (EVGHostTextMeasurer.baseFamily(fontFamily))
|
|
198
|
+
def i:int 0
|
|
199
|
+
while (i < (array_length known)) {
|
|
200
|
+
if ((itemAt known i) == base) {
|
|
201
|
+
return true
|
|
202
|
+
}
|
|
203
|
+
i = (i + 1)
|
|
204
|
+
}
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
fn measureKey:string () {
|
|
209
|
+
def out@(mutable):string ("host:" + hostName + ":" + (to_string generation))
|
|
210
|
+
if (attached == false) {
|
|
211
|
+
out = (out + ":table")
|
|
212
|
+
}
|
|
213
|
+
return out
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
; --- the family convention ------------------------------------------------
|
|
217
|
+
;
|
|
218
|
+
; `EVGElement.effectiveFontFamily` hands the layout `Family-Bold` for a
|
|
219
|
+
; bold element and `Family` otherwise; that suffix is the only way the
|
|
220
|
+
; weight reaches a measurer, and `FontManager.getFont` reads the same
|
|
221
|
+
; convention for print. Italic has no such suffix today, so a slanted run
|
|
222
|
+
; is measured upright — the same thing the table did, recorded here
|
|
223
|
+
; rather than hidden.
|
|
224
|
+
|
|
225
|
+
sfn isBoldFace:boolean (face:string) {
|
|
226
|
+
def n:int (strlen face)
|
|
227
|
+
if (n < 6) {
|
|
228
|
+
return false
|
|
229
|
+
}
|
|
230
|
+
def tail:string (substring face (n - 5) n)
|
|
231
|
+
return (tail == "-Bold")
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
sfn baseFamily:string (face:string) {
|
|
235
|
+
if (EVGHostTextMeasurer.isBoldFace(face)) {
|
|
236
|
+
def n:int (strlen face)
|
|
237
|
+
return (substring face 0 (n - 5))
|
|
238
|
+
}
|
|
239
|
+
return face
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
; --- the face cache -------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
fn faceIndex:int (family:string size:double bold:boolean) {
|
|
245
|
+
def key:string (family + "|" + (to_string size) + "|" + (to_string bold))
|
|
246
|
+
if (key == lastKey) {
|
|
247
|
+
return lastIdx
|
|
248
|
+
}
|
|
249
|
+
def i:int 0
|
|
250
|
+
while (i < (array_length faceKeys)) {
|
|
251
|
+
if ((itemAt faceKeys i) == key) {
|
|
252
|
+
lastKey = key
|
|
253
|
+
lastIdx = i
|
|
254
|
+
return i
|
|
255
|
+
}
|
|
256
|
+
i = (i + 1)
|
|
257
|
+
}
|
|
258
|
+
def f:(fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean)) (unwrap metricFn)
|
|
259
|
+
def asc:double (f(1 "" family size bold false))
|
|
260
|
+
def desc:double (f(2 "" family size bold false))
|
|
261
|
+
def gap:double (f(3 "" family size bold false))
|
|
262
|
+
faceCalls = (faceCalls + 3)
|
|
263
|
+
; A host that cannot say what the gap is says so with a negative
|
|
264
|
+
; number; the line box is then the face's ascent and descent alone.
|
|
265
|
+
if (gap < 0.0) {
|
|
266
|
+
gap = 0.0
|
|
267
|
+
}
|
|
268
|
+
; A host that answers nothing for the vertical — a canvas without
|
|
269
|
+
; `fontBoundingBox*`, say — gets the table's proportions, which are
|
|
270
|
+
; measured off a real face rather than made up.
|
|
271
|
+
if ((asc + desc) <= 0.0) {
|
|
272
|
+
asc = (size * (EVGTextMeasurer.fallbackAscentEm()))
|
|
273
|
+
desc = (size * (EVGTextMeasurer.fallbackDescentEm()))
|
|
274
|
+
}
|
|
275
|
+
push faceKeys key
|
|
276
|
+
push faceAsc asc
|
|
277
|
+
push faceDesc desc
|
|
278
|
+
push faceGap gap
|
|
279
|
+
lastKey = key
|
|
280
|
+
lastIdx = ((array_length faceKeys) - 1)
|
|
281
|
+
return lastIdx
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
; --- measurement ------------------------------------------------------------
|
|
285
|
+
|
|
286
|
+
fn measureText:EVGTextMetrics (text:string fontFamily:string fontSize:double) {
|
|
287
|
+
if (attached == false) {
|
|
288
|
+
return (fallback.measureText(text fontFamily fontSize))
|
|
289
|
+
}
|
|
290
|
+
def bold:boolean (EVGHostTextMeasurer.isBoldFace(fontFamily))
|
|
291
|
+
def family:string (EVGHostTextMeasurer.baseFamily(fontFamily))
|
|
292
|
+
def fi:int (this.faceIndex(family fontSize bold))
|
|
293
|
+
def w:double 0.0
|
|
294
|
+
if ((strlen text) > 0) {
|
|
295
|
+
def f:(fn:double (kind:int text:string family:string size:double bold:boolean italic:boolean)) (unwrap metricFn)
|
|
296
|
+
w = (f(0 text family fontSize bold false))
|
|
297
|
+
widthCalls = (widthCalls + 1)
|
|
298
|
+
}
|
|
299
|
+
def asc:double (itemAt faceAsc fi)
|
|
300
|
+
def desc:double (itemAt faceDesc fi)
|
|
301
|
+
def gap:double (itemAt faceGap fi)
|
|
302
|
+
def m (new EVGTextMetrics())
|
|
303
|
+
m.width = w
|
|
304
|
+
m.ascent = asc
|
|
305
|
+
m.descent = desc
|
|
306
|
+
m.lineHeight = (asc + desc + gap)
|
|
307
|
+
m.height = m.lineHeight
|
|
308
|
+
return m
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
fn measureTextWidth:double (text:string fontFamily:string fontSize:double) {
|
|
312
|
+
def m:EVGTextMetrics (this.measureText(text fontFamily fontSize))
|
|
313
|
+
return m.width
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
; `line-height: normal` is the face's own line box — ascent, descent and
|
|
317
|
+
; the gap the face asks for between lines. The table says 1.15em for its
|
|
318
|
+
; sans; a host says what its face says.
|
|
319
|
+
fn getLineHeight:double (fontFamily:string fontSize:double) {
|
|
320
|
+
if (attached == false) {
|
|
321
|
+
return (fallback.getLineHeight(fontFamily fontSize))
|
|
322
|
+
}
|
|
323
|
+
def bold:boolean (EVGHostTextMeasurer.isBoldFace(fontFamily))
|
|
324
|
+
def family:string (EVGHostTextMeasurer.baseFamily(fontFamily))
|
|
325
|
+
def fi:int (this.faceIndex(family fontSize bold))
|
|
326
|
+
def asc:double (itemAt faceAsc fi)
|
|
327
|
+
def desc:double (itemAt faceDesc fi)
|
|
328
|
+
def gap:double (itemAt faceGap fi)
|
|
329
|
+
return (asc + desc + gap)
|
|
330
|
+
}
|
|
331
|
+
}
|