xbintsc 0.5.31 → 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.
Files changed (181) hide show
  1. package/README.md +16 -10
  2. package/dist/src/binder/references.js +14 -1
  3. package/dist/src/binder/references.js.map +1 -1
  4. package/dist/src/cli/help.d.ts +1 -1
  5. package/dist/src/codegen/generator/module.d.ts +1 -0
  6. package/dist/src/codegen/generator/module.js +54 -0
  7. package/dist/src/codegen/generator/module.js.map +1 -1
  8. package/dist/src/codegen/generator/statements/variables.js +6 -4
  9. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  10. package/dist/src/driver/version.d.ts +1 -1
  11. package/dist/src/driver/version.js +1 -1
  12. package/dist/src/extensions/gui/css.d.ts +26 -0
  13. package/dist/src/extensions/gui/css.js +100 -0
  14. package/dist/src/extensions/gui/css.js.map +1 -0
  15. package/dist/src/extensions/gui/html.js +9 -2
  16. package/dist/src/extensions/gui/html.js.map +1 -1
  17. package/dist/src/extensions/gui/index.js +16 -2
  18. package/dist/src/extensions/gui/index.js.map +1 -1
  19. package/dist/src/extensions/gui/three.d.ts +16 -0
  20. package/dist/src/extensions/gui/three.js +22 -0
  21. package/dist/src/extensions/gui/three.js.map +1 -0
  22. package/dist/src/extensions/media/index.d.ts +6 -5
  23. package/dist/src/extensions/media/index.js +12 -14
  24. package/dist/src/extensions/media/index.js.map +1 -1
  25. package/dist/tests/e2e/compile-builtins.test.js +24 -0
  26. package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
  27. package/dist/tests/e2e/compile-objects-classes.test.js +23 -0
  28. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  29. package/dist/tests/e2e/gui-browser.test.js +1 -1
  30. package/dist/tests/e2e/gui-browser.test.js.map +1 -1
  31. package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
  32. package/dist/tests/e2e/gui-effects.test.js +262 -0
  33. package/dist/tests/e2e/gui-effects.test.js.map +1 -0
  34. package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
  35. package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
  36. package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
  37. package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
  38. package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
  39. package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
  40. package/dist/tests/e2e/gui-layout.test.js +48 -0
  41. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  42. package/dist/tests/e2e/gui-media.test.js +5 -4
  43. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  44. package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
  45. package/dist/tests/e2e/gui-webgl.test.js +179 -0
  46. package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
  47. package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
  48. package/dist/tests/e2e/gui-webgl2.test.js +238 -0
  49. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
  50. package/dist/tests/extensions/gui.test.js +41 -0
  51. package/dist/tests/extensions/gui.test.js.map +1 -1
  52. package/dist/tests/extensions/media.test.js +7 -3
  53. package/dist/tests/extensions/media.test.js.map +1 -1
  54. package/doc/ai/extensions.md +29 -9
  55. package/doc/ai/troubleshooting.md +12 -8
  56. package/doc/ai/zh-CN/extensions.md +26 -8
  57. package/doc/ai/zh-CN/troubleshooting.md +10 -6
  58. package/doc/gui/api.md +3 -2
  59. package/doc/gui/build.md +72 -16
  60. package/doc/gui/canvas.md +11 -3
  61. package/doc/gui/dom.md +33 -18
  62. package/doc/gui/known-issues.md +57 -24
  63. package/doc/gui/layout.md +18 -0
  64. package/doc/gui/media.md +17 -13
  65. package/doc/gui/rendering.md +50 -3
  66. package/doc/gui/webgl.md +256 -0
  67. package/doc/gui.md +108 -17
  68. package/doc/npm-package.md +6 -4
  69. package/doc/requirements.md +18 -9
  70. package/doc/zh-CN/gui/api.md +3 -2
  71. package/doc/zh-CN/gui/build.md +64 -15
  72. package/doc/zh-CN/gui/canvas.md +9 -2
  73. package/doc/zh-CN/gui/dom.md +20 -7
  74. package/doc/zh-CN/gui/known-issues.md +45 -19
  75. package/doc/zh-CN/gui/layout.md +14 -0
  76. package/doc/zh-CN/gui/media.md +15 -11
  77. package/doc/zh-CN/gui/rendering.md +41 -4
  78. package/doc/zh-CN/gui/webgl.md +115 -0
  79. package/doc/zh-CN/gui.md +89 -14
  80. package/doc/zh-CN/npm-package.md +9 -6
  81. package/doc/zh-CN/requirements.md +12 -6
  82. package/llms.txt +2 -0
  83. package/package.json +1 -1
  84. package/runtime/ext_gui/browser.cpp +39 -13
  85. package/runtime/ext_gui/canvas.cpp +3 -18
  86. package/runtime/ext_gui/canvas_internal.h +10 -0
  87. package/runtime/ext_gui/canvas_raster.cpp +60 -0
  88. package/runtime/ext_gui/clip_values.cpp +246 -0
  89. package/runtime/ext_gui/css.cpp +94 -0
  90. package/runtime/ext_gui/css.h +22 -1
  91. package/runtime/ext_gui/css_match.cpp +3 -0
  92. package/runtime/ext_gui/css_selector.cpp +9 -0
  93. package/runtime/ext_gui/css_sheet.cpp +89 -45
  94. package/runtime/ext_gui/document.cpp +4 -1
  95. package/runtime/ext_gui/document.h +2 -0
  96. package/runtime/ext_gui/dom.h +16 -0
  97. package/runtime/ext_gui/dom_api.cpp +1 -0
  98. package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
  99. package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
  100. package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
  101. package/runtime/ext_gui/dom_api_internal.h +259 -0
  102. package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
  103. package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
  104. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
  105. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
  106. package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
  107. package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
  108. package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
  109. package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
  110. package/runtime/ext_gui/effect_values.cpp +312 -0
  111. package/runtime/ext_gui/gradient_values.cpp +476 -0
  112. package/runtime/ext_gui/grid_values.cpp +230 -0
  113. package/runtime/ext_gui/gui_canvas.cpp +50 -2
  114. package/runtime/ext_gui/gui_engine.h +27 -0
  115. package/runtime/ext_gui/gui_events.cpp +4 -1
  116. package/runtime/ext_gui/gui_media.cpp +1 -1
  117. package/runtime/ext_gui/gui_webgl.cpp +83 -0
  118. package/runtime/ext_gui/layout.cpp +21 -0
  119. package/runtime/ext_gui/layout_flow.cpp +81 -4
  120. package/runtime/ext_gui/layout_flow_internal.h +31 -0
  121. package/runtime/ext_gui/layout_grid.cpp +374 -0
  122. package/runtime/ext_gui/media.h +1 -1
  123. package/runtime/ext_gui/media_api.h +2 -2
  124. package/runtime/ext_gui/media_query.cpp +211 -0
  125. package/runtime/ext_gui/paint.cpp +111 -77
  126. package/runtime/ext_gui/paint.h +33 -3
  127. package/runtime/ext_gui/paint_background.cpp +229 -0
  128. package/runtime/ext_gui/paint_clip.cpp +268 -0
  129. package/runtime/ext_gui/paint_effects.cpp +324 -0
  130. package/runtime/ext_gui/paint_internal.h +85 -0
  131. package/runtime/ext_gui/renderer.cpp +8 -31
  132. package/runtime/ext_gui/renderer_clip.cpp +196 -0
  133. package/runtime/ext_gui/renderer_image.cpp +13 -8
  134. package/runtime/ext_gui/renderer_internal.h +15 -8
  135. package/runtime/ext_gui/renderer_text.cpp +6 -31
  136. package/runtime/ext_gui/style.cpp +343 -20
  137. package/runtime/ext_gui/style.h +144 -3
  138. package/runtime/ext_gui/style_print.cpp +134 -1
  139. package/runtime/ext_gui/style_values.cpp +152 -126
  140. package/runtime/ext_gui/style_values_internal.h +35 -0
  141. package/runtime/ext_gui/webgl.h +466 -0
  142. package/runtime/ext_gui/webgl2_constants.h +274 -0
  143. package/runtime/ext_gui/webgl_buffer.cpp +565 -0
  144. package/runtime/ext_gui/webgl_constants.h +317 -0
  145. package/runtime/ext_gui/webgl_context.cpp +466 -0
  146. package/runtime/ext_gui/webgl_draw.cpp +495 -0
  147. package/runtime/ext_gui/webgl_glsl.h +125 -0
  148. package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
  149. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
  150. package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
  151. package/runtime/ext_gui/webgl_msl.cpp +62 -0
  152. package/runtime/ext_gui/webgl_msl.h +33 -0
  153. package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
  154. package/runtime/ext_gui/webgl_program_internal.h +18 -0
  155. package/runtime/ext_gui/webgl_shader.cpp +582 -0
  156. package/runtime/ext_gui/webgl_texture.cpp +293 -0
  157. package/runtime/ext_gui/webgl_uniform.cpp +167 -0
  158. package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
  159. package/runtime/ext_media/media.cpp +1 -1
  160. package/runtime/ext_media/media_bridge.c +9 -3
  161. package/runtime/rt_internal.h +1 -0
  162. package/runtime/xt_containers/access.inc +8 -0
  163. package/runtime/xt_regex/api.inc +2 -0
  164. package/runtime/xt_regex/matcher.inc +16 -3
  165. package/runtime/xt_regex/parser.inc +8 -2
  166. package/runtime/xt_regex/types.inc +3 -0
  167. package/runtime/xt_stdlib2/regexp-match.inc +60 -21
  168. package/runtime/xt_stdlib2/regexp.inc +1 -0
  169. package/runtime/xt_typed_array.c +1 -1
  170. package/scripts/build-gui.ts +90 -3
  171. package/scripts/build-media.ts +323 -58
  172. package/scripts/setup-vs-toolchain.ps1 +152 -0
  173. package/src/binder/references.ts +13 -1
  174. package/src/codegen/generator/module.ts +50 -0
  175. package/src/codegen/generator/statements/variables.ts +6 -3
  176. package/src/driver/version.ts +1 -1
  177. package/src/extensions/gui/css.ts +113 -0
  178. package/src/extensions/gui/html.ts +9 -2
  179. package/src/extensions/gui/index.ts +16 -2
  180. package/src/extensions/gui/three.ts +25 -0
  181. package/src/extensions/media/index.ts +13 -16
package/doc/zh-CN/gui.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 语言 / Language:[English](../gui.md) | **简体中文**
4
4
 
5
- 状态:**M16** —— 功能(M1–M15)已全部完成:HTML 解析、CSS 选择器匹配、层叠(cascade)、计算样式与布局(块级、行内、Flexbox 与 CSS 定位)均已就位,引擎还会**绘制**:它构建一个由矩形、图像与排版后的文本 run 组成的显示列表,并通过 SDL_GPU 渲染。输入事件会经过命中测试并投递给原生 TS 处理器,`:hover`/`:focus` 会被动态匹配,`<img>` 依据其固有尺寸确定大小并从纹理绘制——位图(PNG/JPEG/…)与 SVG 文件皆可,后者按绘制尺寸光栅化,因此矢量图保持清晰——CSS transition 会为绘制属性做动画。**M16** 让内联 `<svg>` 子树获得同样的处理:子树被序列化回 SVG 文档,并按绘制设备尺寸光栅化,因此图标不再需要单独的文件。**M8** 增加了交互式 DOM:具有稳定标识的元素句柄、变更操作(`appendChild`、`textContent`、`classList`、`style` 等)以及支持捕获/冒泡的元素级事件。**M9** 会提前编译 `<script>` 主体(内联与 `<script src>`)——参见 `gui-scripts.md`。**M10** 增加 `requestAnimationFrame` 以及若干 DOM 辅助方法。**M11** 增加 `position: relative`/`absolute`/`fixed` 及其偏移,`examples/gui/pelican-bike`(一个可玩的 2D 游戏)就构建在它之上。**M12** 明确了 DOM 节点生命周期(哪些变更释放、哪些保留),并让引擎内存有界:参见[节点生命周期](./gui/dom.md)与[内存与 GC](./gui/runtime.md)。**M13** 真正播放
5
+ 状态:**M19** —— 功能(M1–M15)已全部完成:HTML 解析、CSS 选择器匹配、层叠(cascade)、计算样式与布局(块级、行内、Flexbox 与 CSS 定位)均已就位,引擎还会**绘制**:它构建一个由矩形、图像与排版后的文本 run 组成的显示列表,并通过 SDL_GPU 渲染。输入事件会经过命中测试并投递给原生 TS 处理器,`:hover`/`:focus` 会被动态匹配,`<img>` 依据其固有尺寸确定大小并从纹理绘制——位图(PNG/JPEG/…)与 SVG 文件皆可,后者按绘制尺寸光栅化,因此矢量图保持清晰——CSS transition 会为绘制属性做动画。**M16** 让内联 `<svg>` 子树获得同样的处理:子树被序列化回 SVG 文档,并按绘制设备尺寸光栅化,因此图标不再需要单独的文件。**M8** 增加了交互式 DOM:具有稳定标识的元素句柄、变更操作(`appendChild`、`textContent`、`classList`、`style` 等)以及支持捕获/冒泡的元素级事件。**M9** 会提前编译 `<script>` 主体(内联与 `<script src>`)——参见 `gui-scripts.md`。**M10** 增加 `requestAnimationFrame` 以及若干 DOM 辅助方法。**M11** 增加 `position: relative`/`absolute`/`fixed` 及其偏移,`examples/gui/pelican-bike`(一个可玩的 2D 游戏)就构建在它之上。**M12** 明确了 DOM 节点生命周期(哪些变更释放、哪些保留),并让引擎内存有界:参见[节点生命周期](./gui/dom.md)与[内存与 GC](./gui/runtime.md)。**M13** 真正播放
6
6
  `<video>`/`<audio>`——可选的 `media` 扩展用 vendored 的最小 FFmpeg 在主线程解码,
7
7
  视频帧走图像纹理路径、音频进入 SDL 流,DOM 媒体 API 暴露
8
8
  `play`/`pause`/`currentTime`/… 与媒体事件。只启用 `gui` 不会链接 FFmpeg。**M14** 增加了 `<canvas>`,配一个自研的 2D 软件光栅器(抗锯齿
@@ -12,7 +12,7 @@
12
12
  渲染器,因此盒子(以及其中的文本、图像与子元素)可以被平移、缩放与旋转而
13
13
  不触发任何重排——再加上 `transition: transform`,这些姿态可以动画(自绘的示例
14
14
  `examples/gui/pelican-svg` 正是用它让矢量画动起来)。参见
15
- [布局](./gui/layout.md#变换m15)与[动画](./gui/animation.md#css-transformm15)。本总览记录了锁定决策、架构、里程碑计划与当前进度;引擎本身按功能拆分在以上各页中。
15
+ [布局](./gui/layout.md#变换m15)与[动画](./gui/animation.md#css-transformm15)。**M17** 增加了真正的 **WebGL 1.0**,**M18** 增加了 **WebGL 2.0**:`<canvas>.getContext("webgl2")` 接受 `#version 300 es` 着色器、顶点数组对象、实例化绘制与采样器对象,全部由内置 glslang 编译为 SPIR-V(Metal 上再由内置 SPIRV-Cross 转成 MSL)并通过 SDL_GPU 渲染,几何、光照、纹理采样与混合都在 GPU 上完成,页面直接合成颜色纹理而无须读回——见 [WebGL](./gui/webgl.md)。**M19** 补齐 CSS 装饰层:`@media` 查询、生成内容(`::before`/`::after`)、线性/径向多层背景、`text-shadow`、`clip-path` 与 `filter` 颜色/阴影效果。`backdrop-filter` 与真正的组模糊需要离屏合成器,仍为有文档说明的近似或未支持——见[绘制](./gui/rendering.md#背景生成内容与特效m19)。本总览记录了锁定决策、架构、里程碑计划与当前进度;引擎本身按功能拆分在以上各页中。
16
16
 
17
17
  ## 目录
18
18
 
@@ -135,19 +135,24 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
135
135
  - **M6b — transition/动画** ✅ `transition` 简写 + 长写、对
136
136
  `background-color`/`color`/`border-color`/`border-radius` 的动画、重定向
137
137
  与 `win.advance(ms)`。`@keyframes` 仍待完成。
138
- 7. **M7 — CI 与发布** ✅(Linux/macOS 构建) / 🚧(运行 + Windows)
138
+ 7. **M7 — CI 与发布** ✅(Linux/macOS 构建) / 🚧(运行 + Windows arm64)
139
139
  - `compile-examples` 在 Linux 与 macOS 上构建 `gui.a` 与 `media.a`(必需),
140
140
  然后在 Linux 上的 Xvfb + lavapipe 下运行示例与 `tests/e2e/gui-*.test.ts`
141
141
  (必需)。macOS 运行在确认 WindowServer 之前为试验性;它被保护起来,失败
142
142
  只记录日志而不标注运行。
143
- - `package` job 在组装发布之前构建 `gui.a` 与 `media.a`,因此两者都会随现有
144
- runtime 归档一起发布(`package-release` 复制整个 `runtime/`)。
145
- - `vendor/`(`gui.a` 的 SDL3/FreeType/HarfBuzz,以及 `media.a` 的 FFmpeg,
143
+ - `package` job 在组装发布之前构建 `gui.a`/`gui.lib` 与 `media.a`/`media.lib`,
144
+ 因此两者都会随现有 runtime 归档一起发布(`package-release` 复制整个
145
+ `runtime/`)。Windows x64 已包含;Windows arm64 仍跳过。
146
+ - `vendor/`(GUI 归档的 SDL3/FreeType/HarfBuzz,以及 `media` 的 FFmpeg,
146
147
  缓慢的部分)按 OS/arch 缓存,以 `scripts/build-gui.ts` /
147
- `scripts/build-media.ts` 为键。
148
- - Windows(构建 + 运行)在 CI 中保持试验性:MSVC 兼容的 `gui.lib` 可在本机
149
- 通过 SDL_GPU 的 Vulkan 后端构建并运行,但托管 runner 没有 GPU/Vulkan
150
- 驱动。失败只记录日志而不标注运行(见[待决问题](./gui/known-issues.md))。
148
+ `scripts/build-media.ts` 为键。Windows x64 有独立的源码 + FFmpeg 安装前缀
149
+ 缓存。
150
+ - Windows x64 在 CI 中构建两个归档并链接一个 `gui,media` 程序;托管 runner
151
+ 没有 GPU/Vulkan 驱动,因此 GUI/媒体示例的*运行*仍为试验性(失败只记录
152
+ 日志而不标注运行)。Windows arm64 仍跳过两个归档(见
153
+ [待决问题](./gui/known-issues.md))。CI 通过
154
+ `.github/actions/vs-toolchain` → `scripts/setup-vs-toolchain.ps1` 使用与
155
+ 本地构建相同的 Visual Studio MSVC + 自带 LLVM 工具链。
151
156
  8. **M8 — 交互式 DOM** ✅
152
157
  - 具有稳定标识的元素/文档句柄、通过运行时访问器读写属性、遍历/特性/查询、
153
158
  带有延迟重算样式/重新布局的变更
@@ -225,6 +230,47 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
225
230
  通过与 SVG 文件相同的 NanoSVG 缓存(`svg.{h,cpp}`)解析并光栅化;markup
226
231
  缓存有界,DOM 变更会在下一次布局时重新序列化。e2e 见
227
232
  `tests/e2e/gui-inline-svg.test.ts`。
233
+ 17. **M17 — WebGL** ✅
234
+ - `canvas.getContext("webgl")` 创建真正的 GPU 上下文(`webgl.{h,cpp}`):
235
+ 一张离屏 RGBA8 颜色纹理加一张深度纹理、自己的 SDL_GPU 命令缓冲,并根据
236
+ 程序、顶点布局与固定功能状态惰性创建管线。页面通过既有图像路径直接合成
237
+ 颜色纹理,不需要 CPU 读回。
238
+ - `webgl_glsl*.cpp` 把 GLSL ES 1.00/3.00 改写为 Vulkan GLSL ES 3.10
239
+ (属性/`varying` 位置、`gl_FragColor`、`texture2D`、每阶段一个 std140
240
+ uniform 块、显式采样器绑定),用静态打包的 glslang 编译,反射 SPIR-V
241
+ 得到 uniform 偏移,并在 Metal 上用内置 SPIRV-Cross(`webgl_msl.cpp`)
242
+ 把同一份模块交叉编译为 MSL。
243
+ - `dom_api_webgl*.cpp` 暴露 WebGL 1.0 接口,包括纹理、mipmap、
244
+ 渲染到纹理的 framebuffer 与 `readPixels`。见 [WebGL](./gui/webgl.md);
245
+ e2e 见 `tests/e2e/gui-webgl.test.ts` 与
246
+ `tests/e2e/gui-example-webgl.test.ts`,示例见 `examples/gui/webgl-cube`。
247
+ 18. **M18 — WebGL 2** ✅
248
+ - `canvas.getContext("webgl2")` 返回的上下文原型继承 WebGL 1 原型,并带有
249
+ WebGL 2 常量与方法。
250
+ - GLSL ES 3.00 源码(`#version 300 es`、`in`/`out`、命名片元输出、
251
+ `gl_InstanceID`)走同一个改写器编译。
252
+ - 顶点数组对象保存/恢复属性表,实例化绘制使用 SDL 的按实例输入频率,采样器
253
+ 对象覆盖纹理单元的过滤/环绕状态。`texStorage2D`、`copyBufferSubData`、
254
+ `getBufferSubData` 与 `clearBuffer*` 已实现;查询/栅栏/UBO 与 transform
255
+ feedback 入口存在并优雅降级。见 [WebGL](./gui/webgl.md);e2e 见
256
+ `tests/e2e/gui-webgl2.test.ts` 与 `tests/e2e/gui-example-webgl2.test.ts`,
257
+ 示例见 `examples/gui/webgl2-cubes`。
258
+ 19. **M19 — 装饰性 CSS** ✅
259
+ - `@media` 块递归解析,并按视口求值(宽高范围、朝向、hover/pointer 与偏好
260
+ 特性);`matchMedia()` 使用同一个求值器。
261
+ - 生成内容:`::before`/`::after` 选择器、继承的伪样式、`content` 字符串/
262
+ 转义/`attr()`,以及不会泄漏到 DOM 遍历的合成布局盒。
263
+ - 多层 `background-image` 的线性与径向渐变,自下而上按纯色带绘制
264
+ (线性 18 条、径向 32 个同心椭圆)。
265
+ - `text-shadow` 作为阴影文本 run,并带九次采样模糊近似。
266
+ - `clip-path` 多边形(`inset`/`circle`/`ellipse`/`polygon`)解析到设备空间,
267
+ 用耳切法三角化,并在 `renderer_clip.cpp` 中与图形几何求交——不需要模板/
268
+ shader 改动。
269
+ - `filter` 颜色函数、九次采样 `blur()` 与轮廓 `drop-shadow()`;
270
+ `backdrop-filter` 会解析并参与层叠,但需要离屏背景通道(见
271
+ [已知问题](./gui/known-issues.md))。
272
+ - e2e 覆盖见 `tests/e2e/gui-effects.test.ts`;参见
273
+ [绘制](./gui/rendering.md#背景生成内容与特效m19)。
228
274
 
229
275
  ## 进度日志
230
276
 
@@ -252,10 +298,13 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
252
298
  按绘制设备像素尺寸光栅化并按该尺寸缓存,因此缩放与 HiDPI 保持清晰。
253
299
  - **M6b** ✅ CSS transition(在 `style.*` 中解析、在 `document.*` 中维护动画
254
300
  时钟与 transition 状态、`advance`/`advance(ms)` 钩子、e2e 覆盖)。
255
- - **M7** ✅ 在 CI 中于 Linux 与 macOS 上构建 `gui.a`(以及可选的 `media.a`,
256
- 必需),并在 Linux 的 Xvfb 下运行示例与 GUI e2e 套件;`package` 发布两个归档,
257
- `vendor/` 被缓存,`ar -M` 合并在 GNU/Linux 与 macOS 上可用。macOS 运行与所有
258
- Windows 在 CI 中仍为试验性。
301
+ - **M7** ✅ 在 CI 中于 Linux、macOS 与 Windows x64 上构建 `gui.a`/`gui.lib` 与
302
+ `media.a`/`media.lib`(必需),并在 Linux 的 Xvfb 下运行示例与 GUI e2e 套件;
303
+ `package` 发布这些归档(Windows x64 已包含),`vendor/` 被缓存,`ar -M` 合并
304
+ 在 GNU/Linux、macOS 与 COFF/Windows 上可用。macOS 运行、Windows 示例的*运行*
305
+ 以及 Windows arm64 在 CI 中仍为试验性。Windows job 通过
306
+ `.github/actions/vs-toolchain` 使用与本地构建相同的 Visual Studio MSVC +
307
+ 自带 LLVM 工具链。
259
308
  - **M8** ✅ 元素/文档句柄(`dom_api.*`)、带延迟重算样式/重新布局的 DOM 变更
260
309
  (`document.*`、`xt_gui_flush_dom`)、带捕获/冒泡与 `stopPropagation` 的
261
310
  元素事件分发(`dom_api.*`、`gui.cpp`),以及
@@ -325,4 +374,30 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
325
374
  markup 采用有界 LRU)按绘制设备像素尺寸光栅化。`win.inlineSvg` 诊断钩子
326
375
  暴露序列化文档,`tests/e2e/gui-inline-svg.test.ts` 固定了尺寸、命中测试、
327
376
  渐变、CSS 盒样式与 DOM 变更。
377
+ - **M17** ✅ WebGL。`xtgui::WebGLContext`(`webgl.{h,cpp}`)拥有离屏颜色/深度
378
+ 目标与命令缓冲,`webgl_buffer/texture/draw/shader` 实现 GL 对象模型,
379
+ `webgl_glsl*.cpp` 用内置 glslang 把 GLSL ES 翻译为 SPIR-V
380
+ (`webgl_msl.cpp`/SPIRV-Cross 在 Metal 上把该模块转成 MSL),
381
+ `dom_api_webgl*.cpp` 绑定 WebGL 1.0 接口。`renderer_image.cpp` 按 canvas id
382
+ 返回上下文的颜色纹理,页面直接合成 GPU 输出。示例
383
+ `examples/gui/webgl-cube`;e2e 见 `tests/e2e/gui-webgl.test.ts` 与
384
+ `tests/e2e/gui-example-webgl.test.ts`。
385
+ - **M18** ✅ WebGL 2。`webgl2_proto()` 在 WebGL 1 原型上增加 WebGL 2 常量与
386
+ 方法;`webgl_webgl2.cpp` 实现顶点数组对象与采样器/查询/栅栏句柄,
387
+ `webgl_draw.cpp` 增加实例化绘制(由 `vertexAttribDivisor` 决定输入频率)与
388
+ 整数属性,`webgl_texture.cpp` 增加 `texStorage2D` 与 `clearBuffer*`。着色器
389
+ 改写器为 `#version 300 es` 输出分配连续 location,块反射会把结构体字段展开
390
+ 成 three.js 灯光可寻址的成员。three.js r160 已在真实渲染器上跑通基础/标准/
391
+ Phong 材质、纹理、灯光、雾、精灵、线段、点与实例化;Canvas2D 回退已删除。
392
+ 示例 `examples/gui/webgl2-cubes`(64 个立方体,一次实例化绘制);e2e 见
393
+ `tests/e2e/gui-webgl2.test.ts` 与 `tests/e2e/gui-example-webgl2.test.ts`。
394
+ - **M19** ✅ 装饰性 CSS。`css_sheet.cpp` 解析嵌套 `@media` 块,
395
+ `media_query.cpp` 按视口求值(`matchMedia` 也用它);`css_selector.cpp`
396
+ 识别 `::before`/`::after`。`style.cpp` 把伪样式算进每次重算样式时重建的
397
+ arena、解析 `content`,布局在真实子元素前后插入它们的盒子。
398
+ `gradient_values.cpp` 建模背景层列表(线性/径向、形状/尺寸/位置/色标),
399
+ `paint_background.cpp` 绘制它,`paint_effects.cpp` 应用滤镜颜色函数与九次
400
+ 采样模糊/投影并生成 `text-shadow` run,`paint_clip.cpp`/`renderer_clip.cpp`
401
+ 对三角化的 `clip-path` 多边形裁剪几何。e2e 见
402
+ `tests/e2e/gui-effects.test.ts`。
328
403
 
@@ -58,8 +58,9 @@ TypeScript 编译器。
58
58
  - 预编译的运行时归档(`runtime/lib/<os>-<arch>/core.a`)。驱动会在首次使用时
59
59
  从随包发布的源码编译 C 运行时并缓存目标文件,所以第一次构建会更慢
60
60
  (见[首次构建与缓存](#首次构建与缓存));
61
- - GUI/media 的原生归档(`gui.a`、`media.a`)。如果你需要 `--ext gui` 或
62
- `--ext media`,请使用 Linux/macOS 的发布压缩包,或从源码检出中构建这些归档。
61
+ - GUI/media 的原生归档(`gui.a`/`gui.lib`、`media.a`/`media.lib`)。如果你需要
62
+ `--ext gui` 或 `--ext media`,请使用 Linux/macOS/Windows x64 的发布压缩包,
63
+ 或从源码检出中构建这些归档。
63
64
 
64
65
  ## 环境要求
65
66
 
@@ -339,8 +340,10 @@ jobs:
339
340
  目标文件名是内容哈希,因此旧缓存不会污染新构建。
340
341
  - xbintsc 只为**宿主**平台构建,不是交叉编译器:要给多个平台产出产物,请使用
341
342
  CI matrix(每个 OS/arch 一个 job)。
342
- - macOS runner 已经带有 Xcode Command Line Tools;Windows runner 需要安装 LLVM
343
- 与 MSVC 生成工具,产物是 `build\main.exe`。
343
+ - macOS runner 已经带有 Xcode Command Line Tools;Windows runner 需要安装
344
+ Visual Studio C++ 生成工具(MSVC + 自带的 LLVM),产物是 `build\main.exe`。
345
+ 在源码检出中可运行 `pwsh -File scripts/setup-vs-toolchain.ps1` 显式导入该
346
+ 工具链。
344
347
 
345
348
  ## npm 包还是发布压缩包?
346
349
 
@@ -348,7 +351,7 @@ jobs:
348
351
  | --- | --- | --- |
349
352
  | 需要 Node.js | 是,22+ | 否 |
350
353
  | 首次构建 | 从源码编译 C 运行时 | 直接链接预编译运行时 |
351
- | GUI / media 扩展 | 不包含 | Linux/macOS 压缩包包含 |
354
+ | GUI / media 扩展 | 不包含 | Linux/macOS 与 Windows x64 压缩包包含 |
352
355
  | 安装方式 | `npm install` + lockfile / provenance | 下载、校验 `.sha256`、解压 |
353
356
  | 编程 API | 有 | 无(仅 CLI) |
354
357
  | 交叉编译 | 否——只构建宿主平台 | 否——只构建宿主平台 |
@@ -383,7 +386,7 @@ jobs:
383
386
  | 第一次构建很慢 | 正常:正在编译并缓存运行时 C 源码。后续构建会复用 `.xbintsc/`;`--time` 可确认。如果冷启动必须快,请使用发布压缩包。 |
384
387
  | 写 `.xbintsc/` 权限错误 | 用 `xbintsc_CACHE_DIR` 指向可写目录,或在可写目录中运行。 |
385
388
  | `module 'fs' is provided by the 'node' extension` | 加 `--ext node`,或在配置里写 `"extensions": ["node"]`。 |
386
- | `GUI native library not found` / `media native library not found` | npm 包不包含 `gui.a`/`media.a`;请使用 Linux/macOS 发布压缩包,或从源码检出构建。 |
389
+ | `GUI native library not found` / `media native library not found` | npm 包不包含 `gui.a`/`gui.lib` 或 `media.a`/`media.lib`;请使用 Linux/macOS/Windows x64 发布压缩包,或从源码检出构建。 |
387
390
  | `require("xbintsc")` 失败 | 包只提供 ESM;使用 `import`(或动态 `import()`)。 |
388
391
  | Windows 链接时报缺少 MSVC 库 | 在 Native Tools 命令提示符中运行,安装 VS C++ 生成工具,并检查 `npx xbintsc doctor`。 |
389
392
  | `npm ci --omit=dev` 后构建找不到 `xbintsc` | 在构建阶段安装 devDependencies,或把 `xbintsc` 移到 `dependencies`。 |
@@ -116,19 +116,21 @@ sudo apk add clang lld # Alpine
116
116
  用 `clang --version` 验证。如果 xbintsc 用错了链接器,可用 `xbintsc_CLANG` 指定
117
117
  clang,并通过 `xbintsc_LINKER_ARGS` 追加参数(例如 `-fuse-ld=lld`)。
118
118
 
119
- ## Windows —— 安装 MSVC C++ 生成工具(与 LLVM)
119
+ ## Windows —— 安装 MSVC C++ 生成工具(含 LLVM)
120
120
 
121
- Windows 上的 xbintsc 面向 **MSVC ABI**。用 `winget` 安装 Visual Studio C++
122
- 生成工具和 LLVM:
121
+ Windows 上的 xbintsc 面向 **MSVC ABI**。一条 `winget` 命令即可安装 Visual
122
+ Studio C++ 工作负载、MSBuild,以及本地构建脚本与 CI 使用的 Clang 组件:
123
123
 
124
124
  ```powershell
125
- winget install -e --id LLVM.LLVM
126
125
  winget install -e --id Microsoft.VisualStudio.2022.BuildTools `
127
- --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
126
+ --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended"
128
127
  ```
129
128
 
130
129
  Visual Studio 2022 自带的 LLVM(`VC\Tools\Llvm\x64\bin\clang.exe`,当前版本
131
- 19.1.5)已经够用,独立安装的 LLVM 也可以。但编译器必须以 MSVC ABI 为目标
130
+ 19.1.5)就是 `scripts/setup-vs-toolchain.ps1` 选择的工具链。独立安装的 LLVM
131
+ (`winget install -e --id LLVM.LLVM`)对 `xbintsc` 本身也可用,但 GUI/媒体
132
+ 归档构建与 CI 都使用 Visual Studio 这一套,从而让运行时、预编译归档与最终
133
+ 二进制出自同一条工具链。无论哪种,编译器必须以 MSVC ABI 为目标
132
134
  (`Target: *-windows-msvc`):面向其他 Windows ABI 的 clang 无法与 MSVC
133
135
  运行库链接,`xbintsc` 会直接给出明确错误并拒绝使用。
134
136
 
@@ -141,6 +143,10 @@ Visual Studio 2022 自带的 LLVM(`VC\Tools\Llvm\x64\bin\clang.exe`,当前
141
143
  & "$env:ProgramFiles\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
142
144
  ```
143
145
 
146
+ 在源码检出中,`pwsh -File scripts/setup-vs-toolchain.ps1` 会完成同样的导入,
147
+ 并把 `xbintsc_CLANG` 指向该 Visual Studio 安装自带的 LLVM。CI 调用的是同一个
148
+ 脚本,因此本地构建、发布归档与 CI 共用一条 Visual Studio 工具链。
149
+
144
150
  用 `xbintsc doctor`(或 `clang --version`)验证;输出会列出解析到的编译器、
145
151
  版本与目标。
146
152
 
package/llms.txt CHANGED
@@ -75,6 +75,8 @@
75
75
  - [doc/gui/input.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/input.md): hit testing, events and `:hover`/`:focus`
76
76
  - [doc/gui/animation.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/animation.md): `requestAnimationFrame` and CSS transitions
77
77
  - [doc/gui/runtime.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/runtime.md): event loop integration, the native bridge and memory
78
+ - [doc/gui/canvas.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/canvas.md): `<canvas>` and the 2D context
79
+ - [doc/gui/webgl.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/webgl.md): WebGL 1.0 on the GPU — GLSL ES to SPIR-V, textures, framebuffers and readback
78
80
  - [doc/gui/build.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/build.md): building `gui.a` and running the examples
79
81
  - [doc/gui/known-issues.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui/known-issues.md): known issues and open questions
80
82
  - [doc/gui-scripts.md](https://raw.githubusercontent.com/zy445566/xbintsc/main/doc/gui-scripts.md): the GUI scripting surface
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xbintsc",
3
- "version": "0.5.31",
3
+ "version": "0.5.32",
4
4
  "description": "xbintsc - a TypeScript binary compiler (TypeScript -> LLVM IR -> native binary)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -156,15 +156,25 @@ xt_value win_location_get(xt_value self, xt_value env, int32_t argc, xt_value *a
156
156
  return g_location;
157
157
  }
158
158
 
159
- /** `matchMedia(query)` -> a MediaQueryList-shaped object. The engine has no
160
- * media queries of its own; a coarse-pointer probe is always false because a
161
- * window is driven by a mouse and a keyboard. */
159
+ xt_value media_list_build(const std::string &query, bool matches);
160
+
161
+ /** `matchMedia(query)` -> a MediaQueryList-shaped object evaluated against the
162
+ * current window's viewport, using the same evaluator as `@media` rules. The
163
+ * list is a snapshot (there is no live change event), which matches the
164
+ * engine's restyle-on-resize model. */
162
165
  xt_value win_match_media(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
163
- (void)self;
164
166
  (void)env;
165
- (void)argc;
166
- (void)argv;
167
- return g_media_list;
167
+ std::string query;
168
+ if (argc >= 1) query = cstr(xt_arg(argc, argv, 0));
169
+ XtGuiWindow *win = xt_gui_window_from_this(self);
170
+ if (win == NULL) {
171
+ xt_value handle = xt_gui_ensure_window();
172
+ win = xt_gui_window_from_this(handle);
173
+ }
174
+ float width = 0.0f;
175
+ float height = 0.0f;
176
+ if (win != NULL) xt_gui_window_viewport(win, &width, &height);
177
+ return media_list_build(query, xtgui::xt_css_media_matches(query, width, height));
168
178
  }
169
179
 
170
180
  /** `getComputedStyle(el)`: the engine exposes the element's style handle, which
@@ -243,10 +253,10 @@ xt_value location_build(void) {
243
253
  return location;
244
254
  }
245
255
 
246
- xt_value media_list_build(void) {
256
+ xt_value media_list_build(const std::string &query, bool matches) {
247
257
  xt_value list = xt_object_new();
248
- set_prop(list, "media", string_of(""));
249
- set_prop(list, "matches", XT_FALSE);
258
+ set_prop(list, "media", xt_string_from_cstr(query.c_str()));
259
+ set_prop(list, "matches", matches ? XT_TRUE : XT_FALSE);
250
260
  set_method(list, "addListener", (void *)noop);
251
261
  set_method(list, "removeListener", (void *)noop);
252
262
  set_method(list, "addEventListener", (void *)noop);
@@ -332,6 +342,21 @@ xt_value type_proto(const std::string &name) {
332
342
  return domapi::event_proto();
333
343
  }
334
344
  if (name == "AudioContext" || name == "webkitAudioContext") return xt_gui_audio_proto();
345
+ if (name == "WebGLRenderingContext") return domapi::webgl_proto();
346
+ if (name == "WebGL2RenderingContext") return domapi::webgl2_proto();
347
+ if (name == "WebGLBuffer") return domapi::webgl_object_proto("buffer");
348
+ if (name == "WebGLTexture") return domapi::webgl_object_proto("texture");
349
+ if (name == "WebGLShader") return domapi::webgl_object_proto("shader");
350
+ if (name == "WebGLProgram") return domapi::webgl_object_proto("program");
351
+ if (name == "WebGLFramebuffer") return domapi::webgl_object_proto("framebuffer");
352
+ if (name == "WebGLRenderbuffer") return domapi::webgl_object_proto("renderbuffer");
353
+ if (name == "WebGLUniformLocation") return domapi::webgl_object_proto("uniform");
354
+ if (name == "WebGLActiveInfo") return domapi::webgl_object_proto("info");
355
+ if (name == "WebGLVertexArrayObject") return domapi::webgl_object_proto("vertexarray");
356
+ if (name == "WebGLSampler") return domapi::webgl_object_proto("sampler");
357
+ if (name == "WebGLQuery") return domapi::webgl_object_proto("query");
358
+ if (name == "WebGLSync") return domapi::webgl_object_proto("sync");
359
+ if (name == "WebGLTransformFeedback") return domapi::webgl_object_proto("transformfeedback");
335
360
  return domapi::node_proto();
336
361
  }
337
362
 
@@ -382,6 +407,8 @@ void install_window_globals(xt_value win) {
382
407
  set_prop(win, "Audio", type_value("Audio"));
383
408
  set_prop(win, "Event", type_value("Event"));
384
409
  set_prop(win, "CustomEvent", type_value("CustomEvent"));
410
+ set_prop(win, "WebGLRenderingContext", type_value("WebGLRenderingContext"));
411
+ set_prop(win, "WebGL2RenderingContext", type_value("WebGL2RenderingContext"));
385
412
  set_prop(win, "isSecureContext", XT_TRUE);
386
413
  set_number(win, "screenX", 0);
387
414
  set_number(win, "screenY", 0);
@@ -402,7 +429,7 @@ void ensure_singletons(void) {
402
429
  xt_gc_add_root(&g_location);
403
430
  }
404
431
  if (!XT_IS_OBJECT(g_media_list)) {
405
- g_media_list = media_list_build();
432
+ g_media_list = media_list_build("", false);
406
433
  xt_gc_add_root(&g_media_list);
407
434
  }
408
435
  }
@@ -500,8 +527,7 @@ xt_value xt_browser_type(int32_t argc, xt_value *argv) {
500
527
  (void)argv;
501
528
  if (argc < 1) return XT_UNDEFINED;
502
529
  std::string name = cstr(xt_arg(argc, argv, 0));
503
- if (name == "WebGLRenderingContext" || name == "WebGL2RenderingContext" ||
504
- name == "XRWebGLLayer" || name == "XRWebGLBinding" || name == "OffscreenCanvas" ||
530
+ if (name == "XRWebGLLayer" || name == "XRWebGLBinding" || name == "OffscreenCanvas" ||
505
531
  name == "ImageBitmap" || name == "ImageData" || name == "Response" ||
506
532
  name == "ReadableStream" || name == "Request" || name == "Headers" ||
507
533
  name == "DOMParser") {
@@ -457,24 +457,9 @@ void Canvas2D::draw_image(const Image &source, float dx, float dy, float dw, flo
457
457
  canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, x0, y0, x1 - x0,
458
458
  y1 - y0, sx, sy, sw, sh, state_.global_alpha);
459
459
  } else {
460
- float cornersX[4], cornersY[4];
461
- const float corners[4][2] = {
462
- {dx, dy}, {dx + dw, dy}, {dx + dw, dy + dh}, {dx, dy + dh}};
463
- float minX = 0.0f, minY = 0.0f, maxX = 0.0f, maxY = 0.0f;
464
- for (int i = 0; i < 4; i++) {
465
- to_device(corners[i][0], corners[i][1], &cornersX[i], &cornersY[i]);
466
- if (i == 0) {
467
- minX = maxX = cornersX[i];
468
- minY = maxY = cornersY[i];
469
- } else {
470
- minX = std::min(minX, cornersX[i]);
471
- maxX = std::max(maxX, cornersX[i]);
472
- minY = std::min(minY, cornersY[i]);
473
- maxY = std::max(maxY, cornersY[i]);
474
- }
475
- }
476
- canvas_detail::draw_image(image_.pixels, image_.width, image_.height, source, minX, minY,
477
- 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);
478
463
  }
479
464
  generation_++;
480
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,
@@ -269,6 +269,66 @@ void draw_image(std::vector<unsigned char> &pixels, int width, int height, const
269
269
  }
270
270
  }
271
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
+ }
326
+ float color[4] = {texel[0] / 255.0f, texel[1] / 255.0f, texel[2] / 255.0f, texel[3] / 255.0f};
327
+ blend_pixel(dst, color, 1.0f, alpha);
328
+ }
329
+ }
330
+ }
331
+
272
332
  void blit_glyph(std::vector<unsigned char> &pixels, int width, int height,
273
333
  const std::vector<unsigned char> &glyph, int glyphWidth, int glyphHeight, int left,
274
334
  int top, float x, float baselineY, const CanvasPaint &paint, float alpha) {