xbintsc 0.5.37 → 0.5.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.js +23 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/deferred.d.ts +63 -0
- package/dist/src/driver/bundler/deferred.js +279 -0
- package/dist/src/driver/bundler/deferred.js.map +1 -0
- package/dist/src/driver/bundler/merge.js +214 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/html.js +98 -15
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +1 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +4 -3
- package/dist/src/extensions/gui/three.js +4 -3
- package/dist/src/extensions/gui/three.js.map +1 -1
- package/dist/tests/codegen/closures.test.js +7 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
- package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
- package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
- package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
- package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
- package/dist/tests/e2e/gui-perf.test.js +283 -0
- package/dist/tests/e2e/gui-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +169 -0
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl.test.js +4 -4
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
- package/dist/tests/e2e/url.test.d.ts +6 -0
- package/dist/tests/e2e/url.test.js +114 -0
- package/dist/tests/e2e/url.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +45 -10
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/api.md +28 -2
- package/doc/gui/canvas.md +110 -27
- package/doc/gui/known-issues.md +32 -10
- package/doc/gui/rendering.md +77 -0
- package/doc/gui/runtime.md +18 -3
- package/doc/gui/webgl.md +58 -29
- package/doc/gui-scripts.md +19 -19
- package/doc/gui.md +43 -9
- package/doc/implemented/fetch.md +5 -0
- package/doc/implemented/modules.md +13 -0
- package/doc/implemented/stdlib.md +17 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/api.md +25 -2
- package/doc/zh-CN/gui/canvas.md +95 -26
- package/doc/zh-CN/gui/known-issues.md +21 -4
- package/doc/zh-CN/gui/rendering.md +59 -0
- package/doc/zh-CN/gui/runtime.md +13 -3
- package/doc/zh-CN/gui/webgl.md +30 -8
- package/doc/zh-CN/gui-scripts.md +14 -13
- package/doc/zh-CN/gui.md +32 -8
- package/doc/zh-CN/implemented/fetch.md +4 -0
- package/doc/zh-CN/implemented/modules.md +10 -0
- package/doc/zh-CN/implemented/stdlib.md +15 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +3 -1
- package/runtime/ext_gui/canvas.cpp +135 -89
- package/runtime/ext_gui/canvas.h +116 -0
- package/runtime/ext_gui/canvas_clip.cpp +143 -0
- package/runtime/ext_gui/canvas_composite.cpp +241 -0
- package/runtime/ext_gui/canvas_coverage.cpp +241 -0
- package/runtime/ext_gui/canvas_gradient.cpp +41 -4
- package/runtime/ext_gui/canvas_image_data.cpp +4 -0
- package/runtime/ext_gui/canvas_internal.h +34 -9
- package/runtime/ext_gui/canvas_raster.cpp +207 -178
- package/runtime/ext_gui/canvas_shadow.cpp +161 -0
- package/runtime/ext_gui/canvas_stroke.cpp +37 -9
- package/runtime/ext_gui/canvas_style.cpp +59 -0
- package/runtime/ext_gui/canvas_text.cpp +140 -0
- package/runtime/ext_gui/css.h +7 -0
- package/runtime/ext_gui/css_sheet.cpp +22 -0
- package/runtime/ext_gui/document.cpp +25 -1
- package/runtime/ext_gui/document.h +8 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +16 -1
- package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
- package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
- package/runtime/ext_gui/dom_api_internal.h +36 -37
- package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
- package/runtime/ext_gui/dom_api_proto.cpp +18 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +29 -9
- package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
- package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
- package/runtime/ext_gui/gradient_values.cpp +12 -1
- package/runtime/ext_gui/gui.cpp +5 -0
- package/runtime/ext_gui/gui_canvas.cpp +4 -0
- package/runtime/ext_gui/gui_engine.h +32 -0
- package/runtime/ext_gui/gui_events.cpp +182 -58
- package/runtime/ext_gui/gui_media.cpp +3 -0
- package/runtime/ext_gui/image.cpp +69 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
- package/runtime/ext_gui/layout.cpp +4 -0
- package/runtime/ext_gui/paint.cpp +19 -0
- package/runtime/ext_gui/paint_background.cpp +18 -1
- package/runtime/ext_gui/perf.cpp +171 -0
- package/runtime/ext_gui/perf.h +127 -0
- package/runtime/ext_gui/renderer.cpp +109 -41
- package/runtime/ext_gui/renderer.h +33 -9
- package/runtime/ext_gui/renderer_image.cpp +135 -65
- package/runtime/ext_gui/renderer_internal.h +15 -3
- package/runtime/ext_gui/renderer_text.cpp +24 -12
- package/runtime/ext_gui/script.cpp +31 -0
- package/runtime/ext_gui/style.cpp +101 -30
- package/runtime/ext_gui/style.h +6 -3
- package/runtime/ext_gui/style_print.cpp +7 -1
- package/runtime/ext_gui/text.cpp +23 -4
- package/runtime/ext_gui/text.h +29 -0
- package/runtime/ext_gui/text_cache.cpp +118 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
- package/runtime/ext_gui/webgl.h +48 -146
- package/runtime/ext_gui/webgl_blit.cpp +12 -1
- package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
- package/runtime/ext_gui/webgl_buffer.cpp +59 -1
- package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
- package/runtime/ext_gui/webgl_clear.cpp +3 -0
- package/runtime/ext_gui/webgl_context.cpp +29 -3
- package/runtime/ext_gui/webgl_draw.cpp +75 -270
- package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
- package/runtime/ext_gui/webgl_draw_state.h +130 -0
- package/runtime/ext_gui/webgl_glsl.h +3 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
- package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
- package/runtime/ext_gui/webgl_msl.cpp +4 -0
- package/runtime/ext_gui/webgl_objects.h +148 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
- package/runtime/ext_gui/webgl_program_internal.h +35 -0
- package/runtime/ext_gui/webgl_shader.cpp +34 -36
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/runtime/rt.h +3 -0
- package/runtime/xt_fetch/async.inc +60 -0
- package/runtime/xt_url_object.c +463 -0
- package/src/codegen/generator/module.ts +22 -7
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/bundler/deferred.ts +351 -0
- package/src/driver/bundler/merge.ts +219 -2
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +100 -17
- package/src/extensions/gui/index.ts +1 -0
- package/src/extensions/gui/three.ts +4 -3
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — the Canvas2D state additions.
|
|
3
|
+
*
|
|
4
|
+
* `globalCompositeOperation`, the four shadow properties, the image-smoothing
|
|
5
|
+
* flags, and the path/clip hit-testing entry points. They live apart from the
|
|
6
|
+
* original style bindings so both translation units stay small.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "dom_api_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
#include "canvas.h"
|
|
15
|
+
|
|
16
|
+
#define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
|
|
17
|
+
|
|
18
|
+
namespace domapi {
|
|
19
|
+
|
|
20
|
+
namespace {
|
|
21
|
+
|
|
22
|
+
/** Parse a trailing fill-rule argument (`"evenodd"`/`"nonzero"`). */
|
|
23
|
+
bool fill_rule_arg(xt_value value, bool *even_odd) {
|
|
24
|
+
if (!XT_IS_STRING(value)) return false;
|
|
25
|
+
const std::string rule = to_string_value(value);
|
|
26
|
+
if (rule == "evenodd") {
|
|
27
|
+
*even_odd = true;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (rule == "nonzero") {
|
|
31
|
+
*even_odd = false;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
} // namespace
|
|
38
|
+
|
|
39
|
+
METHOD(canvas_global_composite_get) {
|
|
40
|
+
(void)env;
|
|
41
|
+
(void)argc;
|
|
42
|
+
(void)argv;
|
|
43
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
44
|
+
return xt_string_from_cstr(canvas != nullptr ? canvas->global_composite_operation().c_str()
|
|
45
|
+
: "source-over");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
METHOD(canvas_global_composite_set) {
|
|
49
|
+
(void)env;
|
|
50
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
51
|
+
if (canvas != nullptr) canvas->set_global_composite_operation(canvas_string_arg(argc, argv, 0));
|
|
52
|
+
return XT_UNDEFINED;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
METHOD(canvas_shadow_color_get) {
|
|
56
|
+
(void)env;
|
|
57
|
+
(void)argc;
|
|
58
|
+
(void)argv;
|
|
59
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
60
|
+
return xt_string_from_cstr(canvas != nullptr ? canvas->shadow_color().c_str()
|
|
61
|
+
: "rgba(0, 0, 0, 0)");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
METHOD(canvas_shadow_color_set) {
|
|
65
|
+
(void)env;
|
|
66
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
67
|
+
if (canvas != nullptr) canvas->set_shadow_color(canvas_string_arg(argc, argv, 0));
|
|
68
|
+
return XT_UNDEFINED;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
METHOD(canvas_shadow_blur_get) {
|
|
72
|
+
(void)env;
|
|
73
|
+
(void)argc;
|
|
74
|
+
(void)argv;
|
|
75
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
76
|
+
return xt_number(canvas != nullptr ? canvas->shadow_blur() : 0.0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
METHOD(canvas_shadow_blur_set) {
|
|
80
|
+
(void)env;
|
|
81
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
82
|
+
if (canvas != nullptr) canvas->set_shadow_blur((float)canvas_number_arg(argc, argv, 0, 0.0));
|
|
83
|
+
return XT_UNDEFINED;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
METHOD(canvas_shadow_offset_x_get) {
|
|
87
|
+
(void)env;
|
|
88
|
+
(void)argc;
|
|
89
|
+
(void)argv;
|
|
90
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
91
|
+
return xt_number(canvas != nullptr ? canvas->shadow_offset_x() : 0.0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
METHOD(canvas_shadow_offset_x_set) {
|
|
95
|
+
(void)env;
|
|
96
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
97
|
+
if (canvas != nullptr) canvas->set_shadow_offset_x((float)canvas_number_arg(argc, argv, 0, 0.0));
|
|
98
|
+
return XT_UNDEFINED;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
METHOD(canvas_shadow_offset_y_get) {
|
|
102
|
+
(void)env;
|
|
103
|
+
(void)argc;
|
|
104
|
+
(void)argv;
|
|
105
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
106
|
+
return xt_number(canvas != nullptr ? canvas->shadow_offset_y() : 0.0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
METHOD(canvas_shadow_offset_y_set) {
|
|
110
|
+
(void)env;
|
|
111
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
112
|
+
if (canvas != nullptr) canvas->set_shadow_offset_y((float)canvas_number_arg(argc, argv, 0, 0.0));
|
|
113
|
+
return XT_UNDEFINED;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
METHOD(canvas_image_smoothing_enabled_get) {
|
|
117
|
+
(void)env;
|
|
118
|
+
(void)argc;
|
|
119
|
+
(void)argv;
|
|
120
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
121
|
+
return xt_bool(canvas == nullptr || canvas->image_smoothing_enabled());
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
METHOD(canvas_image_smoothing_enabled_set) {
|
|
125
|
+
(void)env;
|
|
126
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
127
|
+
if (canvas != nullptr) {
|
|
128
|
+
canvas->set_image_smoothing_enabled(value_truthy(xt_arg(argc, argv, 0)));
|
|
129
|
+
}
|
|
130
|
+
return XT_UNDEFINED;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
METHOD(canvas_image_smoothing_quality_get) {
|
|
134
|
+
(void)env;
|
|
135
|
+
(void)argc;
|
|
136
|
+
(void)argv;
|
|
137
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
138
|
+
return xt_string_from_cstr(canvas != nullptr ? canvas->image_smoothing_quality().c_str()
|
|
139
|
+
: "low");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
METHOD(canvas_image_smoothing_quality_set) {
|
|
143
|
+
(void)env;
|
|
144
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
145
|
+
if (canvas != nullptr) canvas->set_image_smoothing_quality(canvas_string_arg(argc, argv, 0));
|
|
146
|
+
return XT_UNDEFINED;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
METHOD(canvas_clip) {
|
|
150
|
+
(void)env;
|
|
151
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
152
|
+
if (canvas == nullptr) return XT_UNDEFINED;
|
|
153
|
+
bool even_odd = false;
|
|
154
|
+
bool has_path = false;
|
|
155
|
+
std::vector<xtgui::CanvasSubpath> path;
|
|
156
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
157
|
+
xt_value value = xt_arg(argc, argv, i);
|
|
158
|
+
bool rule = false;
|
|
159
|
+
if (fill_rule_arg(value, &rule)) {
|
|
160
|
+
even_odd = rule;
|
|
161
|
+
} else if (path2d_is(value)) {
|
|
162
|
+
path = path2d_subpaths(value);
|
|
163
|
+
has_path = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (has_path) {
|
|
167
|
+
canvas->clip_paths(path, even_odd);
|
|
168
|
+
} else {
|
|
169
|
+
canvas->clip(even_odd);
|
|
170
|
+
}
|
|
171
|
+
return XT_UNDEFINED;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
METHOD(canvas_is_point_in_path) {
|
|
175
|
+
(void)env;
|
|
176
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
177
|
+
if (canvas == nullptr || argc == 0) return XT_FALSE;
|
|
178
|
+
int32_t index = 0;
|
|
179
|
+
std::vector<xtgui::CanvasSubpath> path;
|
|
180
|
+
bool has_path = false;
|
|
181
|
+
if (path2d_is(xt_arg(argc, argv, 0))) {
|
|
182
|
+
path = path2d_subpaths(xt_arg(argc, argv, 0));
|
|
183
|
+
has_path = true;
|
|
184
|
+
index = 1;
|
|
185
|
+
}
|
|
186
|
+
const float x = (float)canvas_number_arg(argc, argv, index, 0.0);
|
|
187
|
+
const float y = (float)canvas_number_arg(argc, argv, index + 1, 0.0);
|
|
188
|
+
bool even_odd = false;
|
|
189
|
+
for (int32_t i = index + 2; i < argc; i++) fill_rule_arg(xt_arg(argc, argv, i), &even_odd);
|
|
190
|
+
const bool inside =
|
|
191
|
+
has_path ? canvas->is_point_in_paths(path, x, y, even_odd)
|
|
192
|
+
: canvas->is_point_in_path(x, y, even_odd);
|
|
193
|
+
return xt_bool(inside);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
METHOD(canvas_is_point_in_stroke) {
|
|
197
|
+
(void)env;
|
|
198
|
+
xtgui::Canvas2D *canvas = canvas_from_context(self);
|
|
199
|
+
if (canvas == nullptr || argc == 0) return XT_FALSE;
|
|
200
|
+
int32_t index = 0;
|
|
201
|
+
std::vector<xtgui::CanvasSubpath> path;
|
|
202
|
+
bool has_path = false;
|
|
203
|
+
if (path2d_is(xt_arg(argc, argv, 0))) {
|
|
204
|
+
path = path2d_subpaths(xt_arg(argc, argv, 0));
|
|
205
|
+
has_path = true;
|
|
206
|
+
index = 1;
|
|
207
|
+
}
|
|
208
|
+
const float x = (float)canvas_number_arg(argc, argv, index, 0.0);
|
|
209
|
+
const float y = (float)canvas_number_arg(argc, argv, index + 1, 0.0);
|
|
210
|
+
const bool inside =
|
|
211
|
+
has_path ? canvas->is_point_in_stroke_paths(path, x, y) : canvas->is_point_in_stroke(x, y);
|
|
212
|
+
return xt_bool(inside);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
} // namespace domapi
|
|
216
|
+
|
|
217
|
+
#undef METHOD
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
#include <vector>
|
|
18
18
|
|
|
19
19
|
#include "gui_engine.h"
|
|
20
|
+
#include "dom_api_webgl_internal.h"
|
|
20
21
|
|
|
21
22
|
namespace domapi {
|
|
22
23
|
|
|
@@ -52,6 +53,23 @@ xt_value class_list_proto();
|
|
|
52
53
|
xt_value style_proto();
|
|
53
54
|
xt_value computed_style_proto();
|
|
54
55
|
xt_value canvas_proto();
|
|
56
|
+
/** The `getContextAttributes()` object for a freshly created 2D context. */
|
|
57
|
+
xt_value canvas_context_attributes(xt_value requested, bool alpha);
|
|
58
|
+
/** `OffscreenCanvas.prototype`. */
|
|
59
|
+
xt_value offscreen_canvas_proto();
|
|
60
|
+
/** `new OffscreenCanvas(width, height)`. */
|
|
61
|
+
xt_value offscreen_canvas_create(int32_t argc, xt_value *argv);
|
|
62
|
+
/** `canvas.transferControlToOffscreen()`. */
|
|
63
|
+
xt_value canvas_transfer_control_to_offscreen(xt_value self, xt_value env, int32_t argc,
|
|
64
|
+
xt_value *argv);
|
|
65
|
+
xt_value offscreen_get_context(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
66
|
+
xt_value offscreen_width_get(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
67
|
+
xt_value offscreen_width_set(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
68
|
+
xt_value offscreen_height_get(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
69
|
+
xt_value offscreen_height_set(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
70
|
+
xt_value offscreen_transfer_to_image_bitmap(xt_value self, xt_value env, int32_t argc,
|
|
71
|
+
xt_value *argv);
|
|
72
|
+
xt_value offscreen_convert_to_blob(xt_value self, xt_value env, int32_t argc, xt_value *argv);
|
|
55
73
|
xt_value canvas_gradient_proto();
|
|
56
74
|
xt_value webgl_proto();
|
|
57
75
|
xt_value webgl2_proto();
|
|
@@ -91,43 +109,7 @@ xt_value canvas_gradient_handle(xt_value context, const xtgui::Canvas2D *canvas,
|
|
|
91
109
|
uint64_t canvas_gradient_id(xt_value handle, const xtgui::Canvas2D *canvas);
|
|
92
110
|
|
|
93
111
|
/* -- WebGL helpers shared by `dom_api_webgl*.cpp` ------------------------- */
|
|
94
|
-
|
|
95
|
-
/** The engine WebGL context behind a context handle, or null. */
|
|
96
|
-
xtgui::WebGLContext *webgl_from_context(xt_value self);
|
|
97
|
-
/** Like `webgl_from_context`, but null while the context is lost: every GL
|
|
98
|
-
* entry point except `getError`/`isContextLost` is a no-op in that state. */
|
|
99
|
-
xtgui::WebGLContext *webgl_live_context(xt_value self);
|
|
100
|
-
/** The numeric context id stored on a context handle (0 when absent). */
|
|
101
|
-
uint64_t webgl_context_id(xt_value self);
|
|
102
|
-
/** Create the JavaScript handle for a canvas's WebGL context. */
|
|
103
|
-
xt_value webgl_context_handle(xt_value element, xtgui::WebGLContext *context);
|
|
104
|
-
/** The id stored on an object handle under `key`, or 0. */
|
|
105
|
-
uint32_t webgl_object_id(xt_value handle, const char *key);
|
|
106
|
-
/** Build an object handle (`{__xt_gl_context, __xt_gl_<key>}`). */
|
|
107
|
-
xt_value webgl_make_object(xt_value context, const char *key, uint32_t id,
|
|
108
|
-
const std::string &kind);
|
|
109
|
-
double webgl_number(int32_t argc, xt_value *argv, int32_t index, double fallback);
|
|
110
|
-
int webgl_int(int32_t argc, xt_value *argv, int32_t index, int fallback);
|
|
111
|
-
std::string webgl_string(int32_t argc, xt_value *argv, int32_t index);
|
|
112
|
-
/** Read an array/typed array of numbers. */
|
|
113
|
-
std::vector<double> webgl_numbers(xt_value value);
|
|
114
|
-
/** Read the raw bytes of a typed array / ArrayBuffer (or a byte array). */
|
|
115
|
-
std::vector<uint8_t> webgl_bytes(xt_value value);
|
|
116
|
-
/** Store `count` bytes into a typed array / array handle. */
|
|
117
|
-
void webgl_write_bytes(xt_value target, const uint8_t *bytes, size_t count);
|
|
118
|
-
/** Convert a source pixel array (RGBA/RGB/LUMINANCE/…) to RGBA8. */
|
|
119
|
-
void webgl_convert_pixels(const uint8_t *source, int count, int format, bool premultiply,
|
|
120
|
-
std::vector<uint8_t> *out);
|
|
121
|
-
/** Decode a `texImage2D` source (`<img>`, `<canvas>`, `<video>`, `ImageData`,
|
|
122
|
-
* `ImageBitmap`) into top-down RGBA8. */
|
|
123
|
-
bool webgl_read_source(xt_value source, int *width, int *height,
|
|
124
|
-
std::vector<uint8_t> *rgba, bool premultiply);
|
|
125
|
-
/** Read the `UNPACK_FLIP_Y_WEBGL` / `UNPACK_PREMULTIPLY_ALPHA_WEBGL` flags set
|
|
126
|
-
* through `pixelStorei`. */
|
|
127
|
-
void webgl_unpack_flags(xt_value context, bool *flip_y, bool *premultiply);
|
|
128
|
-
/** Extension object for a compressed-texture family (null when unsupported,
|
|
129
|
-
* undefined when the name is not one of those extensions). */
|
|
130
|
-
xt_value webgl_compressed_extension(const std::string &name, xtgui::WebGLContext *context);
|
|
112
|
+
/* Declared in `dom_api_webgl_internal.h`, included above. */
|
|
131
113
|
|
|
132
114
|
/** How a pending handle names the node it will bind to. */
|
|
133
115
|
enum PendingKind { pending_by_id = 1, pending_by_selector = 2 };
|
|
@@ -285,6 +267,23 @@ METHOD(canvas_line_width_get);
|
|
|
285
267
|
METHOD(canvas_line_width_set);
|
|
286
268
|
METHOD(canvas_global_alpha_get);
|
|
287
269
|
METHOD(canvas_global_alpha_set);
|
|
270
|
+
METHOD(canvas_global_composite_get);
|
|
271
|
+
METHOD(canvas_global_composite_set);
|
|
272
|
+
METHOD(canvas_shadow_color_get);
|
|
273
|
+
METHOD(canvas_shadow_color_set);
|
|
274
|
+
METHOD(canvas_shadow_blur_get);
|
|
275
|
+
METHOD(canvas_shadow_blur_set);
|
|
276
|
+
METHOD(canvas_shadow_offset_x_get);
|
|
277
|
+
METHOD(canvas_shadow_offset_x_set);
|
|
278
|
+
METHOD(canvas_shadow_offset_y_get);
|
|
279
|
+
METHOD(canvas_shadow_offset_y_set);
|
|
280
|
+
METHOD(canvas_image_smoothing_enabled_get);
|
|
281
|
+
METHOD(canvas_image_smoothing_enabled_set);
|
|
282
|
+
METHOD(canvas_image_smoothing_quality_get);
|
|
283
|
+
METHOD(canvas_image_smoothing_quality_set);
|
|
284
|
+
METHOD(canvas_clip);
|
|
285
|
+
METHOD(canvas_is_point_in_path);
|
|
286
|
+
METHOD(canvas_is_point_in_stroke);
|
|
288
287
|
METHOD(canvas_font_get);
|
|
289
288
|
METHOD(canvas_font_set);
|
|
290
289
|
METHOD(canvas_text_align_get);
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `OffscreenCanvas`.
|
|
3
|
+
*
|
|
4
|
+
* An offscreen canvas is a `Canvas2D` bitmap with no DOM element behind it. It
|
|
5
|
+
* is created either by `new OffscreenCanvas(w, h)` or by transferring a live
|
|
6
|
+
* `<canvas>` element (`transferControlToOffscreen`), in which case the element
|
|
7
|
+
* keeps its bitmap and only the context ownership moves.
|
|
8
|
+
*
|
|
9
|
+
* Ownership stays with the window (`offscreen_canvases`), like every other
|
|
10
|
+
* canvas; the process-wide id table makes the bitmap reachable from
|
|
11
|
+
* `drawImage`/`createPattern`/`texImage2D` without a DOM node.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include "dom_api_internal.h"
|
|
15
|
+
|
|
16
|
+
#include <string>
|
|
17
|
+
#include <vector>
|
|
18
|
+
|
|
19
|
+
#include "canvas.h"
|
|
20
|
+
#include "gui_engine.h"
|
|
21
|
+
#include "image_bitmap.h"
|
|
22
|
+
|
|
23
|
+
#define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
|
|
24
|
+
|
|
25
|
+
namespace domapi {
|
|
26
|
+
|
|
27
|
+
namespace {
|
|
28
|
+
|
|
29
|
+
xtgui::Canvas2D *offscreen_canvas(xt_value self) {
|
|
30
|
+
xt_value id = xt_object_get_cstr(self, "__xt_gui_canvas");
|
|
31
|
+
if (!XT_IS_NUMBER(id)) return nullptr;
|
|
32
|
+
return xtgui::xt_canvas_by_id((uint64_t)xt_to_number(id));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
xt_value make_offscreen(xtgui::Canvas2D *canvas, xt_value window) {
|
|
36
|
+
xt_value handle = xt_object_new_with_proto(offscreen_canvas_proto());
|
|
37
|
+
xt_object_set(handle, xt_string_from_cstr("__xt_gui_canvas"), xt_number((double)canvas->id()));
|
|
38
|
+
xt_object_set(handle, xt_string_from_cstr("__xt_gui_window"), window);
|
|
39
|
+
xt_object_set(handle, xt_string_from_cstr("__xt_gui_offscreen"), XT_TRUE);
|
|
40
|
+
/* `ctx.canvas` of an offscreen context returns the offscreen object. */
|
|
41
|
+
xt_object_set(handle, xt_string_from_cstr("__xt_gui_node"), handle);
|
|
42
|
+
return handle;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
xt_value image_bitmap_handle(const xtgui::Image &image) {
|
|
46
|
+
const uint64_t id = xtgui::xt_image_bitmap_add(image);
|
|
47
|
+
xt_value name = xt_string_from_cstr("ImageBitmap");
|
|
48
|
+
xt_value constructor = xt_browser_type(1, &name);
|
|
49
|
+
xt_value prototype = xt_object_get_cstr(constructor, "prototype");
|
|
50
|
+
xt_value bitmap = XT_IS_OBJECT(prototype) ? xt_object_new_with_proto(prototype)
|
|
51
|
+
: xt_object_new();
|
|
52
|
+
xt_object_set(bitmap, xt_string_from_cstr("width"), xt_number(image.width));
|
|
53
|
+
xt_object_set(bitmap, xt_string_from_cstr("height"), xt_number(image.height));
|
|
54
|
+
xt_object_set(bitmap, xt_string_from_cstr("__xt_bitmap"), xt_number((double)id));
|
|
55
|
+
return bitmap;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
} // namespace
|
|
59
|
+
|
|
60
|
+
xt_value offscreen_canvas_proto() {
|
|
61
|
+
static xt_value proto = XT_UNDEFINED;
|
|
62
|
+
if (XT_IS_OBJECT(proto)) return proto;
|
|
63
|
+
proto = xt_object_new();
|
|
64
|
+
xt_gc_add_root(&proto);
|
|
65
|
+
struct Entry {
|
|
66
|
+
const char *name;
|
|
67
|
+
void *getter;
|
|
68
|
+
void *setter;
|
|
69
|
+
};
|
|
70
|
+
const Entry properties[] = {
|
|
71
|
+
{"width", (void *)offscreen_width_get, (void *)offscreen_width_set},
|
|
72
|
+
{"height", (void *)offscreen_height_get, (void *)offscreen_height_set},
|
|
73
|
+
};
|
|
74
|
+
for (const Entry &property : properties) {
|
|
75
|
+
xt_object_define_getter(proto, xt_string_from_cstr(property.name),
|
|
76
|
+
xt_closure_new(property.getter, 0, nullptr));
|
|
77
|
+
xt_object_define_setter(proto, xt_string_from_cstr(property.name),
|
|
78
|
+
xt_closure_new(property.setter, 0, nullptr));
|
|
79
|
+
}
|
|
80
|
+
struct Method {
|
|
81
|
+
const char *name;
|
|
82
|
+
void *fn;
|
|
83
|
+
};
|
|
84
|
+
const Method methods[] = {
|
|
85
|
+
{"getContext", (void *)offscreen_get_context},
|
|
86
|
+
{"transferToImageBitmap", (void *)offscreen_transfer_to_image_bitmap},
|
|
87
|
+
{"convertToBlob", (void *)offscreen_convert_to_blob},
|
|
88
|
+
};
|
|
89
|
+
for (const Method &method : methods) {
|
|
90
|
+
xt_object_set(proto, xt_string_from_cstr(method.name),
|
|
91
|
+
xt_closure_new(method.fn, 0, nullptr));
|
|
92
|
+
}
|
|
93
|
+
return proto;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
xt_value offscreen_canvas_create(int32_t argc, xt_value *argv) {
|
|
97
|
+
xt_value window = xt_gui_ensure_window();
|
|
98
|
+
XtGuiWindow *win = xt_gui_window_from_this(window);
|
|
99
|
+
if (win == nullptr) return XT_NULL;
|
|
100
|
+
int width = argc >= 1 ? (int)xt_to_number(xt_arg(argc, argv, 0)) : 300;
|
|
101
|
+
int height = argc >= 2 ? (int)xt_to_number(xt_arg(argc, argv, 1)) : 150;
|
|
102
|
+
if (width < 1) width = 1;
|
|
103
|
+
if (height < 1) height = 1;
|
|
104
|
+
auto canvas = std::make_unique<xtgui::Canvas2D>(width, height);
|
|
105
|
+
xtgui::Canvas2D *raw = canvas.get();
|
|
106
|
+
win->offscreen_canvases[raw->id()] = std::move(canvas);
|
|
107
|
+
return make_offscreen(raw, window);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
METHOD(offscreen_width_get) {
|
|
111
|
+
(void)env;
|
|
112
|
+
(void)argc;
|
|
113
|
+
(void)argv;
|
|
114
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
115
|
+
return xt_number(canvas != nullptr ? canvas->width() : 0);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
METHOD(offscreen_width_set) {
|
|
119
|
+
(void)env;
|
|
120
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
121
|
+
if (canvas != nullptr) canvas->resize((int)canvas_number_arg(argc, argv, 0, 0.0), canvas->height());
|
|
122
|
+
return XT_UNDEFINED;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
METHOD(offscreen_height_get) {
|
|
126
|
+
(void)env;
|
|
127
|
+
(void)argc;
|
|
128
|
+
(void)argv;
|
|
129
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
130
|
+
return xt_number(canvas != nullptr ? canvas->height() : 0);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
METHOD(offscreen_height_set) {
|
|
134
|
+
(void)env;
|
|
135
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
136
|
+
if (canvas != nullptr) canvas->resize(canvas->width(), (int)canvas_number_arg(argc, argv, 0, 0.0));
|
|
137
|
+
return XT_UNDEFINED;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
METHOD(offscreen_get_context) {
|
|
141
|
+
(void)env;
|
|
142
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
143
|
+
if (canvas == nullptr) return XT_NULL;
|
|
144
|
+
const std::string mode = canvas_string_arg(argc, argv, 0);
|
|
145
|
+
/* The GPU context needs a DOM node for its texture table; the 2D bitmap does
|
|
146
|
+
* not, so only "2d" resolves here. */
|
|
147
|
+
if (mode != "2d") return XT_NULL;
|
|
148
|
+
xt_value cached = xt_object_get_cstr(self, "__xt_gui_ctx");
|
|
149
|
+
if (XT_IS_OBJECT(cached)) return cached;
|
|
150
|
+
xt_value attributes = xt_arg(argc, argv, 1);
|
|
151
|
+
bool alpha = true;
|
|
152
|
+
if (XT_IS_OBJECT(attributes)) {
|
|
153
|
+
xt_value value = xt_object_get_cstr(attributes, "alpha");
|
|
154
|
+
if (XT_IS_BOOL(value)) alpha = value_truthy(value);
|
|
155
|
+
}
|
|
156
|
+
canvas->set_alpha(alpha);
|
|
157
|
+
xt_value context = xt_object_new_with_proto(canvas_proto());
|
|
158
|
+
xt_object_set(context, xt_string_from_cstr("__xt_gui_canvas"), xt_number((double)canvas->id()));
|
|
159
|
+
xt_object_set(context, xt_string_from_cstr("__xt_gui_node"), self);
|
|
160
|
+
xt_object_set(context, xt_string_from_cstr("__xt_gui_ctx_attributes"),
|
|
161
|
+
canvas_context_attributes(attributes, alpha));
|
|
162
|
+
xt_object_set(self, xt_string_from_cstr("__xt_gui_ctx"), context);
|
|
163
|
+
return context;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
METHOD(offscreen_transfer_to_image_bitmap) {
|
|
167
|
+
(void)env;
|
|
168
|
+
(void)argc;
|
|
169
|
+
(void)argv;
|
|
170
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
171
|
+
if (canvas == nullptr || canvas->image().width <= 0) return XT_NULL;
|
|
172
|
+
return image_bitmap_handle(canvas->image());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
METHOD(offscreen_convert_to_blob) {
|
|
176
|
+
(void)env;
|
|
177
|
+
(void)argc;
|
|
178
|
+
(void)argv;
|
|
179
|
+
xtgui::Canvas2D *canvas = offscreen_canvas(self);
|
|
180
|
+
if (canvas == nullptr) return xt_promise_reject(xt_string_from_cstr("InvalidStateError"));
|
|
181
|
+
std::vector<unsigned char> png;
|
|
182
|
+
if (!canvas->encode_png(&png)) return xt_promise_reject(xt_string_from_cstr("InvalidStateError"));
|
|
183
|
+
xt_value data = xt_array_new(0, nullptr);
|
|
184
|
+
for (unsigned char byte : png) xt_array_push(data, xt_number((double)byte));
|
|
185
|
+
xt_value blob = xt_object_new();
|
|
186
|
+
xt_object_set(blob, xt_string_from_cstr("type"), xt_string_from_cstr("image/png"));
|
|
187
|
+
xt_object_set(blob, xt_string_from_cstr("size"), xt_number((double)png.size()));
|
|
188
|
+
xt_object_set(blob, xt_string_from_cstr("__xt_gui_blob_data"), data);
|
|
189
|
+
return xt_promise_resolve(blob);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
METHOD(canvas_transfer_control_to_offscreen) {
|
|
193
|
+
(void)env;
|
|
194
|
+
(void)argc;
|
|
195
|
+
(void)argv;
|
|
196
|
+
xt_value existing = xt_object_get_cstr(self, "__xt_gui_offscreen");
|
|
197
|
+
if (XT_IS_OBJECT(existing)) return existing;
|
|
198
|
+
XtGuiWindow *win = nullptr;
|
|
199
|
+
xtgui::Node *node = resolve_node(self, &win);
|
|
200
|
+
if (win == nullptr || node == nullptr || !node->isElement() || !node->isTag("canvas")) {
|
|
201
|
+
return XT_NULL;
|
|
202
|
+
}
|
|
203
|
+
if (xt_gui_webgl_find(win, node) != nullptr) return XT_NULL;
|
|
204
|
+
xtgui::Canvas2D *canvas = xt_gui_canvas_get(win, node);
|
|
205
|
+
if (canvas == nullptr) return XT_NULL;
|
|
206
|
+
xt_value handle = make_offscreen(canvas, win->object);
|
|
207
|
+
xt_object_set(self, xt_string_from_cstr("__xt_gui_offscreen"), handle);
|
|
208
|
+
return handle;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
} // namespace domapi
|
|
212
|
+
|
|
213
|
+
#undef METHOD
|
|
@@ -111,6 +111,7 @@ xt_value node_proto() {
|
|
|
111
111
|
define_method(proto, "pause", (void *)node_pause);
|
|
112
112
|
define_method(proto, "load", (void *)node_load);
|
|
113
113
|
define_method(proto, "getContext", (void *)node_get_context);
|
|
114
|
+
define_method(proto, "transferControlToOffscreen", (void *)canvas_transfer_control_to_offscreen);
|
|
114
115
|
/* `toDataURL`/`toBlob` belong to the canvas *element*, as in the DOM. */
|
|
115
116
|
define_method(proto, "toDataURL", (void *)canvas_to_data_url);
|
|
116
117
|
define_method(proto, "toBlob", (void *)canvas_to_blob);
|
|
@@ -210,6 +211,20 @@ xt_value canvas_proto() {
|
|
|
210
211
|
define_setter(proto, "lineWidth", (void *)canvas_line_width_set);
|
|
211
212
|
define_getter(proto, "globalAlpha", (void *)canvas_global_alpha_get);
|
|
212
213
|
define_setter(proto, "globalAlpha", (void *)canvas_global_alpha_set);
|
|
214
|
+
define_getter(proto, "globalCompositeOperation", (void *)canvas_global_composite_get);
|
|
215
|
+
define_setter(proto, "globalCompositeOperation", (void *)canvas_global_composite_set);
|
|
216
|
+
define_getter(proto, "shadowColor", (void *)canvas_shadow_color_get);
|
|
217
|
+
define_setter(proto, "shadowColor", (void *)canvas_shadow_color_set);
|
|
218
|
+
define_getter(proto, "shadowBlur", (void *)canvas_shadow_blur_get);
|
|
219
|
+
define_setter(proto, "shadowBlur", (void *)canvas_shadow_blur_set);
|
|
220
|
+
define_getter(proto, "shadowOffsetX", (void *)canvas_shadow_offset_x_get);
|
|
221
|
+
define_setter(proto, "shadowOffsetX", (void *)canvas_shadow_offset_x_set);
|
|
222
|
+
define_getter(proto, "shadowOffsetY", (void *)canvas_shadow_offset_y_get);
|
|
223
|
+
define_setter(proto, "shadowOffsetY", (void *)canvas_shadow_offset_y_set);
|
|
224
|
+
define_getter(proto, "imageSmoothingEnabled", (void *)canvas_image_smoothing_enabled_get);
|
|
225
|
+
define_setter(proto, "imageSmoothingEnabled", (void *)canvas_image_smoothing_enabled_set);
|
|
226
|
+
define_getter(proto, "imageSmoothingQuality", (void *)canvas_image_smoothing_quality_get);
|
|
227
|
+
define_setter(proto, "imageSmoothingQuality", (void *)canvas_image_smoothing_quality_set);
|
|
213
228
|
define_getter(proto, "font", (void *)canvas_font_get);
|
|
214
229
|
define_setter(proto, "font", (void *)canvas_font_set);
|
|
215
230
|
define_getter(proto, "textAlign", (void *)canvas_text_align_get);
|
|
@@ -245,6 +260,9 @@ xt_value canvas_proto() {
|
|
|
245
260
|
define_method(proto, "bezierCurveTo", (void *)canvas_bezier_curve_to);
|
|
246
261
|
define_method(proto, "fill", (void *)canvas_fill);
|
|
247
262
|
define_method(proto, "stroke", (void *)canvas_stroke);
|
|
263
|
+
define_method(proto, "clip", (void *)canvas_clip);
|
|
264
|
+
define_method(proto, "isPointInPath", (void *)canvas_is_point_in_path);
|
|
265
|
+
define_method(proto, "isPointInStroke", (void *)canvas_is_point_in_stroke);
|
|
248
266
|
define_method(proto, "clearRect", (void *)canvas_clear_rect);
|
|
249
267
|
define_method(proto, "fillRect", (void *)canvas_fill_rect);
|
|
250
268
|
define_method(proto, "strokeRect", (void *)canvas_stroke_rect);
|
|
@@ -223,6 +223,16 @@ xt_value webgl_proto() {
|
|
|
223
223
|
define_getter(proto, "canvas", (void *)webgl_canvas_get);
|
|
224
224
|
define_getter(proto, "drawingBufferWidth", (void *)webgl_drawing_buffer_width_get);
|
|
225
225
|
define_getter(proto, "drawingBufferHeight", (void *)webgl_drawing_buffer_height_get);
|
|
226
|
+
/* `gl.constructor.name` is how three.js tells a WebGL 2 context from a
|
|
227
|
+
* WebGL 1 one. A host-type value from `xt_browser_type` later replaces this
|
|
228
|
+
* with the real constructor (and its `prototype`), but the context must
|
|
229
|
+
* answer the name even when the page never read the global. */
|
|
230
|
+
{
|
|
231
|
+
xt_value constructor = xt_object_new();
|
|
232
|
+
xt_object_set(constructor, xt_string_from_cstr("name"),
|
|
233
|
+
xt_string_from_cstr("WebGLRenderingContext"));
|
|
234
|
+
xt_object_set(proto, xt_string_from_cstr("constructor"), constructor);
|
|
235
|
+
}
|
|
226
236
|
g_webgl_proto = proto;
|
|
227
237
|
return proto;
|
|
228
238
|
}
|
|
@@ -321,15 +331,17 @@ std::vector<uint8_t> webgl_bytes(xt_value value) {
|
|
|
321
331
|
const double length = xt_to_number(xt_get(value, xt_string_from_cstr("byteLength")));
|
|
322
332
|
if (!(length > 0.0) || !xt_is_array_buffer(buffer)) return out;
|
|
323
333
|
out.resize((size_t)length);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
334
|
+
/* The runtime stores an ArrayBuffer as one byte value per array slot, so
|
|
335
|
+
* this is still an element loop — but one call into the runtime instead of
|
|
336
|
+
* one extern call per byte, which is what a multi-megabyte vertex buffer or
|
|
337
|
+
* `texImage2D` pays for. */
|
|
338
|
+
out.resize(xt_array_buffer_copy_bytes_out(buffer, offset, out.data(), (uint32_t)length));
|
|
327
339
|
return out;
|
|
328
340
|
}
|
|
329
341
|
if (xt_is_array_buffer(value)) {
|
|
330
342
|
const uint32_t length = xt_array_buffer_byte_length(value);
|
|
331
343
|
out.resize(length);
|
|
332
|
-
|
|
344
|
+
out.resize(xt_array_buffer_copy_bytes_out(value, 0, out.data(), length));
|
|
333
345
|
return out;
|
|
334
346
|
}
|
|
335
347
|
const std::vector<double> numbers = webgl_numbers(value);
|
|
@@ -346,13 +358,21 @@ std::vector<uint8_t> webgl_bytes(xt_value value) {
|
|
|
346
358
|
void webgl_write_bytes(xt_value target, const uint8_t *bytes, size_t count) {
|
|
347
359
|
if (!XT_IS_OBJECT(target) || bytes == nullptr) return;
|
|
348
360
|
const int kind = xt_typed_array_kind_of(target);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
361
|
+
if (kind >= 0) {
|
|
362
|
+
xt_value buffer = xt_typed_array_buffer_of(target);
|
|
363
|
+
const uint32_t offset = xt_typed_array_byte_offset_of(target);
|
|
364
|
+
if (xt_is_array_buffer(buffer)) {
|
|
365
|
+
xt_array_buffer_copy_bytes_in(buffer, offset, bytes, (uint32_t)count);
|
|
366
|
+
return;
|
|
354
367
|
}
|
|
355
368
|
}
|
|
369
|
+
if (xt_is_array_buffer(target)) {
|
|
370
|
+
xt_array_buffer_copy_bytes_in(target, 0, bytes, (uint32_t)count);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
for (size_t i = 0; i < count; i++) {
|
|
374
|
+
xt_set(target, xt_number((double)i), xt_number((double)bytes[i]));
|
|
375
|
+
}
|
|
356
376
|
}
|
|
357
377
|
|
|
358
378
|
/* -- context handle members ---------------------------------------------- */
|
|
@@ -121,12 +121,44 @@ xt_value uint_array(const unsigned int *values, int count) {
|
|
|
121
121
|
xt_value webgl2_proto() {
|
|
122
122
|
xt_gc_add_root(&g_webgl2_proto);
|
|
123
123
|
if (XT_IS_OBJECT(g_webgl2_proto)) return g_webgl2_proto;
|
|
124
|
-
|
|
124
|
+
/* WebGL 2 shares the WebGL 1 surface but not its prototype: in a browser
|
|
125
|
+
* `gl2 instanceof WebGLRenderingContext` is false, which is how three.js and
|
|
126
|
+
* other libraries detect WebGL 2. Copy the WebGL 1 members instead of
|
|
127
|
+
* inheriting the WebGL 1 prototype. */
|
|
128
|
+
xt_value webgl1 = webgl_proto();
|
|
129
|
+
xt_value proto = xt_object_new();
|
|
130
|
+
xt_value keys = xt_object_keys(webgl1);
|
|
131
|
+
const double count = xt_to_number(xt_array_length(keys));
|
|
132
|
+
for (int32_t i = 0; i < (int32_t)count; i++) {
|
|
133
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
134
|
+
const char *name = xt_string_data(key);
|
|
135
|
+
if (name == nullptr) continue;
|
|
136
|
+
/* `constructor` gets the WebGL 2 name below. The three host getters are
|
|
137
|
+
* accessors, not values: reading them here would run them against the
|
|
138
|
+
* WebGL 1 prototype and copy `undefined`. Reinstall them as accessors. */
|
|
139
|
+
if (strcmp(name, "constructor") == 0 || strcmp(name, "canvas") == 0 ||
|
|
140
|
+
strcmp(name, "drawingBufferWidth") == 0 || strcmp(name, "drawingBufferHeight") == 0) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
xt_object_set(proto, key, xt_object_get(webgl1, key));
|
|
144
|
+
}
|
|
145
|
+
xt_object_define_getter(proto, xt_string_from_cstr("canvas"),
|
|
146
|
+
xt_closure_new((void *)webgl_canvas_get, 0, nullptr));
|
|
147
|
+
xt_object_define_getter(proto, xt_string_from_cstr("drawingBufferWidth"),
|
|
148
|
+
xt_closure_new((void *)webgl_drawing_buffer_width_get, 0, nullptr));
|
|
149
|
+
xt_object_define_getter(proto, xt_string_from_cstr("drawingBufferHeight"),
|
|
150
|
+
xt_closure_new((void *)webgl_drawing_buffer_height_get, 0, nullptr));
|
|
125
151
|
#define XT_WEBGL2_CONSTANT(name, value) \
|
|
126
152
|
xt_object_set(proto, xt_string_from_cstr(#name), xt_number((double)(value)));
|
|
127
153
|
XT_WEBGL2_CONSTANTS(XT_WEBGL2_CONSTANT)
|
|
128
154
|
#undef XT_WEBGL2_CONSTANT
|
|
129
155
|
for (const MethodEntry &method : kMethods) define_method(proto, method.name, method.fn);
|
|
156
|
+
{
|
|
157
|
+
xt_value constructor = xt_object_new();
|
|
158
|
+
xt_object_set(constructor, xt_string_from_cstr("name"),
|
|
159
|
+
xt_string_from_cstr("WebGL2RenderingContext"));
|
|
160
|
+
xt_object_set(proto, xt_string_from_cstr("constructor"), constructor);
|
|
161
|
+
}
|
|
130
162
|
g_webgl2_proto = proto;
|
|
131
163
|
return proto;
|
|
132
164
|
}
|