xbintsc 0.5.23 → 0.5.32
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/AGENTS.md +11 -2
- package/README.md +47 -16
- package/README.zh-CN.md +21 -2
- package/dist/scripts/support-matrix.d.ts +18 -0
- package/dist/scripts/support-matrix.js +141 -0
- package/dist/scripts/support-matrix.js.map +1 -0
- package/dist/src/ast/common.d.ts +2 -2
- package/dist/src/ast/declarations.d.ts +7 -1
- package/dist/src/ast/expressions.d.ts +5 -0
- package/dist/src/ast/kinds.d.ts +2 -0
- package/dist/src/ast/kinds.js +2 -0
- package/dist/src/ast/kinds.js.map +1 -1
- package/dist/src/binder/binder.d.ts +2 -1
- package/dist/src/binder/binder.js +2 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +9 -0
- package/dist/src/binder/declarations.js +64 -0
- package/dist/src/binder/declarations.js.map +1 -1
- package/dist/src/binder/references.js +99 -4
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/binder/types.d.ts +32 -0
- package/dist/src/binder/types.js.map +1 -1
- package/dist/src/canonical.d.ts +29 -0
- package/dist/src/canonical.js +35 -0
- package/dist/src/canonical.js.map +1 -0
- package/dist/src/checker/assignability.d.ts +13 -0
- package/dist/src/checker/assignability.js +146 -0
- package/dist/src/checker/assignability.js.map +1 -0
- package/dist/src/checker/calls.d.ts +13 -0
- package/dist/src/checker/calls.js +127 -0
- package/dist/src/checker/calls.js.map +1 -0
- package/dist/src/checker/checker.d.ts +26 -0
- package/dist/src/checker/checker.js +31 -0
- package/dist/src/checker/checker.js.map +1 -0
- package/dist/src/checker/declarations.d.ts +9 -0
- package/dist/src/checker/declarations.js +15 -0
- package/dist/src/checker/declarations.js.map +1 -0
- package/dist/src/checker/flow.d.ts +21 -0
- package/dist/src/checker/flow.js +241 -0
- package/dist/src/checker/flow.js.map +1 -0
- package/dist/src/checker/globals.d.ts +9 -0
- package/dist/src/checker/globals.js +29 -0
- package/dist/src/checker/globals.js.map +1 -0
- package/dist/src/checker/source.d.ts +38 -0
- package/dist/src/checker/source.js +48 -0
- package/dist/src/checker/source.js.map +1 -0
- package/dist/src/checker/type-infer.d.ts +18 -0
- package/dist/src/checker/type-infer.js +173 -0
- package/dist/src/checker/type-infer.js.map +1 -0
- package/dist/src/checker/type-model.d.ts +73 -0
- package/dist/src/checker/type-model.js +151 -0
- package/dist/src/checker/type-model.js.map +1 -0
- package/dist/src/checker/type-system.d.ts +58 -0
- package/dist/src/checker/type-system.js +569 -0
- package/dist/src/checker/type-system.js.map +1 -0
- package/dist/src/checker/typecheck-types.d.ts +22 -0
- package/dist/src/checker/typecheck-types.js +109 -0
- package/dist/src/checker/typecheck-types.js.map +1 -0
- package/dist/src/checker/typecheck.d.ts +62 -0
- package/dist/src/checker/typecheck.js +574 -0
- package/dist/src/checker/typecheck.js.map +1 -0
- package/dist/src/checker/undefined.d.ts +14 -0
- package/dist/src/checker/undefined.js +32 -0
- package/dist/src/checker/undefined.js.map +1 -0
- package/dist/src/checker/walk.d.ts +10 -0
- package/dist/src/checker/walk.js +15 -0
- package/dist/src/checker/walk.js.map +1 -0
- package/dist/src/cli/help.d.ts +7 -0
- package/dist/src/cli/help.js +64 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/hints.js +2 -1
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +12 -48
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -8
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +9 -4
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/calls/super.d.ts +9 -1
- package/dist/src/codegen/generator/calls/super.js +56 -5
- package/dist/src/codegen/generator/calls/super.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +13 -2
- package/dist/src/codegen/generator/context.js +25 -19
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.js +2 -1
- package/dist/src/codegen/generator/debug.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.d.ts +4 -1
- package/dist/src/codegen/generator/expressions/primary.js +68 -8
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.js +11 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +3 -0
- package/dist/src/codegen/generator/module.js +116 -26
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.d.ts +11 -1
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +26 -7
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +2 -0
- package/dist/src/codegen/generator/tables.js +4 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/bundler/graph.js +5 -1
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +16 -1
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +12 -0
- package/dist/src/driver/compiler.d.ts +1 -1
- package/dist/src/driver/compiler.js +3 -0
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.js +2 -1
- package/dist/src/driver/fingerprint.js.map +1 -1
- package/dist/src/driver/frontend.d.ts +8 -6
- package/dist/src/driver/frontend.js +4 -0
- package/dist/src/driver/frontend.js.map +1 -1
- package/dist/src/driver/options.d.ts +6 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/css.d.ts +26 -0
- package/dist/src/extensions/gui/css.js +100 -0
- package/dist/src/extensions/gui/css.js.map +1 -0
- package/dist/src/extensions/gui/html.js +28 -7
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +79 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +16 -0
- package/dist/src/extensions/gui/three.js +22 -0
- package/dist/src/extensions/gui/three.js.map +1 -0
- package/dist/src/extensions/media/index.d.ts +6 -5
- package/dist/src/extensions/media/index.js +12 -14
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/src/extensions/registry.d.ts +38 -0
- package/dist/src/extensions/registry.js +10 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +7 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/expressions.js +14 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/literals.js +6 -2
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/binder/binder.test.js +29 -0
- package/dist/tests/binder/binder.test.js.map +1 -1
- package/dist/tests/canonical.test.d.ts +1 -0
- package/dist/tests/canonical.test.js +19 -0
- package/dist/tests/canonical.test.js.map +1 -0
- package/dist/tests/checker/checker.test.d.ts +1 -0
- package/dist/tests/checker/checker.test.js +245 -0
- package/dist/tests/checker/checker.test.js.map +1 -0
- package/dist/tests/cli/check.test.js +20 -0
- package/dist/tests/cli/check.test.js.map +1 -1
- package/dist/tests/conformance/matrix.test.d.ts +6 -0
- package/dist/tests/conformance/matrix.test.js +23 -0
- package/dist/tests/conformance/matrix.test.js.map +1 -0
- package/dist/tests/conformance/test262/manifest.d.ts +115 -0
- package/dist/tests/conformance/test262/manifest.js +257 -0
- package/dist/tests/conformance/test262/manifest.js.map +1 -0
- package/dist/tests/conformance/test262.test.d.ts +11 -0
- package/dist/tests/conformance/test262.test.js +74 -0
- package/dist/tests/conformance/test262.test.js.map +1 -0
- package/dist/tests/docs/structure.test.js +9 -11
- package/dist/tests/docs/structure.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.js +3 -2
- package/dist/tests/e2e/child-process.test.js.map +1 -1
- package/dist/tests/e2e/compile-builtins.test.js +45 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +77 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/differential-syntax.test.d.ts +5 -0
- package/dist/tests/e2e/differential-syntax.test.js +95 -0
- package/dist/tests/e2e/differential-syntax.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.js +15 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -1
- package/dist/tests/e2e/gui-browser.test.d.ts +13 -0
- package/dist/tests/e2e/gui-browser.test.js +163 -0
- package/dist/tests/e2e/gui-browser.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
- package/dist/tests/e2e/gui-effects.test.js +262 -0
- package/dist/tests/e2e/gui-effects.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-browser.test.js +2 -2
- package/dist/tests/e2e/gui-example-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-canvas.test.js +5 -4
- package/dist/tests/e2e/gui-example-canvas.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-svg.test.js +4 -3
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
- package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
- package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/gui-example.test.js +4 -3
- package/dist/tests/e2e/gui-example.test.js.map +1 -1
- package/dist/tests/e2e/gui-helpers.js +4 -3
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +48 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +10 -8
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
- package/dist/tests/e2e/gui-webgl.test.js +179 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2.test.js +238 -0
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +9 -0
- package/dist/tests/e2e/harness.js +14 -2
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/native-extensions.test.js +2 -1
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/property-descriptors.test.js +20 -0
- package/dist/tests/e2e/property-descriptors.test.js.map +1 -1
- package/dist/tests/e2e/unicode-output.test.js +5 -3
- package/dist/tests/e2e/unicode-output.test.js.map +1 -1
- package/dist/tests/e2e/weak-collections.test.js +16 -2
- package/dist/tests/e2e/weak-collections.test.js.map +1 -1
- package/dist/tests/extensions/gui.test.js +41 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +7 -3
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/dist/tests/helpers.d.ts +1 -0
- package/dist/tests/helpers.js +1 -0
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/declarations.test.js +20 -0
- package/dist/tests/parser/declarations.test.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +36 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/platform.d.ts +32 -0
- package/dist/tests/platform.js +40 -0
- package/dist/tests/platform.js.map +1 -0
- package/dist/tests/platform.test.d.ts +12 -0
- package/dist/tests/platform.test.js +51 -0
- package/dist/tests/platform.test.js.map +1 -0
- package/dist/tests/version.test.js +4 -4
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/README.md +10 -4
- package/doc/ai/build-recipe.md +1 -0
- package/doc/ai/cli.md +17 -5
- package/doc/ai/contributing.md +59 -2
- package/doc/ai/extensions.md +38 -7
- package/doc/ai/language-support.md +25 -16
- package/doc/ai/troubleshooting.md +12 -8
- package/doc/ai/zh-CN/README.md +9 -4
- package/doc/ai/zh-CN/build-recipe.md +1 -0
- package/doc/ai/zh-CN/cli.md +13 -3
- package/doc/ai/zh-CN/contributing.md +49 -3
- package/doc/ai/zh-CN/extensions.md +33 -6
- package/doc/ai/zh-CN/language-support.md +23 -14
- package/doc/ai/zh-CN/troubleshooting.md +10 -6
- package/doc/gui/api.md +47 -1
- package/doc/gui/build.md +72 -16
- package/doc/gui/canvas.md +11 -3
- package/doc/gui/dom.md +33 -18
- package/doc/gui/known-issues.md +58 -15
- package/doc/gui/layout.md +18 -0
- package/doc/gui/media.md +17 -13
- package/doc/gui/rendering.md +50 -3
- package/doc/gui/runtime.md +18 -0
- package/doc/gui/webgl.md +256 -0
- package/doc/gui-scripts.md +7 -0
- package/doc/gui.md +108 -17
- package/doc/implemented/binder.md +2 -0
- package/doc/implemented/checker.md +117 -0
- package/doc/implemented/cli.md +13 -1
- package/doc/implemented/codegen.md +3 -2
- package/doc/implemented/driver.md +2 -2
- package/doc/implemented/operators.md +2 -1
- package/doc/implemented/parser.md +3 -2
- package/doc/implemented/pipeline.md +8 -1
- package/doc/implemented/stdlib.md +2 -1
- package/doc/implemented/tests.md +3 -1
- package/doc/implemented.md +2 -0
- package/doc/npm-package.md +419 -0
- package/doc/requirements.md +22 -10
- package/doc/support-matrix.md +83 -0
- package/doc/unimplemented/classes.md +3 -0
- package/doc/unimplemented/deviations.md +3 -2
- package/doc/unimplemented/toolchain.md +1 -1
- package/doc/unimplemented/types.md +24 -8
- package/doc/unimplemented.md +1 -1
- package/doc/zh-CN/gui/api.md +43 -1
- package/doc/zh-CN/gui/build.md +64 -15
- package/doc/zh-CN/gui/canvas.md +9 -2
- package/doc/zh-CN/gui/dom.md +20 -7
- package/doc/zh-CN/gui/known-issues.md +46 -13
- package/doc/zh-CN/gui/layout.md +14 -0
- package/doc/zh-CN/gui/media.md +15 -11
- package/doc/zh-CN/gui/rendering.md +41 -4
- package/doc/zh-CN/gui/runtime.md +16 -0
- package/doc/zh-CN/gui/webgl.md +115 -0
- package/doc/zh-CN/gui-scripts.md +5 -0
- package/doc/zh-CN/gui.md +89 -14
- package/doc/zh-CN/implemented/binder.md +2 -0
- package/doc/zh-CN/implemented/checker.md +99 -0
- package/doc/zh-CN/implemented/cli.md +12 -1
- package/doc/zh-CN/implemented/codegen.md +3 -2
- package/doc/zh-CN/implemented/driver.md +2 -2
- package/doc/zh-CN/implemented/operators.md +1 -1
- package/doc/zh-CN/implemented/parser.md +3 -2
- package/doc/zh-CN/implemented/pipeline.md +3 -1
- package/doc/zh-CN/implemented/stdlib.md +2 -1
- package/doc/zh-CN/implemented/tests.md +3 -1
- package/doc/zh-CN/implemented.md +2 -0
- package/doc/zh-CN/npm-package.md +394 -0
- package/doc/zh-CN/post/announce.md +47 -47
- package/doc/zh-CN/requirements.md +16 -7
- package/doc/zh-CN/support-matrix.md +82 -0
- package/doc/zh-CN/unimplemented/classes.md +3 -0
- package/doc/zh-CN/unimplemented/deviations.md +3 -2
- package/doc/zh-CN/unimplemented/toolchain.md +1 -1
- package/doc/zh-CN/unimplemented/types.md +16 -6
- package/doc/zh-CN/unimplemented.md +1 -1
- package/llms.txt +6 -1
- package/package.json +2 -1
- package/runtime/ext_gui/audio.cpp +316 -0
- package/runtime/ext_gui/browser.cpp +573 -0
- package/runtime/ext_gui/browser_escape.cpp +85 -0
- package/runtime/ext_gui/browser_loop.cpp +83 -0
- package/runtime/ext_gui/canvas.cpp +12 -21
- package/runtime/ext_gui/canvas_internal.h +10 -0
- package/runtime/ext_gui/canvas_raster.cpp +79 -1
- package/runtime/ext_gui/clip_values.cpp +246 -0
- package/runtime/ext_gui/css.cpp +94 -0
- package/runtime/ext_gui/css.h +22 -1
- package/runtime/ext_gui/css_match.cpp +3 -0
- package/runtime/ext_gui/css_selector.cpp +9 -0
- package/runtime/ext_gui/css_sheet.cpp +89 -45
- package/runtime/ext_gui/document.cpp +4 -1
- package/runtime/ext_gui/document.h +2 -0
- package/runtime/ext_gui/dom.h +16 -0
- package/runtime/ext_gui/dom_api.cpp +37 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
- package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
- package/runtime/ext_gui/dom_api_document.cpp +96 -5
- package/runtime/ext_gui/dom_api_events.cpp +20 -0
- package/runtime/ext_gui/dom_api_internal.h +278 -0
- package/runtime/ext_gui/dom_api_proto.cpp +6 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
- package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
- package/runtime/ext_gui/effect_values.cpp +312 -0
- package/runtime/ext_gui/gradient_values.cpp +476 -0
- package/runtime/ext_gui/grid_values.cpp +230 -0
- package/runtime/ext_gui/gui.cpp +90 -23
- package/runtime/ext_gui/gui_canvas.cpp +50 -2
- package/runtime/ext_gui/gui_engine.h +71 -0
- package/runtime/ext_gui/gui_events.cpp +4 -1
- package/runtime/ext_gui/gui_media.cpp +1 -1
- package/runtime/ext_gui/gui_webgl.cpp +83 -0
- package/runtime/ext_gui/layout.cpp +21 -0
- package/runtime/ext_gui/layout_flow.cpp +81 -4
- package/runtime/ext_gui/layout_flow_internal.h +31 -0
- package/runtime/ext_gui/layout_grid.cpp +374 -0
- package/runtime/ext_gui/media.h +1 -1
- package/runtime/ext_gui/media_api.h +2 -2
- package/runtime/ext_gui/media_query.cpp +211 -0
- package/runtime/ext_gui/paint.cpp +111 -77
- package/runtime/ext_gui/paint.h +33 -3
- package/runtime/ext_gui/paint_background.cpp +229 -0
- package/runtime/ext_gui/paint_clip.cpp +268 -0
- package/runtime/ext_gui/paint_effects.cpp +324 -0
- package/runtime/ext_gui/paint_internal.h +85 -0
- package/runtime/ext_gui/renderer.cpp +8 -31
- package/runtime/ext_gui/renderer_clip.cpp +196 -0
- package/runtime/ext_gui/renderer_image.cpp +13 -8
- package/runtime/ext_gui/renderer_internal.h +15 -8
- package/runtime/ext_gui/renderer_text.cpp +6 -31
- package/runtime/ext_gui/style.cpp +343 -20
- package/runtime/ext_gui/style.h +144 -3
- package/runtime/ext_gui/style_print.cpp +134 -1
- package/runtime/ext_gui/style_values.cpp +152 -126
- package/runtime/ext_gui/style_values_internal.h +35 -0
- package/runtime/ext_gui/webgl.h +466 -0
- package/runtime/ext_gui/webgl2_constants.h +274 -0
- package/runtime/ext_gui/webgl_buffer.cpp +565 -0
- package/runtime/ext_gui/webgl_constants.h +317 -0
- package/runtime/ext_gui/webgl_context.cpp +466 -0
- package/runtime/ext_gui/webgl_draw.cpp +495 -0
- package/runtime/ext_gui/webgl_glsl.h +125 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
- package/runtime/ext_gui/webgl_msl.cpp +62 -0
- package/runtime/ext_gui/webgl_msl.h +33 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
- package/runtime/ext_gui/webgl_program_internal.h +18 -0
- package/runtime/ext_gui/webgl_shader.cpp +582 -0
- package/runtime/ext_gui/webgl_texture.cpp +293 -0
- package/runtime/ext_gui/webgl_uniform.cpp +167 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
- package/runtime/ext_gui/window.cpp +9 -0
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +9 -3
- package/runtime/ext_node/path/path.c +7 -7
- package/runtime/ext_node/url/url.c +4 -2
- package/runtime/rt.h +15 -0
- package/runtime/rt_internal.h +1 -0
- package/runtime/xt_constructors.c +2 -1
- package/runtime/xt_containers/access.inc +8 -0
- package/runtime/xt_containers/objects.inc +22 -2
- package/runtime/xt_io/exception.inc +4 -2
- package/runtime/xt_regex/api.inc +2 -0
- package/runtime/xt_regex/matcher.inc +16 -3
- package/runtime/xt_regex/parser.inc +8 -2
- package/runtime/xt_regex/types.inc +3 -0
- package/runtime/xt_stdlib/math.inc +62 -0
- package/runtime/xt_stdlib2/date.inc +7 -1
- package/runtime/xt_stdlib2/objects.inc +14 -0
- package/runtime/xt_stdlib2/regexp-match.inc +60 -21
- package/runtime/xt_stdlib2/regexp.inc +1 -0
- package/runtime/xt_typed_array.c +1 -1
- package/scripts/build-gui.ts +90 -3
- package/scripts/build-media.ts +323 -58
- package/scripts/setup-vs-toolchain.ps1 +152 -0
- package/scripts/support-matrix.ts +167 -0
- package/src/ast/common.ts +2 -0
- package/src/ast/declarations.ts +12 -1
- package/src/ast/expressions.ts +6 -0
- package/src/ast/kinds.ts +2 -0
- package/src/binder/binder.ts +3 -0
- package/src/binder/declarations.ts +70 -0
- package/src/binder/references.ts +97 -4
- package/src/binder/types.ts +30 -0
- package/src/canonical.ts +37 -0
- package/src/checker/assignability.ts +134 -0
- package/src/checker/calls.ts +135 -0
- package/src/checker/checker.ts +47 -0
- package/src/checker/declarations.ts +26 -0
- package/src/checker/flow.ts +236 -0
- package/src/checker/globals.ts +40 -0
- package/src/checker/source.ts +53 -0
- package/src/checker/type-infer.ts +185 -0
- package/src/checker/type-model.ts +212 -0
- package/src/checker/type-system.ts +578 -0
- package/src/checker/typecheck-types.ts +112 -0
- package/src/checker/typecheck.ts +586 -0
- package/src/checker/undefined.ts +43 -0
- package/src/checker/walk.ts +16 -0
- package/src/cli/help.ts +65 -0
- package/src/cli/hints.ts +2 -1
- package/src/cli/main.ts +12 -49
- package/src/codegen/generator/calls/access.ts +8 -8
- package/src/codegen/generator/calls/invocation.ts +8 -5
- package/src/codegen/generator/calls/super.ts +67 -5
- package/src/codegen/generator/context.ts +31 -19
- package/src/codegen/generator/debug.ts +2 -1
- package/src/codegen/generator/expressions/primary.ts +84 -13
- package/src/codegen/generator/generator.ts +11 -1
- package/src/codegen/generator/module.ts +115 -24
- package/src/codegen/generator/state.ts +11 -1
- package/src/codegen/generator/statements/variables.ts +26 -6
- package/src/codegen/generator/tables.ts +5 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/bundler/graph.ts +6 -2
- package/src/driver/bundler/merge.ts +14 -1
- package/src/driver/bundler/types.ts +13 -0
- package/src/driver/compiler.ts +4 -1
- package/src/driver/fingerprint.ts +2 -1
- package/src/driver/frontend.ts +13 -2
- package/src/driver/options.ts +6 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/css.ts +113 -0
- package/src/extensions/gui/html.ts +31 -11
- package/src/extensions/gui/index.ts +81 -2
- package/src/extensions/gui/three.ts +25 -0
- package/src/extensions/media/index.ts +13 -16
- package/src/extensions/registry.ts +48 -0
- package/src/index.ts +1 -0
- package/src/parser/declarations/classes.ts +7 -0
- package/src/parser/expressions.ts +13 -1
- package/src/parser/literals.ts +6 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — the frame pump for browser-style pages.
|
|
3
|
+
*
|
|
4
|
+
* A program that calls `run()` hands the frame loop to the engine: `xt_gui_run`
|
|
5
|
+
* polls input, renders and drains microtasks until the last window closes. A
|
|
6
|
+
* *page* — the kind xbintsc compiles straight from browser code — never calls
|
|
7
|
+
* `run()`. It asks for the next frame with `requestAnimationFrame` and expects
|
|
8
|
+
* the host to keep serving frames; without a pump the window would open and
|
|
9
|
+
* then never paint.
|
|
10
|
+
*
|
|
11
|
+
* This unit closes that gap with one repeating runtime timer. Each tick
|
|
12
|
+
* dispatches input, renders (which also drains the queued animation-frame
|
|
13
|
+
* callbacks before layout, so a mutation a callback makes lands in the same
|
|
14
|
+
* frame) and re-arms itself only while callbacks are still queued. A page that
|
|
15
|
+
* stops animating therefore lets the event loop drain, and the program exits on
|
|
16
|
+
* its own — the same lifecycle a browser tab has when it goes idle.
|
|
17
|
+
*
|
|
18
|
+
* `XT_GUI_AUTOCLOSE_MS` is honoured here too, so a headless run of such a page
|
|
19
|
+
* cannot hang.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#include "gui_engine.h"
|
|
23
|
+
|
|
24
|
+
namespace {
|
|
25
|
+
|
|
26
|
+
/** The tick callback, built once and rooted for the life of the program. */
|
|
27
|
+
xt_value g_tick = XT_UNDEFINED;
|
|
28
|
+
int g_tick_pending = 0;
|
|
29
|
+
double g_tick_started_ms = 0;
|
|
30
|
+
double g_tick_deadline_ms = 0;
|
|
31
|
+
|
|
32
|
+
xt_value browser_tick(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
33
|
+
|
|
34
|
+
void arm_tick(void) {
|
|
35
|
+
/* `run()` renders its own frames; a second pump would paint each window
|
|
36
|
+
* twice per tick. */
|
|
37
|
+
if (g_tick_pending || xt_gui_run_active()) return;
|
|
38
|
+
if (!XT_IS_FUNCTION(g_tick)) {
|
|
39
|
+
g_tick = xt_closure_new((void *)browser_tick, 0, NULL);
|
|
40
|
+
xt_gc_add_root(&g_tick);
|
|
41
|
+
}
|
|
42
|
+
xt_value args[2] = {g_tick, xt_number(16)};
|
|
43
|
+
g_tick_pending = 1;
|
|
44
|
+
xt_set_timeout(2, args);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
xt_value browser_tick(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
|
|
48
|
+
(void)self;
|
|
49
|
+
(void)env;
|
|
50
|
+
(void)argc;
|
|
51
|
+
(void)argv;
|
|
52
|
+
g_tick_pending = 0;
|
|
53
|
+
if (xt_gui_run_active()) return XT_UNDEFINED;
|
|
54
|
+
if (g_tick_deadline_ms > 0 && (double)SDL_GetTicks() >= g_tick_deadline_ms) {
|
|
55
|
+
/* Shared with `run()`: stop animating and let the program exit instead of
|
|
56
|
+
* hanging a headless run. */
|
|
57
|
+
xt_gui_quit(0, NULL);
|
|
58
|
+
return XT_UNDEFINED;
|
|
59
|
+
}
|
|
60
|
+
xt_value win = xt_browser_window(0, NULL);
|
|
61
|
+
if (XT_IS_UNDEFINED(win)) return XT_UNDEFINED;
|
|
62
|
+
XtGuiWindow *record = xt_gui_window_from_this(win);
|
|
63
|
+
if (record == NULL || !record->open) return XT_UNDEFINED;
|
|
64
|
+
xt_gui_pump_events();
|
|
65
|
+
xt_gui_render_window(record);
|
|
66
|
+
if (record->open && !record->animation_frames.empty()) arm_tick();
|
|
67
|
+
return XT_UNDEFINED;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} // namespace
|
|
71
|
+
|
|
72
|
+
/** Make sure a frame will be served: start the clock on the first request and
|
|
73
|
+
* arm the repeating tick unless one is already queued. */
|
|
74
|
+
extern "C" void xt_browser_schedule_frame(void) {
|
|
75
|
+
if (g_tick_started_ms == 0.0) {
|
|
76
|
+
g_tick_started_ms = (double)SDL_GetTicks();
|
|
77
|
+
const char *autoclose = SDL_getenv("XT_GUI_AUTOCLOSE_MS");
|
|
78
|
+
if (autoclose != NULL && autoclose[0] != '\0') {
|
|
79
|
+
g_tick_deadline_ms = g_tick_started_ms + (double)SDL_atoi(autoclose);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
arm_tick();
|
|
83
|
+
}
|
|
@@ -24,10 +24,16 @@ namespace {
|
|
|
24
24
|
std::atomic<uint64_t> g_next_canvas_id{1};
|
|
25
25
|
|
|
26
26
|
/** Process-wide id -> canvas table. The engine is single-threaded; the table
|
|
27
|
-
* lives for the process while the objects are owned by the window.
|
|
27
|
+
* lives for the process while the objects are owned by the window.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately leaked: `g_windows` is a global array, so the canvases it owns
|
|
30
|
+
* are destroyed *after* this function-local static would have been, and
|
|
31
|
+
* `~Canvas2D` has to remove itself from the table. Ordering that destruction by
|
|
32
|
+
* hand is not worth it — the table is one map for the whole process. */
|
|
28
33
|
std::unordered_map<uint64_t, Canvas2D *> &canvas_registry() {
|
|
29
|
-
static std::unordered_map<uint64_t, Canvas2D *> registry
|
|
30
|
-
|
|
34
|
+
static std::unordered_map<uint64_t, Canvas2D *> *registry =
|
|
35
|
+
new std::unordered_map<uint64_t, Canvas2D *>();
|
|
36
|
+
return *registry;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
CanvasPoint lerp(const CanvasPoint &a, const CanvasPoint &b, float t) {
|
|
@@ -451,24 +457,9 @@ void Canvas2D::draw_image(const Image &source, float dx, float dy, float dw, flo
|
|
|
451
457
|
canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, x0, y0, x1 - x0,
|
|
452
458
|
y1 - y0, sx, sy, sw, sh, state_.global_alpha);
|
|
453
459
|
} else {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
float minX = 0.0f, minY = 0.0f, maxX = 0.0f, maxY = 0.0f;
|
|
458
|
-
for (int i = 0; i < 4; i++) {
|
|
459
|
-
to_device(corners[i][0], corners[i][1], &cornersX[i], &cornersY[i]);
|
|
460
|
-
if (i == 0) {
|
|
461
|
-
minX = maxX = cornersX[i];
|
|
462
|
-
minY = maxY = cornersY[i];
|
|
463
|
-
} else {
|
|
464
|
-
minX = std::min(minX, cornersX[i]);
|
|
465
|
-
maxX = std::max(maxX, cornersX[i]);
|
|
466
|
-
minY = std::min(minY, cornersY[i]);
|
|
467
|
-
maxY = std::max(maxY, cornersY[i]);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, minX, minY,
|
|
471
|
-
maxX - minX, maxY - minY, sx, sy, sw, sh, state_.global_alpha);
|
|
460
|
+
canvas_detail::draw_image_affine(image_.pixels, image_.width, image_.height, source, dx, dy,
|
|
461
|
+
dw, dh, sx, sy, sw, sh, state_.transform,
|
|
462
|
+
state_.global_alpha);
|
|
472
463
|
}
|
|
473
464
|
generation_++;
|
|
474
465
|
}
|
|
@@ -48,6 +48,16 @@ void draw_image(std::vector<unsigned char> &pixels, int width, int height, const
|
|
|
48
48
|
float dx, float dy, float dw, float dh, float sx, float sy, float sw, float sh,
|
|
49
49
|
float alpha);
|
|
50
50
|
|
|
51
|
+
/** Blit an RGBA8 source through a full affine transform. The destination
|
|
52
|
+
* rectangle is mapped to a parallelogram by `transform`; each device pixel is
|
|
53
|
+
* inverse-mapped and sampled from the source rectangle. This is the path that
|
|
54
|
+
* makes rotated/skewed `drawImage` (and perspective-grid canvas textures) draw
|
|
55
|
+
* the image instead of squashing it into the bounding box. */
|
|
56
|
+
void draw_image_affine(std::vector<unsigned char> &pixels, int width, int height,
|
|
57
|
+
const Image &source, float dx, float dy, float dw, float dh, float sx,
|
|
58
|
+
float sy, float sw, float sh, const CanvasTransform &transform,
|
|
59
|
+
float alpha);
|
|
60
|
+
|
|
51
61
|
/** Composite one grayscale glyph bitmap at `(x, baselineY)` with `paint`. */
|
|
52
62
|
void blit_glyph(std::vector<unsigned char> &pixels, int width, int height,
|
|
53
63
|
const std::vector<unsigned char> &glyph, int glyphWidth, int glyphHeight, int left,
|
|
@@ -53,6 +53,15 @@ void paint_color_at(const CanvasPaint &paint, float x, float y, float out[4]) {
|
|
|
53
53
|
} // namespace
|
|
54
54
|
|
|
55
55
|
void blend_pixel(unsigned char *pixel, const float color[4], float coverage, float alpha) {
|
|
56
|
+
/* Fully opaque source-over is a plain copy; this is the hot path for paper
|
|
57
|
+
textures, terrain and the opaque parts of every sprite. */
|
|
58
|
+
if (alpha >= 0.999f && coverage >= 0.999f && color[3] >= 0.999f) {
|
|
59
|
+
pixel[0] = (unsigned char)clamp_byte(color[0] * 255.0f);
|
|
60
|
+
pixel[1] = (unsigned char)clamp_byte(color[1] * 255.0f);
|
|
61
|
+
pixel[2] = (unsigned char)clamp_byte(color[2] * 255.0f);
|
|
62
|
+
pixel[3] = 255;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
56
65
|
float sa = color[3] * coverage * alpha;
|
|
57
66
|
if (sa <= 0.0f) return;
|
|
58
67
|
if (sa > 1.0f) sa = 1.0f;
|
|
@@ -245,8 +254,77 @@ void draw_image(std::vector<unsigned char> &pixels, int width, int height, const
|
|
|
245
254
|
if (syi >= source.height) syi = source.height - 1;
|
|
246
255
|
const unsigned char *texel =
|
|
247
256
|
source.pixels.data() + ((size_t)syi * (size_t)source.width + (size_t)sxi) * 4;
|
|
257
|
+
unsigned char *dst = pixels.data() + ((size_t)py * (size_t)width + (size_t)px) * 4;
|
|
258
|
+
if (alpha >= 0.999f) {
|
|
259
|
+
const unsigned char ta = texel[3];
|
|
260
|
+
if (ta == 255) {
|
|
261
|
+
dst[0] = texel[0]; dst[1] = texel[1]; dst[2] = texel[2]; dst[3] = 255;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (ta == 0) continue;
|
|
265
|
+
}
|
|
266
|
+
float color[4] = {texel[0] / 255.0f, texel[1] / 255.0f, texel[2] / 255.0f, texel[3] / 255.0f};
|
|
267
|
+
blend_pixel(dst, color, 1.0f, alpha);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
void draw_image_affine(std::vector<unsigned char> &pixels, int width, int height,
|
|
274
|
+
const Image &source, float dx, float dy, float dw, float dh, float sx,
|
|
275
|
+
float sy, float sw, float sh, const CanvasTransform &transform,
|
|
276
|
+
float alpha) {
|
|
277
|
+
if (source.width <= 0 || source.height <= 0 || dw <= 0.0f || dh <= 0.0f || sw <= 0.0f ||
|
|
278
|
+
sh <= 0.0f)
|
|
279
|
+
return;
|
|
280
|
+
CanvasTransform inverse = transform.inverted();
|
|
281
|
+
float cornersX[4];
|
|
282
|
+
float cornersY[4];
|
|
283
|
+
const float corners[4][2] = {{dx, dy}, {dx + dw, dy}, {dx + dw, dy + dh}, {dx, dy + dh}};
|
|
284
|
+
float minX = 0.0f, minY = 0.0f, maxX = 0.0f, maxY = 0.0f;
|
|
285
|
+
for (int i = 0; i < 4; i++) {
|
|
286
|
+
transform.apply(corners[i][0], corners[i][1], &cornersX[i], &cornersY[i]);
|
|
287
|
+
if (i == 0) {
|
|
288
|
+
minX = maxX = cornersX[i];
|
|
289
|
+
minY = maxY = cornersY[i];
|
|
290
|
+
} else {
|
|
291
|
+
minX = std::min(minX, cornersX[i]);
|
|
292
|
+
maxX = std::max(maxX, cornersX[i]);
|
|
293
|
+
minY = std::min(minY, cornersY[i]);
|
|
294
|
+
maxY = std::max(maxY, cornersY[i]);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
int ix0 = std::max(0, (int)std::floor(minX));
|
|
298
|
+
int ix1 = std::min(width, (int)std::ceil(maxX));
|
|
299
|
+
int iy0 = std::max(0, (int)std::floor(minY));
|
|
300
|
+
int iy1 = std::min(height, (int)std::ceil(maxY));
|
|
301
|
+
for (int py = iy0; py < iy1; py++) {
|
|
302
|
+
for (int px = ix0; px < ix1; px++) {
|
|
303
|
+
float ux = 0.0f;
|
|
304
|
+
float uy = 0.0f;
|
|
305
|
+
inverse.apply((float)px + 0.5f, (float)py + 0.5f, &ux, &uy);
|
|
306
|
+
float u = (ux - dx) / dw;
|
|
307
|
+
float v = (uy - dy) / dh;
|
|
308
|
+
if (u < 0.0f || u >= 1.0f || v < 0.0f || v >= 1.0f) continue;
|
|
309
|
+
int sxi = (int)(sx + u * sw);
|
|
310
|
+
int syi = (int)(sy + v * sh);
|
|
311
|
+
if (sxi < 0) sxi = 0;
|
|
312
|
+
if (syi < 0) syi = 0;
|
|
313
|
+
if (sxi >= source.width) sxi = source.width - 1;
|
|
314
|
+
if (syi >= source.height) syi = source.height - 1;
|
|
315
|
+
const unsigned char *texel =
|
|
316
|
+
source.pixels.data() + ((size_t)syi * (size_t)source.width + (size_t)sxi) * 4;
|
|
317
|
+
unsigned char *dst = pixels.data() + ((size_t)py * (size_t)width + (size_t)px) * 4;
|
|
318
|
+
if (alpha >= 0.999f) {
|
|
319
|
+
const unsigned char ta = texel[3];
|
|
320
|
+
if (ta == 255) {
|
|
321
|
+
dst[0] = texel[0]; dst[1] = texel[1]; dst[2] = texel[2]; dst[3] = 255;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (ta == 0) continue;
|
|
325
|
+
}
|
|
248
326
|
float color[4] = {texel[0] / 255.0f, texel[1] / 255.0f, texel[2] / 255.0f, texel[3] / 255.0f};
|
|
249
|
-
blend_pixel(
|
|
327
|
+
blend_pixel(dst, color, 1.0f, alpha);
|
|
250
328
|
}
|
|
251
329
|
}
|
|
252
330
|
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `clip-path` value parsing.
|
|
3
|
+
*
|
|
4
|
+
* The geometry is resolved in `paint_clip.cpp`, where the element's border box
|
|
5
|
+
* and transform are known. Values here keep CSS lengths unresolved so `%`, em
|
|
6
|
+
* and viewport units survive the cascade.
|
|
7
|
+
*/
|
|
8
|
+
#include <cctype>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <utility>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
#include "css_internal.h"
|
|
14
|
+
#include "style_internal.h"
|
|
15
|
+
#include "style_values_internal.h"
|
|
16
|
+
|
|
17
|
+
namespace xtgui {
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
std::vector<std::string> splitTokens(const std::string &text) {
|
|
22
|
+
std::vector<std::string> parts;
|
|
23
|
+
std::string current;
|
|
24
|
+
int depth = 0;
|
|
25
|
+
for (char c : text) {
|
|
26
|
+
if (c == '(') depth++;
|
|
27
|
+
if (c == ')') depth--;
|
|
28
|
+
if ((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ',') && depth == 0) {
|
|
29
|
+
if (!current.empty()) {
|
|
30
|
+
parts.push_back(current);
|
|
31
|
+
current.clear();
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
current.push_back(c);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!current.empty()) parts.push_back(current);
|
|
38
|
+
return parts;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Split `text` on a top-level keyword (`at` / `round`), keeping both sides. */
|
|
42
|
+
bool splitKeyword(const std::string &text, const std::string &keyword, std::string *left,
|
|
43
|
+
std::string *right) {
|
|
44
|
+
std::string lower = xt_css_lower(text);
|
|
45
|
+
int depth = 0;
|
|
46
|
+
for (size_t i = 0; i + keyword.size() <= text.size(); i++) {
|
|
47
|
+
char c = text[i];
|
|
48
|
+
if (c == '(') depth++;
|
|
49
|
+
else if (c == ')') depth--;
|
|
50
|
+
if (depth != 0) continue;
|
|
51
|
+
if (lower.compare(i, keyword.size(), keyword) != 0) continue;
|
|
52
|
+
bool before = i == 0 || xt_is_css_space(text[i - 1]) || text[i - 1] == ',';
|
|
53
|
+
bool after = i + keyword.size() >= text.size() ||
|
|
54
|
+
xt_is_css_space(text[i + keyword.size()]) || text[i + keyword.size()] == ',';
|
|
55
|
+
if (!before || !after) continue;
|
|
56
|
+
*left = xt_css_trim(text.substr(0, i));
|
|
57
|
+
*right = xt_css_trim(text.substr(i + keyword.size()));
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
bool parsePositionToken(const std::string &raw, Length *out, bool *vertical) {
|
|
64
|
+
std::string text = xt_css_lower(xt_css_trim(raw));
|
|
65
|
+
if (text == "left") { *out = {0.0f, Unit::Percent}; *vertical = false; return true; }
|
|
66
|
+
if (text == "right") { *out = {100.0f, Unit::Percent}; *vertical = false; return true; }
|
|
67
|
+
if (text == "top") { *out = {0.0f, Unit::Percent}; *vertical = true; return true; }
|
|
68
|
+
if (text == "bottom") { *out = {100.0f, Unit::Percent}; *vertical = true; return true; }
|
|
69
|
+
if (text == "center") { *out = {50.0f, Unit::Percent}; *vertical = false; return true; }
|
|
70
|
+
Length length = xt_css_parse_length(text);
|
|
71
|
+
if (length.unit == Unit::Invalid || length.unit == Unit::Auto || length.unit == Unit::None)
|
|
72
|
+
return false;
|
|
73
|
+
*out = length;
|
|
74
|
+
*vertical = false;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
bool parseCenter(const std::string &text, Length *x, Length *y) {
|
|
79
|
+
std::vector<std::string> tokens = splitTokens(text);
|
|
80
|
+
if (tokens.empty() || tokens.size() > 2) return false;
|
|
81
|
+
Length values[2];
|
|
82
|
+
bool vertical[2] = {false, false};
|
|
83
|
+
for (size_t i = 0; i < tokens.size(); i++) {
|
|
84
|
+
if (!parsePositionToken(tokens[i], &values[i], &vertical[i])) return false;
|
|
85
|
+
}
|
|
86
|
+
if (tokens.size() == 1) {
|
|
87
|
+
if (vertical[0]) {
|
|
88
|
+
*x = {50.0f, Unit::Percent};
|
|
89
|
+
*y = values[0];
|
|
90
|
+
} else {
|
|
91
|
+
*x = values[0];
|
|
92
|
+
*y = {50.0f, Unit::Percent};
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (vertical[0] && !vertical[1]) {
|
|
97
|
+
*x = values[1];
|
|
98
|
+
*y = values[0];
|
|
99
|
+
} else {
|
|
100
|
+
*x = values[0];
|
|
101
|
+
*y = values[1];
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Parse the 1–4 side lengths of `inset(...)` and an optional round radius. */
|
|
107
|
+
bool parseInset(const std::string &body, ClipPathSpec *spec) {
|
|
108
|
+
std::string sides = body;
|
|
109
|
+
std::string round;
|
|
110
|
+
if (splitKeyword(body, "round", &sides, &round)) {
|
|
111
|
+
std::vector<std::string> radiusTokens = splitTokens(round);
|
|
112
|
+
if (!radiusTokens.empty()) {
|
|
113
|
+
Length radius = xt_css_parse_length(radiusTokens[0]);
|
|
114
|
+
if (radius.unit != Unit::Invalid && radius.unit != Unit::Auto &&
|
|
115
|
+
radius.unit != Unit::None)
|
|
116
|
+
spec->inset_radius = radius;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
std::vector<std::string> tokens = splitTokens(sides);
|
|
120
|
+
if (tokens.empty() || tokens.size() > 4) return false;
|
|
121
|
+
Length values[4];
|
|
122
|
+
for (size_t i = 0; i < tokens.size(); i++) {
|
|
123
|
+
values[i] = xt_css_parse_length(tokens[i]);
|
|
124
|
+
if (values[i].unit == Unit::Invalid) return false;
|
|
125
|
+
}
|
|
126
|
+
switch (tokens.size()) {
|
|
127
|
+
case 1:
|
|
128
|
+
spec->inset_top = spec->inset_right = spec->inset_bottom = spec->inset_left = values[0];
|
|
129
|
+
break;
|
|
130
|
+
case 2:
|
|
131
|
+
spec->inset_top = spec->inset_bottom = values[0];
|
|
132
|
+
spec->inset_right = spec->inset_left = values[1];
|
|
133
|
+
break;
|
|
134
|
+
case 3:
|
|
135
|
+
spec->inset_top = values[0];
|
|
136
|
+
spec->inset_right = spec->inset_left = values[1];
|
|
137
|
+
spec->inset_bottom = values[2];
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
spec->inset_top = values[0];
|
|
141
|
+
spec->inset_right = values[1];
|
|
142
|
+
spec->inset_bottom = values[2];
|
|
143
|
+
spec->inset_left = values[3];
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
spec->type = ClipPathSpec::Type::Inset;
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
bool parseCircle(const std::string &body, ClipPathSpec *spec) {
|
|
151
|
+
std::string radius;
|
|
152
|
+
std::string center;
|
|
153
|
+
if (splitKeyword(body, "at", &radius, ¢er)) {
|
|
154
|
+
if (!parseCenter(center, &spec->center_x, &spec->center_y)) return false;
|
|
155
|
+
} else {
|
|
156
|
+
radius = body;
|
|
157
|
+
}
|
|
158
|
+
std::vector<std::string> tokens = splitTokens(radius);
|
|
159
|
+
if (!tokens.empty()) {
|
|
160
|
+
Length length = xt_css_parse_length(tokens[0]);
|
|
161
|
+
if (length.unit == Unit::Invalid) return false;
|
|
162
|
+
spec->radius_x = length;
|
|
163
|
+
spec->radius_y = length;
|
|
164
|
+
spec->radius_explicit = true;
|
|
165
|
+
}
|
|
166
|
+
spec->type = ClipPathSpec::Type::Circle;
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
bool parseEllipse(const std::string &body, ClipPathSpec *spec) {
|
|
171
|
+
std::string radii = body;
|
|
172
|
+
std::string center;
|
|
173
|
+
splitKeyword(body, "at", &radii, ¢er);
|
|
174
|
+
if (!center.empty() && !parseCenter(center, &spec->center_x, &spec->center_y)) return false;
|
|
175
|
+
std::vector<std::string> tokens = splitTokens(radii);
|
|
176
|
+
if (!tokens.empty()) {
|
|
177
|
+
Length rx = xt_css_parse_length(tokens[0]);
|
|
178
|
+
Length ry = tokens.size() > 1 ? xt_css_parse_length(tokens[1]) : rx;
|
|
179
|
+
if (rx.unit == Unit::Invalid || ry.unit == Unit::Invalid) return false;
|
|
180
|
+
spec->radius_x = rx;
|
|
181
|
+
spec->radius_y = ry;
|
|
182
|
+
spec->radius_explicit = true;
|
|
183
|
+
}
|
|
184
|
+
spec->type = ClipPathSpec::Type::Ellipse;
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
bool parsePolygon(const std::string &body, ClipPathSpec *spec) {
|
|
189
|
+
std::string text = xt_css_trim(body);
|
|
190
|
+
std::string lower = xt_css_lower(text);
|
|
191
|
+
if (lower.rfind("nonzero", 0) == 0) text = xt_css_trim(text.substr(7));
|
|
192
|
+
else if (lower.rfind("evenodd", 0) == 0) text = xt_css_trim(text.substr(7));
|
|
193
|
+
/* Pairs are separated by commas in CSS, but whitespace is accepted too. */
|
|
194
|
+
std::vector<std::string> tokens = splitTokens(text);
|
|
195
|
+
if (tokens.size() < 3) return false;
|
|
196
|
+
std::vector<Length> points;
|
|
197
|
+
for (const std::string &token : tokens) {
|
|
198
|
+
Length length = xt_css_parse_length(token);
|
|
199
|
+
if (length.unit == Unit::Invalid) return false;
|
|
200
|
+
points.push_back(length);
|
|
201
|
+
}
|
|
202
|
+
if (points.size() < 3) return false;
|
|
203
|
+
if (points.size() % 2 != 0) points.pop_back();
|
|
204
|
+
spec->polygon = std::move(points);
|
|
205
|
+
spec->type = ClipPathSpec::Type::Polygon;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
} // namespace
|
|
210
|
+
|
|
211
|
+
bool xt_style_apply_clip_path(XtStyle *style, const std::string &property,
|
|
212
|
+
const std::string &value) {
|
|
213
|
+
if (property != "clip-path") return false;
|
|
214
|
+
std::string text = xt_css_trim(value);
|
|
215
|
+
std::string lower = xt_css_lower(text);
|
|
216
|
+
ClipPathSpec spec;
|
|
217
|
+
if (lower == "none" || text.empty()) {
|
|
218
|
+
style->clip_path = spec;
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
if (text.size() < 8 || text.back() != ')') {
|
|
222
|
+
style->clip_path = spec;
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
if (lower.rfind("inset(", 0) == 0) {
|
|
226
|
+
if (parseInset(text.substr(6, text.size() - 7), &spec)) style->clip_path = spec;
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
if (lower.rfind("circle(", 0) == 0) {
|
|
230
|
+
if (parseCircle(text.substr(7, text.size() - 8), &spec)) style->clip_path = spec;
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
if (lower.rfind("ellipse(", 0) == 0) {
|
|
234
|
+
if (parseEllipse(text.substr(8, text.size() - 9), &spec)) style->clip_path = spec;
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
if (lower.rfind("polygon(", 0) == 0) {
|
|
238
|
+
if (parsePolygon(text.substr(8, text.size() - 9), &spec)) style->clip_path = spec;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
/* `url(#…)`, `path()` and other shapes are not part of the subset. */
|
|
242
|
+
style->clip_path = spec;
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
} // namespace xtgui
|
package/runtime/ext_gui/css.cpp
CHANGED
|
@@ -45,6 +45,39 @@ std::vector<std::string> xt_css_split_whitespace(const std::string &text) {
|
|
|
45
45
|
return parts;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
std::vector<std::string> xt_css_split_commas(const std::string &text) {
|
|
49
|
+
std::vector<std::string> parts;
|
|
50
|
+
std::string current;
|
|
51
|
+
int depth = 0;
|
|
52
|
+
char quote = 0;
|
|
53
|
+
for (char c : text) {
|
|
54
|
+
if (quote != 0) {
|
|
55
|
+
current.push_back(c);
|
|
56
|
+
if (c == quote) quote = 0;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (c == '"' || c == '\'') {
|
|
60
|
+
quote = c;
|
|
61
|
+
current.push_back(c);
|
|
62
|
+
} else if (c == '(' || c == '[') {
|
|
63
|
+
depth++;
|
|
64
|
+
current.push_back(c);
|
|
65
|
+
} else if (c == ')' || c == ']') {
|
|
66
|
+
if (depth > 0) depth--;
|
|
67
|
+
current.push_back(c);
|
|
68
|
+
} else if (c == ',' && depth == 0) {
|
|
69
|
+
std::string part = xt_css_trim(current);
|
|
70
|
+
if (!part.empty()) parts.push_back(part);
|
|
71
|
+
current.clear();
|
|
72
|
+
} else {
|
|
73
|
+
current.push_back(c);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
std::string part = xt_css_trim(current);
|
|
77
|
+
if (!part.empty()) parts.push_back(part);
|
|
78
|
+
return parts;
|
|
79
|
+
}
|
|
80
|
+
|
|
48
81
|
/* -- numbers / lengths / colors ------------------------------------------- */
|
|
49
82
|
|
|
50
83
|
bool xt_css_parse_number(const std::string &value, float *out) {
|
|
@@ -59,6 +92,60 @@ bool xt_css_parse_number(const std::string &value, float *out) {
|
|
|
59
92
|
return true;
|
|
60
93
|
}
|
|
61
94
|
|
|
95
|
+
|
|
96
|
+
/** Split a CSS function's argument list at top-level commas. */
|
|
97
|
+
static std::vector<std::string> splitFunctionArgs(const std::string &text) {
|
|
98
|
+
std::vector<std::string> args;
|
|
99
|
+
std::string current;
|
|
100
|
+
int depth = 0;
|
|
101
|
+
for (char c : text) {
|
|
102
|
+
if (c == '(') depth++;
|
|
103
|
+
if (c == ')') depth--;
|
|
104
|
+
if (c == ',' && depth == 0) {
|
|
105
|
+
args.push_back(xt_css_trim(current));
|
|
106
|
+
current.clear();
|
|
107
|
+
} else {
|
|
108
|
+
current.push_back(c);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!current.empty() || !args.empty()) args.push_back(xt_css_trim(current));
|
|
112
|
+
return args;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** `clamp(min, value, max)`, `min(...)` and `max(...)` over lengths. The
|
|
116
|
+
* arguments stay unresolved; layout resolves them against the element's em and
|
|
117
|
+
* the viewport. `env(safe-area-inset-*)` has no notch information in a desktop
|
|
118
|
+
* window, so it resolves to zero (its fallback is ignored, matching the
|
|
119
|
+
* browser's value without insets). */
|
|
120
|
+
static Length parseFunctionLength(const std::string &name, const std::string &inner) {
|
|
121
|
+
Length result;
|
|
122
|
+
if (name == "env") {
|
|
123
|
+
result.unit = Unit::Px;
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
if (name != "clamp" && name != "min" && name != "max") {
|
|
127
|
+
result.unit = Unit::Invalid;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
std::vector<std::string> args = splitFunctionArgs(inner);
|
|
131
|
+
size_t expected = name == "clamp" ? 3 : 1;
|
|
132
|
+
if (args.size() < expected) {
|
|
133
|
+
result.unit = Unit::Invalid;
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
result.unit = name == "clamp" ? Unit::Clamp : (name == "min" ? Unit::Min : Unit::Max);
|
|
137
|
+
for (const std::string &arg : args) {
|
|
138
|
+
Length value = xt_css_parse_length(arg);
|
|
139
|
+
if (value.unit == Unit::Invalid) {
|
|
140
|
+
result.unit = Unit::Invalid;
|
|
141
|
+
result.args.clear();
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
result.args.push_back(value);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
62
149
|
Length xt_css_parse_length(const std::string &value) {
|
|
63
150
|
Length length;
|
|
64
151
|
std::string text = xt_css_lower(xt_css_trim(value));
|
|
@@ -74,6 +161,13 @@ Length xt_css_parse_length(const std::string &value) {
|
|
|
74
161
|
length.unit = Unit::None;
|
|
75
162
|
return length;
|
|
76
163
|
}
|
|
164
|
+
size_t open = text.find('(');
|
|
165
|
+
if (open != std::string::npos && !text.empty() && text.back() == ')') {
|
|
166
|
+
std::string name = text.substr(0, open);
|
|
167
|
+
if (name == "clamp" || name == "min" || name == "max" || name == "env") {
|
|
168
|
+
return parseFunctionLength(name, text.substr(open + 1, text.size() - open - 2));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
77
171
|
char *end = nullptr;
|
|
78
172
|
float number = strtof(text.c_str(), &end);
|
|
79
173
|
if (end == text.c_str()) {
|
package/runtime/ext_gui/css.h
CHANGED
|
@@ -17,11 +17,15 @@
|
|
|
17
17
|
|
|
18
18
|
namespace xtgui {
|
|
19
19
|
|
|
20
|
-
enum class Unit { Auto, None, Px, Percent, Em, Rem, Vw, Vh, Number, Invalid };
|
|
20
|
+
enum class Unit { Auto, None, Px, Percent, Em, Rem, Vw, Vh, Number, Clamp, Min, Max, Invalid };
|
|
21
21
|
|
|
22
22
|
struct Length {
|
|
23
23
|
float value = 0.0f;
|
|
24
24
|
Unit unit = Unit::Auto;
|
|
25
|
+
/* Arguments of `clamp(...)`, `min(...)` and `max(...)`; empty for a scalar
|
|
26
|
+
* length. Kept unresolved so vw/vh/em are resolved against the element that
|
|
27
|
+
* uses the length, not the viewport at parse time. */
|
|
28
|
+
std::vector<Length> args = {};
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
struct Color {
|
|
@@ -52,6 +56,9 @@ struct CompoundSelector {
|
|
|
52
56
|
std::vector<std::string> classes;
|
|
53
57
|
std::vector<AttrSelector> attrs;
|
|
54
58
|
std::vector<std::string> pseudoClasses;
|
|
59
|
+
/** `before`/`after` for a `::before`/`::after` (or legacy `:before`)
|
|
60
|
+
* pseudo-element; empty for an ordinary selector. */
|
|
61
|
+
std::string pseudo_element;
|
|
55
62
|
};
|
|
56
63
|
|
|
57
64
|
enum class Combinator { Descendant, Child, Adjacent, Sibling };
|
|
@@ -66,6 +73,10 @@ struct Rule {
|
|
|
66
73
|
std::vector<ComplexSelector> selectors;
|
|
67
74
|
std::vector<Declaration> declarations;
|
|
68
75
|
int order = 0;
|
|
76
|
+
/** Raw `@media` prelude this rule came from (empty = unconditional). The
|
|
77
|
+
* query is evaluated against the current viewport during the cascade, so a
|
|
78
|
+
* resize restyles with the right rules. */
|
|
79
|
+
std::string media;
|
|
69
80
|
};
|
|
70
81
|
|
|
71
82
|
struct StyleSheet {
|
|
@@ -85,6 +96,16 @@ std::vector<Declaration> xt_css_parse_declarations(const std::string &text);
|
|
|
85
96
|
bool xt_css_match(const Node *node, const ComplexSelector &selector);
|
|
86
97
|
bool xt_css_match(const Node *node, const ComplexSelector &selector, const MatchState &state);
|
|
87
98
|
|
|
99
|
+
/** True when a raw `@media` prelude matches a viewport. Supports media types
|
|
100
|
+
* (`all`/`screen`), comma-separated query lists, `not`/`only`, `and`, and the
|
|
101
|
+
* width/height/orientation/hover/pointer/colour-scheme features (with
|
|
102
|
+
* `min-`/`max-` ranges). Unknown features never match, as in a browser. */
|
|
103
|
+
bool xt_css_media_matches(const std::string &query, float viewport_width, float viewport_height);
|
|
104
|
+
|
|
105
|
+
/** Split `text` at top-level commas (outside `(...)`, `[...]` and quotes),
|
|
106
|
+
* trimming each part and dropping empty ones. */
|
|
107
|
+
std::vector<std::string> xt_css_split_commas(const std::string &text);
|
|
108
|
+
|
|
88
109
|
Length xt_css_parse_length(const std::string &value);
|
|
89
110
|
Color xt_css_parse_color(const std::string &value);
|
|
90
111
|
bool xt_css_parse_number(const std::string &value, float *out);
|
|
@@ -132,6 +132,9 @@ bool matchPseudo(const Node *node, const std::string &pseudo, const MatchState &
|
|
|
132
132
|
|
|
133
133
|
bool matchCompound(const Node *node, const CompoundSelector &compound, const MatchState &state) {
|
|
134
134
|
if (!node->isElement()) return false;
|
|
135
|
+
/* A pseudo-element selector matches a generated node, never the origin
|
|
136
|
+
* element; the cascade matches it separately in `style.cpp`. */
|
|
137
|
+
if (!compound.pseudo_element.empty()) return false;
|
|
135
138
|
if (!compound.tag.empty() && node->tag != compound.tag) return false;
|
|
136
139
|
if (!compound.id.empty()) {
|
|
137
140
|
const std::string *id = node->attr("id");
|