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,1252 @@
|
|
|
1
|
+
# EVG Layout Format Specification
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0
|
|
4
|
+
**Status:** Draft
|
|
5
|
+
**Date:** December 2024
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Introduction](#1-introduction)
|
|
10
|
+
2. [Document Structure](#2-document-structure)
|
|
11
|
+
3. [Element Types](#3-element-types)
|
|
12
|
+
4. [Attributes Reference](#4-attributes-reference)
|
|
13
|
+
5. [Unit System](#5-unit-system)
|
|
14
|
+
6. [Layout Algorithm](#6-layout-algorithm)
|
|
15
|
+
7. [Font Integration](#7-font-integration)
|
|
16
|
+
8. [Rendering Targets](#8-rendering-targets)
|
|
17
|
+
9. [Components](#9-components)
|
|
18
|
+
10. [Examples](#10-examples)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. Introduction
|
|
23
|
+
|
|
24
|
+
### 1.1 Overview
|
|
25
|
+
|
|
26
|
+
EVG (Extended Vector Graphics) is an XML-based declarative layout format designed for creating visual layouts that can be rendered to multiple output formats including PDF, images (PNG, JPEG), video frames, SVG, and HTML/CSS.
|
|
27
|
+
|
|
28
|
+
### 1.2 Design Goals
|
|
29
|
+
|
|
30
|
+
- **Declarative**: Describe *what* should be rendered, not *how*
|
|
31
|
+
- **Cross-platform**: XML input can be rendered by implementations in any language
|
|
32
|
+
- **Multi-target**: Single source renders to PDF, images, video, HTML, or SVG
|
|
33
|
+
- **CSS-like**: Familiar box model with margins, padding, and borders
|
|
34
|
+
- **Flexible layout**: Flow-based layout with wrapping, alignment, and absolute positioning
|
|
35
|
+
- **Typography-aware**: First-class font support with text measurement
|
|
36
|
+
|
|
37
|
+
### 1.3 Basic Example
|
|
38
|
+
|
|
39
|
+
```xml
|
|
40
|
+
<div width="400" height="300" background-color="#ffffff">
|
|
41
|
+
<div padding="20" background-color="#3498db" border-radius="10">
|
|
42
|
+
<span font-size="24" font-family="Helvetica" color="#ffffff">
|
|
43
|
+
Hello, EVG!
|
|
44
|
+
</span>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 2. Document Structure
|
|
52
|
+
|
|
53
|
+
### 2.1 Root Element
|
|
54
|
+
|
|
55
|
+
An EVG document is a well-formed XML document. The root element is typically a `<div>` or `<View>` element that defines the canvas dimensions.
|
|
56
|
+
|
|
57
|
+
```xml
|
|
58
|
+
<div width="800" height="600" background-color="#ffffff">
|
|
59
|
+
<!-- Child elements -->
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2.2 Element Hierarchy
|
|
64
|
+
|
|
65
|
+
EVG uses a hierarchical tree structure where:
|
|
66
|
+
- Container elements (`<div>`, `<View>`) can have child elements
|
|
67
|
+
- Leaf elements (`<span>`, `<img>`, `<path>`) typically do not have children
|
|
68
|
+
- Elements inherit certain properties from their parent (e.g., font settings)
|
|
69
|
+
|
|
70
|
+
### 2.3 Coordinate System
|
|
71
|
+
|
|
72
|
+
- Origin (0, 0) is at the **top-left** corner
|
|
73
|
+
- X-axis increases to the **right**
|
|
74
|
+
- Y-axis increases **downward**
|
|
75
|
+
- All position and dimension values are in logical pixels (can be scaled)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 3. Element Types
|
|
80
|
+
|
|
81
|
+
### 3.1 Container Elements
|
|
82
|
+
|
|
83
|
+
#### `<div>` / `<View>`
|
|
84
|
+
|
|
85
|
+
A rectangular container that can hold child elements. Supports all layout and styling attributes.
|
|
86
|
+
|
|
87
|
+
```xml
|
|
88
|
+
<div width="200" height="100" background-color="#f0f0f0" padding="10">
|
|
89
|
+
<!-- children -->
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Aliases:** `div`, `View`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### 3.2 Text Elements
|
|
98
|
+
|
|
99
|
+
#### `<span>` / `<Label>`
|
|
100
|
+
|
|
101
|
+
Renders text content. Text can be provided as element content or via the `text` attribute.
|
|
102
|
+
|
|
103
|
+
```xml
|
|
104
|
+
<span font-size="16" font-family="Arial" color="#333333">
|
|
105
|
+
This is text content
|
|
106
|
+
</span>
|
|
107
|
+
|
|
108
|
+
<!-- Or using attribute -->
|
|
109
|
+
<span font-size="16" text="This is text content" />
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Key behaviors:**
|
|
113
|
+
- Text wraps within the parent's available width
|
|
114
|
+
- Height is auto-calculated based on text measurement
|
|
115
|
+
- Supports `inline="true"` for inline-block behavior
|
|
116
|
+
- Preserves whitespace (pre-line behavior)
|
|
117
|
+
|
|
118
|
+
**Aliases:** `span`, `Label`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### 3.3 Image Elements
|
|
123
|
+
|
|
124
|
+
#### `<img>` / `<Image>`
|
|
125
|
+
|
|
126
|
+
Displays an image from a URL or embedded source.
|
|
127
|
+
|
|
128
|
+
```xml
|
|
129
|
+
<img src="https://example.com/image.png" width="200" height="150" />
|
|
130
|
+
<img src="./local/image.jpg" border-radius="10" />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Attributes:**
|
|
134
|
+
- `src` or `imageUrl`: Image source (URL or file path)
|
|
135
|
+
- Standard dimension and styling attributes apply
|
|
136
|
+
|
|
137
|
+
**Aliases:** `img`, `Image`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### 3.4 SVG Path Elements
|
|
142
|
+
|
|
143
|
+
#### `<path>` / `<Path>`
|
|
144
|
+
|
|
145
|
+
Renders an SVG path definition. Used for vector graphics, icons, and shapes.
|
|
146
|
+
|
|
147
|
+
```xml
|
|
148
|
+
<path
|
|
149
|
+
d="M10,6.5c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S12.2,6.5,10,6.5"
|
|
150
|
+
width="20"
|
|
151
|
+
height="20"
|
|
152
|
+
background-color="#333333"
|
|
153
|
+
viewBox="0 0 20 20"
|
|
154
|
+
/>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Attributes:**
|
|
158
|
+
- `d` or `svgPath`: SVG path data string (M, L, C, Z commands, etc.)
|
|
159
|
+
- `viewBox`: SVG viewBox for scaling ("minX minY width height")
|
|
160
|
+
- `background-color`: Fill color
|
|
161
|
+
- `border-color`: Stroke color
|
|
162
|
+
- `opacity`: Fill and stroke opacity
|
|
163
|
+
|
|
164
|
+
**Aliases:** `path`, `Path`
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### 3.5 Input Elements (Interactive)
|
|
169
|
+
|
|
170
|
+
For interactive applications (browser rendering):
|
|
171
|
+
|
|
172
|
+
#### `<input>` / `<Input>`
|
|
173
|
+
Single-line text input.
|
|
174
|
+
|
|
175
|
+
#### `<textarea>` / `<TextField>`
|
|
176
|
+
Multi-line text input.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 4. Attributes Reference
|
|
181
|
+
|
|
182
|
+
### 4.1 Dimension Attributes
|
|
183
|
+
|
|
184
|
+
| Attribute | Type | Description | Default |
|
|
185
|
+
|-----------|------|-------------|---------|
|
|
186
|
+
| `width` | unit | Element width | 100% of parent |
|
|
187
|
+
| `height` | unit | Element height | Auto (content-based) |
|
|
188
|
+
| `innerWidth` | read-only | Computed inner width (after padding/border) | - |
|
|
189
|
+
| `innerHeight` | read-only | Computed inner height (after padding/border) | - |
|
|
190
|
+
|
|
191
|
+
### 4.2 Position Attributes
|
|
192
|
+
|
|
193
|
+
| Attribute | Type | Description | Effect |
|
|
194
|
+
|-----------|------|-------------|--------|
|
|
195
|
+
| `x` | unit | X position | For absolute positioning |
|
|
196
|
+
| `y` | unit | Y position | For absolute positioning |
|
|
197
|
+
| `left` | unit | Distance from parent's left edge | Enables absolute positioning |
|
|
198
|
+
| `top` | unit | Distance from parent's top edge | Enables absolute positioning |
|
|
199
|
+
| `right` | unit | Distance from parent's right edge | Enables absolute positioning |
|
|
200
|
+
| `bottom` | unit | Distance from parent's bottom edge | Enables absolute positioning |
|
|
201
|
+
|
|
202
|
+
| `position` | string | `relative` (default), `absolute` or `fixed` | See below |
|
|
203
|
+
|
|
204
|
+
**Note:** When `left`, `top`, `right`, or `bottom` is set, the element uses **absolute positioning** and is removed from the flow layout.
|
|
205
|
+
|
|
206
|
+
**`position: fixed`** is out of flow the same way, and differs in two things:
|
|
207
|
+
it is positioned against the **viewport** rather than against its parent — its
|
|
208
|
+
`left`/`top`/`right`/`bottom` and every percentage inside it resolve against the
|
|
209
|
+
page — and **a scroll does not move it**. That is the mode: the content slides
|
|
210
|
+
under the furniture. Both scroll paths honour it, the full layout's
|
|
211
|
+
`applyScroll` and the incremental `scrollOnlyFrom`. It is checked by
|
|
212
|
+
`npm run evg:fixed:test`.
|
|
213
|
+
|
|
214
|
+
`left` and `right` (or `top` and `bottom`) BOTH set with no `width` (or
|
|
215
|
+
`height`) stretches the box between them, CSS 2.1 10.3.7 — that is how a bar
|
|
216
|
+
inset by 16 on each side is written without knowing the page's width. It
|
|
217
|
+
applies to `absolute` as well as `fixed`.
|
|
218
|
+
|
|
219
|
+
One limit: a fixed box inside a container that clips still clips against that
|
|
220
|
+
container. In CSS a fixed box escapes an ancestor's `overflow`; here the clip
|
|
221
|
+
stack is built from the tree, so it does not. Put the bar beside the scroller
|
|
222
|
+
rather than inside it.
|
|
223
|
+
|
|
224
|
+
### 4.3 Spacing Attributes
|
|
225
|
+
|
|
226
|
+
#### Margin (outer spacing)
|
|
227
|
+
|
|
228
|
+
| Attribute | Type | Description |
|
|
229
|
+
|-----------|------|-------------|
|
|
230
|
+
| `margin` | unit | All sides margin |
|
|
231
|
+
| `margin-left` | unit | Left margin |
|
|
232
|
+
| `margin-right` | unit | Right margin |
|
|
233
|
+
| `margin-top` | unit | Top margin |
|
|
234
|
+
| `margin-bottom` | unit | Bottom margin |
|
|
235
|
+
|
|
236
|
+
#### Padding (inner spacing)
|
|
237
|
+
|
|
238
|
+
| Attribute | Type | Description |
|
|
239
|
+
|-----------|------|-------------|
|
|
240
|
+
| `padding` | unit | All sides padding |
|
|
241
|
+
| `padding-left` | unit | Left padding |
|
|
242
|
+
| `padding-right` | unit | Right padding |
|
|
243
|
+
| `padding-top` | unit | Top padding |
|
|
244
|
+
| `padding-bottom` | unit | Bottom padding |
|
|
245
|
+
|
|
246
|
+
### 4.4 Layout Attributes
|
|
247
|
+
|
|
248
|
+
| Attribute | Type | Values | Description |
|
|
249
|
+
|-----------|------|--------|-------------|
|
|
250
|
+
| `direction` | string | `row` (default), `column`, `bottom-to-top` | Child layout direction |
|
|
251
|
+
| `align` | string | `left` (default), `center`, `right` | Horizontal alignment |
|
|
252
|
+
| `vertical-align` | string | `top` (default), `center`, `bottom` | Vertical alignment |
|
|
253
|
+
| `inline` | boolean | `true`, `false` | Inline-block behavior |
|
|
254
|
+
| `line-break` | boolean | `true`, `false` | Force line break after element |
|
|
255
|
+
| `overflow` | string | `visible`, `hidden`, `clip`, `page-break` | Overflow behavior |
|
|
256
|
+
|
|
257
|
+
### 4.5 Visual Attributes
|
|
258
|
+
|
|
259
|
+
#### Colors
|
|
260
|
+
|
|
261
|
+
| Attribute | Type | Description |
|
|
262
|
+
|-----------|------|-------------|
|
|
263
|
+
| `color` | color | Text/foreground color |
|
|
264
|
+
| `background-color` | color | Background fill color |
|
|
265
|
+
|
|
266
|
+
#### Gradients
|
|
267
|
+
|
|
268
|
+
| Attribute | Type | Description |
|
|
269
|
+
|-----------|------|-------------|
|
|
270
|
+
| `linear-gradient` | string | Linear gradient fill (see format below) |
|
|
271
|
+
| `radial-gradient` | string | Radial gradient fill (see format below) |
|
|
272
|
+
|
|
273
|
+
**Linear Gradient Format:**
|
|
274
|
+
```
|
|
275
|
+
linear-gradient="[angle,] color1 [stop1], color2 [stop2], ..."
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
- **angle** (optional): Direction in degrees (e.g., `90deg`, `135deg`, `-20deg`)
|
|
279
|
+
- **color**: Any valid color value
|
|
280
|
+
- **stop** (optional): Position as percentage (e.g., `20%`, `80%`)
|
|
281
|
+
|
|
282
|
+
**Examples:**
|
|
283
|
+
```xml
|
|
284
|
+
<!-- Simple two-color gradient (top to bottom) -->
|
|
285
|
+
<View linear-gradient="#31a6ED, #51C6ED" />
|
|
286
|
+
|
|
287
|
+
<!-- With angle (135 degrees) -->
|
|
288
|
+
<View linear-gradient="135deg, red, yellow 20%, black, blue" />
|
|
289
|
+
|
|
290
|
+
<!-- Multiple colors with stops -->
|
|
291
|
+
<View linear-gradient="90deg, green, blue, red 20%, yellow, black, blue" />
|
|
292
|
+
|
|
293
|
+
<!-- With rgba colors -->
|
|
294
|
+
<View linear-gradient="-20deg, #f2a2f2, #121232 80%, rgba(242, 162, 242, 0.7)" />
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Radial Gradient Format:**
|
|
298
|
+
```
|
|
299
|
+
radial-gradient="color1 [stop1], color2 [stop2], ..."
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Radial gradients radiate from the center outward.
|
|
303
|
+
|
|
304
|
+
**Examples:**
|
|
305
|
+
```xml
|
|
306
|
+
<!-- Simple two-color radial -->
|
|
307
|
+
<View radial-gradient="red, blue" />
|
|
308
|
+
|
|
309
|
+
<!-- Multiple colors -->
|
|
310
|
+
<View radial-gradient="red, green, blue" />
|
|
311
|
+
|
|
312
|
+
<!-- With color stops -->
|
|
313
|
+
<View radial-gradient="red, green 50%, blue" />
|
|
314
|
+
|
|
315
|
+
<!-- With rgba and multiple stops (halo effect) -->
|
|
316
|
+
<View radial-gradient="white, rgba(255,255,255,0.1) 10%, rgba(255,255,255,0.5) 30%, rgba(0,0,255,0.1)"
|
|
317
|
+
border-radius="50%" />
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### Border
|
|
321
|
+
|
|
322
|
+
| Attribute | Type | Description |
|
|
323
|
+
|-----------|------|-------------|
|
|
324
|
+
| `border` | shorthand | Width, style and colour in any order (`1px solid #cbd5e1`); `none` clears it. The style keyword is accepted and ignored — EVG strokes one way |
|
|
325
|
+
| `border-width` | unit | Border thickness |
|
|
326
|
+
| `border-color` | color | Border color |
|
|
327
|
+
| `border-radius` | unit | Corner radius (supports percentage, e.g., `50%` for circle) |
|
|
328
|
+
|
|
329
|
+
#### Shadow Effects
|
|
330
|
+
|
|
331
|
+
| Attribute | Type | Description |
|
|
332
|
+
|-----------|------|-------------|
|
|
333
|
+
| `shadow-radius` | unit | Box shadow blur radius |
|
|
334
|
+
| `shadow-color` | color | Box shadow color (default: `rgba(0,0,0,0.75)`) |
|
|
335
|
+
| `shadow-offset-x` | unit | Shadow horizontal offset |
|
|
336
|
+
| `shadow-offset-y` | unit | Shadow vertical offset |
|
|
337
|
+
| `shadow-opacity` | float | Shadow opacity (0.0 to 1.0) |
|
|
338
|
+
|
|
339
|
+
**Shadow Examples:**
|
|
340
|
+
```xml
|
|
341
|
+
<!-- Simple shadow -->
|
|
342
|
+
<View shadow-radius="10px" background-color="#222222" />
|
|
343
|
+
|
|
344
|
+
<!-- Shadow with custom color -->
|
|
345
|
+
<View shadow-radius="2px" shadow-color="rgba(0,0,0,0.2)" />
|
|
346
|
+
|
|
347
|
+
<!-- Shadow on a card-like panel -->
|
|
348
|
+
<View padding="20" background-color="white" border-radius="10"
|
|
349
|
+
shadow-radius="5" shadow-color="rgba(0,0,0,0.1)" />
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
#### Opacity
|
|
353
|
+
|
|
354
|
+
| Attribute | Type | Description |
|
|
355
|
+
|-----------|------|-------------|
|
|
356
|
+
| `opacity` | float | Element transparency (0.0 = fully transparent, 1.0 = fully opaque) |
|
|
357
|
+
|
|
358
|
+
### 4.6 Typography Attributes
|
|
359
|
+
|
|
360
|
+
| Attribute | Type | Description |
|
|
361
|
+
|-----------|------|-------------|
|
|
362
|
+
| `font-size` | unit | Text size |
|
|
363
|
+
| `font-family` | string | Font family name |
|
|
364
|
+
| `text` | string | Text content (alternative to element content) |
|
|
365
|
+
| `align` | string | Text alignment (left, center, right) |
|
|
366
|
+
|
|
367
|
+
### 4.7 Transform Attributes
|
|
368
|
+
|
|
369
|
+
| Attribute | Type | Description |
|
|
370
|
+
|-----------|------|-------------|
|
|
371
|
+
| `rotate` | number | Rotation in degrees |
|
|
372
|
+
| `scale` | number | Scale factor (1.0 = 100%) |
|
|
373
|
+
|
|
374
|
+
### 4.8 Identification Attributes
|
|
375
|
+
|
|
376
|
+
| Attribute | Type | Description |
|
|
377
|
+
|-----------|------|-------------|
|
|
378
|
+
| `id` | string | Unique identifier for element lookup |
|
|
379
|
+
| `key` | string | Reconciliation identity, scoped to the parent (see below) |
|
|
380
|
+
| `cname` | string | Component name for registration |
|
|
381
|
+
|
|
382
|
+
**`id` and `key` are not the same thing.** `id` is global and outward-facing:
|
|
383
|
+
the hit test reports it, the accessibility tree carries it, and an application
|
|
384
|
+
addresses a control by it, so no two elements may share one. `key` is
|
|
385
|
+
sibling-scoped and inward-facing: it tells `EVGReconcile` that a newly built
|
|
386
|
+
child is the same *logical* child as one already in the live tree, so a rebuild
|
|
387
|
+
can keep the element — and with it, anything the element remembers, a
|
|
388
|
+
transition in flight most of all. Two lists on one page may both key a row
|
|
389
|
+
`"video"`.
|
|
390
|
+
|
|
391
|
+
A child with no key is matched by **position among its unkeyed siblings**, and
|
|
392
|
+
a match also requires the same element type. Reordering an unkeyed list
|
|
393
|
+
therefore keeps the elements but moves the data under them, which is exactly
|
|
394
|
+
what makes a reordered unkeyed list animate wrongly.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## 5. Unit System
|
|
399
|
+
|
|
400
|
+
### 5.1 Supported Units
|
|
401
|
+
|
|
402
|
+
EVG supports multiple unit types for dimension and position values:
|
|
403
|
+
|
|
404
|
+
| Unit | Suffix | Description | Example |
|
|
405
|
+
|------|--------|-------------|---------|
|
|
406
|
+
| Pixels | `px` or none | Absolute pixel values | `100`, `100px` |
|
|
407
|
+
| Percentage | `%` | Percentage of parent's dimension | `50%` |
|
|
408
|
+
| Em | `em` | Relative to font size | `1.5em` |
|
|
409
|
+
| Height-relative Percentage | `hp` | Percentage of parent's height | `50hp` |
|
|
410
|
+
| Fill | `fill` | Flexible fill (like CSS flex: 1) | `fill` |
|
|
411
|
+
|
|
412
|
+
### 5.2 Unit Resolution
|
|
413
|
+
|
|
414
|
+
Units are resolved during the layout phase in this order:
|
|
415
|
+
|
|
416
|
+
1. **Pixels (px):** Used directly
|
|
417
|
+
2. **Percentage (%):** Calculated against parent's `innerWidth`
|
|
418
|
+
3. **Em (em):** Calculated as `fontSize × value`
|
|
419
|
+
4. **Height Percentage (hp):** Calculated against parent's `innerHeight`
|
|
420
|
+
5. **Fill:** Expands to fill available space
|
|
421
|
+
|
|
422
|
+
### 5.3 Parsing Logic
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
Function parseUnit(value: string) -> {value: number, type: UnitType}:
|
|
426
|
+
If value ends with "%":
|
|
427
|
+
return {parseFloat(value), PERCENTAGE}
|
|
428
|
+
If value ends with "em":
|
|
429
|
+
return {parseFloat(value), EM}
|
|
430
|
+
If value ends with "px":
|
|
431
|
+
return {parseFloat(value), PIXELS}
|
|
432
|
+
If value ends with "hp":
|
|
433
|
+
return {parseFloat(value), HEIGHT_PERCENTAGE}
|
|
434
|
+
If value equals "fill":
|
|
435
|
+
return {100, FILL}
|
|
436
|
+
Else:
|
|
437
|
+
return {parseFloat(value), PIXELS} // Default to pixels
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 6. Layout Algorithm
|
|
443
|
+
|
|
444
|
+
### 6.1 Overview
|
|
445
|
+
|
|
446
|
+
EVG uses a **flow-based layout algorithm** similar to CSS block/inline layout:
|
|
447
|
+
|
|
448
|
+
1. **Parse:** Convert XML to element tree with property values
|
|
449
|
+
2. **Adjust:** Resolve units to pixel values based on parent dimensions
|
|
450
|
+
3. **Layout:** Calculate positions using flow algorithm
|
|
451
|
+
4. **Render:** Draw elements in tree order
|
|
452
|
+
|
|
453
|
+
### 6.2 Box Model
|
|
454
|
+
|
|
455
|
+
Each element follows the CSS box model:
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
+------------------------------------------+
|
|
459
|
+
| MARGIN |
|
|
460
|
+
| +------------------------------------+ |
|
|
461
|
+
| | BORDER | |
|
|
462
|
+
| | +------------------------------+ | |
|
|
463
|
+
| | | PADDING | | |
|
|
464
|
+
| | | +------------------------+ | | |
|
|
465
|
+
| | | | | | | |
|
|
466
|
+
| | | | CONTENT | | | |
|
|
467
|
+
| | | | (innerWidth x | | | |
|
|
468
|
+
| | | | innerHeight) | | | |
|
|
469
|
+
| | | +------------------------+ | | |
|
|
470
|
+
| | +------------------------------+ | |
|
|
471
|
+
| +------------------------------------+ |
|
|
472
|
+
+------------------------------------------+
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Dimension calculations:**
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
innerWidth = width - paddingLeft - paddingRight - (borderWidth × 2)
|
|
479
|
+
innerHeight = height - paddingTop - paddingBottom - (borderWidth × 2)
|
|
480
|
+
totalWidth = width + marginLeft + marginRight
|
|
481
|
+
totalHeight = height + marginTop + marginBottom
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### 6.3 Flow Layout Algorithm
|
|
485
|
+
|
|
486
|
+
```
|
|
487
|
+
Function layoutChildren(parent, children):
|
|
488
|
+
currentX = parent.paddingLeft
|
|
489
|
+
currentY = parent.paddingTop
|
|
490
|
+
rowHeight = 0
|
|
491
|
+
currentRow = []
|
|
492
|
+
|
|
493
|
+
For each child in children:
|
|
494
|
+
// Resolve child dimensions
|
|
495
|
+
adjustLayoutParams(child, parent)
|
|
496
|
+
|
|
497
|
+
// Check if child uses absolute positioning
|
|
498
|
+
If child.left.is_set OR child.top.is_set OR child.bottom.is_set:
|
|
499
|
+
child.calculated.absolute = true
|
|
500
|
+
positionAbsoluteChild(child, parent)
|
|
501
|
+
Continue
|
|
502
|
+
|
|
503
|
+
// Calculate child's total width
|
|
504
|
+
childTotalWidth = child.width.pixels + child.marginLeft + child.marginRight
|
|
505
|
+
|
|
506
|
+
// Check if we need to wrap to next row
|
|
507
|
+
If currentX + childTotalWidth > parent.innerWidth AND currentRow.length > 0:
|
|
508
|
+
// Apply row alignment
|
|
509
|
+
alignRow(currentRow, parent, rowHeight)
|
|
510
|
+
|
|
511
|
+
// Move to next row
|
|
512
|
+
currentY += rowHeight
|
|
513
|
+
currentX = parent.paddingLeft
|
|
514
|
+
rowHeight = 0
|
|
515
|
+
currentRow = []
|
|
516
|
+
|
|
517
|
+
// Position child
|
|
518
|
+
child.calculated.x = currentX + child.marginLeft
|
|
519
|
+
child.calculated.y = currentY + child.marginTop
|
|
520
|
+
|
|
521
|
+
// Update row tracking
|
|
522
|
+
currentX += childTotalWidth
|
|
523
|
+
rowHeight = max(rowHeight, child.calculated.height)
|
|
524
|
+
currentRow.push(child)
|
|
525
|
+
|
|
526
|
+
// Handle explicit line breaks
|
|
527
|
+
If child.lineBreak.b_value:
|
|
528
|
+
alignRow(currentRow, parent, rowHeight)
|
|
529
|
+
currentY += rowHeight
|
|
530
|
+
currentX = parent.paddingLeft
|
|
531
|
+
rowHeight = 0
|
|
532
|
+
currentRow = []
|
|
533
|
+
|
|
534
|
+
// Handle last row
|
|
535
|
+
alignRow(currentRow, parent, rowHeight)
|
|
536
|
+
|
|
537
|
+
Return currentY + rowHeight + parent.paddingBottom
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### 6.4 Alignment
|
|
541
|
+
|
|
542
|
+
#### Horizontal Alignment (`align`)
|
|
543
|
+
|
|
544
|
+
```
|
|
545
|
+
Function alignRow(row, parent, rowHeight):
|
|
546
|
+
If parent.align.s_value == "center":
|
|
547
|
+
rowWidth = sum of all children widths
|
|
548
|
+
offset = (parent.innerWidth - rowWidth) / 2
|
|
549
|
+
For each child in row:
|
|
550
|
+
child.calculated.x += offset
|
|
551
|
+
|
|
552
|
+
Else If parent.align.s_value == "right":
|
|
553
|
+
rowWidth = sum of all children widths
|
|
554
|
+
offset = parent.innerWidth - rowWidth
|
|
555
|
+
For each child in row:
|
|
556
|
+
child.calculated.x += offset
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
#### Vertical Alignment (`vertical-align`)
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
Function alignRowVertically(row, rowHeight):
|
|
563
|
+
For each child in row:
|
|
564
|
+
If parent.verticalAlign.s_value == "center":
|
|
565
|
+
offset = (rowHeight - child.calculated.height) / 2
|
|
566
|
+
child.calculated.y += offset
|
|
567
|
+
|
|
568
|
+
Else If parent.verticalAlign.s_value == "bottom":
|
|
569
|
+
offset = rowHeight - child.calculated.height
|
|
570
|
+
child.calculated.y += offset
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### 6.5 Absolute Positioning
|
|
574
|
+
|
|
575
|
+
When `left`, `top`, `right`, or `bottom` is set:
|
|
576
|
+
|
|
577
|
+
```
|
|
578
|
+
Function positionAbsoluteChild(child, parent):
|
|
579
|
+
If child.left.is_set:
|
|
580
|
+
child.calculated.x = child.marginLeft + child.left.pixels
|
|
581
|
+
Else If child.right.is_set:
|
|
582
|
+
child.calculated.x = parent.innerWidth - child.right.pixels - child.width.pixels
|
|
583
|
+
|
|
584
|
+
If child.top.is_set:
|
|
585
|
+
child.calculated.y = child.marginTop + child.top.pixels
|
|
586
|
+
Else If child.bottom.is_set:
|
|
587
|
+
child.calculated.y = parent.innerHeight - child.bottom.pixels - child.height.pixels
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### 6.6 Text Measurement
|
|
591
|
+
|
|
592
|
+
For text elements (`<span>`, `<Label>`), the layout algorithm must measure text to determine height:
|
|
593
|
+
|
|
594
|
+
```
|
|
595
|
+
Function measureText(text, fontFamily, fontSize, maxWidth) -> {width, height}:
|
|
596
|
+
// Implementation depends on rendering target
|
|
597
|
+
// Must handle:
|
|
598
|
+
// - Multi-line text wrapping at maxWidth
|
|
599
|
+
// - Font metrics (ascent, descent, line height)
|
|
600
|
+
// - Unicode and special characters
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## 7. Font Integration
|
|
606
|
+
|
|
607
|
+
### 7.1 Font Provider Interface
|
|
608
|
+
|
|
609
|
+
Implementations must provide a font provider that supports:
|
|
610
|
+
|
|
611
|
+
```
|
|
612
|
+
Interface IFontProvider:
|
|
613
|
+
// Register a font with a name
|
|
614
|
+
registerFont(name: string, source: FontSource): void
|
|
615
|
+
|
|
616
|
+
// Get font source by name
|
|
617
|
+
getFont(name: string): FontSource | null
|
|
618
|
+
|
|
619
|
+
// Check if font is available
|
|
620
|
+
hasFont(name: string): boolean
|
|
621
|
+
|
|
622
|
+
// List all registered fonts
|
|
623
|
+
listFonts(): string[]
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### 7.2 Font Sources
|
|
627
|
+
|
|
628
|
+
Fonts can be provided as:
|
|
629
|
+
- **File path:** `"/fonts/MyFont.ttf"` (for file system access)
|
|
630
|
+
- **URL:** `"https://example.com/fonts/MyFont.woff2"`
|
|
631
|
+
- **ArrayBuffer:** Binary font data loaded in memory
|
|
632
|
+
- **Uint8Array:** Binary font data
|
|
633
|
+
|
|
634
|
+
### 7.3 Font Registration
|
|
635
|
+
|
|
636
|
+
Fonts must be registered before use:
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
// Node.js example
|
|
640
|
+
EVG.registerFont("CustomFont", "/path/to/font.ttf");
|
|
641
|
+
|
|
642
|
+
// Browser example
|
|
643
|
+
const fontData = await fetch('/fonts/custom.woff2').then(r => r.arrayBuffer());
|
|
644
|
+
EVG.registerFont("CustomFont", fontData);
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### 7.4 Font Fallback
|
|
648
|
+
|
|
649
|
+
When a specified font is not available:
|
|
650
|
+
1. Check registered fonts
|
|
651
|
+
2. Fall back to system fonts
|
|
652
|
+
3. Use default font (implementation-specific, typically "Helvetica" or "Arial")
|
|
653
|
+
|
|
654
|
+
### 7.5 Font Metrics for Text Measurement
|
|
655
|
+
|
|
656
|
+
Text measurement requires access to font metrics:
|
|
657
|
+
|
|
658
|
+
```
|
|
659
|
+
Interface ITextMeasurer:
|
|
660
|
+
measureText(text: string, fontFamily: string, fontSize: number): {
|
|
661
|
+
width: number,
|
|
662
|
+
height: number
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
Different renderers provide their own measurement:
|
|
667
|
+
- **PDF:** Use PDFKit's text measurement
|
|
668
|
+
- **Canvas:** Use CanvasRenderingContext2D.measureText()
|
|
669
|
+
- **Browser:** Use DOM-based measurement with actual fonts
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## 8. Rendering Targets
|
|
674
|
+
|
|
675
|
+
### 8.1 Renderer Interface
|
|
676
|
+
|
|
677
|
+
All renderers must implement:
|
|
678
|
+
|
|
679
|
+
```
|
|
680
|
+
Interface IRenderer:
|
|
681
|
+
// Document lifecycle
|
|
682
|
+
beginDocument(width: number, height: number): void
|
|
683
|
+
endDocument(): void
|
|
684
|
+
addPage(width?: number, height?: number): void
|
|
685
|
+
|
|
686
|
+
// Drawing primitives
|
|
687
|
+
drawRect(x, y, width, height, options): void
|
|
688
|
+
drawRoundedRect(x, y, width, height, radius, options): void
|
|
689
|
+
drawText(text, x, y, options): void
|
|
690
|
+
drawImage(source, x, y, width, height): void
|
|
691
|
+
drawPath(pathData, x, y, width, height, options): void
|
|
692
|
+
|
|
693
|
+
// Gradient rendering
|
|
694
|
+
drawLinearGradient(x, y, width, height, gradient): void
|
|
695
|
+
drawRadialGradient(x, y, width, height, gradient): void
|
|
696
|
+
|
|
697
|
+
// Shadow rendering
|
|
698
|
+
drawShadow(x, y, width, height, shadowOptions): void
|
|
699
|
+
|
|
700
|
+
// State management
|
|
701
|
+
save(): void
|
|
702
|
+
restore(): void
|
|
703
|
+
translate(x, y): void
|
|
704
|
+
rotate(angle): void
|
|
705
|
+
scale(sx, sy): void
|
|
706
|
+
setClipRect(x, y, width, height): void
|
|
707
|
+
setOpacity(opacity): void
|
|
708
|
+
|
|
709
|
+
// Text measurement
|
|
710
|
+
measureText(text, fontFamily, fontSize): {width, height}
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### 8.2 Gradient Rendering
|
|
714
|
+
|
|
715
|
+
#### Linear Gradient Data Structure
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
Interface LinearGradient:
|
|
719
|
+
angle: number // Rotation angle in degrees (0 = left-to-right)
|
|
720
|
+
stops: GradientStop[] // Color stops
|
|
721
|
+
|
|
722
|
+
Interface GradientStop:
|
|
723
|
+
offset: number // Position from 0.0 to 1.0
|
|
724
|
+
color: string // Color value (hex, rgb, rgba)
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
**Rendering Algorithm:**
|
|
728
|
+
1. Parse gradient string to extract angle and color stops
|
|
729
|
+
2. Calculate gradient start and end points based on angle and bounding box
|
|
730
|
+
3. Create gradient fill with color stops
|
|
731
|
+
4. Apply to element background
|
|
732
|
+
|
|
733
|
+
**Example Implementation (Canvas):**
|
|
734
|
+
```javascript
|
|
735
|
+
function drawLinearGradient(ctx, x, y, width, height, gradient) {
|
|
736
|
+
// Calculate gradient line based on angle
|
|
737
|
+
const angleRad = (gradient.angle - 90) * Math.PI / 180;
|
|
738
|
+
const centerX = x + width / 2;
|
|
739
|
+
const centerY = y + height / 2;
|
|
740
|
+
const length = Math.sqrt(width * width + height * height) / 2;
|
|
741
|
+
|
|
742
|
+
const x1 = centerX - Math.cos(angleRad) * length;
|
|
743
|
+
const y1 = centerY - Math.sin(angleRad) * length;
|
|
744
|
+
const x2 = centerX + Math.cos(angleRad) * length;
|
|
745
|
+
const y2 = centerY + Math.sin(angleRad) * length;
|
|
746
|
+
|
|
747
|
+
const grad = ctx.createLinearGradient(x1, y1, x2, y2);
|
|
748
|
+
gradient.stops.forEach(stop => {
|
|
749
|
+
grad.addColorStop(stop.offset, stop.color);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
ctx.fillStyle = grad;
|
|
753
|
+
ctx.fillRect(x, y, width, height);
|
|
754
|
+
}
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
#### Radial Gradient Data Structure
|
|
758
|
+
|
|
759
|
+
```
|
|
760
|
+
Interface RadialGradient:
|
|
761
|
+
centerX: number // Center X (default: 50% of width)
|
|
762
|
+
centerY: number // Center Y (default: 50% of height)
|
|
763
|
+
radius: number // Radius (default: max dimension / 2)
|
|
764
|
+
stops: GradientStop[] // Color stops
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Rendering Algorithm:**
|
|
768
|
+
1. Parse gradient string to extract color stops
|
|
769
|
+
2. Center gradient at element center
|
|
770
|
+
3. Set radius to cover the element (typically half the diagonal)
|
|
771
|
+
4. Create radial gradient fill
|
|
772
|
+
|
|
773
|
+
**Example Implementation (Canvas):**
|
|
774
|
+
```javascript
|
|
775
|
+
function drawRadialGradient(ctx, x, y, width, height, gradient) {
|
|
776
|
+
const centerX = x + width / 2;
|
|
777
|
+
const centerY = y + height / 2;
|
|
778
|
+
const radius = Math.max(width, height) / 2;
|
|
779
|
+
|
|
780
|
+
const grad = ctx.createRadialGradient(
|
|
781
|
+
centerX, centerY, 0, // Inner circle (center point)
|
|
782
|
+
centerX, centerY, radius // Outer circle
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
gradient.stops.forEach(stop => {
|
|
786
|
+
grad.addColorStop(stop.offset, stop.color);
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
ctx.fillStyle = grad;
|
|
790
|
+
ctx.fillRect(x, y, width, height);
|
|
791
|
+
}
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### 8.3 Shadow Rendering
|
|
795
|
+
|
|
796
|
+
#### Shadow Data Structure
|
|
797
|
+
|
|
798
|
+
```
|
|
799
|
+
Interface ShadowOptions:
|
|
800
|
+
radius: number // Blur radius in pixels
|
|
801
|
+
color: string // Shadow color (default: rgba(0,0,0,0.75))
|
|
802
|
+
offsetX: number // Horizontal offset (default: 0)
|
|
803
|
+
offsetY: number // Vertical offset (default: 0)
|
|
804
|
+
opacity: number // Shadow opacity (default: 1.0)
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
**Rendering Algorithm:**
|
|
808
|
+
1. Save current rendering state
|
|
809
|
+
2. Set shadow properties before drawing the element
|
|
810
|
+
3. Draw the element (shadow is rendered automatically by the graphics context)
|
|
811
|
+
4. Restore state
|
|
812
|
+
|
|
813
|
+
**Example Implementation (Canvas):**
|
|
814
|
+
```javascript
|
|
815
|
+
function drawWithShadow(ctx, drawFn, shadowOptions) {
|
|
816
|
+
ctx.save();
|
|
817
|
+
|
|
818
|
+
ctx.shadowColor = shadowOptions.color || 'rgba(0,0,0,0.75)';
|
|
819
|
+
ctx.shadowBlur = shadowOptions.radius || 0;
|
|
820
|
+
ctx.shadowOffsetX = shadowOptions.offsetX || 0;
|
|
821
|
+
ctx.shadowOffsetY = shadowOptions.offsetY || 0;
|
|
822
|
+
|
|
823
|
+
drawFn(); // Execute the actual drawing
|
|
824
|
+
|
|
825
|
+
ctx.restore();
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
**Example Implementation (SVG):**
|
|
830
|
+
```xml
|
|
831
|
+
<defs>
|
|
832
|
+
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
|
|
833
|
+
<feDropShadow dx="0" dy="0" stdDeviation="5" flood-color="rgba(0,0,0,0.75)"/>
|
|
834
|
+
</filter>
|
|
835
|
+
</defs>
|
|
836
|
+
<rect filter="url(#shadow)" ... />
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Example Implementation (CSS):**
|
|
840
|
+
```css
|
|
841
|
+
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
### 8.4 PDF Rendering
|
|
845
|
+
|
|
846
|
+
PDF output uses libraries like PDFKit (Node.js) or jsPDF (browser).
|
|
847
|
+
|
|
848
|
+
**Considerations:**
|
|
849
|
+
- Fonts must be embedded for custom fonts
|
|
850
|
+
- Use actual PDF units (72 DPI by default)
|
|
851
|
+
- Support multi-page documents via `overflow="page-break"`
|
|
852
|
+
- Gradients require native PDF gradient support or rasterization
|
|
853
|
+
- Shadows may need to be simulated with multiple offset shapes
|
|
854
|
+
|
|
855
|
+
### 8.5 Image Rendering (PNG, JPEG)
|
|
856
|
+
|
|
857
|
+
Image output uses canvas APIs (node-canvas, browser Canvas).
|
|
858
|
+
|
|
859
|
+
**Considerations:**
|
|
860
|
+
- Set pixel ratio for high-DPI output
|
|
861
|
+
- Support transparency (PNG) or no transparency (JPEG)
|
|
862
|
+
- Flatten layers to single raster output
|
|
863
|
+
- Native shadow and gradient support via Canvas API
|
|
864
|
+
|
|
865
|
+
### 8.6 SVG Rendering
|
|
866
|
+
|
|
867
|
+
SVG output generates an XML SVG document.
|
|
868
|
+
|
|
869
|
+
**Considerations:**
|
|
870
|
+
- Embed fonts as base64 or reference external fonts
|
|
871
|
+
- Convert all elements to SVG equivalents
|
|
872
|
+
- Preserve vector quality (no rasterization)
|
|
873
|
+
- Use `<linearGradient>` and `<radialGradient>` elements in `<defs>`
|
|
874
|
+
- Use `<filter>` with `<feDropShadow>` for shadows
|
|
875
|
+
|
|
876
|
+
### 8.7 HTML/CSS Rendering
|
|
877
|
+
|
|
878
|
+
HTML output generates semantic HTML with CSS styling.
|
|
879
|
+
|
|
880
|
+
**Considerations:**
|
|
881
|
+
- Choose CSS strategy: inline styles, CSS classes, or CSS-in-JS
|
|
882
|
+
- Use flexbox or absolute positioning for layout
|
|
883
|
+
- Support responsive output with percentage-based dimensions
|
|
884
|
+
- Use CSS `linear-gradient()`, `radial-gradient()` for gradients
|
|
885
|
+
- Use CSS `box-shadow` for shadow effects
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
## 9. Components
|
|
890
|
+
|
|
891
|
+
### 9.1 Component Definition
|
|
892
|
+
|
|
893
|
+
Components are reusable EVG fragments registered by name:
|
|
894
|
+
|
|
895
|
+
```xml
|
|
896
|
+
<!-- Define a component -->
|
|
897
|
+
<div cname="Button">
|
|
898
|
+
<div padding="10" background-color="#3498db" border-radius="5">
|
|
899
|
+
<span id="content" color="white" font-size="14" />
|
|
900
|
+
</div>
|
|
901
|
+
</div>
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
### 9.2 Component Registration
|
|
905
|
+
|
|
906
|
+
```javascript
|
|
907
|
+
EVG.registerComponent("Button", buttonXML);
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
### 9.3 Component Usage
|
|
911
|
+
|
|
912
|
+
```xml
|
|
913
|
+
<Button>Click Me</Button>
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
When parsed, the component's XML replaces the custom element, with content inserted at the `id="content"` slot.
|
|
917
|
+
|
|
918
|
+
### 9.4 Content Slot
|
|
919
|
+
|
|
920
|
+
Components can define content slots using `id="content"` or `<content>` element:
|
|
921
|
+
|
|
922
|
+
```xml
|
|
923
|
+
<div cname="Card">
|
|
924
|
+
<div padding="20" background-color="white" shadow-radius="10">
|
|
925
|
+
<div id="content" />
|
|
926
|
+
</div>
|
|
927
|
+
</div>
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
## 10. Examples
|
|
933
|
+
|
|
934
|
+
### 10.1 Simple Card
|
|
935
|
+
|
|
936
|
+
```xml
|
|
937
|
+
<div width="400" height="300" background-color="#ecf0f1">
|
|
938
|
+
<div margin="20" padding="20" background-color="white"
|
|
939
|
+
border-radius="10" shadow-radius="5" shadow-color="rgba(0,0,0,0.1)">
|
|
940
|
+
<span font-size="24" font-family="Helvetica" color="#2c3e50">
|
|
941
|
+
Card Title
|
|
942
|
+
</span>
|
|
943
|
+
<div margin-top="10">
|
|
944
|
+
<span font-size="14" color="#7f8c8d">
|
|
945
|
+
This is the card description text that can wrap to multiple lines.
|
|
946
|
+
</span>
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
</div>
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
### 10.2 Horizontal Layout with Alignment
|
|
953
|
+
|
|
954
|
+
```xml
|
|
955
|
+
<div width="600" height="100" background-color="#34495e"
|
|
956
|
+
align="center" vertical-align="center">
|
|
957
|
+
<div width="80" height="80" background-color="#e74c3c"
|
|
958
|
+
border-radius="10" margin="10" />
|
|
959
|
+
<div width="80" height="80" background-color="#e67e22"
|
|
960
|
+
border-radius="10" margin="10" />
|
|
961
|
+
<div width="80" height="80" background-color="#f1c40f"
|
|
962
|
+
border-radius="10" margin="10" />
|
|
963
|
+
</div>
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
### 10.3 Icon with SVG Path
|
|
967
|
+
|
|
968
|
+
```xml
|
|
969
|
+
<div width="200" height="200" background-color="#ffffff"
|
|
970
|
+
align="center" vertical-align="center">
|
|
971
|
+
<path
|
|
972
|
+
d="M10,6.5c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S12.2,6.5,10,6.5M10,13.9c-1.8,0-3.2-1.5-3.2-3.2S8.2,7.4,10,7.4c1.8,0,3.2,1.5,3.2,3.2S11.8,13.9,10,13.9M17.1,5.7l-3.2,0L12.5,3.7c-0.1-0.1-0.2-0.2-0.3-0.2H7.8c-0.1,0-0.3,0.1-0.3,0.2L6.1,5.7H2.9c-1,0-1.7,0.7-1.7,1.7v7.4c0,1,0.8,1.7,1.7,1.7h14.2c1,0,1.7-0.8,1.7-1.7V7.2C18.8,6.2,18.1,5.7,17.1,5.7"
|
|
973
|
+
width="100"
|
|
974
|
+
height="100"
|
|
975
|
+
viewBox="0 0 20 20"
|
|
976
|
+
background-color="#3498db"
|
|
977
|
+
/>
|
|
978
|
+
</div>
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
### 10.4 Absolute Positioning
|
|
982
|
+
|
|
983
|
+
```xml
|
|
984
|
+
<div width="400" height="300" background-color="#2c3e50">
|
|
985
|
+
<!-- Centered content -->
|
|
986
|
+
<div width="200" height="100" background-color="white"
|
|
987
|
+
left="100" top="100" border-radius="10">
|
|
988
|
+
<span>Centered Box</span>
|
|
989
|
+
</div>
|
|
990
|
+
|
|
991
|
+
<!-- Bottom-right badge -->
|
|
992
|
+
<div width="50" height="50" background-color="#e74c3c"
|
|
993
|
+
right="20" bottom="20" border-radius="25"
|
|
994
|
+
align="center" vertical-align="center">
|
|
995
|
+
<span font-size="20" color="white">!</span>
|
|
996
|
+
</div>
|
|
997
|
+
</div>
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
### 10.5 Container Component Example
|
|
1001
|
+
|
|
1002
|
+
From `components/container.xml`:
|
|
1003
|
+
|
|
1004
|
+
```xml
|
|
1005
|
+
<div margin="10" border-radius="5" background-color="#337799"
|
|
1006
|
+
color="white" padding="10">
|
|
1007
|
+
<div font-size="16" color="#ffee77">
|
|
1008
|
+
This is a container component from components/container.xml
|
|
1009
|
+
</div>
|
|
1010
|
+
<div id="content" font-size="12" margin-top="10" />
|
|
1011
|
+
</div>
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## Appendix A: Color Format
|
|
1017
|
+
|
|
1018
|
+
EVG supports the following color formats:
|
|
1019
|
+
|
|
1020
|
+
| Format | Example | Description |
|
|
1021
|
+
|--------|---------|-------------|
|
|
1022
|
+
| Hex 6-digit | `#FF5733` | RGB in hexadecimal |
|
|
1023
|
+
| Hex 3-digit | `#F53` | Shorthand RGB |
|
|
1024
|
+
| Hex 8-digit | `#FF573388` | RGBA with alpha |
|
|
1025
|
+
| RGB | `rgb(255, 87, 51)` | RGB functional notation |
|
|
1026
|
+
| RGBA | `rgba(255, 87, 51, 0.5)` | RGB with alpha channel |
|
|
1027
|
+
| Named | `red`, `blue`, `white` | CSS named colors |
|
|
1028
|
+
|
|
1029
|
+
---
|
|
1030
|
+
|
|
1031
|
+
## Appendix B: SVG Path Commands
|
|
1032
|
+
|
|
1033
|
+
The `d` attribute in `<path>` elements supports standard SVG path commands:
|
|
1034
|
+
|
|
1035
|
+
| Command | Parameters | Description |
|
|
1036
|
+
|---------|------------|-------------|
|
|
1037
|
+
| `M` | x,y | Move to absolute position |
|
|
1038
|
+
| `m` | dx,dy | Move relative |
|
|
1039
|
+
| `L` | x,y | Line to absolute position |
|
|
1040
|
+
| `l` | dx,dy | Line relative |
|
|
1041
|
+
| `H` | x | Horizontal line to absolute X |
|
|
1042
|
+
| `h` | dx | Horizontal line relative |
|
|
1043
|
+
| `V` | y | Vertical line to absolute Y |
|
|
1044
|
+
| `v` | dy | Vertical line relative |
|
|
1045
|
+
| `C` | x1,y1 x2,y2 x,y | Cubic Bézier curve |
|
|
1046
|
+
| `c` | dx1,dy1 dx2,dy2 dx,dy | Cubic Bézier relative |
|
|
1047
|
+
| `S` | x2,y2 x,y | Smooth cubic Bézier |
|
|
1048
|
+
| `Q` | x1,y1 x,y | Quadratic Bézier curve |
|
|
1049
|
+
| `A` | rx ry rotation large-arc sweep x y | Arc |
|
|
1050
|
+
| `Z` | - | Close path |
|
|
1051
|
+
|
|
1052
|
+
---
|
|
1053
|
+
|
|
1054
|
+
## Appendix C: Implementation Checklist
|
|
1055
|
+
|
|
1056
|
+
When implementing an EVG renderer in a new language, ensure support for:
|
|
1057
|
+
|
|
1058
|
+
### Required
|
|
1059
|
+
- [ ] XML parsing with attribute extraction
|
|
1060
|
+
- [ ] Unit value parsing (px, %, em, rem, vw, vh, hp, fill)
|
|
1061
|
+
- [ ] Box model calculations (margin, padding, border)
|
|
1062
|
+
- [ ] Flow layout algorithm with wrapping
|
|
1063
|
+
- [ ] Absolute positioning
|
|
1064
|
+
- [ ] Horizontal and vertical alignment
|
|
1065
|
+
- [ ] Rectangle rendering (with rounded corners)
|
|
1066
|
+
- [ ] Text rendering with font support
|
|
1067
|
+
- [ ] Text measurement for layout calculations
|
|
1068
|
+
- [ ] Basic color parsing (hex, rgb, rgba)
|
|
1069
|
+
|
|
1070
|
+
### Recommended
|
|
1071
|
+
- [ ] SVG path rendering
|
|
1072
|
+
- [ ] Image rendering
|
|
1073
|
+
- [ ] Opacity and transparency
|
|
1074
|
+
- [ ] Box shadows
|
|
1075
|
+
- [ ] Linear gradients
|
|
1076
|
+
- [ ] Transforms (rotate, scale)
|
|
1077
|
+
- [ ] Component registration and expansion
|
|
1078
|
+
|
|
1079
|
+
### Optional
|
|
1080
|
+
- [ ] Page breaks for multi-page documents
|
|
1081
|
+
- [ ] Interactive elements (input, textarea)
|
|
1082
|
+
- [ ] Event handling
|
|
1083
|
+
- [ ] Animation support
|
|
1084
|
+
|
|
1085
|
+
---
|
|
1086
|
+
|
|
1087
|
+
## Appendix D: Attribute Name Aliases
|
|
1088
|
+
|
|
1089
|
+
EVG supports both camelCase and kebab-case for attribute names:
|
|
1090
|
+
|
|
1091
|
+
| Canonical | Alias |
|
|
1092
|
+
|-----------|-------|
|
|
1093
|
+
| `background-color` | `backgroundColor` |
|
|
1094
|
+
| `border-radius` | `borderRadius` |
|
|
1095
|
+
| `border-width` | `borderWidth` |
|
|
1096
|
+
| `border-color` | `borderColor` |
|
|
1097
|
+
| `font-size` | `fontSize` |
|
|
1098
|
+
| `font-family` | `fontFamily` |
|
|
1099
|
+
| `margin-left` | `marginLeft` |
|
|
1100
|
+
| `margin-right` | `marginRight` |
|
|
1101
|
+
| `margin-top` | `marginTop` |
|
|
1102
|
+
| `margin-bottom` | `marginBottom` |
|
|
1103
|
+
| `padding-left` | `paddingLeft` |
|
|
1104
|
+
| `padding-right` | `paddingRight` |
|
|
1105
|
+
| `padding-top` | `paddingTop` |
|
|
1106
|
+
| `padding-bottom` | `paddingBottom` |
|
|
1107
|
+
| `vertical-align` | `verticalAlign` |
|
|
1108
|
+
| `line-break` | `lineBreak` |
|
|
1109
|
+
| `shadow-radius` | `shadowRadius` |
|
|
1110
|
+
| `shadow-color` | `shadowColor` |
|
|
1111
|
+
| `shadow-offset-x` | `shadowOffsetX` |
|
|
1112
|
+
| `shadow-offset-y` | `shadowOffsetY` |
|
|
1113
|
+
| `linear-gradient` | `linearGradient` |
|
|
1114
|
+
| `radial-gradient` | `radialGradient` |
|
|
1115
|
+
|
|
1116
|
+
---
|
|
1117
|
+
|
|
1118
|
+
## Appendix E: Default Values
|
|
1119
|
+
|
|
1120
|
+
| Property | Default Value |
|
|
1121
|
+
|----------|---------------|
|
|
1122
|
+
| `width` | 100% of parent |
|
|
1123
|
+
| `height` | Auto (content-based) |
|
|
1124
|
+
| `font-size` | 14px |
|
|
1125
|
+
| `font-family` | Implementation-specific (typically "Arial" or "Helvetica") |
|
|
1126
|
+
| `color` | #000000 (black) |
|
|
1127
|
+
| `background-color` | transparent |
|
|
1128
|
+
| `opacity` | 1.0 |
|
|
1129
|
+
| `margin` | 0 |
|
|
1130
|
+
| `padding` | 0 |
|
|
1131
|
+
| `border-width` | 0 |
|
|
1132
|
+
| `border-radius` | 0 |
|
|
1133
|
+
| `align` | left |
|
|
1134
|
+
| `vertical-align` | top |
|
|
1135
|
+
| `direction` | row |
|
|
1136
|
+
| `overflow` | visible |
|
|
1137
|
+
| `shadow-color` | rgba(0,0,0,0.75) |
|
|
1138
|
+
| `shadow-radius` | 0 |
|
|
1139
|
+
| `shadow-offset-x` | 0 |
|
|
1140
|
+
| `shadow-offset-y` | 0 |
|
|
1141
|
+
|
|
1142
|
+
---
|
|
1143
|
+
|
|
1144
|
+
## Appendix F: Gradient String Parsing
|
|
1145
|
+
|
|
1146
|
+
### Linear Gradient Parsing Algorithm
|
|
1147
|
+
|
|
1148
|
+
```
|
|
1149
|
+
Function parseLinearGradient(value: string) -> LinearGradient:
|
|
1150
|
+
tokens = tokenize(value) // Split by comma, respecting parentheses
|
|
1151
|
+
angle = 180 // Default: top to bottom
|
|
1152
|
+
stops = []
|
|
1153
|
+
|
|
1154
|
+
For each token in tokens:
|
|
1155
|
+
token = trim(token)
|
|
1156
|
+
|
|
1157
|
+
// Check if first token is an angle
|
|
1158
|
+
If isAngle(token): // ends with "deg"
|
|
1159
|
+
angle = parseFloat(token)
|
|
1160
|
+
Continue
|
|
1161
|
+
|
|
1162
|
+
// Parse color stop: "color [position]"
|
|
1163
|
+
parts = splitByWhitespace(token)
|
|
1164
|
+
color = parts[0]
|
|
1165
|
+
position = null
|
|
1166
|
+
|
|
1167
|
+
If parts.length > 1 AND isPercentage(parts[1]):
|
|
1168
|
+
position = parseFloat(parts[1]) / 100
|
|
1169
|
+
|
|
1170
|
+
stops.push({color, position})
|
|
1171
|
+
|
|
1172
|
+
// Fill in missing positions (evenly distributed)
|
|
1173
|
+
fillMissingPositions(stops)
|
|
1174
|
+
|
|
1175
|
+
Return {angle, stops}
|
|
1176
|
+
|
|
1177
|
+
Function fillMissingPositions(stops):
|
|
1178
|
+
// First stop defaults to 0, last to 1
|
|
1179
|
+
If stops[0].position is null:
|
|
1180
|
+
stops[0].position = 0
|
|
1181
|
+
If stops[last].position is null:
|
|
1182
|
+
stops[last].position = 1
|
|
1183
|
+
|
|
1184
|
+
// Interpolate missing positions between defined ones
|
|
1185
|
+
For i from 1 to stops.length - 1:
|
|
1186
|
+
If stops[i].position is null:
|
|
1187
|
+
// Find next defined position
|
|
1188
|
+
nextDefined = findNextDefinedPosition(stops, i)
|
|
1189
|
+
prevDefined = findPrevDefinedPosition(stops, i)
|
|
1190
|
+
|
|
1191
|
+
// Linear interpolation
|
|
1192
|
+
range = nextDefined.position - prevDefined.position
|
|
1193
|
+
count = nextDefined.index - prevDefined.index
|
|
1194
|
+
stops[i].position = prevDefined.position + range * (i - prevDefined.index) / count
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
### Radial Gradient Parsing Algorithm
|
|
1198
|
+
|
|
1199
|
+
```
|
|
1200
|
+
Function parseRadialGradient(value: string) -> RadialGradient:
|
|
1201
|
+
tokens = tokenize(value) // Split by comma, respecting parentheses
|
|
1202
|
+
stops = []
|
|
1203
|
+
|
|
1204
|
+
For each token in tokens:
|
|
1205
|
+
token = trim(token)
|
|
1206
|
+
|
|
1207
|
+
// Parse color stop: "color [position]"
|
|
1208
|
+
parts = splitByWhitespace(token)
|
|
1209
|
+
color = parts[0]
|
|
1210
|
+
position = null
|
|
1211
|
+
|
|
1212
|
+
If parts.length > 1 AND isPercentage(parts[1]):
|
|
1213
|
+
position = parseFloat(parts[1]) / 100
|
|
1214
|
+
|
|
1215
|
+
stops.push({color, position})
|
|
1216
|
+
|
|
1217
|
+
// Fill in missing positions
|
|
1218
|
+
fillMissingPositions(stops)
|
|
1219
|
+
|
|
1220
|
+
Return {stops}
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### Example Parsing Results
|
|
1224
|
+
|
|
1225
|
+
**Input:** `"135deg, red, yellow 20%, black, blue"`
|
|
1226
|
+
```json
|
|
1227
|
+
{
|
|
1228
|
+
"angle": 135,
|
|
1229
|
+
"stops": [
|
|
1230
|
+
{"color": "red", "position": 0},
|
|
1231
|
+
{"color": "yellow", "position": 0.2},
|
|
1232
|
+
{"color": "black", "position": 0.6},
|
|
1233
|
+
{"color": "blue", "position": 1.0}
|
|
1234
|
+
]
|
|
1235
|
+
}
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
**Input:** `"red, green 50%, blue"` (radial)
|
|
1239
|
+
```json
|
|
1240
|
+
{
|
|
1241
|
+
"stops": [
|
|
1242
|
+
{"color": "red", "position": 0},
|
|
1243
|
+
{"color": "green", "position": 0.5},
|
|
1244
|
+
{"color": "blue", "position": 1.0}
|
|
1245
|
+
]
|
|
1246
|
+
}
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
---
|
|
1250
|
+
|
|
1251
|
+
*This specification is maintained as part of the EVG project.*
|
|
1252
|
+
|