xbintsc 0.5.45 → 0.5.51
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 +1 -1
- package/README.md +5 -4
- package/README.zh-CN.md +4 -3
- package/dist/src/cli/extensions.d.ts +24 -0
- package/dist/src/cli/extensions.js +62 -0
- package/dist/src/cli/extensions.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/help.js +3 -1
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hints.js +8 -3
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +21 -28
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +2 -0
- package/dist/src/diagnostics/diagnostic.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/compiler.js +61 -8
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +4 -0
- package/dist/src/driver/config.js +2 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/link-features.d.ts +37 -0
- package/dist/src/driver/link-features.js +123 -0
- package/dist/src/driver/link-features.js.map +1 -0
- package/dist/src/driver/options.d.ts +10 -0
- package/dist/src/driver/runtime-objects.d.ts +5 -0
- package/dist/src/driver/runtime-objects.js +20 -1
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/usage.d.ts +23 -0
- package/dist/src/driver/usage.js +353 -0
- package/dist/src/driver/usage.js.map +1 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/catalog.js +1 -2
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/features.d.ts +31 -0
- package/dist/src/extensions/gui/features.js +160 -0
- package/dist/src/extensions/gui/features.js.map +1 -0
- package/dist/src/extensions/gui/index.js +10 -4
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/link-feature.d.ts +70 -0
- package/dist/src/extensions/link-feature.js +18 -0
- package/dist/src/extensions/link-feature.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +24 -4
- package/dist/src/extensions/registry.js +26 -3
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +5 -7
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/driver/link-features.test.js +105 -0
- package/dist/tests/driver/link-features.test.js.map +1 -0
- package/dist/tests/driver/usage.test.d.ts +1 -0
- package/dist/tests/driver/usage.test.js +88 -0
- package/dist/tests/driver/usage.test.js.map +1 -0
- package/dist/tests/e2e/gui-audio.test.js +4 -4
- package/dist/tests/e2e/gui-audio.test.js.map +1 -1
- package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
- package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
- package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +5 -1
- package/dist/tests/e2e/gui-helpers.js +2 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +4 -1
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
- package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media.test.js +9 -9
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +5 -2
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
- package/dist/tests/e2e/gui-shaping.test.js +47 -0
- package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
- package/dist/tests/extensions/gui-features.test.d.ts +1 -0
- package/dist/tests/extensions/gui-features.test.js +168 -0
- package/dist/tests/extensions/gui-features.test.js.map +1 -0
- package/doc/ai/cli.md +5 -1
- package/doc/ai/extensions.md +48 -23
- package/doc/ai/troubleshooting.md +10 -7
- package/doc/ai/zh-CN/cli.md +5 -1
- package/doc/ai/zh-CN/extensions.md +41 -20
- package/doc/ai/zh-CN/troubleshooting.md +6 -5
- package/doc/gui/api.md +2 -1
- package/doc/gui/build.md +136 -19
- package/doc/gui/canvas.md +1 -1
- package/doc/gui/known-issues.md +32 -3
- package/doc/gui/layout.md +1 -1
- package/doc/gui/media.md +13 -7
- package/doc/gui/rendering.md +32 -15
- package/doc/gui/runtime.md +5 -0
- package/doc/gui/webgl.md +24 -6
- package/doc/gui.md +50 -35
- package/doc/implemented/cli.md +2 -0
- package/doc/implemented/extensions.md +9 -3
- package/doc/npm-package.md +4 -4
- package/doc/xbintsc.config.schema.json +10 -0
- package/doc/zh-CN/gui/api.md +2 -1
- package/doc/zh-CN/gui/build.md +110 -16
- package/doc/zh-CN/gui/canvas.md +1 -1
- package/doc/zh-CN/gui/known-issues.md +24 -3
- package/doc/zh-CN/gui/layout.md +1 -1
- package/doc/zh-CN/gui/media.md +11 -6
- package/doc/zh-CN/gui/rendering.md +26 -9
- package/doc/zh-CN/gui/runtime.md +3 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui.md +42 -29
- package/doc/zh-CN/implemented/cli.md +2 -0
- package/doc/zh-CN/implemented/extensions.md +9 -3
- package/doc/zh-CN/npm-package.md +4 -3
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +22 -15
- package/runtime/ext_gui/browser_loop.cpp +13 -1
- package/runtime/ext_gui/canvas.h +1 -1
- package/runtime/ext_gui/canvas_raster.cpp +1 -1
- package/runtime/ext_gui/canvas_text.cpp +1 -1
- package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
- package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
- package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
- package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
- package/runtime/ext_gui/dom_api_style.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
- package/runtime/ext_gui/gpu_bridge.c +28 -0
- package/runtime/ext_gui/gpu_feature.cpp +30 -0
- package/runtime/ext_gui/gpu_shader.cpp +22 -0
- package/runtime/ext_gui/gpu_shader_api.h +50 -0
- package/runtime/ext_gui/gui.cpp +6 -37
- package/runtime/ext_gui/gui_canvas.cpp +14 -6
- package/runtime/ext_gui/gui_engine.h +1 -18
- package/runtime/ext_gui/gui_events.cpp +3 -2
- package/runtime/ext_gui/gui_webgl.cpp +25 -10
- package/runtime/ext_gui/image_api.cpp +18 -0
- package/runtime/ext_gui/image_api.h +41 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
- package/runtime/ext_gui/image_bridge.c +22 -0
- package/runtime/ext_gui/image_feature.cpp +105 -0
- package/runtime/ext_gui/layout.cpp +13 -8
- package/runtime/ext_gui/layout.h +2 -2
- package/runtime/ext_gui/media.cpp +4 -2
- package/runtime/ext_gui/media.h +3 -3
- package/runtime/ext_gui/media_api.h +7 -6
- package/runtime/ext_gui/renderer.h +1 -1
- package/runtime/ext_gui/renderer_image.cpp +13 -6
- package/runtime/ext_gui/renderer_layer.cpp +10 -5
- package/runtime/ext_gui/stb_truetype.h +5077 -0
- package/runtime/ext_gui/text.cpp +24 -498
- package/runtime/ext_gui/text.h +7 -5
- package/runtime/ext_gui/text_api.h +45 -0
- package/runtime/ext_gui/text_bridge.c +23 -0
- package/runtime/ext_gui/text_cache.cpp +1 -1
- package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
- package/runtime/ext_gui/text_hb.cpp +554 -0
- package/runtime/ext_gui/text_stb.cpp +513 -0
- package/runtime/ext_gui/webgl_api.cpp +19 -0
- package/runtime/ext_gui/webgl_api.h +53 -0
- package/runtime/ext_gui/webgl_bridge.c +25 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
- package/runtime/ext_gui/webgl_feature.cpp +82 -0
- package/runtime/ext_gui/webgl_feature.h +28 -0
- package/runtime/ext_gui/webgl_msl.cpp +41 -0
- package/runtime/ext_gui/webgl_msl.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +40 -32
- package/runtime/ext_gui/window.cpp +7 -7
- package/runtime/ext_media/decode_audio.cpp +1 -1
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +7 -7
- package/scripts/build-gui.ts +97 -98
- package/scripts/check-file-length.ts +1 -0
- package/scripts/gui-build-options.ts +122 -0
- package/src/cli/extensions.ts +72 -0
- package/src/cli/help.ts +3 -1
- package/src/cli/hints.ts +9 -3
- package/src/cli/main.ts +21 -27
- package/src/diagnostics/diagnostic.ts +2 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/compiler.ts +63 -8
- package/src/driver/config.ts +6 -0
- package/src/driver/link-features.ts +163 -0
- package/src/driver/options.ts +10 -0
- package/src/driver/runtime-objects.ts +26 -1
- package/src/driver/usage.ts +376 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/catalog.ts +1 -2
- package/src/extensions/gui/features.ts +162 -0
- package/src/extensions/gui/index.ts +10 -4
- package/src/extensions/link-feature.ts +72 -0
- package/src/extensions/registry.ts +45 -4
- package/src/index.ts +3 -2
- package/dist/src/extensions/media/index.d.ts +0 -28
- package/dist/src/extensions/media/index.js +0 -59
- package/dist/src/extensions/media/index.js.map +0 -1
- package/dist/tests/extensions/media.test.js +0 -63
- package/dist/tests/extensions/media.test.js.map +0 -1
- package/src/extensions/media/index.ts +0 -65
- /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
package/doc/gui.md
CHANGED
|
@@ -21,13 +21,15 @@ what `examples/gui/pelican-bike` — a playable 2D game — is built on. **M12**
|
|
|
21
21
|
DOM node lifetime explicit (what a mutation releases, what it keeps) and gives the
|
|
22
22
|
engine bounded memory: see [Node lifetime](./gui/dom.md#node-lifetime) and
|
|
23
23
|
[Memory & GC](./gui/runtime.md#memory--gc). **M13** plays real
|
|
24
|
-
`<video>`/`<audio>` — the optional
|
|
25
|
-
thread with a vendored minimal FFmpeg, video frames go through the image
|
|
26
|
-
path and audio to an SDL stream, with the DOM media API exposing
|
|
27
|
-
`play`/`pause`/`currentTime`/… and media events.
|
|
24
|
+
`<video>`/`<audio>` — the optional **`media` link feature** decodes them on the
|
|
25
|
+
main thread with a vendored minimal FFmpeg, video frames go through the image
|
|
26
|
+
texture path and audio to an SDL stream, with the DOM media API exposing
|
|
27
|
+
`play`/`pause`/`currentTime`/… and media events. The compiler selects the
|
|
28
|
+
feature from the program (a `<video>`/`<audio>` element, `new Audio()`,
|
|
29
|
+
`decodeAudioData`, or markup built at run time), so a DOM/CSS program does not
|
|
28
30
|
link FFmpeg. The browser globals also get a real `AudioContext`: a 48 kHz mixer
|
|
29
31
|
in `runtime/ext_gui/audio_mixer.cpp` plus `decodeAudioData` (WAV in-engine,
|
|
30
|
-
compressed formats through `media`) — see
|
|
32
|
+
compressed formats through the `media` feature) — see
|
|
31
33
|
[GUI API](./gui/api.md#web-audio).
|
|
32
34
|
**M14** adds `<canvas>` with a self-written 2D software rasteriser (anti-aliased
|
|
33
35
|
fills, paths, text and `drawImage`) uploaded through the image texture path —
|
|
@@ -38,7 +40,7 @@ them) can be translated, scaled and rotated without reflowing anything — and
|
|
|
38
40
|
`transition: transform`, so those poses animate. See
|
|
39
41
|
[Layout](./gui/layout.md#transforms-m15) and
|
|
40
42
|
[Animation](./gui/animation.md#css-transforms-m15).
|
|
41
|
-
**M17** adds real **WebGL 1.0**, and **M18** adds **WebGL 2.0**: `<canvas>.getContext("webgl2")` accepts `#version 300 es` shaders, vertex-array objects, instanced draws and sampler objects, all compiled to SPIR-V by the bundled glslang (and to MSL by the bundled SPIRV-Cross on Metal) and rendered through SDL_GPU. Geometry, lighting, texture sampling and blending run on the GPU and the page composites the colour texture without a readback — see [WebGL](./gui/webgl.md).
|
|
43
|
+
**M17** adds real **WebGL 1.0**, and **M18** adds **WebGL 2.0**: `<canvas>.getContext("webgl2")` accepts `#version 300 es` shaders, vertex-array objects, instanced draws and sampler objects, all compiled to SPIR-V by the bundled glslang (and to MSL by the bundled SPIRV-Cross on Metal) and rendered through SDL_GPU. Geometry, lighting, texture sampling and blending run on the GPU and the page composites the colour texture without a readback — see [WebGL](./gui/webgl.md). glslang is an optional **`gpu` link feature** shared with `mix-blend-mode`; the WebGL context/DOM bindings are the separate **`webgl` feature**, which requires `gpu`. A DOM/2D-canvas page links neither.
|
|
42
44
|
**M19** fills in the decorative CSS layer: `@media` queries, generated content
|
|
43
45
|
(`::before`/`::after`), multi-layer linear/radial/repeating backgrounds,
|
|
44
46
|
`text-shadow`, `clip-path`, `mix-blend-mode` (through an offscreen compositor)
|
|
@@ -100,7 +102,8 @@ pages above.
|
|
|
100
102
|
| 4 | The engine is **not self-hosted** (it is C/C++, not TS), but must not affect the compiler's platform-agnostic design. Delivered as a per-platform prebuilt archive linked via `nativeObjects`. |
|
|
101
103
|
| 5 | The **event loop is generic**: the runtime exposes a generic main-loop hook and a poll primitive; nothing GUI-specific enters `runtime/`. |
|
|
102
104
|
| 6 | **Multiple windows** are supported by the core object model. |
|
|
103
|
-
| 7 | Third-party low-level libs are **statically linked into the extension archives** so releases stay self-contained; only OS frameworks are added at link time. `gui.a` carries SDL3
|
|
105
|
+
| 7 | Third-party low-level libs are **statically linked into the extension archives** so releases stay self-contained; only OS frameworks are added at link time. `gui.a` carries SDL3, FreeType/HarfBuzz for the optional `shaping` feature, glslang and (on macOS only) SPIRV-Cross; the default text path uses the bundled stb_truetype. glslang and SPIRV-Cross are only *extracted* when the compiler selects the **`gpu` link feature**; Metal is the only SDL_GPU backend that consumes MSL, so merging SPIRV-Cross elsewhere would add ~2.5 MiB no driver can ask for. The WebGL context/DOM code is the **`webgl` feature** (requires `gpu`), and stb_image/NanoSVG are the **`images` feature**. The optional `media.a` carries FFmpeg and is linked only when the **`media` link feature** is selected. All features are chosen from the program's static usage; `--feature`/`--no-feature` override the scan. |
|
|
106
|
+
| 8 | **Heavy optional halves are link features, not extensions.** FFmpeg and glslang are selected by what the bundled HTML/CSS/TS may use, and a small C bridge (linked only when active) installs the feature's dispatch table and forces the linker to extract the implementation. This keeps one user-facing `gui` extension while a DOM-only program pays for neither stack. |
|
|
104
107
|
|
|
105
108
|
## Architecture
|
|
106
109
|
|
|
@@ -120,7 +123,7 @@ pages above.
|
|
|
120
123
|
│
|
|
121
124
|
▼
|
|
122
125
|
windowing + input (SDL3) ── multiple windows
|
|
123
|
-
text (
|
|
126
|
+
text (stb_truetype) ── glyph atlas
|
|
124
127
|
images (stb_image; SVG via NanoSVG)
|
|
125
128
|
media DOM + audio sink ── optional media.a (FFmpeg) installs the decoder
|
|
126
129
|
```
|
|
@@ -134,14 +137,19 @@ with `nativeObjects()`, `linkerFlags()` and `modules()`.
|
|
|
134
137
|
| --- | --- | --- |
|
|
135
138
|
| Window + input + multi-window | **SDL3** | cross-platform windows, HiDPI, IME, clipboard, DnD, close/hide events |
|
|
136
139
|
| GPU | **SDL_GPU** (SDL3) | one render path over Metal / Vulkan / D3D12; avoids three backends |
|
|
137
|
-
| Text shaping | **
|
|
138
|
-
| Glyph raster | **FreeType
|
|
140
|
+
| Text shaping | **stb_truetype** simple shaper; optional **`shaping`** feature links HarfBuzz + FreeType | default keeps the DOM-only binary near 3 MiB; `shaping` restores ligatures and complex-script shaping |
|
|
141
|
+
| Glyph raster | **stb_truetype**; FreeType only under `shaping` | TrueType outlines → grayscale atlas by default |
|
|
139
142
|
| Images | **stb_image** (vendored header) for bitmaps, **NanoSVG** (vendored headers) for SVG | single headers to start; SVG files rasterise on demand |
|
|
140
|
-
| Video + audio | **FFmpeg** (statically vendored, minimal build, optional `media`
|
|
143
|
+
| Video + audio | **FFmpeg** (statically vendored, minimal build, optional `media` link feature) | decodes the common container/codec set; no WebView or platform media framework |
|
|
141
144
|
|
|
142
|
-
Pinned versions: SDL3 `release-3.2.10`, FreeType `2.13.3`, HarfBuzz `10.1.0
|
|
143
|
-
|
|
144
|
-
`
|
|
145
|
+
Pinned versions: SDL3 `release-3.2.10`, FreeType `2.13.3`, HarfBuzz `10.1.0`
|
|
146
|
+
(for the optional `shaping` feature), glslang `16.6.0`, SPIRV-Cross
|
|
147
|
+
`vulkan-sdk-1.4.313.0`, FFmpeg `7.1` for the optional `media` archive
|
|
148
|
+
(overridable with `SDL3_TAG` / `FREETYPE_VERSION` / `HARFBUZZ_VERSION` /
|
|
149
|
+
`GLSLANG_VERSION` / `SPIRV_CROSS_VERSION` / `FFMPEG_VERSION`). The default text
|
|
150
|
+
backend is the bundled `stb_truetype.h`; it accepts TrueType outlines (not
|
|
151
|
+
CFF/OTF or variable fonts). The `shaping` feature swaps in HarfBuzz + FreeType
|
|
152
|
+
for full OpenType shaping.
|
|
145
153
|
|
|
146
154
|
Alternative if SDL3 is rejected: **GLFW + OpenGL 3.3** (simpler, but OpenGL is
|
|
147
155
|
deprecated on macOS and gives no modern GPU abstraction). **wgpu-native** if the
|
|
@@ -169,10 +177,11 @@ engine were Rust.
|
|
|
169
177
|
4. **M4 — paint + text + display list**
|
|
170
178
|
- **M4a — display list + GPU shapes** ✅ background/border display list,
|
|
171
179
|
rounded-rect SDL_GPU pipeline (`paint.*`, `renderer.*`).
|
|
172
|
-
- **M4b-1 — text stack + metrics** ✅
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
- **M4b-1 — text stack + metrics** ✅ the text module (`text.*`) with font
|
|
181
|
+
resolution/caching and shaping-based metrics used by layout
|
|
182
|
+
(`measureText`/`fontMetrics`); originally HarfBuzz + FreeType, now the
|
|
183
|
+
bundled stb_truetype.
|
|
184
|
+
- **M4b-2 — glyph rendering** ✅ stb_truetype rasterisation, a shared shelf-packed
|
|
176
185
|
glyph atlas, textured text quads in the display list and HiDPI-aware raster
|
|
177
186
|
scaling. Gradients remain.
|
|
178
187
|
5. **M5 — input + events** ✅
|
|
@@ -199,16 +208,17 @@ engine were Rust.
|
|
|
199
208
|
(`package-release` copies all of `runtime/`) and inside the optional
|
|
200
209
|
`@xbintsc/<os>-<arch>` npm package. Windows x64 is included; Windows arm64
|
|
201
210
|
still skips them.
|
|
202
|
-
- `vendor/` (SDL3/FreeType/HarfBuzz for the GUI archive, FFmpeg for `media`)
|
|
211
|
+
- `vendor/` (SDL3/FreeType/HarfBuzz/glslang for the GUI archive, FFmpeg for `media`)
|
|
203
212
|
is cached per OS/arch, keyed by `scripts/build-gui.ts` /
|
|
204
213
|
`scripts/build-media.ts`. Windows x64 gets its own source cache plus the
|
|
205
214
|
installed `vendor/ffmpeg-build-msvc/dist` prefix.
|
|
206
|
-
- Windows x64 builds both archives in CI and links a `gui
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
- Windows x64 builds both archives in CI and links a `gui` program that
|
|
216
|
+
exercises the `media` link feature (plus an explicit `--feature media`
|
|
217
|
+
build), using the same Visual Studio `vcvarsall` + bundled LLVM toolchain
|
|
218
|
+
as a local build (`.github/actions/vs-toolchain`); the host has no
|
|
219
|
+
GPU/Vulkan driver, so *running* the GUI/media examples there remains
|
|
220
|
+
provisional (a failure is logged without annotating the run). The Windows
|
|
221
|
+
arm64 job still skips both archives (see
|
|
212
222
|
[Open questions](./gui/known-issues.md#open-questions)).
|
|
213
223
|
8. **M8 — interactive DOM** ✅
|
|
214
224
|
- Element/document handles with stable identity, read/write properties via
|
|
@@ -260,15 +270,17 @@ engine were Rust.
|
|
|
260
270
|
`tests/e2e/gui-retention.test.ts` (see [Memory & GC](./gui/runtime.md#memory--gc)).
|
|
261
271
|
13. **M13 — video & audio** ✅
|
|
262
272
|
- `<video>` / `<audio>` decode through a statically vendored minimal FFmpeg
|
|
263
|
-
in the optional `media`
|
|
273
|
+
in the optional `media` link feature (`runtime/ext_media/media.cpp`); the
|
|
274
|
+
compiler selects it from the program and only then compiles the bridge and
|
|
275
|
+
links `media.a`. Frames
|
|
264
276
|
upload to GPU textures through the existing image pipeline, audio is
|
|
265
277
|
pushed to an SDL stream on the main thread by the GUI's audio sink, and
|
|
266
278
|
the DOM media API plus `loadedmetadata`/`play`/`pause`/`ended`/
|
|
267
279
|
`timeupdate`/`error` events are exposed on element handles
|
|
268
280
|
(`dom_api_media.cpp`, `dom_api_proto.cpp`). Controlled from TS + CSS;
|
|
269
281
|
there are no built-in controls. Example in `examples/gui/media.*`, e2e in
|
|
270
|
-
`tests/e2e/gui-media.test.ts` (
|
|
271
|
-
`tests/e2e/gui-media-disabled.test.ts` (
|
|
282
|
+
`tests/e2e/gui-media.test.ts` (auto-selected) and
|
|
283
|
+
`tests/e2e/gui-media-disabled.test.ts` (`--no-feature media`).
|
|
272
284
|
14. **M14 — `<canvas>` 2D** ✅
|
|
273
285
|
- `<canvas>` is a replaced element (`xtgui::Canvas2D`, `layout.*`), the
|
|
274
286
|
`getContext("2d")` handle and drawing API live in `dom_api_canvas.cpp`,
|
|
@@ -373,9 +385,10 @@ engine were Rust.
|
|
|
373
385
|
coverage.
|
|
374
386
|
- **M4a** ✅ display list (`paint.*`) and the SDL_GPU 2D renderer with an MSL
|
|
375
387
|
rounded-rect pipeline (`renderer.*`), `paintList`/`paintCount`, e2e coverage.
|
|
376
|
-
- **M4b-1** ✅
|
|
377
|
-
|
|
378
|
-
|
|
388
|
+
- **M4b-1** ✅ the text module (`text.*`) with font resolution, shaping and
|
|
389
|
+
metrics, real text metrics in layout, `measureText`/`fontMetrics`, e2e
|
|
390
|
+
coverage. Originally HarfBuzz + FreeType; now stb_truetype (see the stack
|
|
391
|
+
table and the size trade-off in [build](./gui/build.md#binary-size)).
|
|
379
392
|
- **M4b-2** ✅ glyph atlas + textured text pipeline in `renderer.*`, shaped text
|
|
380
393
|
runs in `paint.*`, `xt_text_shape_run`/`xt_text_rasterize` in `text.*`, HiDPI
|
|
381
394
|
raster scaling, e2e coverage.
|
|
@@ -430,17 +443,19 @@ engine were Rust.
|
|
|
430
443
|
ratcheting upwards. `win.stats()` exposes the engine counters and
|
|
431
444
|
`tests/e2e/gui-retention.test.ts` pins them; a game loop rewriting its sprite
|
|
432
445
|
every frame now runs in constant memory (see [Memory & GC](./gui/runtime.md#memory--gc)).
|
|
433
|
-
- **M13** ✅ `<video>` / `<audio>` support. The optional `media`
|
|
446
|
+
- **M13** ✅ `<video>` / `<audio>` support. The optional `media` **link feature**
|
|
434
447
|
vendors and builds a minimal static FFmpeg (`scripts/build-media.ts`) and
|
|
435
448
|
merges it into `media.a` (or `media.lib` from clang-cl/MSVC objects on
|
|
436
|
-
Windows)
|
|
449
|
+
Windows). The compiler selects the feature from the program and only then
|
|
450
|
+
compiles `media_bridge.c` and links `media.a`; a DOM/CSS program never links
|
|
451
|
+
FFmpeg. `runtime/ext_media/media.cpp` decodes video to RGBA
|
|
437
452
|
frames and audio to 48 kHz stereo PCM on the main thread,
|
|
438
453
|
`runtime/ext_gui/gui_media.cpp` owns the players, implements the SDL audio
|
|
439
454
|
sink and pumps the media clock and events each frame,
|
|
440
455
|
`renderer_image.cpp` uploads each new video frame through the image texture
|
|
441
456
|
path, and `dom_api_media.cpp` exposes `play`/`pause`/`load` plus the media
|
|
442
|
-
properties on element handles. `gui.a` stays FFmpeg-free
|
|
443
|
-
|
|
457
|
+
properties on element handles. `gui.a` stays FFmpeg-free.
|
|
458
|
+
`examples/gui/media.*` demonstrates
|
|
444
459
|
the TS-plus-CSS-controls pattern and `tests/e2e/gui-media.test.ts` pins it.
|
|
445
460
|
- **M14** ✅ `<canvas>` support. A new replaced element (`layout.*`) carries an
|
|
446
461
|
intrinsic size from its `width`/`height` attributes (default `300x150`),
|
package/doc/implemented/cli.md
CHANGED
|
@@ -29,6 +29,8 @@ default; `--no-check` skips it (and is part of the cache key). See
|
|
|
29
29
|
--emit <kind> exe | obj | ir (default: exe)
|
|
30
30
|
-O0..-O3 Optimization level (default: -O2)
|
|
31
31
|
--ext <names> Comma separated extensions (e.g. node)
|
|
32
|
+
--feature <names> Force optional link features on (media,gpu,images,shaping,webgl,all)
|
|
33
|
+
--no-feature <n> Keep optional link features out even when detected
|
|
32
34
|
--ext-native <m> Register a C++/Rust extension from a JSON manifest
|
|
33
35
|
--config <path> Use a project config (default: xbintsc.config.json)
|
|
34
36
|
--no-config Do not read any project config
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of [Implemented syntax and features](../implemented.md) · [简体中文](../zh-CN/implemented/extensions.md)
|
|
4
4
|
|
|
5
|
-
Location: `src/extensions/registry.ts`, `src/extensions/node
|
|
5
|
+
Location: `src/extensions/registry.ts`, `src/extensions/node/`, `src/extensions/link-feature.ts`, `src/driver/usage.ts`, `src/driver/link-features.ts`
|
|
6
6
|
|
|
7
|
-
- An extension is a plain object: `runtimeSources()` (extra C sources), `linkerFlags()` (extra link flags), `builtins()` (global identifier → runtime symbol, uniform `(argc, argv)` ABI)
|
|
8
|
-
- `ExtensionRegistry`: register / unregister / lookup / aggregate builtins, modules, runtime sources and link
|
|
7
|
+
- An extension is a plain object: `runtimeSources()` (extra C sources), `linkerFlags()` (extra link flags), `builtins()` (global identifier → runtime symbol, uniform `(argc, argv)` ABI), `modules()` (import specifier → named exports / namespace) and `linkFeatures()` (optional heavy capabilities).
|
|
8
|
+
- `ExtensionRegistry`: register / unregister / lookup / aggregate builtins, modules, runtime sources, link flags and link features.
|
|
9
|
+
- **Optional link features** (`media`, `gpu`, `images`, `shaping`, `webgl`):
|
|
10
|
+
- A feature declares `runtimeSources()` (a C bridge compiled only when active), `nativeObjects()` (archives linked only when active), `linkerFlags()`, optional `requires` (another feature it depends on) and `used(usage)`.
|
|
11
|
+
- The driver builds `ProgramUsage` from the bundled AST (`collectUsage` in `src/driver/usage.ts`): string literals (including imported HTML and inlined CSS), identifiers/property names, `getContext(...)` kinds, and whether markup can be built at run time. Simple `const` aliases are resolved; unresolved markup makes the program conservative.
|
|
12
|
+
- `resolveLinkFeatures` applies `--feature` / `--no-feature` (and `all`), expands `requires`, reports an unavailable auto-detected feature as a warning and a forced one as an error, and returns the bridges/archives/flags to link.
|
|
13
|
+
- The bridge is the strong reference: its constructor installs the feature's dispatch table and its references force the linker to extract the implementation. With no bridge, the table stays null and the implementation members are never linked.
|
|
14
|
+
- Current clients: `media` (FFmpeg, `runtime/ext_media/media_bridge.c` + `media.a`), `gpu` (glslang/SPIRV-Cross, `runtime/ext_gui/gpu_bridge.c` + `gpu_feature.cpp` inside `gui.a`), `images` (stb_image/NanoSVG, `runtime/ext_gui/image_bridge.c` + `image_feature.cpp`), `shaping` (HarfBuzz/FreeType, `runtime/ext_gui/text_bridge.c` + `text_hb.cpp`), and `webgl` (context/DOM bindings, `runtime/ext_gui/webgl_bridge.c` + `webgl_feature.cpp`, requiring `gpu`).
|
|
9
15
|
- The built-in core extension `core`: exposes `print` (mapped to `xt_println`), always registered.
|
|
10
16
|
- The Node extension `node`:
|
|
11
17
|
- Modular organisation: `src/extensions/node/fs/` + `runtime/ext_node/fs/read_file.c`
|
package/doc/npm-package.md
CHANGED
|
@@ -69,8 +69,8 @@ The package does **not** contain:
|
|
|
69
69
|
If npm skips the optional package (`--omit=optional`, a package manager that
|
|
70
70
|
does not install optional dependencies, or a host the release does not build
|
|
71
71
|
for), the driver falls back to compiling the C runtime from the shipped sources
|
|
72
|
-
and caches the objects; that build works but is slower, and `--ext gui`
|
|
73
|
-
|
|
72
|
+
and caches the objects; that build works but is slower, and `--ext gui` (plus
|
|
73
|
+
the auto-selected `media`/`gpu`/`images`/`shaping`/`webgl` link features) needs the archive to be present.
|
|
74
74
|
|
|
75
75
|
## Requirements
|
|
76
76
|
|
|
@@ -398,7 +398,7 @@ jobs:
|
|
|
398
398
|
| --- | --- | --- |
|
|
399
399
|
| Needs Node.js | Yes, 22+ | No |
|
|
400
400
|
| First build | Links the prebuilt runtime from the optional platform package | Links the prebuilt runtime |
|
|
401
|
-
| GUI
|
|
401
|
+
| GUI engine + media archive | Included on Linux/macOS and Windows x64 (the hosts the release builds them for) | Included in Linux/macOS and Windows x64 archives |
|
|
402
402
|
| Installation | `npm install` + lockfile / provenance | Download, verify `.sha256`, unpack |
|
|
403
403
|
| Programmatic API | Yes | No (CLI only) |
|
|
404
404
|
| Cross-compiles | No — host only | No — host only |
|
|
@@ -439,7 +439,7 @@ the same file under `node_modules/xbintsc/doc/ai/`.
|
|
|
439
439
|
| The first build takes a long time | The optional `@xbintsc/<os>-<arch>` package was skipped (or this host has no prebuilt package), so the runtime C sources are compiled and cached. Check `npm ls @xbintsc/<os>-<arch>` and reinstall without `--omit=optional`; `--time` confirms. |
|
|
440
440
|
| Permission errors writing `.xbintsc/` | Set `xbintsc_CACHE_DIR` to a writable directory, or run from a writable working directory. |
|
|
441
441
|
| `module 'fs' is provided by the 'node' extension` | Add `--ext node`, or `"extensions": ["node"]` in the config. |
|
|
442
|
-
| `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. |
|
|
442
|
+
| `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. An auto-detected `media` feature with a missing archive only warns; `--feature media` makes it an error. |
|
|
443
443
|
| `require("xbintsc")` fails | The package is ESM-only; use `import` (or dynamic `import()`). |
|
|
444
444
|
| Windows link errors about missing MSVC libraries | Run from a Native Tools prompt, install the VS C++ build tools, and check `npx xbintsc doctor`. |
|
|
445
445
|
| `npm ci --omit=dev` then the build cannot find `xbintsc` | Install devDependencies for the build stage, or move `xbintsc` to `dependencies`. |
|
|
@@ -48,6 +48,16 @@
|
|
|
48
48
|
"items": { "type": "string" },
|
|
49
49
|
"description": "Paths to native C++/Rust extension manifests."
|
|
50
50
|
},
|
|
51
|
+
"features": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": { "type": "string" },
|
|
54
|
+
"description": "Optional link features to force on, e.g. [\"media\", \"gpu\", \"images\", \"shaping\", \"webgl\"] or [\"all\"]."
|
|
55
|
+
},
|
|
56
|
+
"noFeatures": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": { "type": "string" },
|
|
59
|
+
"description": "Optional link features to keep out even when auto-detection finds a use."
|
|
60
|
+
},
|
|
51
61
|
"force": {
|
|
52
62
|
"type": "boolean",
|
|
53
63
|
"description": "Ignore the incremental cache."
|
package/doc/zh-CN/gui/api.md
CHANGED
|
@@ -128,7 +128,8 @@ requestAnimationFrame(frame);
|
|
|
128
128
|
`getChannelData(i)` 是真正的 `Float32Array`,可以用代码逐样本填充。
|
|
129
129
|
`decodeAudioData(bytes)` 返回解码后的 AudioBuffer Promise:WAV(PCM 8/16/24/32 位、
|
|
130
130
|
IEEE float 32/64、A-law 与 µ-law)由引擎自身解码;MP3、AAC/M4A、Vorbis、Opus 与 FLAC
|
|
131
|
-
需要可选的 `media`
|
|
131
|
+
需要可选的 `media` 链接特性(程序调用 `decodeAudioData` 时自动选中),以其中的
|
|
132
|
+
FFmpeg 解码器作为回退。
|
|
132
133
|
`bytes` 可以是 ArrayBuffer、类型化数组、Node `Buffer`,或 `fs.readFileSync`
|
|
133
134
|
返回的原始字节字符串(本运行时没有专门的二进制类型,而该字符串的存储正是文件字节)。
|
|
134
135
|
解码结果会重采样到上下文的 48 kHz,因此 `buffer.sampleRate` 与
|
package/doc/zh-CN/gui/build.md
CHANGED
|
@@ -7,13 +7,29 @@
|
|
|
7
7
|
- 源码位于 `runtime/ext_gui/`(C/C++),外加 `vendor/` 下的 vendored 库
|
|
8
8
|
(被 gitignore;按需获取)。媒体解码位于 `runtime/ext_media/`,单独构建。
|
|
9
9
|
- `npm run gui`(`scripts/build-gui.ts`)获取固定版本的 SDL3(`SDL3_TAG`,
|
|
10
|
-
默认 `release-3.2.10`),构建静态 SDL3,获取并构建静态 FreeType
|
|
11
|
-
(`FREETYPE_VERSION`)与 HarfBuzz
|
|
10
|
+
默认 `release-3.2.10`),构建静态 SDL3,获取并构建静态 **FreeType**
|
|
11
|
+
(`FREETYPE_VERSION`,默认 `2.13.3`)与 **HarfBuzz**(`HARFBUZZ_VERSION`,
|
|
12
|
+
默认 `10.1.0`)供可选的 `shaping` 特性使用,并获取、构建静态
|
|
12
13
|
**glslang**(`GLSLANG_VERSION`,默认 `16.6.0`)、固定版本的 SPIR-V 头文件
|
|
13
|
-
(`SPIRV_HEADERS_VERSION
|
|
14
|
-
`vulkan-sdk-1.4.313.0`)。glslang 是 WebGL
|
|
15
|
-
SPIRV-Cross 把它的 SPIR-V 转成 Metal 后端使用的
|
|
16
|
-
[WebGL](./webgl.md)
|
|
14
|
+
(`SPIRV_HEADERS_VERSION`)以及——**仅 macOS**——**SPIRV-Cross**
|
|
15
|
+
(`SPIRV_CROSS_VERSION`,默认 `vulkan-sdk-1.4.313.0`)。glslang 是 WebGL
|
|
16
|
+
背后的运行时 GLSL ES 编译器,SPIRV-Cross 把它的 SPIR-V 转成 Metal 后端使用的
|
|
17
|
+
MSL(见 [WebGL](./webgl.md)),两者都与其他库一样合并进归档。Metal 是唯一消费
|
|
18
|
+
MSL 的 SDL_GPU 后端,因此 Windows/Linux 上脚本既不获取也不合并 SPIRV-Cross:
|
|
19
|
+
那里的 `webgl_msl.cpp` 编译为空,合并进来只会多出约 2.5 MiB 不可达代码。
|
|
20
|
+
默认文本路径使用内置的 **stb_truetype**(`runtime/ext_gui/stb_truetype.h`);
|
|
21
|
+
HarfBuzz/FreeType 只在 `shaping` 特性启用时被取出。
|
|
22
|
+
每个库(SDL3、FreeType、HarfBuzz、glslang、SPIRV-Cross 与引擎)都用
|
|
23
|
+
`-ffunction-sections -fdata-sections` 编译;SDL 关闭引擎从不调用的子系统
|
|
24
|
+
(`SDL_JOYSTICK`、`SDL_HAPTIC`、`SDL_SENSOR`、`SDL_CAMERA`、`SDL_RENDER`、
|
|
25
|
+
`SDL_OPENGL`/`SDL_OPENGLES`、`SDL_OFFSCREEN`、`SDL_HIDAPI`);HarfBuzz 关闭
|
|
26
|
+
整形后端从不使用的 API(`HB_NO_DRAW`/`PAINT`/`COLOR`/`NAME`/`STYLE`/`METRICS`/…,
|
|
27
|
+
但保留 `CFF`/`OPEN`/`VAR` 以支持 OTF 与可变字体),并以
|
|
28
|
+
`HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR` 编译:`src/hb.hh` 会把自身警告集提升为
|
|
29
|
+
错误,而两个精简宏(`HB_NO_MMAP` 与 `HB_NO_OT_FONT_GLYPH_NAMES`)会让
|
|
30
|
+
macOS/CoreText 的辅助函数变成未引用。链接器随后丢弃
|
|
31
|
+
不可达函数(`--gc-sections`、`-dead_strip` 或 link.exe 默认的 `/OPT:REF`)。
|
|
32
|
+
随后编译引擎,并把
|
|
17
33
|
所有内容合并到 `runtime/lib/<os>-<arch>/gui.a`(Windows 上 MSVC ABI 则为
|
|
18
34
|
`gui.lib`),与 `core.a` 采用相同约定,静态打包这些库。合并使用 macOS 上的
|
|
19
35
|
`libtool` 与其他平台上的 `ar -M`(GNU/LLVM);CMake 归档会在构建根目录或
|
|
@@ -23,12 +39,15 @@
|
|
|
23
39
|
demuxer/parser/decoder 的最小静态构建,用它编译
|
|
24
40
|
`runtime/ext_media/media.cpp`,并把所有内容合并到
|
|
25
41
|
`runtime/lib/<os>-<arch>/media.a`(Windows 上 MSVC ABI 则为 `media.lib`)。
|
|
26
|
-
`gui.a` **不会**链接 FFmpeg
|
|
42
|
+
`gui.a` **不会**链接 FFmpeg:编译器为可能播放媒体的程序选中 `media` 链接特性后
|
|
43
|
+
才链接 `media.a`(见[链接特性](#链接特性))。
|
|
27
44
|
- `src/extensions/gui/index.ts` 通过 `nativeObjects()` 暴露引擎归档(经由
|
|
28
45
|
`findRuntimeLibrary`,因此 `.a`/`.lib` 都可用),并通过 `linkerFlags()`
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
暴露操作系统框架。它的 `linkFeatures()`(位于
|
|
47
|
+
`src/extensions/gui/features.ts`)声明 `media`、`gpu`、`images`、`shaping` 与 `webgl`;driver 只在该特性
|
|
48
|
+
启用时编译对应的 bridge。
|
|
49
|
+
- glslang(以及 macOS 上的 SPIRV-Cross)与 SDL3 一样合并进 `gui.a`,但引擎只
|
|
50
|
+
通过 `gpu` 特性的分发表访问它;从不编译 GLSL 的程序不会取出这些归档成员。
|
|
32
51
|
- `scripts/build-gui.ts` 使用与驱动**相同**的 clang
|
|
33
52
|
(`src/driver/toolchain-provider.ts`);Windows 上就是 Visual Studio 自带的、
|
|
34
53
|
面向 MSVC 的 LLVM,并配套使用其同目录下的 `clang++`/`llvm-ar` 来配置 CMake、
|
|
@@ -53,9 +72,10 @@
|
|
|
53
72
|
- CI 在组装发布归档之前构建 `gui.a`/`gui.lib` 与 `media.a`/`media.lib`,因此它们
|
|
54
73
|
会随 `runtime/lib/<slug>/` 一起发布(发布 tarball 会复制整个 `runtime/` 树)。
|
|
55
74
|
同一批目录还会打进可选的 `@xbintsc/<slug>` npm 包,因此发布覆盖的宿主平台从
|
|
56
|
-
npm 安装后也能使用 `--ext gui
|
|
75
|
+
npm 安装后也能使用 `--ext gui`(`media`/`gpu`/`images`/`shaping`/`webgl` 自动选择)。归档在 Linux(Xvfb 下,使用
|
|
57
76
|
lavapipe 软件 Vulkan 驱动)与 macOS 上构建并运行
|
|
58
|
-
示例;Windows x64
|
|
77
|
+
示例;Windows x64 也会构建两个归档并链接一个会触发 `media` 特性的 `gui` 程序
|
|
78
|
+
(另有一条显式 `--feature media` 的构建),因此 MSVC
|
|
59
79
|
构建在 CI 中得到验证,只是*运行*示例仍为试验性(托管 runner 没有 GPU/Vulkan
|
|
60
80
|
驱动)。macOS 的运行同样是试验性的:Intel runner 的虚拟 GPU 缺少
|
|
61
81
|
`MTLGPUFamilyMac2`,引擎会以 **77**(“此机器无法运行 GUI”)退出,任务记录为跳过,
|
|
@@ -69,8 +89,9 @@
|
|
|
69
89
|
configure/make 构建树本身不缓存(其中记录了另一台机器的绝对路径与编译选项)。
|
|
70
90
|
- 现有的缓存指纹已经会对 `nativeObjects()` 的内容与 `runtimeSources()` 的内容
|
|
71
91
|
做哈希,因此重建任一归档都会自动使缓存二进制失效。
|
|
72
|
-
- CMake 构建树位于其源码**旁边**(`vendor/sdl-build
|
|
73
|
-
`vendor/harfbuzz-build
|
|
92
|
+
- CMake 构建树位于其源码**旁边**(`vendor/sdl-build-lean`、
|
|
93
|
+
`vendor/freetype-build-lean`、`vendor/harfbuzz-build-lean`、
|
|
94
|
+
`vendor/glslang-build-lean`、`vendor/spirv-cross-build-lean`),绝不放在源码内部:`CMakeCache.txt` 记录的是配置它
|
|
74
95
|
的那台机器,而 SDL 的视频后端是 `option()`,因此先运行的那次配置会一直生效。
|
|
75
96
|
所以一个同时携带 `build/` 的 `vendor/SDL` 缓存树,会把某台机器的
|
|
76
97
|
`SDL_X11`/`SDL_WAYLAND` 选择带进另一台机器的配置——即使头文件已安装,SDL 也会
|
|
@@ -79,6 +100,78 @@
|
|
|
79
100
|
检查 X11/Wayland 头文件,并按名称报告缺失的开发包(当头文件位于该检查未知的
|
|
80
101
|
前缀下时,可设置 `xbintsc_SKIP_HEADER_CHECK=1`)。
|
|
81
102
|
|
|
103
|
+
## 链接特性
|
|
104
|
+
|
|
105
|
+
用户只启用一个 `gui` 扩展,但其中的重型部分是可选的**链接特性**,按程序选择:
|
|
106
|
+
|
|
107
|
+
| 特性 | 链接什么 | 程序可能用到时 |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `media` | `media_bridge.c` + `media.a`(FFmpeg) | HTML 里有 `<video>`/`<audio>`、`createElement("video"/"audio")`、`new Audio()`、`decodeAudioData`,或运行时拼出的 HTML |
|
|
110
|
+
| `gpu` | `gpu_bridge.c`(实现本身已在 `gui.a`) | `getContext("webgl"/"webgl2"/"experimental-webgl")`(或运行时决定的 kind)、任意 `webgl` 字符串、`mix-blend-mode`/`mixBlendMode`,或运行时拼出的 HTML |
|
|
111
|
+
| `images` | `image_bridge.c`(实现本身已在 `gui.a`) | `<img>`、内联 `<svg>`、`background-image`/`url(...)`、`.svg` 路径、`drawImage`/`createImageBitmap`/`Image`,或运行时拼出的 HTML |
|
|
112
|
+
| `shaping` | `text_bridge.c`(实现本身已在 `gui.a`) | 非 ASCII 文本(CJK/西里尔/希腊文等)、转义或实体码点,或运行时拼出的 HTML |
|
|
113
|
+
| `webgl` | `webgl_bridge.c`(实现本身已在 `gui.a`,依赖 `gpu`) | WebGL 的 `getContext(...)`、`webgl` 字符串,或运行时拼出的 HTML |
|
|
114
|
+
|
|
115
|
+
driver 会扫描打包后的 AST(`src/driver/usage.ts`):所有字符串字面量(包括导入的
|
|
116
|
+
`.html` 与内联进来的 CSS)、标识符与属性名、每个 `getContext(...)` 的 kind,以及
|
|
117
|
+
HTML/CSS 是否可能来自编译器看不见的数据。简单的 `const` 别名会被解析;无法解析的
|
|
118
|
+
markup 会让程序按“动态 markup”保守处理,启用可选特性。
|
|
119
|
+
|
|
120
|
+
特性启用时,driver 只为本构建编译它的 C **bridge**,并链接在 `gui.a` 之前:
|
|
121
|
+
|
|
122
|
+
- `media` → `runtime/ext_media/media_bridge.c`;构造函数安装解码表并引用
|
|
123
|
+
`xt_media_backend_*`,从而把 FFmpeg 成员从 `media.a` 里取出。
|
|
124
|
+
- `gpu` → `runtime/ext_gui/gpu_bridge.c`;构造函数调用 `gpu_feature.cpp` 里的
|
|
125
|
+
`xt_gpu_feature_register`,安装 `XtGpuShaderApi` 表并引用 `compile_glsl` /
|
|
126
|
+
`cross_compile_msl` / 反射函数,从而取出 glslang(macOS 上还有 SPIRV-Cross)。
|
|
127
|
+
- `images` → `runtime/ext_gui/image_bridge.c`;构造函数通过 `image_feature.cpp`
|
|
128
|
+
安装 `XtImageApi`,其引用取出 stb_image 与 NanoSVG。layout、paint、canvas
|
|
129
|
+
`drawImage` 与应用图标都走这张表,因此纯文本页面不链接这两个解码器。
|
|
130
|
+
- `shaping` → `runtime/ext_gui/text_bridge.c`;构造函数通过 `text_hb.cpp` 安装
|
|
131
|
+
`TextApi`,其引用取出 HarfBuzz 与 FreeType。没有它时引擎使用内置 stb_truetype,
|
|
132
|
+
纯拉丁页面两个库都不链接。
|
|
133
|
+
- `webgl` → `runtime/ext_gui/webgl_bridge.c`;构造函数通过 `webgl_feature.cpp` 安装
|
|
134
|
+
`XtWebglApi`,其引用取出 WebGL context 与 DOM 绑定。core 的 `getContext`、
|
|
135
|
+
canvas 宽高 setter、`createImageBitmap`、host type 与 renderer 都走这张表,因此
|
|
136
|
+
不用 WebGL 的页面不链接任何 `webgl_*`/`dom_api_webgl*`。
|
|
137
|
+
|
|
138
|
+
bridge 就是让链接器搜索归档的“强引用”;没有 bridge 时引擎的表保持 null,
|
|
139
|
+
实现成员永不被取出。因此大库可以留在现有归档里,不需要新的包布局。
|
|
140
|
+
|
|
141
|
+
覆盖方式:`--feature media,gpu,images,shaping,webgl`(或 `all`)强制开启;
|
|
142
|
+
`--no-feature media` 即使检测到也不链接。`webgl` 依赖 `gpu`,resolver 会一起
|
|
143
|
+
激活;配置应用图标会强制 `images`,因为图标走同一条解码管线。`--ext media` 是
|
|
144
|
+
`--ext gui --feature media` 的弃用别名。
|
|
145
|
+
自动检测到的特性归档缺失时构建打印 warning 并继续(元素/上下文按文档降级);
|
|
146
|
+
显式强制的特性则报错。
|
|
147
|
+
|
|
148
|
+
> 检测是静态的。用 `fetch`、`readFileSync` 等运行时数据拼 HTML/CSS 的页面应传
|
|
149
|
+
> `--feature all`(或具体特性)。`--verbose` 会打印选中的集合,例如
|
|
150
|
+
> `xbintsc: link features: none`。
|
|
151
|
+
|
|
152
|
+
### 二进制体积
|
|
153
|
+
|
|
154
|
+
DOM-only 程序的小体积来自上述 lean 构建。Windows x64 上,一个 `hello` 规模的程序
|
|
155
|
+
从约 6.4 MiB 降到约 3.1 MiB:SDL 按上面的选项配置,function/data sections 让
|
|
156
|
+
`/OPT:REF` 丢弃页面触达不到的函数,WebGL/图片链接特性保持关闭,文本改用内置
|
|
157
|
+
stb_truetype 而不是 HarfBuzz + FreeType。剩余重量主要是静态 CRT、lean SDL
|
|
158
|
+
(约 1 MiB)、stb_truetype(约 0.1 MiB)以及 DOM/CSS/layout/paint 引擎本身
|
|
159
|
+
(约 1.2 MiB)。Linux 与 macOS 使用各自的链接器 section(`--gc-sections`/
|
|
160
|
+
`-dead_strip`),数字会有差异,但相对排序相同。
|
|
161
|
+
|
|
162
|
+
WebGL 与图片/SVG 是链接特性(约 0.4 MiB 的 WebGL context/DOM 代码与 0.23 MiB 的
|
|
163
|
+
stb_image/NanoSVG,DOM-only 页面不链接)。Canvas2D、Web Audio 与
|
|
164
|
+
`mix-blend-mode` 合成器尚未按需化;不使用它们的程序仍要付出其 API 面积(每项大约
|
|
165
|
+
0.1–0.2 MiB)。
|
|
166
|
+
|
|
167
|
+
文本替换是有意的取舍。默认后端是 stb_truetype:只接受 TrueType 轮廓,整形是逐码点
|
|
168
|
+
映射加字体的 `kern` 表,因此 CFF/OTF 与可变字体、OpenType 连字以及复杂文种
|
|
169
|
+
(阿拉伯/印度/泰文)整形不可用;fallback 链仍会在主字体缺字时切换到其他字体。
|
|
170
|
+
选中可选的 **`shaping`** 特性(非 ASCII 文本会自动选中,也可用
|
|
171
|
+
`--feature shaping`)会重新链接 HarfBuzz + FreeType(约 1.2 MiB),恢复完整的
|
|
172
|
+
OpenType 整形与 CFF/OTF/可变字体支持。纯拉丁 DOM 页面因此保持约 3.1 MiB;
|
|
173
|
+
中文/复杂文种页面更接近 4.3 MiB。
|
|
174
|
+
|
|
82
175
|
## 运行示例
|
|
83
176
|
|
|
84
177
|
```sh
|
|
@@ -117,9 +210,10 @@ Chocolatey/独立 LLVM,CI、本地构建与预编译归档共用同一条编
|
|
|
117
210
|
|
|
118
211
|
`examples/gui/media.ts`(配合 `media.html`)演示 `<video>`/`<audio>`:它在
|
|
119
212
|
`<video>` 上叠一个 CSS 进度条,并用 `play()`/`pause()`/`currentTime`/
|
|
120
|
-
`volume`
|
|
213
|
+
`volume` 驱动播放。编译器从 `media.html` 里看到这些元素后会自动选中 `media`
|
|
214
|
+
特性;先用 `npm run media` 构建一次 `media.a`。
|
|
121
215
|
媒体 `src` 相对于进程工作目录解析,因此从仓库根目录运行:
|
|
122
|
-
`xbintsc run examples/gui/media.ts --ext gui
|
|
216
|
+
`xbintsc run examples/gui/media.ts --ext gui`。几何报告见该目录的 README。
|
|
123
217
|
|
|
124
218
|
这些测试套件在 Windows 上默认跳过(归档可以在本机通过 Vulkan 运行,但 CI
|
|
125
219
|
runner 没有可用的 GPU 驱动)。如果本机有 `gui.lib` 与可用的 GPU,可用
|
package/doc/zh-CN/gui/canvas.md
CHANGED
|
@@ -156,7 +156,7 @@ canvas 由脚本重绘而不是引擎重绘,因此开销按绘制调用计。
|
|
|
156
156
|
(奇数长度列表会复制一遍,负数/非有限值会被忽略,全零列表表示实线)。
|
|
157
157
|
|
|
158
158
|
文本:`measureText(text)`(返回 `{ width }`)、`fillText(text, x, y, maxWidth?)` 与
|
|
159
|
-
`strokeText(text, x, y, maxWidth?)`。文本经
|
|
159
|
+
`strokeText(text, x, y, maxWidth?)`。文本经 stb_truetype 整形与光栅化(与 HTML
|
|
160
160
|
文本相同的技术栈),按变换的近似缩放绘制。正的 `maxWidth` 会按比例压缩步进与字形位图,
|
|
161
161
|
使文本宽度不超过该值(与 canvas API 一致),而不是忽略该参数。**仅支持平移与均匀
|
|
162
162
|
缩放**——旋转或斜切变换仍会把每个字形放到其变换后的基线点,但不会旋转字形位图。
|
|
@@ -20,6 +20,15 @@
|
|
|
20
20
|
`WebGLRenderer` 直接运行在真实后端上,不再有 Canvas2D 回退。阴影贴图
|
|
21
21
|
(比较型 `sampler2DShadow` 采样深度纹理)、立方体贴图/环境贴图与 HDR 渲染目标
|
|
22
22
|
均已支持。
|
|
23
|
+
- **部分 Intel Mac 上比较型采样器会被错误编译。** 在 Intel GPU(在 Intel Iris
|
|
24
|
+
Plus Graphics + macOS 26 上观察到)上,Metal 着色器编译器会丢弃调用
|
|
25
|
+
`sample_compare` 的片元函数:绘制不产生任何像素,于是
|
|
26
|
+
`texture(sampler2DShadow, …)` 读到黑色,阴影贴图消失。MSL 本身是正确的
|
|
27
|
+
(`depth2d<float>` + `sample_compare`),采样器也带比较操作,而同一个程序在
|
|
28
|
+
打开 Metal GPU 着色器校验后渲染正常——在这类机器上以
|
|
29
|
+
`MTL_SHADER_VALIDATION=1` 运行即可让
|
|
30
|
+
`tests/e2e/gui-webgl2-shadow-sampler.test.ts` 通过。这指向驱动的着色器编译器
|
|
31
|
+
而非引擎,因此以环境变量作为绕过办法;其他 Apple GPU 未必存在该问题。
|
|
23
32
|
|
|
24
33
|
|
|
25
34
|
- **自动关闭时的偶发崩溃。** 设置 `XT_GUI_AUTOCLOSE_MS` 结束运行时,约五次中有两次会以原生
|
|
@@ -79,6 +88,17 @@
|
|
|
79
88
|
`win.stats()` 的 `textCacheBytes`/`textShapeHits` 能看出它是否成为瓶颈。
|
|
80
89
|
元素自带的 `style="…"` 内联属性在该元素每次重算样式时都会重新解析。
|
|
81
90
|
|
|
91
|
+
- **文本整形是简单整形器。** stb_truetype 覆盖拉丁/CJK/西里尔/希腊文、基础
|
|
92
|
+
`kern` 与逐码点回退,但不执行 OpenType 连字或复杂文种(阿拉伯/印度/泰文)整形,
|
|
93
|
+
且只接受 TrueType 轮廓(不支持 CFF/OTF 或可变字体);彩色 emoji 也不会以彩色
|
|
94
|
+
渲染。这是 DOM-only 二进制约 3 MiB 的代价;可选的 `shaping` 特性会重新链接
|
|
95
|
+
HarfBuzz + FreeType,恢复完整整形。
|
|
96
|
+
- **链接特性检测是静态的。** `media`/`gpu`/`images`/`shaping`/`webgl` 从打包后的 HTML/CSS/TS(包括导入的
|
|
97
|
+
`.html` 与其内联 CSS)里选择。用运行时数据(`fetch`、`readFileSync`、函数返回值)
|
|
98
|
+
拼 HTML/CSS 的页面无法被看到;扫描器在能证明 sink 是动态时会保守地启用可选特性,
|
|
99
|
+
但对于它无法分类的不透明值,需要显式 `--feature media`/`gpu`/`images`/`shaping`/`webgl`(或 `all`)。
|
|
100
|
+
`--verbose` 会打印选中的集合。见[链接特性](./build.md#链接特性)。
|
|
101
|
+
|
|
82
102
|
## 待决问题
|
|
83
103
|
|
|
84
104
|
- Linux 首发是只发布 X11、Wayland,还是两者都发布。(决定:先 X11,
|
|
@@ -97,7 +117,8 @@
|
|
|
97
117
|
- Windows:`scripts/build-gui.ts` 会生成 MSVC 兼容的 `gui.lib`
|
|
98
118
|
(COFF 对象 + `ar -M`/`llvm-ar`)。Windows x64 的 CI job 使用 Visual Studio
|
|
99
119
|
工具链(`.github/actions/vs-toolchain` 导入 `vcvarsall` 并采用 VS 自带的
|
|
100
|
-
LLVM
|
|
120
|
+
LLVM)构建它、链接一个会触发 `media` 链接特性的 `gui` 程序,并随 x64 发布归档
|
|
121
|
+
一起发布。示例在
|
|
101
122
|
托管 runner 上的*运行*仍为试验性,因为那里没有 GPU/Vulkan 驱动(SDL_GPU 在
|
|
102
123
|
Windows 上选择 **Vulkan** 后端,因此不需要 DXIL/`dxc` 工具链)。Windows
|
|
103
124
|
arm64 仍跳过两个归档。在开发者机器上构建并运行
|
|
@@ -105,12 +126,12 @@
|
|
|
105
126
|
- **Windows:x64 在 CI 中构建,arm64 与运行时验证仍为试验性。**
|
|
106
127
|
`scripts/build-media.ts` 用 FFmpeg 的 MSVC 工具链
|
|
107
128
|
(`--toolchain=msvc --cc=clang-cl`)生成 `media.lib`,其 COFF 对象与静态 CRT
|
|
108
|
-
和 `gui.lib`
|
|
129
|
+
和 `gui.lib` 一致,自动选中的 `media` 特性在 Windows 上可以正常链接并播放。构建它需要
|
|
109
130
|
POSIX shell 运行 FFmpeg 的 `configure` 以及 GNU make;shell 来自 Git for
|
|
110
131
|
Windows(克隆 SDL3 本来就需要 Git),make 是原生 GNU make(Chocolatey 的
|
|
111
132
|
`make`,或 `xbintsc_MAKE`)。CI 会显式安装 make,在
|
|
112
133
|
Windows x64 上使用与本地构建相同的 Visual Studio `vcvarsall` + 自带 LLVM
|
|
113
|
-
构建 `gui.lib` 与 `media.lib
|
|
134
|
+
构建 `gui.lib` 与 `media.lib`,链接一个会触发该特性的 `gui` 程序,并把两个归档放进
|
|
114
135
|
Windows x64 发布包;示例的*运行*仍因托管 runner 没有 GPU/Vulkan 驱动而保持
|
|
115
136
|
试验性。Windows arm64 仍跳过两个归档;`<video controls>` 同样推迟——预期模式
|
|
116
137
|
是 TS + CSS 叠层,如 `examples/gui/media.ts`。
|
package/doc/zh-CN/gui/layout.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
基于单词的断行、`text-align` 与 `line-height`。行内元素获得其后代几何信息
|
|
19
19
|
的并集;`display: inline-block` 以 shrink-to-fit 宽度原子化布局。每一行会收缩到
|
|
20
20
|
与之重叠的浮动(`float: left|right`)所留出的空白带,因此后续行会绕开它们。
|
|
21
|
-
每个文本片段会记住它覆盖的 run,以便绘制时对它整形。文本使用
|
|
21
|
+
每个文本片段会记住它覆盖的 run,以便绘制时对它整形。文本使用 stb_truetype
|
|
22
22
|
技术栈测量(见[文本技术栈](./rendering.md))。
|
|
23
23
|
- **Flexbox** —— `row`/`column`(以及 `-reverse` 变体),支持 `gap`、
|
|
24
24
|
`flex-basis`/`flex-grow`/`flex-shrink`、`justify-content` 与 `align-items`
|
package/doc/zh-CN/gui/media.md
CHANGED
|
@@ -62,7 +62,8 @@ opacity、`display`——与任何其他元素一样。盒子内部的艺术内
|
|
|
62
62
|
|
|
63
63
|
## 视频与音频(M13)
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
媒体播放拆在 `gui` 扩展内部,因此只做界面的 GUI 程序不必为用不到的解码器付出
|
|
66
|
+
体积。解码是可选的 **`media` 链接特性**,不是独立扩展:
|
|
66
67
|
|
|
67
68
|
- **`gui`**(`gui.a`/`gui.lib`)负责 `<video>`/`<audio>` 元素、DOM API、渲染器
|
|
68
69
|
集成与 SDL 音频 sink,但**不含 FFmpeg**。`runtime/ext_gui/media.{h,cpp}`
|
|
@@ -71,12 +72,16 @@ opacity、`display`——与任何其他元素一样。盒子内部的艺术内
|
|
|
71
72
|
- **`media`**(`media.a`,Windows 上 MSVC ABI 则为 `media.lib`;
|
|
72
73
|
`runtime/ext_media/`)是可选的解码后端:`runtime/ext_media/media.cpp`
|
|
73
74
|
封装静态 vendored 的 **FFmpeg** 构建,`runtime/ext_media/media_bridge.c`
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
把它注册进引擎。编译器在程序可能用到媒体时(导入 HTML 里的
|
|
76
|
+
`<video>`/`<audio>`、`createElement("video"/"audio")`、`new Audio()`、
|
|
77
|
+
`decodeAudioData`,或运行时拼出的 HTML)自动选中该特性,只在那时才编译
|
|
78
|
+
bridge 并链接 `media.a`。`--feature media` 强制开启,`--no-feature media`
|
|
79
|
+
保持关闭;见[链接特性](./build.md#链接特性)。
|
|
76
80
|
|
|
77
|
-
没有 `media`
|
|
78
|
-
`error`。任何没有构建该归档的宿主(先运行 `npm run media
|
|
79
|
-
|
|
81
|
+
没有 `media` 特性时,元素仍然存在、DOM API 仍可调用,但打开源会失败并触发
|
|
82
|
+
`error`。任何没有构建该归档的宿主(先运行 `npm run media`)都是如此——自动
|
|
83
|
+
检测到但归档缺失时构建给出 warning 并按此降级,显式 `--feature media` 则直接
|
|
84
|
+
报错。Windows 已不再特殊:`media.lib` 是用 clang-cl 为 MSVC ABI 编译的 FFmpeg,
|
|
80
85
|
因此可以和 `gui.lib` 一起链接并正常播放。两条路径都没有 WebView,也没有平台
|
|
81
86
|
媒体框架。
|
|
82
87
|
|