xbintsc 0.3.69 → 0.3.79

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 (99) hide show
  1. package/README.md +59 -4
  2. package/README.zh-CN.md +52 -2
  3. package/dist/tests/e2e/gui-advanced.test.d.ts +6 -0
  4. package/dist/tests/e2e/gui-advanced.test.js +261 -0
  5. package/dist/tests/e2e/gui-advanced.test.js.map +1 -0
  6. package/dist/tests/e2e/gui-canvas.test.d.ts +9 -0
  7. package/dist/tests/e2e/gui-canvas.test.js +233 -0
  8. package/dist/tests/e2e/gui-canvas.test.js.map +1 -0
  9. package/dist/tests/e2e/gui-example.test.d.ts +1 -1
  10. package/dist/tests/e2e/gui-example.test.js +2 -2
  11. package/dist/tests/e2e/gui-helpers.d.ts +3 -0
  12. package/dist/tests/e2e/gui-helpers.js +5 -0
  13. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  14. package/dist/tests/e2e/gui-layout.test.js +73 -0
  15. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  16. package/dist/tests/e2e/gui-media.test.d.ts +8 -0
  17. package/dist/tests/e2e/gui-media.test.js +119 -0
  18. package/dist/tests/e2e/gui-media.test.js.map +1 -0
  19. package/dist/tests/e2e/gui-paint.test.js +40 -0
  20. package/dist/tests/e2e/gui-paint.test.js.map +1 -1
  21. package/doc/ai/extensions.md +16 -3
  22. package/doc/ai/zh-CN/extensions.md +10 -3
  23. package/doc/gui/animation.md +46 -0
  24. package/doc/gui/api.md +92 -0
  25. package/doc/gui/build.md +91 -0
  26. package/doc/gui/canvas.md +98 -0
  27. package/doc/gui/dom.md +123 -0
  28. package/doc/gui/input.md +22 -0
  29. package/doc/gui/known-issues.md +66 -0
  30. package/doc/gui/layout.md +72 -0
  31. package/doc/gui/media.md +87 -0
  32. package/doc/gui/rendering.md +98 -0
  33. package/doc/gui/runtime.md +88 -0
  34. package/doc/gui-scripts.md +7 -3
  35. package/doc/gui.md +80 -612
  36. package/doc/implemented.md +1 -0
  37. package/doc/zh-CN/gui/animation.md +46 -0
  38. package/doc/zh-CN/gui/api.md +88 -0
  39. package/doc/zh-CN/gui/build.md +84 -0
  40. package/doc/zh-CN/gui/canvas.md +80 -0
  41. package/doc/zh-CN/gui/dom.md +114 -0
  42. package/doc/zh-CN/gui/input.md +21 -0
  43. package/doc/zh-CN/gui/known-issues.md +50 -0
  44. package/doc/zh-CN/gui/layout.md +60 -0
  45. package/doc/zh-CN/gui/media.md +71 -0
  46. package/doc/zh-CN/gui/rendering.md +81 -0
  47. package/doc/zh-CN/gui/runtime.md +76 -0
  48. package/doc/zh-CN/gui-scripts.md +6 -2
  49. package/doc/zh-CN/gui.md +64 -532
  50. package/doc/zh-CN/implemented.md +1 -0
  51. package/llms.txt +15 -2
  52. package/package.json +1 -1
  53. package/runtime/ext_gui/canvas.cpp +580 -0
  54. package/runtime/ext_gui/canvas.h +170 -0
  55. package/runtime/ext_gui/canvas_internal.h +59 -0
  56. package/runtime/ext_gui/canvas_raster.cpp +254 -0
  57. package/runtime/ext_gui/document.cpp +24 -1
  58. package/runtime/ext_gui/document.h +11 -0
  59. package/runtime/ext_gui/dom_api.cpp +3 -0
  60. package/runtime/ext_gui/dom_api_canvas.cpp +548 -0
  61. package/runtime/ext_gui/dom_api_internal.h +73 -0
  62. package/runtime/ext_gui/dom_api_media.cpp +274 -0
  63. package/runtime/ext_gui/dom_api_proto.cpp +80 -0
  64. package/runtime/ext_gui/gui.cpp +6 -0
  65. package/runtime/ext_gui/gui_canvas.cpp +95 -0
  66. package/runtime/ext_gui/gui_engine.h +49 -0
  67. package/runtime/ext_gui/gui_events.cpp +21 -5
  68. package/runtime/ext_gui/gui_media.cpp +193 -0
  69. package/runtime/ext_gui/image.cpp +31 -12
  70. package/runtime/ext_gui/image.h +20 -7
  71. package/runtime/ext_gui/layout.cpp +52 -5
  72. package/runtime/ext_gui/layout.h +33 -1
  73. package/runtime/ext_gui/layout_flex.cpp +263 -99
  74. package/runtime/ext_gui/layout_flow.cpp +85 -9
  75. package/runtime/ext_gui/layout_flow_internal.h +84 -5
  76. package/runtime/ext_gui/layout_inline.cpp +54 -37
  77. package/runtime/ext_gui/media.cpp +514 -0
  78. package/runtime/ext_gui/media.h +104 -0
  79. package/runtime/ext_gui/nanosvg.h +3278 -0
  80. package/runtime/ext_gui/nanosvgrast.h +1472 -0
  81. package/runtime/ext_gui/paint.cpp +123 -38
  82. package/runtime/ext_gui/paint.h +36 -6
  83. package/runtime/ext_gui/renderer.cpp +113 -10
  84. package/runtime/ext_gui/renderer.h +49 -9
  85. package/runtime/ext_gui/renderer_image.cpp +203 -77
  86. package/runtime/ext_gui/renderer_internal.h +6 -8
  87. package/runtime/ext_gui/renderer_text.cpp +11 -26
  88. package/runtime/ext_gui/style.h +11 -0
  89. package/runtime/ext_gui/style_print.cpp +11 -0
  90. package/runtime/ext_gui/style_ua.cpp +7 -0
  91. package/runtime/ext_gui/style_values.cpp +40 -1
  92. package/runtime/ext_gui/svg.cpp +182 -0
  93. package/runtime/ext_gui/svg.h +46 -0
  94. package/runtime/ext_gui/text.cpp +156 -25
  95. package/runtime/ext_gui/text.h +11 -2
  96. package/runtime/ext_gui/window.cpp +4 -1
  97. package/scripts/build-gui.ts +148 -6
  98. package/scripts/check-file-length.ts +5 -1
  99. package/scripts/install-gui-deps.sh +28 -0
@@ -0,0 +1,548 @@
1
+ /*
2
+ * xbintsc GUI engine — the `<canvas>` DOM bindings.
3
+ *
4
+ * `element.getContext("2d")` returns a context handle whose methods and
5
+ * accessors live on a shared prototype here. The handle only stores the canvas
6
+ * id (looked up in `canvas.h`'s process-wide registry) and a strong reference
7
+ * to the element handle, so the GC keeps the element alive for as long as the
8
+ * script can still draw.
9
+ */
10
+
11
+ #include "dom_api_internal.h"
12
+
13
+ #include <string>
14
+ #include <vector>
15
+
16
+ #include "canvas.h"
17
+ #include "css.h"
18
+
19
+ #define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
20
+
21
+ namespace domapi {
22
+
23
+ namespace {
24
+
25
+ /** The canvas behind a context handle, or null (stale/foreign handle). */
26
+ xtgui::Canvas2D *context_canvas(xt_value self) {
27
+ xt_value value = xt_object_get_cstr(self, "__xt_gui_canvas");
28
+ if (!XT_IS_NUMBER(value)) return nullptr;
29
+ double id = xt_to_number(value);
30
+ if (!(id > 0.0)) return nullptr;
31
+ return xtgui::xt_canvas_by_id((uint64_t)id);
32
+ }
33
+
34
+ double number_arg(int32_t argc, xt_value *argv, int32_t index, double fallback) {
35
+ if (index >= argc) return fallback;
36
+ return xt_to_number(xt_arg(argc, argv, index));
37
+ }
38
+
39
+ std::string string_arg(int32_t argc, xt_value *argv, int32_t index) {
40
+ if (index >= argc) return std::string();
41
+ return to_string_value(xt_arg(argc, argv, index));
42
+ }
43
+
44
+ } // namespace
45
+
46
+ METHOD(node_get_context) {
47
+ (void)env;
48
+ std::string mode = string_arg(argc, argv, 0);
49
+ XtGuiWindow *win = nullptr;
50
+ xtgui::Node *node = resolve_node(self, &win);
51
+ if (node == nullptr || !node->isElement() || !node->isTag("canvas")) return XT_NULL;
52
+ if (mode != "2d") return XT_NULL;
53
+ xtgui::Canvas2D *canvas = xt_gui_canvas_get(win, node);
54
+ if (canvas == nullptr) return XT_NULL;
55
+ xt_value cached = xt_object_get_cstr(self, "__xt_gui_ctx");
56
+ if (XT_IS_OBJECT(cached)) return cached;
57
+ xt_value ctx = xt_object_new_with_proto(canvas_proto());
58
+ xt_object_set(ctx, xt_string_from_cstr("__xt_gui_canvas"), xt_number((double)canvas->id()));
59
+ /* Keep the element handle alive (and reachable) from the context. */
60
+ xt_object_set(ctx, xt_string_from_cstr("__xt_gui_node"), self);
61
+ xt_object_set(self, xt_string_from_cstr("__xt_gui_ctx"), ctx);
62
+ return ctx;
63
+ }
64
+
65
+ METHOD(node_width_get) {
66
+ (void)env;
67
+ (void)argc;
68
+ (void)argv;
69
+ XtGuiWindow *win = nullptr;
70
+ xtgui::Node *node = resolve_node(self, &win);
71
+ if (node == nullptr || !node->isElement()) return xt_number(0);
72
+ if (node->isTag("canvas")) {
73
+ xtgui::Canvas2D *canvas = xt_gui_canvas_find(win, node);
74
+ if (canvas != nullptr) return xt_number(canvas->width());
75
+ }
76
+ const std::string *attr = node->attr("width");
77
+ float value = 0.0f;
78
+ if (attr != nullptr && xtgui::xt_css_parse_number(*attr, &value)) return xt_number(value);
79
+ return xt_number(0);
80
+ }
81
+
82
+ METHOD(node_width_set) {
83
+ (void)env;
84
+ XtGuiWindow *win = nullptr;
85
+ xtgui::Node *node = resolve_node(self, &win);
86
+ if (node == nullptr || !node->isElement()) return XT_UNDEFINED;
87
+ double value = number_arg(argc, argv, 0, 0.0);
88
+ if (node->isTag("canvas")) {
89
+ xtgui::Canvas2D *canvas = xt_gui_canvas_get(win, node);
90
+ if (canvas != nullptr) {
91
+ canvas->resize((int)value, canvas->height());
92
+ if (win != nullptr && win->document != nullptr) {
93
+ win->document->setCanvasInfo(node, (float)canvas->width(), (float)canvas->height(),
94
+ canvas->id());
95
+ }
96
+ }
97
+ return XT_UNDEFINED;
98
+ }
99
+ set_attribute(win, node, "width", std::to_string((long long)value));
100
+ return XT_UNDEFINED;
101
+ }
102
+
103
+ METHOD(node_height_get) {
104
+ (void)env;
105
+ (void)argc;
106
+ (void)argv;
107
+ XtGuiWindow *win = nullptr;
108
+ xtgui::Node *node = resolve_node(self, &win);
109
+ if (node == nullptr || !node->isElement()) return xt_number(0);
110
+ if (node->isTag("canvas")) {
111
+ xtgui::Canvas2D *canvas = xt_gui_canvas_find(win, node);
112
+ if (canvas != nullptr) return xt_number(canvas->height());
113
+ }
114
+ const std::string *attr = node->attr("height");
115
+ float value = 0.0f;
116
+ if (attr != nullptr && xtgui::xt_css_parse_number(*attr, &value)) return xt_number(value);
117
+ return xt_number(0);
118
+ }
119
+
120
+ METHOD(node_height_set) {
121
+ (void)env;
122
+ XtGuiWindow *win = nullptr;
123
+ xtgui::Node *node = resolve_node(self, &win);
124
+ if (node == nullptr || !node->isElement()) return XT_UNDEFINED;
125
+ double value = number_arg(argc, argv, 0, 0.0);
126
+ if (node->isTag("canvas")) {
127
+ xtgui::Canvas2D *canvas = xt_gui_canvas_get(win, node);
128
+ if (canvas != nullptr) {
129
+ canvas->resize(canvas->width(), (int)value);
130
+ if (win != nullptr && win->document != nullptr) {
131
+ win->document->setCanvasInfo(node, (float)canvas->width(), (float)canvas->height(),
132
+ canvas->id());
133
+ }
134
+ }
135
+ return XT_UNDEFINED;
136
+ }
137
+ set_attribute(win, node, "height", std::to_string((long long)value));
138
+ return XT_UNDEFINED;
139
+ }
140
+
141
+ /* -- state / style getters and setters ------------------------------------ */
142
+
143
+ METHOD(canvas_get_canvas) {
144
+ (void)env;
145
+ (void)argc;
146
+ (void)argv;
147
+ return xt_object_get_cstr(self, "__xt_gui_node");
148
+ }
149
+
150
+ METHOD(canvas_fill_style_get) {
151
+ (void)env;
152
+ (void)argc;
153
+ (void)argv;
154
+ xtgui::Canvas2D *canvas = context_canvas(self);
155
+ return xt_string_from_cstr(canvas != nullptr ? canvas->fill_style().c_str() : "#000000");
156
+ }
157
+
158
+ METHOD(canvas_fill_style_set) {
159
+ (void)env;
160
+ xtgui::Canvas2D *canvas = context_canvas(self);
161
+ if (canvas != nullptr) canvas->set_fill_style(string_arg(argc, argv, 0));
162
+ return XT_UNDEFINED;
163
+ }
164
+
165
+ METHOD(canvas_stroke_style_get) {
166
+ (void)env;
167
+ (void)argc;
168
+ (void)argv;
169
+ xtgui::Canvas2D *canvas = context_canvas(self);
170
+ return xt_string_from_cstr(canvas != nullptr ? canvas->stroke_style().c_str() : "#000000");
171
+ }
172
+
173
+ METHOD(canvas_stroke_style_set) {
174
+ (void)env;
175
+ xtgui::Canvas2D *canvas = context_canvas(self);
176
+ if (canvas != nullptr) canvas->set_stroke_style(string_arg(argc, argv, 0));
177
+ return XT_UNDEFINED;
178
+ }
179
+
180
+ METHOD(canvas_line_width_get) {
181
+ (void)env;
182
+ (void)argc;
183
+ (void)argv;
184
+ xtgui::Canvas2D *canvas = context_canvas(self);
185
+ return xt_number(canvas != nullptr ? canvas->line_width() : 1.0);
186
+ }
187
+
188
+ METHOD(canvas_line_width_set) {
189
+ (void)env;
190
+ xtgui::Canvas2D *canvas = context_canvas(self);
191
+ if (canvas != nullptr) canvas->set_line_width((float)number_arg(argc, argv, 0, 1.0));
192
+ return XT_UNDEFINED;
193
+ }
194
+
195
+ METHOD(canvas_global_alpha_get) {
196
+ (void)env;
197
+ (void)argc;
198
+ (void)argv;
199
+ xtgui::Canvas2D *canvas = context_canvas(self);
200
+ return xt_number(canvas != nullptr ? canvas->global_alpha() : 1.0);
201
+ }
202
+
203
+ METHOD(canvas_global_alpha_set) {
204
+ (void)env;
205
+ xtgui::Canvas2D *canvas = context_canvas(self);
206
+ if (canvas != nullptr) canvas->set_global_alpha((float)number_arg(argc, argv, 0, 1.0));
207
+ return XT_UNDEFINED;
208
+ }
209
+
210
+ METHOD(canvas_font_get) {
211
+ (void)env;
212
+ (void)argc;
213
+ (void)argv;
214
+ xtgui::Canvas2D *canvas = context_canvas(self);
215
+ return xt_string_from_cstr(canvas != nullptr ? canvas->font().c_str() : "10px sans-serif");
216
+ }
217
+
218
+ METHOD(canvas_font_set) {
219
+ (void)env;
220
+ xtgui::Canvas2D *canvas = context_canvas(self);
221
+ if (canvas != nullptr) canvas->set_font(string_arg(argc, argv, 0));
222
+ return XT_UNDEFINED;
223
+ }
224
+
225
+ METHOD(canvas_text_align_get) {
226
+ (void)env;
227
+ (void)argc;
228
+ (void)argv;
229
+ xtgui::Canvas2D *canvas = context_canvas(self);
230
+ return xt_string_from_cstr(canvas != nullptr ? canvas->text_align().c_str() : "start");
231
+ }
232
+
233
+ METHOD(canvas_text_align_set) {
234
+ (void)env;
235
+ xtgui::Canvas2D *canvas = context_canvas(self);
236
+ if (canvas != nullptr) canvas->set_text_align(string_arg(argc, argv, 0));
237
+ return XT_UNDEFINED;
238
+ }
239
+
240
+ METHOD(canvas_text_baseline_get) {
241
+ (void)env;
242
+ (void)argc;
243
+ (void)argv;
244
+ xtgui::Canvas2D *canvas = context_canvas(self);
245
+ return xt_string_from_cstr(canvas != nullptr ? canvas->text_baseline().c_str() : "alphabetic");
246
+ }
247
+
248
+ METHOD(canvas_text_baseline_set) {
249
+ (void)env;
250
+ xtgui::Canvas2D *canvas = context_canvas(self);
251
+ if (canvas != nullptr) canvas->set_text_baseline(string_arg(argc, argv, 0));
252
+ return XT_UNDEFINED;
253
+ }
254
+
255
+ /* -- state / transform ---------------------------------------------------- */
256
+
257
+ METHOD(canvas_save) {
258
+ (void)env;
259
+ (void)argc;
260
+ (void)argv;
261
+ xtgui::Canvas2D *canvas = context_canvas(self);
262
+ if (canvas != nullptr) canvas->save();
263
+ return XT_UNDEFINED;
264
+ }
265
+
266
+ METHOD(canvas_restore) {
267
+ (void)env;
268
+ (void)argc;
269
+ (void)argv;
270
+ xtgui::Canvas2D *canvas = context_canvas(self);
271
+ if (canvas != nullptr) canvas->restore();
272
+ return XT_UNDEFINED;
273
+ }
274
+
275
+ METHOD(canvas_translate) {
276
+ (void)env;
277
+ xtgui::Canvas2D *canvas = context_canvas(self);
278
+ if (canvas != nullptr)
279
+ canvas->translate((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0));
280
+ return XT_UNDEFINED;
281
+ }
282
+
283
+ METHOD(canvas_rotate) {
284
+ (void)env;
285
+ xtgui::Canvas2D *canvas = context_canvas(self);
286
+ if (canvas != nullptr) canvas->rotate((float)number_arg(argc, argv, 0, 0.0));
287
+ return XT_UNDEFINED;
288
+ }
289
+
290
+ METHOD(canvas_scale) {
291
+ (void)env;
292
+ xtgui::Canvas2D *canvas = context_canvas(self);
293
+ if (canvas != nullptr)
294
+ canvas->scale((float)number_arg(argc, argv, 0, 1.0), (float)number_arg(argc, argv, 1, 1.0));
295
+ return XT_UNDEFINED;
296
+ }
297
+
298
+ METHOD(canvas_transform) {
299
+ (void)env;
300
+ xtgui::Canvas2D *canvas = context_canvas(self);
301
+ if (canvas != nullptr)
302
+ canvas->transform((float)number_arg(argc, argv, 0, 1.0), (float)number_arg(argc, argv, 1, 0.0),
303
+ (float)number_arg(argc, argv, 2, 0.0), (float)number_arg(argc, argv, 3, 1.0),
304
+ (float)number_arg(argc, argv, 4, 0.0), (float)number_arg(argc, argv, 5, 0.0));
305
+ return XT_UNDEFINED;
306
+ }
307
+
308
+ METHOD(canvas_set_transform) {
309
+ (void)env;
310
+ xtgui::Canvas2D *canvas = context_canvas(self);
311
+ if (canvas != nullptr)
312
+ canvas->set_transform((float)number_arg(argc, argv, 0, 1.0),
313
+ (float)number_arg(argc, argv, 1, 0.0),
314
+ (float)number_arg(argc, argv, 2, 0.0),
315
+ (float)number_arg(argc, argv, 3, 1.0),
316
+ (float)number_arg(argc, argv, 4, 0.0),
317
+ (float)number_arg(argc, argv, 5, 0.0));
318
+ return XT_UNDEFINED;
319
+ }
320
+
321
+ METHOD(canvas_reset_transform) {
322
+ (void)env;
323
+ (void)argc;
324
+ (void)argv;
325
+ xtgui::Canvas2D *canvas = context_canvas(self);
326
+ if (canvas != nullptr) canvas->reset_transform();
327
+ return XT_UNDEFINED;
328
+ }
329
+
330
+ /* -- paths ---------------------------------------------------------------- */
331
+
332
+ METHOD(canvas_begin_path) {
333
+ (void)env;
334
+ (void)argc;
335
+ (void)argv;
336
+ xtgui::Canvas2D *canvas = context_canvas(self);
337
+ if (canvas != nullptr) canvas->begin_path();
338
+ return XT_UNDEFINED;
339
+ }
340
+
341
+ METHOD(canvas_close_path) {
342
+ (void)env;
343
+ (void)argc;
344
+ (void)argv;
345
+ xtgui::Canvas2D *canvas = context_canvas(self);
346
+ if (canvas != nullptr) canvas->close_path();
347
+ return XT_UNDEFINED;
348
+ }
349
+
350
+ METHOD(canvas_move_to) {
351
+ (void)env;
352
+ xtgui::Canvas2D *canvas = context_canvas(self);
353
+ if (canvas != nullptr)
354
+ canvas->move_to((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0));
355
+ return XT_UNDEFINED;
356
+ }
357
+
358
+ METHOD(canvas_line_to) {
359
+ (void)env;
360
+ xtgui::Canvas2D *canvas = context_canvas(self);
361
+ if (canvas != nullptr)
362
+ canvas->line_to((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0));
363
+ return XT_UNDEFINED;
364
+ }
365
+
366
+ METHOD(canvas_rect) {
367
+ (void)env;
368
+ xtgui::Canvas2D *canvas = context_canvas(self);
369
+ if (canvas != nullptr)
370
+ canvas->rect((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0),
371
+ (float)number_arg(argc, argv, 2, 0.0), (float)number_arg(argc, argv, 3, 0.0));
372
+ return XT_UNDEFINED;
373
+ }
374
+
375
+ METHOD(canvas_arc) {
376
+ (void)env;
377
+ xtgui::Canvas2D *canvas = context_canvas(self);
378
+ if (canvas != nullptr) {
379
+ canvas->arc((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0),
380
+ (float)number_arg(argc, argv, 2, 0.0), (float)number_arg(argc, argv, 3, 0.0),
381
+ (float)number_arg(argc, argv, 4, 0.0), value_truthy(xt_arg(argc, argv, 5)));
382
+ }
383
+ return XT_UNDEFINED;
384
+ }
385
+
386
+ METHOD(canvas_quadratic_curve_to) {
387
+ (void)env;
388
+ xtgui::Canvas2D *canvas = context_canvas(self);
389
+ if (canvas != nullptr)
390
+ canvas->quadratic_curve_to((float)number_arg(argc, argv, 0, 0.0),
391
+ (float)number_arg(argc, argv, 1, 0.0),
392
+ (float)number_arg(argc, argv, 2, 0.0),
393
+ (float)number_arg(argc, argv, 3, 0.0));
394
+ return XT_UNDEFINED;
395
+ }
396
+
397
+ METHOD(canvas_bezier_curve_to) {
398
+ (void)env;
399
+ xtgui::Canvas2D *canvas = context_canvas(self);
400
+ if (canvas != nullptr)
401
+ canvas->bezier_curve_to((float)number_arg(argc, argv, 0, 0.0),
402
+ (float)number_arg(argc, argv, 1, 0.0),
403
+ (float)number_arg(argc, argv, 2, 0.0),
404
+ (float)number_arg(argc, argv, 3, 0.0),
405
+ (float)number_arg(argc, argv, 4, 0.0),
406
+ (float)number_arg(argc, argv, 5, 0.0));
407
+ return XT_UNDEFINED;
408
+ }
409
+
410
+ METHOD(canvas_fill) {
411
+ (void)env;
412
+ (void)argc;
413
+ (void)argv;
414
+ xtgui::Canvas2D *canvas = context_canvas(self);
415
+ if (canvas != nullptr) canvas->fill();
416
+ return XT_UNDEFINED;
417
+ }
418
+
419
+ METHOD(canvas_stroke) {
420
+ (void)env;
421
+ (void)argc;
422
+ (void)argv;
423
+ xtgui::Canvas2D *canvas = context_canvas(self);
424
+ if (canvas != nullptr) canvas->stroke();
425
+ return XT_UNDEFINED;
426
+ }
427
+
428
+ METHOD(canvas_clear_rect) {
429
+ (void)env;
430
+ xtgui::Canvas2D *canvas = context_canvas(self);
431
+ if (canvas != nullptr)
432
+ canvas->clear_rect((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0),
433
+ (float)number_arg(argc, argv, 2, 0.0), (float)number_arg(argc, argv, 3, 0.0));
434
+ return XT_UNDEFINED;
435
+ }
436
+
437
+ METHOD(canvas_fill_rect) {
438
+ (void)env;
439
+ xtgui::Canvas2D *canvas = context_canvas(self);
440
+ if (canvas != nullptr)
441
+ canvas->fill_rect((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0),
442
+ (float)number_arg(argc, argv, 2, 0.0), (float)number_arg(argc, argv, 3, 0.0));
443
+ return XT_UNDEFINED;
444
+ }
445
+
446
+ METHOD(canvas_stroke_rect) {
447
+ (void)env;
448
+ xtgui::Canvas2D *canvas = context_canvas(self);
449
+ if (canvas != nullptr)
450
+ canvas->stroke_rect((float)number_arg(argc, argv, 0, 0.0), (float)number_arg(argc, argv, 1, 0.0),
451
+ (float)number_arg(argc, argv, 2, 0.0),
452
+ (float)number_arg(argc, argv, 3, 0.0));
453
+ return XT_UNDEFINED;
454
+ }
455
+
456
+ /* -- text ----------------------------------------------------------------- */
457
+
458
+ METHOD(canvas_measure_text) {
459
+ (void)env;
460
+ xtgui::Canvas2D *canvas = context_canvas(self);
461
+ xt_value metrics = xt_object_new();
462
+ xt_object_set(metrics, xt_string_from_cstr("width"),
463
+ xt_number(canvas != nullptr ? canvas->measure_text(string_arg(argc, argv, 0)) : 0.0));
464
+ return metrics;
465
+ }
466
+
467
+ METHOD(canvas_fill_text) {
468
+ (void)env;
469
+ xtgui::Canvas2D *canvas = context_canvas(self);
470
+ if (canvas != nullptr)
471
+ canvas->fill_text(string_arg(argc, argv, 0), (float)number_arg(argc, argv, 1, 0.0),
472
+ (float)number_arg(argc, argv, 2, 0.0));
473
+ return XT_UNDEFINED;
474
+ }
475
+
476
+ METHOD(canvas_stroke_text) {
477
+ (void)env;
478
+ xtgui::Canvas2D *canvas = context_canvas(self);
479
+ if (canvas != nullptr)
480
+ canvas->stroke_text(string_arg(argc, argv, 0), (float)number_arg(argc, argv, 1, 0.0),
481
+ (float)number_arg(argc, argv, 2, 0.0));
482
+ return XT_UNDEFINED;
483
+ }
484
+
485
+ /* -- images --------------------------------------------------------------- */
486
+
487
+ METHOD(canvas_draw_image) {
488
+ (void)env;
489
+ xtgui::Canvas2D *canvas = context_canvas(self);
490
+ if (canvas == nullptr || argc < 3) return XT_UNDEFINED;
491
+ XtGuiWindow *win = nullptr;
492
+ xtgui::Node *source = resolve_node(xt_arg(argc, argv, 0), &win);
493
+ const xtgui::Image *image = nullptr;
494
+ if (source != nullptr && source->isElement() && source->isTag("img")) {
495
+ const std::string *src = source->attr("src");
496
+ if (src != nullptr) image = xtgui::xt_image_load(*src);
497
+ } else if (source != nullptr) {
498
+ xtgui::Canvas2D *other = xt_gui_canvas_find(win, source);
499
+ if (other != nullptr) image = &other->image();
500
+ }
501
+ if (image == nullptr || image->width <= 0 || image->height <= 0) return XT_UNDEFINED;
502
+ float dx = (float)number_arg(argc, argv, 1, 0.0);
503
+ float dy = (float)number_arg(argc, argv, 2, 0.0);
504
+ float dw = (float)image->width;
505
+ float dh = (float)image->height;
506
+ float sx = 0.0f;
507
+ float sy = 0.0f;
508
+ float sw = (float)image->width;
509
+ float sh = (float)image->height;
510
+ if (argc >= 5) {
511
+ dw = (float)number_arg(argc, argv, 3, (double)dw);
512
+ dh = (float)number_arg(argc, argv, 4, (double)dh);
513
+ }
514
+ if (argc >= 9) {
515
+ sx = (float)number_arg(argc, argv, 5, 0.0);
516
+ sy = (float)number_arg(argc, argv, 6, 0.0);
517
+ sw = (float)number_arg(argc, argv, 7, (double)sw);
518
+ sh = (float)number_arg(argc, argv, 8, (double)sh);
519
+ }
520
+ canvas->draw_image(*image, dx, dy, dw, dh, sx, sy, sw, sh);
521
+ return XT_UNDEFINED;
522
+ }
523
+
524
+ METHOD(canvas_get_image_data) {
525
+ (void)env;
526
+ xtgui::Canvas2D *canvas = context_canvas(self);
527
+ xt_value result = xt_object_new();
528
+ if (canvas == nullptr) return result;
529
+ int x = (int)number_arg(argc, argv, 0, 0.0);
530
+ int y = (int)number_arg(argc, argv, 1, 0.0);
531
+ int width = (int)number_arg(argc, argv, 2, 0.0);
532
+ int height = (int)number_arg(argc, argv, 3, 0.0);
533
+ std::vector<unsigned char> pixels;
534
+ if (!canvas->get_image_data(x, y, width, height, &pixels)) {
535
+ width = 0;
536
+ height = 0;
537
+ }
538
+ xt_value data = xt_array_new(0, nullptr);
539
+ for (unsigned char byte : pixels) xt_array_push(data, xt_number((double)byte));
540
+ xt_object_set(result, xt_string_from_cstr("width"), xt_number((double)width));
541
+ xt_object_set(result, xt_string_from_cstr("height"), xt_number((double)height));
542
+ xt_object_set(result, xt_string_from_cstr("data"), data);
543
+ return result;
544
+ }
545
+
546
+ } // namespace domapi
547
+
548
+ #undef METHOD
@@ -27,12 +27,14 @@ extern xt_value g_document_proto;
27
27
  extern xt_value g_event_proto;
28
28
  extern xt_value g_class_list_proto;
29
29
  extern xt_value g_style_proto;
30
+ extern xt_value g_canvas_proto;
30
31
 
31
32
  xt_value node_proto();
32
33
  xt_value document_proto();
33
34
  xt_value event_proto();
34
35
  xt_value class_list_proto();
35
36
  xt_value style_proto();
37
+ xt_value canvas_proto();
36
38
 
37
39
  /* -- cross-unit helpers --------------------------------------------------- */
38
40
 
@@ -123,6 +125,77 @@ METHOD(event_prevent_default);
123
125
  METHOD(event_stop_propagation);
124
126
  METHOD(event_stop_immediate_propagation);
125
127
 
128
+ /* media (`<video>`/`<audio>`) */
129
+ METHOD(node_play);
130
+ METHOD(node_pause);
131
+ METHOD(node_load);
132
+ METHOD(node_paused_get);
133
+ METHOD(node_ended_get);
134
+ METHOD(node_current_time_get);
135
+ METHOD(node_current_time_set);
136
+ METHOD(node_duration_get);
137
+ METHOD(node_volume_get);
138
+ METHOD(node_volume_set);
139
+ METHOD(node_muted_get);
140
+ METHOD(node_muted_set);
141
+ METHOD(node_loop_get);
142
+ METHOD(node_loop_set);
143
+ METHOD(node_autoplay_get);
144
+ METHOD(node_autoplay_set);
145
+ METHOD(node_video_width_get);
146
+ METHOD(node_video_height_get);
147
+ METHOD(node_ready_state_get);
148
+ METHOD(node_media_src_get);
149
+ METHOD(node_media_src_set);
150
+
151
+ /* canvas (`<canvas>` element + 2D context) */
152
+ METHOD(node_get_context);
153
+ METHOD(node_width_get);
154
+ METHOD(node_width_set);
155
+ METHOD(node_height_get);
156
+ METHOD(node_height_set);
157
+ METHOD(canvas_get_canvas);
158
+ METHOD(canvas_fill_style_get);
159
+ METHOD(canvas_fill_style_set);
160
+ METHOD(canvas_stroke_style_get);
161
+ METHOD(canvas_stroke_style_set);
162
+ METHOD(canvas_line_width_get);
163
+ METHOD(canvas_line_width_set);
164
+ METHOD(canvas_global_alpha_get);
165
+ METHOD(canvas_global_alpha_set);
166
+ METHOD(canvas_font_get);
167
+ METHOD(canvas_font_set);
168
+ METHOD(canvas_text_align_get);
169
+ METHOD(canvas_text_align_set);
170
+ METHOD(canvas_text_baseline_get);
171
+ METHOD(canvas_text_baseline_set);
172
+ METHOD(canvas_save);
173
+ METHOD(canvas_restore);
174
+ METHOD(canvas_translate);
175
+ METHOD(canvas_rotate);
176
+ METHOD(canvas_scale);
177
+ METHOD(canvas_transform);
178
+ METHOD(canvas_set_transform);
179
+ METHOD(canvas_reset_transform);
180
+ METHOD(canvas_begin_path);
181
+ METHOD(canvas_close_path);
182
+ METHOD(canvas_move_to);
183
+ METHOD(canvas_line_to);
184
+ METHOD(canvas_rect);
185
+ METHOD(canvas_arc);
186
+ METHOD(canvas_quadratic_curve_to);
187
+ METHOD(canvas_bezier_curve_to);
188
+ METHOD(canvas_fill);
189
+ METHOD(canvas_stroke);
190
+ METHOD(canvas_clear_rect);
191
+ METHOD(canvas_fill_rect);
192
+ METHOD(canvas_stroke_rect);
193
+ METHOD(canvas_measure_text);
194
+ METHOD(canvas_fill_text);
195
+ METHOD(canvas_stroke_text);
196
+ METHOD(canvas_draw_image);
197
+ METHOD(canvas_get_image_data);
198
+
126
199
  /* classList methods */
127
200
  METHOD(class_list_add);
128
201
  METHOD(class_list_remove);