xbintsc 0.5.45 → 0.5.52

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 (286) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +5 -4
  3. package/README.zh-CN.md +4 -3
  4. package/dist/src/cli/extensions.d.ts +24 -0
  5. package/dist/src/cli/extensions.js +62 -0
  6. package/dist/src/cli/extensions.js.map +1 -0
  7. package/dist/src/cli/help.d.ts +1 -1
  8. package/dist/src/cli/help.js +3 -1
  9. package/dist/src/cli/help.js.map +1 -1
  10. package/dist/src/cli/hints.js +8 -3
  11. package/dist/src/cli/hints.js.map +1 -1
  12. package/dist/src/cli/main.js +21 -28
  13. package/dist/src/cli/main.js.map +1 -1
  14. package/dist/src/diagnostics/diagnostic.d.ts +3 -1
  15. package/dist/src/diagnostics/diagnostic.js +2 -0
  16. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  17. package/dist/src/driver/build-key.d.ts +2 -0
  18. package/dist/src/driver/build-key.js +1 -0
  19. package/dist/src/driver/build-key.js.map +1 -1
  20. package/dist/src/driver/compiler.js +61 -8
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +4 -0
  23. package/dist/src/driver/config.js +2 -0
  24. package/dist/src/driver/config.js.map +1 -1
  25. package/dist/src/driver/link-features.d.ts +37 -0
  26. package/dist/src/driver/link-features.js +123 -0
  27. package/dist/src/driver/link-features.js.map +1 -0
  28. package/dist/src/driver/options.d.ts +10 -0
  29. package/dist/src/driver/runtime-objects.d.ts +5 -0
  30. package/dist/src/driver/runtime-objects.js +20 -1
  31. package/dist/src/driver/runtime-objects.js.map +1 -1
  32. package/dist/src/driver/usage.d.ts +23 -0
  33. package/dist/src/driver/usage.js +353 -0
  34. package/dist/src/driver/usage.js.map +1 -0
  35. package/dist/src/driver/version.d.ts +1 -1
  36. package/dist/src/driver/version.js +1 -1
  37. package/dist/src/extensions/catalog.js +1 -2
  38. package/dist/src/extensions/catalog.js.map +1 -1
  39. package/dist/src/extensions/gui/features.d.ts +34 -0
  40. package/dist/src/extensions/gui/features.js +165 -0
  41. package/dist/src/extensions/gui/features.js.map +1 -0
  42. package/dist/src/extensions/gui/index.js +10 -4
  43. package/dist/src/extensions/gui/index.js.map +1 -1
  44. package/dist/src/extensions/link-feature.d.ts +70 -0
  45. package/dist/src/extensions/link-feature.js +18 -0
  46. package/dist/src/extensions/link-feature.js.map +1 -0
  47. package/dist/src/extensions/registry.d.ts +24 -4
  48. package/dist/src/extensions/registry.js +26 -3
  49. package/dist/src/extensions/registry.js.map +1 -1
  50. package/dist/src/index.d.ts +3 -2
  51. package/dist/src/index.js +0 -1
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/tests/cli/hints.test.js +5 -7
  54. package/dist/tests/cli/hints.test.js.map +1 -1
  55. package/dist/tests/driver/link-features.test.js +105 -0
  56. package/dist/tests/driver/link-features.test.js.map +1 -0
  57. package/dist/tests/driver/usage.test.d.ts +1 -0
  58. package/dist/tests/driver/usage.test.js +88 -0
  59. package/dist/tests/driver/usage.test.js.map +1 -0
  60. package/dist/tests/e2e/gui-audio.test.js +4 -4
  61. package/dist/tests/e2e/gui-audio.test.js.map +1 -1
  62. package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
  63. package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
  64. package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
  65. package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
  66. package/dist/tests/e2e/gui-css-features.test.js +270 -0
  67. package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
  68. package/dist/tests/e2e/gui-effects.test.js +92 -11
  69. package/dist/tests/e2e/gui-effects.test.js.map +1 -1
  70. package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
  71. package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
  72. package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
  74. package/dist/tests/e2e/gui-font-face.test.js +142 -0
  75. package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
  76. package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
  77. package/dist/tests/e2e/gui-fonts.test.js +150 -0
  78. package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
  79. package/dist/tests/e2e/gui-helpers.d.ts +10 -1
  80. package/dist/tests/e2e/gui-helpers.js +6 -0
  81. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  82. package/dist/tests/e2e/gui-layout.test.js +7 -3
  83. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  84. package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
  85. package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
  86. package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
  87. package/dist/tests/e2e/gui-media.test.d.ts +5 -4
  88. package/dist/tests/e2e/gui-media.test.js +9 -9
  89. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  90. package/dist/tests/e2e/gui-paint.test.js +5 -2
  91. package/dist/tests/e2e/gui-paint.test.js.map +1 -1
  92. package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
  93. package/dist/tests/e2e/gui-shaping.test.js +47 -0
  94. package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
  95. package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
  96. package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
  97. package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
  98. package/dist/tests/e2e/gui-transform.test.js +3 -2
  99. package/dist/tests/e2e/gui-transform.test.js.map +1 -1
  100. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
  101. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
  102. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
  103. package/dist/tests/extensions/gui-features.test.d.ts +1 -0
  104. package/dist/tests/extensions/gui-features.test.js +175 -0
  105. package/dist/tests/extensions/gui-features.test.js.map +1 -0
  106. package/doc/ai/cli.md +5 -1
  107. package/doc/ai/extensions.md +56 -26
  108. package/doc/ai/troubleshooting.md +10 -7
  109. package/doc/ai/zh-CN/cli.md +5 -1
  110. package/doc/ai/zh-CN/extensions.md +48 -22
  111. package/doc/ai/zh-CN/troubleshooting.md +6 -5
  112. package/doc/gui/animation.md +39 -9
  113. package/doc/gui/api.md +2 -1
  114. package/doc/gui/build.md +137 -19
  115. package/doc/gui/canvas.md +1 -1
  116. package/doc/gui/dom.md +20 -4
  117. package/doc/gui/known-issues.md +63 -26
  118. package/doc/gui/layout.md +31 -8
  119. package/doc/gui/media.md +13 -7
  120. package/doc/gui/rendering.md +114 -39
  121. package/doc/gui/runtime.md +5 -0
  122. package/doc/gui/webgl.md +24 -6
  123. package/doc/gui.md +110 -47
  124. package/doc/implemented/cli.md +2 -0
  125. package/doc/implemented/extensions.md +9 -3
  126. package/doc/npm-package.md +4 -4
  127. package/doc/xbintsc.config.schema.json +10 -0
  128. package/doc/zh-CN/gui/animation.md +33 -10
  129. package/doc/zh-CN/gui/api.md +2 -1
  130. package/doc/zh-CN/gui/build.md +110 -16
  131. package/doc/zh-CN/gui/canvas.md +1 -1
  132. package/doc/zh-CN/gui/dom.md +16 -3
  133. package/doc/zh-CN/gui/known-issues.md +45 -15
  134. package/doc/zh-CN/gui/layout.md +23 -6
  135. package/doc/zh-CN/gui/media.md +11 -6
  136. package/doc/zh-CN/gui/rendering.md +84 -26
  137. package/doc/zh-CN/gui/runtime.md +3 -0
  138. package/doc/zh-CN/gui/webgl.md +3 -3
  139. package/doc/zh-CN/gui.md +92 -41
  140. package/doc/zh-CN/implemented/cli.md +2 -0
  141. package/doc/zh-CN/implemented/extensions.md +9 -3
  142. package/doc/zh-CN/npm-package.md +4 -3
  143. package/package.json +7 -7
  144. package/runtime/ext_gui/animation_values.cpp +425 -0
  145. package/runtime/ext_gui/animation_values.h +64 -0
  146. package/runtime/ext_gui/browser.cpp +22 -15
  147. package/runtime/ext_gui/browser_loop.cpp +13 -1
  148. package/runtime/ext_gui/canvas.h +1 -1
  149. package/runtime/ext_gui/canvas_raster.cpp +1 -1
  150. package/runtime/ext_gui/canvas_text.cpp +1 -1
  151. package/runtime/ext_gui/css.cpp +172 -21
  152. package/runtime/ext_gui/css.h +75 -4
  153. package/runtime/ext_gui/css_match.cpp +4 -0
  154. package/runtime/ext_gui/css_sheet.cpp +218 -2
  155. package/runtime/ext_gui/document.cpp +42 -192
  156. package/runtime/ext_gui/document.h +25 -12
  157. package/runtime/ext_gui/document_animation.cpp +428 -0
  158. package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
  159. package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
  160. package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
  161. package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
  162. package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
  163. package/runtime/ext_gui/dom_api_style.cpp +7 -0
  164. package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
  165. package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
  166. package/runtime/ext_gui/effect_values.cpp +245 -21
  167. package/runtime/ext_gui/gpu_bridge.c +28 -0
  168. package/runtime/ext_gui/gpu_feature.cpp +30 -0
  169. package/runtime/ext_gui/gpu_shader.cpp +22 -0
  170. package/runtime/ext_gui/gpu_shader_api.h +50 -0
  171. package/runtime/ext_gui/gradient_values.cpp +24 -0
  172. package/runtime/ext_gui/grid_values.cpp +23 -0
  173. package/runtime/ext_gui/gui.cpp +6 -37
  174. package/runtime/ext_gui/gui_canvas.cpp +14 -6
  175. package/runtime/ext_gui/gui_cursor.cpp +50 -0
  176. package/runtime/ext_gui/gui_engine.h +1 -18
  177. package/runtime/ext_gui/gui_events.cpp +19 -6
  178. package/runtime/ext_gui/gui_internal.h +3 -0
  179. package/runtime/ext_gui/gui_webgl.cpp +25 -10
  180. package/runtime/ext_gui/image_api.cpp +18 -0
  181. package/runtime/ext_gui/image_api.h +43 -0
  182. package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
  183. package/runtime/ext_gui/image_bridge.c +22 -0
  184. package/runtime/ext_gui/image_feature.cpp +107 -0
  185. package/runtime/ext_gui/inline_svg.cpp +95 -8
  186. package/runtime/ext_gui/inline_svg.h +5 -1
  187. package/runtime/ext_gui/layout.cpp +15 -9
  188. package/runtime/ext_gui/layout.h +8 -2
  189. package/runtime/ext_gui/layout_flex.cpp +134 -29
  190. package/runtime/ext_gui/layout_flow.cpp +58 -7
  191. package/runtime/ext_gui/layout_flow_internal.h +39 -4
  192. package/runtime/ext_gui/layout_grid.cpp +31 -0
  193. package/runtime/ext_gui/layout_inline.cpp +26 -2
  194. package/runtime/ext_gui/layout_vertical.cpp +196 -0
  195. package/runtime/ext_gui/media.cpp +4 -2
  196. package/runtime/ext_gui/media.h +3 -3
  197. package/runtime/ext_gui/media_api.h +7 -6
  198. package/runtime/ext_gui/paint.cpp +67 -9
  199. package/runtime/ext_gui/paint.h +61 -8
  200. package/runtime/ext_gui/paint_backdrop.cpp +211 -0
  201. package/runtime/ext_gui/paint_background.cpp +175 -97
  202. package/runtime/ext_gui/paint_effects.cpp +12 -6
  203. package/runtime/ext_gui/paint_internal.h +27 -0
  204. package/runtime/ext_gui/paint_outline.cpp +44 -0
  205. package/runtime/ext_gui/paint_shadow.cpp +368 -0
  206. package/runtime/ext_gui/renderer.cpp +15 -7
  207. package/runtime/ext_gui/renderer.h +11 -2
  208. package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
  209. package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
  210. package/runtime/ext_gui/renderer_gradient.cpp +51 -17
  211. package/runtime/ext_gui/renderer_image.cpp +19 -7
  212. package/runtime/ext_gui/renderer_internal.h +21 -0
  213. package/runtime/ext_gui/renderer_layer.cpp +37 -6
  214. package/runtime/ext_gui/renderer_text.cpp +2 -1
  215. package/runtime/ext_gui/stb_truetype.h +5077 -0
  216. package/runtime/ext_gui/style.cpp +62 -8
  217. package/runtime/ext_gui/style.h +111 -4
  218. package/runtime/ext_gui/style_cascade.cpp +83 -0
  219. package/runtime/ext_gui/style_internal.h +13 -1
  220. package/runtime/ext_gui/style_length.cpp +92 -0
  221. package/runtime/ext_gui/style_print.cpp +83 -2
  222. package/runtime/ext_gui/style_svg.cpp +40 -0
  223. package/runtime/ext_gui/style_text.cpp +302 -0
  224. package/runtime/ext_gui/style_ui.cpp +150 -0
  225. package/runtime/ext_gui/style_values.cpp +76 -62
  226. package/runtime/ext_gui/style_values_internal.h +23 -0
  227. package/runtime/ext_gui/text.cpp +27 -499
  228. package/runtime/ext_gui/text.h +18 -9
  229. package/runtime/ext_gui/text_api.h +45 -0
  230. package/runtime/ext_gui/text_bridge.c +23 -0
  231. package/runtime/ext_gui/text_cache.cpp +12 -3
  232. package/runtime/ext_gui/text_font_db.cpp +427 -0
  233. package/runtime/ext_gui/text_font_paths.cpp +250 -0
  234. package/runtime/ext_gui/text_font_paths.h +39 -0
  235. package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
  236. package/runtime/ext_gui/text_font_sfnt.h +44 -0
  237. package/runtime/ext_gui/text_fonts.cpp +348 -0
  238. package/runtime/ext_gui/text_fonts.h +78 -0
  239. package/runtime/ext_gui/text_fonts_internal.h +77 -0
  240. package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
  241. package/runtime/ext_gui/text_hb.cpp +438 -0
  242. package/runtime/ext_gui/text_stb.cpp +369 -0
  243. package/runtime/ext_gui/transform.cpp +107 -9
  244. package/runtime/ext_gui/transform.h +5 -0
  245. package/runtime/ext_gui/webgl_api.cpp +19 -0
  246. package/runtime/ext_gui/webgl_api.h +53 -0
  247. package/runtime/ext_gui/webgl_bridge.c +25 -0
  248. package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
  249. package/runtime/ext_gui/webgl_feature.cpp +82 -0
  250. package/runtime/ext_gui/webgl_feature.h +28 -0
  251. package/runtime/ext_gui/webgl_msl.cpp +41 -0
  252. package/runtime/ext_gui/webgl_msl.h +6 -0
  253. package/runtime/ext_gui/webgl_shader.cpp +40 -32
  254. package/runtime/ext_gui/window.cpp +7 -7
  255. package/runtime/ext_media/decode_audio.cpp +1 -1
  256. package/runtime/ext_media/media.cpp +1 -1
  257. package/runtime/ext_media/media_bridge.c +7 -7
  258. package/scripts/build-gui.ts +97 -98
  259. package/scripts/check-file-length.ts +1 -0
  260. package/scripts/gui-build-options.ts +122 -0
  261. package/src/cli/extensions.ts +72 -0
  262. package/src/cli/help.ts +3 -1
  263. package/src/cli/hints.ts +9 -3
  264. package/src/cli/main.ts +21 -27
  265. package/src/diagnostics/diagnostic.ts +2 -0
  266. package/src/driver/build-key.ts +3 -0
  267. package/src/driver/compiler.ts +63 -8
  268. package/src/driver/config.ts +6 -0
  269. package/src/driver/link-features.ts +163 -0
  270. package/src/driver/options.ts +10 -0
  271. package/src/driver/runtime-objects.ts +26 -1
  272. package/src/driver/usage.ts +376 -0
  273. package/src/driver/version.ts +1 -1
  274. package/src/extensions/catalog.ts +1 -2
  275. package/src/extensions/gui/features.ts +166 -0
  276. package/src/extensions/gui/index.ts +10 -4
  277. package/src/extensions/link-feature.ts +72 -0
  278. package/src/extensions/registry.ts +45 -4
  279. package/src/index.ts +3 -2
  280. package/dist/src/extensions/media/index.d.ts +0 -28
  281. package/dist/src/extensions/media/index.js +0 -59
  282. package/dist/src/extensions/media/index.js.map +0 -1
  283. package/dist/tests/extensions/media.test.js +0 -63
  284. package/dist/tests/extensions/media.test.js.map +0 -1
  285. package/src/extensions/media/index.ts +0 -65
  286. /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
@@ -4,7 +4,14 @@
4
4
 
5
5
  #include "document.h"
6
6
 
7
+ #include <cmath>
8
+ #include <string>
9
+ #include <utility>
10
+ #include <vector>
11
+
7
12
  #include "perf.h"
13
+ #include "style_internal.h"
14
+ #include "text_fonts.h"
8
15
 
9
16
  namespace xtgui {
10
17
 
@@ -30,15 +37,37 @@ void XtDocument::load(const std::string &html, float viewportWidth, float viewpo
30
37
  dirty_ = false;
31
38
  hover_ = nullptr;
32
39
  focus_ = nullptr;
40
+ active_ = nullptr;
33
41
  styles_.clear();
34
42
  display_.clear();
35
43
  transitions_.clear();
44
+ animations_.clear();
36
45
  mediaSizes_.clear();
37
46
  canvasInfo_.clear();
38
47
  clock_ms_ = 0.0;
39
48
  std::string css;
40
49
  collectStyleText(root_.get(), &css);
41
50
  sheet_ = xt_css_parse_stylesheet(css);
51
+
52
+ /* Author `@font-face` families are global to the process's text stack, so a
53
+ * new document replaces the previous set before its first layout. */
54
+ std::vector<UserFontFace> user_faces;
55
+ user_faces.reserve(sheet_.font_faces.size());
56
+ for (const FontFaceRule &rule : sheet_.font_faces) {
57
+ UserFontFace face;
58
+ face.family = rule.family;
59
+ face.sources.reserve(rule.sources.size());
60
+ for (const FontFaceSource &source : rule.sources) {
61
+ face.sources.push_back(UserFontSource{source.url, source.format});
62
+ }
63
+ face.has_weight = rule.has_weight;
64
+ face.weight_min = rule.weight_min;
65
+ face.weight_max = rule.weight_max;
66
+ face.has_italic = rule.has_italic;
67
+ face.italic = rule.italic;
68
+ user_faces.push_back(std::move(face));
69
+ }
70
+ xt_font_set_user_faces(user_faces);
42
71
  restyle(viewportWidth, viewportHeight);
43
72
  }
44
73
 
@@ -50,206 +79,19 @@ void XtDocument::restyle(float viewportWidth, float viewportHeight) {
50
79
  MatchState state;
51
80
  state.hover = hover_;
52
81
  state.focus = focus_;
82
+ state.active = active_;
53
83
  bool hasTransitions = sheet_.has_transitions;
84
+ bool hasAnimations = sheet_.has_animations;
54
85
  xt_style_compute(root_.get(), sheet_, styles_, viewportWidth, viewportHeight, state, &pseudos_,
55
- &hasTransitions);
86
+ &hasTransitions, &hasAnimations);
56
87
  has_transitions_ = hasTransitions;
88
+ has_animations_ = hasAnimations;
57
89
  startTransitions();
90
+ startAnimations();
58
91
  updateDisplay();
59
92
  }
60
93
  }
61
94
 
62
- namespace {
63
-
64
- float easeProgress(float t, TimingFunction timing) {
65
- if (t <= 0.0f) return 0.0f;
66
- if (t >= 1.0f) return 1.0f;
67
- switch (timing) {
68
- case TimingFunction::Linear:
69
- return t;
70
- case TimingFunction::EaseIn:
71
- return t * t * t;
72
- case TimingFunction::EaseOut: {
73
- float u = 1.0f - t;
74
- return 1.0f - u * u * u;
75
- }
76
- case TimingFunction::EaseInOut:
77
- return t < 0.5f ? 4.0f * t * t * t : 1.0f - 4.0f * (1.0f - t) * (1.0f - t) * (1.0f - t);
78
- case TimingFunction::Ease:
79
- default:
80
- return t * t * (3.0f - 2.0f * t); // smoothstep approximation of `ease`
81
- }
82
- }
83
-
84
- float mix(float a, float b, float t) { return a + (b - a) * t; }
85
-
86
- const float *colorOf(const XtStyle &style, const std::string &property) {
87
- static const float transparent[4] = {0, 0, 0, 0};
88
- if (property == "background-color") {
89
- return style.has_background ? &style.background.r : transparent;
90
- }
91
- if (property == "border-color") {
92
- return style.has_border_color ? &style.border_color.r : transparent;
93
- }
94
- return &style.color.r;
95
- }
96
-
97
- float numberOf(const XtStyle &style, const std::string &property) {
98
- if (property == "border-radius") return style.border_radius;
99
- return 0.0f;
100
- }
101
-
102
- bool isNumberProperty(const std::string &property) { return property == "border-radius"; }
103
-
104
- bool specMatches(const std::string &spec, const std::string &property) {
105
- return spec == "all" || spec == property;
106
- }
107
-
108
- void applyColor(XtStyle *style, const std::string &property, const float *rgba) {
109
- if (property == "background-color") {
110
- style->background = Color{rgba[0], rgba[1], rgba[2], rgba[3], true};
111
- style->has_background = rgba[3] > 0.0f;
112
- } else if (property == "border-color") {
113
- style->border_color = Color{rgba[0], rgba[1], rgba[2], rgba[3], true};
114
- style->has_border_color = rgba[3] > 0.0f;
115
- } else {
116
- style->color = Color{rgba[0], rgba[1], rgba[2], rgba[3], true};
117
- }
118
- }
119
-
120
- void applyNumber(XtStyle *style, const std::string &property, float value) {
121
- if (property == "border-radius") style->border_radius = value;
122
- }
123
-
124
- } // namespace
125
-
126
- void XtDocument::startTransitions() {
127
- if (display_.empty()) return; // first style computation: nothing to animate from
128
- /* Without a `transition` declaration anywhere in the sheet (or in an inline
129
- * style) no transition can start, so skip the O(nodes) scan `restyle` would
130
- * otherwise do every time. */
131
- if (!has_transitions_) return;
132
- static const char *const kProperties[] = {"background-color", "color", "border-color",
133
- "border-radius", "transform"};
134
- for (auto &entry : styles_) {
135
- const Node *node = entry.first;
136
- const XtStyle &target = entry.second;
137
- /* Generated boxes are rebuilt on every restyle; a transition keyed by one
138
- * would address a node that no longer exists. */
139
- if (node->is_pseudo) continue;
140
- if (target.transitions.empty()) continue;
141
- auto prev_it = display_.find(node);
142
- if (prev_it == display_.end()) continue;
143
- const XtStyle &current = prev_it->second;
144
- for (const TransitionSpec &spec : target.transitions) {
145
- if (spec.duration <= 0.0f) continue;
146
- for (const char *property : kProperties) {
147
- if (!specMatches(spec.property, property)) continue;
148
- ActiveTransition running;
149
- running.node = node;
150
- running.property = property;
151
- running.timing = spec.timing;
152
- running.duration_ms = spec.duration * 1000.0f;
153
- running.delay_ms = spec.delay * 1000.0f;
154
- running.start_ms = (float)clock_ms_ + running.delay_ms;
155
- if (std::string(property) == "transform") {
156
- if (xt_transform_equal(current.transform, target.transform)) continue;
157
- std::vector<TransformOp> probe;
158
- /* Lists of a different shape (or with clashing units) cannot be
159
- * mixed; such a change snaps instead of animating. */
160
- if (!xt_transform_interpolate(current.transform, target.transform, 0.5f, &probe)) {
161
- continue;
162
- }
163
- running.is_transform = true;
164
- running.from_transform = current.transform;
165
- running.to_transform = target.transform;
166
- } else if (isNumberProperty(property)) {
167
- float from = numberOf(current, property);
168
- float to = numberOf(target, property);
169
- if (from == to) continue;
170
- running.is_color = false;
171
- running.from_number = from;
172
- running.to_number = to;
173
- } else {
174
- const float *from = colorOf(current, property);
175
- const float *to = colorOf(target, property);
176
- if (from[0] == to[0] && from[1] == to[1] && from[2] == to[2] && from[3] == to[3]) continue;
177
- running.is_color = true;
178
- for (int i = 0; i < 4; i++) {
179
- running.from_color[i] = from[i];
180
- running.to_color[i] = to[i];
181
- }
182
- }
183
- /* Retarget an existing transition (mid-flight) instead of stacking. */
184
- bool replaced = false;
185
- for (ActiveTransition &existing : transitions_) {
186
- if (existing.node == node && existing.property == property) {
187
- existing = running;
188
- replaced = true;
189
- break;
190
- }
191
- }
192
- if (!replaced) transitions_.push_back(running);
193
- }
194
- }
195
- }
196
- }
197
-
198
- void XtDocument::updateDisplay() {
199
- /* Without a `transition` declaration in the sheet (or an inline style) no
200
- * transition can ever start, so the displayed style *is* the cascade result:
201
- * skip the per-node deep copy of the whole style map (and keep `display_`
202
- * empty, which `styleOf` already falls back from). */
203
- if (!has_transitions_) {
204
- if (!transitions_.empty()) transitions_.clear();
205
- if (!display_.empty()) display_.clear();
206
- layout_.compute(root_.get(), styles_, viewportWidth_, viewportHeight_, &mediaSizes_,
207
- &canvasInfo_);
208
- return;
209
- }
210
- display_ = styles_;
211
- for (size_t i = 0; i < transitions_.size();) {
212
- ActiveTransition &transition = transitions_[i];
213
- auto node_it = display_.find(transition.node);
214
- if (node_it == display_.end()) {
215
- transitions_.erase(transitions_.begin() + (long)i);
216
- continue;
217
- }
218
- float elapsed = (float)clock_ms_ - transition.start_ms;
219
- float progress = transition.duration_ms > 0.0f ? elapsed / transition.duration_ms : 1.0f;
220
- if (progress > 1.0f) progress = 1.0f;
221
- float eased = easeProgress(progress, transition.timing);
222
- XtStyle &style = node_it->second;
223
- if (transition.is_transform) {
224
- std::vector<TransformOp> mixed;
225
- if (xt_transform_interpolate(transition.from_transform, transition.to_transform, eased,
226
- &mixed)) {
227
- style.transform = mixed;
228
- }
229
- } else if (transition.is_color) {
230
- float rgba[4];
231
- for (int c = 0; c < 4; c++) rgba[c] = mix(transition.from_color[c], transition.to_color[c], eased);
232
- applyColor(&style, transition.property, rgba);
233
- } else {
234
- applyNumber(&style, transition.property, mix(transition.from_number, transition.to_number, eased));
235
- }
236
- if (progress >= 1.0f) {
237
- transitions_.erase(transitions_.begin() + (long)i);
238
- } else {
239
- i++;
240
- }
241
- }
242
- layout_.compute(root_.get(), display_, viewportWidth_, viewportHeight_, &mediaSizes_,
243
- &canvasInfo_);
244
- }
245
-
246
- bool XtDocument::advance(double delta_ms) {
247
- clock_ms_ += delta_ms;
248
- if (transitions_.empty()) return false;
249
- updateDisplay();
250
- return true;
251
- }
252
-
253
95
  bool XtDocument::setHover(const Node *node) {
254
96
  if (hover_ == node) return false;
255
97
  hover_ = node;
@@ -267,6 +109,14 @@ bool XtDocument::setFocus(const Node *node) {
267
109
  return true;
268
110
  }
269
111
 
112
+ bool XtDocument::setActive(const Node *node) {
113
+ if (active_ == node) return false;
114
+ active_ = node;
115
+ if (!sheet_.has_active) return false;
116
+ restyle(viewportWidth_, viewportHeight_);
117
+ return true;
118
+ }
119
+
270
120
  const XtStyle *XtDocument::styleOf(const Node *node) const {
271
121
  auto it = display_.find(node);
272
122
  if (it != display_.end()) return &it->second;
@@ -13,6 +13,7 @@
13
13
  #include <unordered_map>
14
14
  #include <vector>
15
15
 
16
+ #include "animation_values.h"
16
17
  #include "css.h"
17
18
  #include "dom.h"
18
19
  #include "layout.h"
@@ -20,22 +21,24 @@
20
21
 
21
22
  namespace xtgui {
22
23
 
23
- /** A running CSS transition (paint-affecting properties, plus `transform`). */
24
+ /** A running CSS transition. */
24
25
  struct ActiveTransition {
25
26
  const Node *node = nullptr;
26
27
  std::string property;
27
- bool is_color = false;
28
- bool is_transform = false;
29
- float from_color[4] = {0, 0, 0, 0};
30
- float to_color[4] = {0, 0, 0, 0};
31
- float from_number = 0;
32
- float to_number = 0;
33
- std::vector<TransformOp> from_transform;
34
- std::vector<TransformOp> to_transform;
28
+ AnimatableValue from;
29
+ AnimatableValue to;
35
30
  float start_ms = 0; // when interpolation begins (after `delay`)
36
31
  float duration_ms = 0;
37
32
  float delay_ms = 0;
38
- TimingFunction timing = TimingFunction::Ease;
33
+ TimingFunction timing;
34
+ };
35
+
36
+ /** A running `@keyframes` animation on one element. */
37
+ struct ActiveAnimation {
38
+ const Node *node = nullptr;
39
+ std::string name;
40
+ AnimationSpec spec;
41
+ float start_ms = 0;
39
42
  };
40
43
 
41
44
  class XtDocument {
@@ -48,17 +51,21 @@ class XtDocument {
48
51
  * and layout when a transition is running. Returns true when anything
49
52
  * transitioned (the caller should repaint). */
50
53
  bool advance(double delta_ms);
51
- /** True while at least one transition is running. */
52
- bool animating() const { return !transitions_.empty(); }
54
+ /** True while at least one transition or animation is running. */
55
+ bool animating() const { return !transitions_.empty() || !animations_.empty(); }
53
56
  /** Set the hovered/focused element; restyles when it changed. Returns true
54
57
  * when the dynamic state (and therefore the styles) changed. */
55
58
  bool setHover(const Node *node);
56
59
  bool setFocus(const Node *node);
60
+ /** Element held down by the primary pointer (`:active`). */
61
+ bool setActive(const Node *node);
57
62
  const Node *hover() const { return hover_; }
58
63
  const Node *focus() const { return focus_; }
64
+ const Node *active() const { return active_; }
59
65
 
60
66
  const Node *root() const { return root_.get(); }
61
67
  const StyleSheet &sheet() const { return sheet_; }
68
+ const std::unordered_map<const Node *, XtStyle> &styles() const { return styles_; }
62
69
  const XtStyle *styleOf(const Node *node) const;
63
70
  const LayoutBox *boxOf(const Node *node) const;
64
71
  const LayoutTree &layout() const { return layout_; }
@@ -117,7 +124,9 @@ class XtDocument {
117
124
  private:
118
125
  void collectStyleText(const Node *node, std::string *out) const;
119
126
  void startTransitions();
127
+ void startAnimations();
120
128
  void updateDisplay();
129
+ void applyAnimations(std::unordered_map<const Node *, XtStyle> *out);
121
130
 
122
131
  std::unique_ptr<Node> root_;
123
132
  /** Detached nodes (created or removed) stay alive here so handles remain valid. */
@@ -131,14 +140,18 @@ class XtDocument {
131
140
  MediaSizeMap mediaSizes_; // `<video>` intrinsic sizes
132
141
  CanvasInfoMap canvasInfo_; // `<canvas>` sizes + ids
133
142
  std::vector<ActiveTransition> transitions_;
143
+ std::vector<ActiveAnimation> animations_;
134
144
  /** Whether any computed style declares a `transition` (from the sheet or an
135
145
  * inline `style="…"`): when false the document skips the transition snapshot
136
146
  * and `display_` stays empty. */
137
147
  bool has_transitions_ = false;
148
+ /** Whether any computed style declares an `animation`. */
149
+ bool has_animations_ = false;
138
150
  double clock_ms_ = 0.0;
139
151
  LayoutTree layout_;
140
152
  const Node *hover_ = nullptr;
141
153
  const Node *focus_ = nullptr;
154
+ const Node *active_ = nullptr;
142
155
  float viewportWidth_ = 0.0f;
143
156
  float viewportHeight_ = 0.0f;
144
157
  };