@next2d/builder 0.1.4 → 0.1.6

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 (55) hide show
  1. package/README.md +11 -0
  2. package/dist/index.js +247 -3
  3. package/package.json +11 -9
  4. package/templates/xbox/CMakeLists.txt +121 -0
  5. package/templates/xbox/MicrosoftGame.config +36 -0
  6. package/templates/xbox/README.md +319 -0
  7. package/templates/xbox/cmake/FetchDawn.cmake +42 -0
  8. package/templates/xbox/cmake/FindV8.cmake +62 -0
  9. package/templates/xbox/js/bootstrap.js +143 -0
  10. package/templates/xbox/js/selftest.js +515 -0
  11. package/templates/xbox/src/AssetLoader.cpp +106 -0
  12. package/templates/xbox/src/AssetLoader.h +35 -0
  13. package/templates/xbox/src/EventLoop.cpp +162 -0
  14. package/templates/xbox/src/EventLoop.h +73 -0
  15. package/templates/xbox/src/HostContext.h +58 -0
  16. package/templates/xbox/src/bindings/Audio.cpp +320 -0
  17. package/templates/xbox/src/bindings/Bindings.h +75 -0
  18. package/templates/xbox/src/bindings/Canvas.cpp +171 -0
  19. package/templates/xbox/src/bindings/Canvas2D.cpp +462 -0
  20. package/templates/xbox/src/bindings/Console.cpp +52 -0
  21. package/templates/xbox/src/bindings/DomShims.cpp +221 -0
  22. package/templates/xbox/src/bindings/EventTarget.cpp +127 -0
  23. package/templates/xbox/src/bindings/EventTarget.h +17 -0
  24. package/templates/xbox/src/bindings/Fetch.cpp +149 -0
  25. package/templates/xbox/src/bindings/Gamepad.cpp +79 -0
  26. package/templates/xbox/src/bindings/Image.cpp +160 -0
  27. package/templates/xbox/src/bindings/ImageSource.h +26 -0
  28. package/templates/xbox/src/bindings/Network.cpp +303 -0
  29. package/templates/xbox/src/bindings/RasterCore.h +265 -0
  30. package/templates/xbox/src/bindings/Timers.cpp +87 -0
  31. package/templates/xbox/src/bindings/Video.cpp +235 -0
  32. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +1318 -0
  33. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +119 -0
  34. package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +245 -0
  35. package/templates/xbox/src/gpu/DawnContext.cpp +170 -0
  36. package/templates/xbox/src/gpu/DawnContext.h +64 -0
  37. package/templates/xbox/src/main.cpp +368 -0
  38. package/templates/xbox/src/platform/AudioEngine.cpp +184 -0
  39. package/templates/xbox/src/platform/AudioEngine.h +65 -0
  40. package/templates/xbox/src/platform/GamepadManager.cpp +83 -0
  41. package/templates/xbox/src/platform/GamepadManager.h +40 -0
  42. package/templates/xbox/src/platform/ImageTypes.h +17 -0
  43. package/templates/xbox/src/platform/TextRasterizer.cpp +183 -0
  44. package/templates/xbox/src/platform/TextRasterizer.h +35 -0
  45. package/templates/xbox/src/platform/WicDecoder.cpp +63 -0
  46. package/templates/xbox/src/platform/WicDecoder.h +16 -0
  47. package/templates/xbox/src/v8/V8Runtime.cpp +284 -0
  48. package/templates/xbox/src/v8/V8Runtime.h +68 -0
  49. package/templates/xbox/src/v8/V8Util.h +56 -0
  50. package/templates/xbox/src/worker/WorkerRuntime.cpp +453 -0
  51. package/templates/xbox/src/worker/WorkerRuntime.h +108 -0
  52. package/templates/xbox/tests/check_local.sh +56 -0
  53. package/templates/xbox/tests/raster_test.bin +0 -0
  54. package/templates/xbox/tests/raster_test.cpp +279 -0
  55. package/templates/xbox/tests/windows_platform_test.cpp +187 -0
@@ -0,0 +1,221 @@
1
+ #include "Bindings.h"
2
+
3
+ #include "HostContext.h"
4
+ #include "EventTarget.h"
5
+ #include "v8/V8Util.h"
6
+
7
+ #include <Windows.h>
8
+
9
+ namespace next2d {
10
+
11
+ using v8util::Str;
12
+ using v8util::SetMethod;
13
+ using v8util::SetValue;
14
+
15
+ namespace {
16
+
17
+ // document.createElement(tag)
18
+ void CreateElement(const v8::FunctionCallbackInfo<v8::Value>& args)
19
+ {
20
+ v8::Isolate* isolate = args.GetIsolate();
21
+ HostContext* host = HostContext::From(isolate);
22
+ const std::string tag = args.Length() > 0 ? v8util::ToStdString(isolate, args[0]) : "";
23
+
24
+ if (tag == "canvas") {
25
+ args.GetReturnValue().Set(CreateCanvasElement(isolate, host, 0, 0));
26
+ return;
27
+ }
28
+ if (tag == "video") {
29
+ args.GetReturnValue().Set(CreateVideoElement(isolate, host));
30
+ return;
31
+ }
32
+
33
+ // その他の要素は最小スタブ (style/子要素操作/イベントを no-op で備える)
34
+ v8::Local<v8::Object> el = v8::Object::New(isolate);
35
+ SetValue(isolate, el, "style", v8::Object::New(isolate));
36
+ SetValue(isolate, el, "tagName", Str(isolate, tag));
37
+ SetMethod(isolate, el, "appendChild", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
38
+ if (a.Length() > 0) a.GetReturnValue().Set(a[0]);
39
+ });
40
+ SetMethod(isolate, el, "removeChild", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
41
+ SetMethod(isolate, el, "setAttribute", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
42
+ SetMethod(isolate, el, "addEventListener", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
43
+ SetMethod(isolate, el, "removeEventListener", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
44
+ args.GetReturnValue().Set(el);
45
+ }
46
+
47
+ // window/document/body 用の EventTarget を設置する (実ディスパッチ対応)。
48
+ void NoopEventTarget(v8::Isolate* isolate, v8::Local<v8::Object> obj)
49
+ {
50
+ InstallEventTarget(isolate, obj);
51
+ }
52
+
53
+ } // namespace
54
+
55
+ namespace {
56
+
57
+ // navigator.clipboard.readText() -> Promise<string> (Win32 クリップボード)
58
+ void ClipboardReadText(const v8::FunctionCallbackInfo<v8::Value>& args)
59
+ {
60
+ v8::Isolate* isolate = args.GetIsolate();
61
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
62
+ auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
63
+ args.GetReturnValue().Set(resolver->GetPromise());
64
+
65
+ std::string text;
66
+ if (OpenClipboard(nullptr)) {
67
+ HANDLE h = GetClipboardData(CF_UNICODETEXT);
68
+ if (h) {
69
+ auto* w = static_cast<const wchar_t*>(GlobalLock(h));
70
+ if (w) {
71
+ int n = WideCharToMultiByte(CP_UTF8, 0, w, -1, nullptr, 0, nullptr, nullptr);
72
+ if (n > 0) {
73
+ text.resize(n - 1);
74
+ WideCharToMultiByte(CP_UTF8, 0, w, -1, text.data(), n, nullptr, nullptr);
75
+ }
76
+ GlobalUnlock(h);
77
+ }
78
+ }
79
+ CloseClipboard();
80
+ }
81
+ resolver->Resolve(ctx, Str(isolate, text)).Check();
82
+ }
83
+
84
+ // navigator.clipboard.writeText(text) -> Promise
85
+ void ClipboardWriteText(const v8::FunctionCallbackInfo<v8::Value>& args)
86
+ {
87
+ v8::Isolate* isolate = args.GetIsolate();
88
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
89
+ auto resolver = v8::Promise::Resolver::New(ctx).ToLocalChecked();
90
+ args.GetReturnValue().Set(resolver->GetPromise());
91
+
92
+ if (args.Length() > 0 && OpenClipboard(nullptr)) {
93
+ const std::string s = v8util::ToStdString(isolate, args[0]);
94
+ int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0);
95
+ if (n > 0) {
96
+ HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, static_cast<size_t>(n) * sizeof(wchar_t));
97
+ if (h) {
98
+ auto* w = static_cast<wchar_t*>(GlobalLock(h));
99
+ MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, w, n);
100
+ GlobalUnlock(h);
101
+ EmptyClipboard();
102
+ SetClipboardData(CF_UNICODETEXT, h);
103
+ }
104
+ }
105
+ CloseClipboard();
106
+ }
107
+ resolver->Resolve(ctx, v8::Undefined(isolate)).Check();
108
+ }
109
+
110
+ // new OffscreenCanvas(width, height)
111
+ void OffscreenCanvasConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
112
+ {
113
+ v8::Isolate* isolate = args.GetIsolate();
114
+ if (!args.IsConstructCall()) {
115
+ v8util::ThrowTypeError(isolate, "OffscreenCanvas must be called with new");
116
+ return;
117
+ }
118
+ HostContext* host = HostContext::From(isolate);
119
+ int w = args.Length() > 0 && args[0]->IsNumber()
120
+ ? static_cast<int>(args[0].As<v8::Number>()->Value()) : host->viewport_width;
121
+ int h = args.Length() > 1 && args[1]->IsNumber()
122
+ ? static_cast<int>(args[1].As<v8::Number>()->Value()) : host->viewport_height;
123
+ args.GetReturnValue().Set(CreateOffscreenCanvas(isolate, host, w, h));
124
+ }
125
+
126
+ } // namespace
127
+
128
+ void InstallDomShims(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* host)
129
+ {
130
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
131
+
132
+ // OffscreenCanvas コンストラクタ (メッシュ生成/テキスト/点内包判定で使用)
133
+ {
134
+ v8::Local<v8::FunctionTemplate> oc =
135
+ v8::FunctionTemplate::New(isolate, OffscreenCanvasConstructor);
136
+ oc->SetClassName(Str(isolate, "OffscreenCanvas"));
137
+ global->Set(ctx, Str(isolate, "OffscreenCanvas"),
138
+ oc->GetFunction(ctx).ToLocalChecked()).Check();
139
+ }
140
+
141
+ // globalThis / window / self は同一オブジェクトを指す
142
+ SetValue(isolate, global, "globalThis", global);
143
+ SetValue(isolate, global, "window", global);
144
+ SetValue(isolate, global, "self", global);
145
+ NoopEventTarget(isolate, global);
146
+
147
+ // devicePixelRatio
148
+ SetValue(isolate, global, "devicePixelRatio",
149
+ v8::Number::New(isolate, host->device_pixel_ratio));
150
+
151
+ // screen
152
+ v8::Local<v8::Object> screen = v8::Object::New(isolate);
153
+ SetValue(isolate, screen, "width", v8::Integer::New(isolate, host->viewport_width));
154
+ SetValue(isolate, screen, "height", v8::Integer::New(isolate, host->viewport_height));
155
+ SetValue(isolate, global, "screen", screen);
156
+
157
+ // innerWidth / innerHeight
158
+ SetValue(isolate, global, "innerWidth", v8::Integer::New(isolate, host->viewport_width));
159
+ SetValue(isolate, global, "innerHeight", v8::Integer::New(isolate, host->viewport_height));
160
+
161
+ // navigator (gpu/getGamepads は後段のバインディングが付与)
162
+ v8::Local<v8::Object> navigator = v8::Object::New(isolate);
163
+ SetValue(isolate, navigator, "userAgent",
164
+ Str(isolate, "Next2D/Xbox (GDK; V8; Dawn/WebGPU)"));
165
+ SetValue(isolate, navigator, "language", Str(isolate, "en-US"));
166
+ SetValue(isolate, navigator, "platform", Str(isolate, "Xbox"));
167
+
168
+ // navigator.clipboard (テキスト貼付/コピー、Win32 クリップボード)
169
+ v8::Local<v8::Object> clipboard = v8::Object::New(isolate);
170
+ SetMethod(isolate, clipboard, "readText", ClipboardReadText);
171
+ SetMethod(isolate, clipboard, "writeText", ClipboardWriteText);
172
+ SetValue(isolate, navigator, "clipboard", clipboard);
173
+
174
+ SetValue(isolate, global, "navigator", navigator);
175
+
176
+ // document
177
+ v8::Local<v8::Object> document = v8::Object::New(isolate);
178
+ SetMethod(isolate, document, "createElement", CreateElement);
179
+ SetMethod(isolate, document, "getElementById",
180
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) { a.GetReturnValue().SetNull(); });
181
+ SetMethod(isolate, document, "querySelector",
182
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) { a.GetReturnValue().SetNull(); });
183
+ SetMethod(isolate, document, "getElementsByTagName",
184
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) {
185
+ a.GetReturnValue().Set(v8::Array::New(a.GetIsolate(), 0));
186
+ });
187
+ NoopEventTarget(isolate, document);
188
+
189
+ // document.body / documentElement は canvas を格納できる最小要素
190
+ v8::Local<v8::Object> body = v8::Object::New(isolate);
191
+ SetValue(isolate, body, "style", v8::Object::New(isolate));
192
+ SetMethod(isolate, body, "appendChild", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
193
+ if (a.Length() > 0) a.GetReturnValue().Set(a[0]);
194
+ });
195
+ NoopEventTarget(isolate, body);
196
+ SetValue(isolate, document, "body", body);
197
+ SetValue(isolate, document, "documentElement", body);
198
+
199
+ // メインの canvas をあらかじめ 1 枚用意し document.__mainCanvas として公開する。
200
+ // bootstrap.js はこれを既定キャンバスとして Next2D に渡す。
201
+ v8::Local<v8::Object> canvas = CreateCanvasElement(isolate, host, 0, 0);
202
+ SetValue(isolate, document, "__mainCanvas", canvas);
203
+
204
+ global->Set(ctx, Str(isolate, "document"), document).Check();
205
+ }
206
+
207
+ void InstallGlobalBindings(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* host)
208
+ {
209
+ // 依存順: console -> DOM -> timers -> fetch -> image -> audio -> webgpu -> gamepad
210
+ InstallConsole(isolate, global);
211
+ InstallDomShims(isolate, global, host);
212
+ InstallTimers(isolate, global, host);
213
+ InstallFetch(isolate, global, host);
214
+ InstallNetwork(isolate, global, host); // XMLHttpRequest/Blob/URL/ImageData
215
+ InstallImage(isolate, global, host);
216
+ InstallAudio(isolate, global, host);
217
+ InstallWebGPU(isolate, global, host); // navigator.gpu
218
+ InstallGamepad(isolate, global, host); // navigator.getGamepads
219
+ }
220
+
221
+ } // namespace next2d
@@ -0,0 +1,127 @@
1
+ #include "EventTarget.h"
2
+
3
+ #include "v8/V8Util.h"
4
+
5
+ #include <string>
6
+
7
+ namespace next2d {
8
+
9
+ using v8util::Str;
10
+ using v8util::SetMethod;
11
+ using v8util::SetValue;
12
+ using v8util::ToStdString;
13
+
14
+ namespace {
15
+
16
+ void AddEventListener(const v8::FunctionCallbackInfo<v8::Value>& args)
17
+ {
18
+ v8::Isolate* isolate = args.GetIsolate();
19
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
20
+ if (args.Length() < 2 || !args[1]->IsFunction()) {
21
+ return;
22
+ }
23
+ const std::string type = ToStdString(isolate, args[0]);
24
+ v8::Local<v8::Object> self = args.This();
25
+
26
+ v8::Local<v8::Value> lv;
27
+ v8::Local<v8::Object> listeners;
28
+ if (self->Get(ctx, Str(isolate, "__listeners")).ToLocal(&lv) && lv->IsObject()) {
29
+ listeners = lv.As<v8::Object>();
30
+ } else {
31
+ listeners = v8::Object::New(isolate);
32
+ SetValue(isolate, self, "__listeners", listeners);
33
+ }
34
+
35
+ v8::Local<v8::Value> arrv;
36
+ v8::Local<v8::Array> arr;
37
+ if (listeners->Get(ctx, Str(isolate, type.c_str())).ToLocal(&arrv) && arrv->IsArray()) {
38
+ arr = arrv.As<v8::Array>();
39
+ } else {
40
+ arr = v8::Array::New(isolate, 0);
41
+ listeners->Set(ctx, Str(isolate, type.c_str()), arr).Check();
42
+ }
43
+ arr->Set(ctx, arr->Length(), args[1]).Check();
44
+ }
45
+
46
+ void RemoveEventListener(const v8::FunctionCallbackInfo<v8::Value>& args)
47
+ {
48
+ v8::Isolate* isolate = args.GetIsolate();
49
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
50
+ if (args.Length() < 2) {
51
+ return;
52
+ }
53
+ const std::string type = ToStdString(isolate, args[0]);
54
+ v8::Local<v8::Value> lv;
55
+ if (!args.This()->Get(ctx, Str(isolate, "__listeners")).ToLocal(&lv) || !lv->IsObject()) {
56
+ return;
57
+ }
58
+ v8::Local<v8::Value> arrv;
59
+ if (!lv.As<v8::Object>()->Get(ctx, Str(isolate, type.c_str())).ToLocal(&arrv) || !arrv->IsArray()) {
60
+ return;
61
+ }
62
+ // 一致する関数を null 化 (簡易)
63
+ auto arr = arrv.As<v8::Array>();
64
+ for (uint32_t i = 0; i < arr->Length(); ++i) {
65
+ v8::Local<v8::Value> fn;
66
+ if (arr->Get(ctx, i).ToLocal(&fn) && fn->StrictEquals(args[1])) {
67
+ arr->Set(ctx, i, v8::Null(isolate)).Check();
68
+ }
69
+ }
70
+ }
71
+
72
+ void DispatchEventJS(const v8::FunctionCallbackInfo<v8::Value>& args)
73
+ {
74
+ v8::Isolate* isolate = args.GetIsolate();
75
+ if (args.Length() >= 1 && args[0]->IsObject()) {
76
+ DispatchEvent(isolate, args.This(), args[0].As<v8::Object>());
77
+ }
78
+ args.GetReturnValue().Set(true);
79
+ }
80
+
81
+ } // namespace
82
+
83
+ void InstallEventTarget(v8::Isolate* isolate, v8::Local<v8::Object> target)
84
+ {
85
+ SetMethod(isolate, target, "addEventListener", AddEventListener);
86
+ SetMethod(isolate, target, "removeEventListener", RemoveEventListener);
87
+ SetMethod(isolate, target, "dispatchEvent", DispatchEventJS);
88
+ }
89
+
90
+ void DispatchEvent(v8::Isolate* isolate, v8::Local<v8::Object> target,
91
+ v8::Local<v8::Object> event)
92
+ {
93
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
94
+ v8::Local<v8::Value> type_val;
95
+ if (!event->Get(ctx, Str(isolate, "type")).ToLocal(&type_val)) {
96
+ return;
97
+ }
98
+ const std::string type = ToStdString(isolate, type_val);
99
+ v8::Local<v8::Value> args1[1] = { event };
100
+
101
+ // on<type> プロパティ
102
+ v8::Local<v8::Value> on;
103
+ const std::string onname = "on" + type;
104
+ if (target->Get(ctx, Str(isolate, onname.c_str())).ToLocal(&on) && on->IsFunction()) {
105
+ v8::TryCatch tc(isolate);
106
+ (void) on.As<v8::Function>()->Call(ctx, target, 1, args1);
107
+ }
108
+
109
+ // __listeners[type]
110
+ v8::Local<v8::Value> lv;
111
+ if (target->Get(ctx, Str(isolate, "__listeners")).ToLocal(&lv) && lv->IsObject()) {
112
+ v8::Local<v8::Value> arrv;
113
+ if (lv.As<v8::Object>()->Get(ctx, Str(isolate, type.c_str())).ToLocal(&arrv) &&
114
+ arrv->IsArray()) {
115
+ auto arr = arrv.As<v8::Array>();
116
+ for (uint32_t i = 0; i < arr->Length(); ++i) {
117
+ v8::Local<v8::Value> fn;
118
+ if (arr->Get(ctx, i).ToLocal(&fn) && fn->IsFunction()) {
119
+ v8::TryCatch tc(isolate);
120
+ (void) fn.As<v8::Function>()->Call(ctx, target, 1, args1);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ } // namespace next2d
@@ -0,0 +1,17 @@
1
+ // DOM EventTarget 相当の最小実装。
2
+ // addEventListener で登録した関数を __listeners[type] に保持し、C++ から DispatchEvent で発火する。
3
+ // main.cpp の WndProc が Win32 入力を PointerEvent/KeyboardEvent/WheelEvent へ変換して使う。
4
+ #pragma once
5
+
6
+ #include <v8.h>
7
+
8
+ namespace next2d {
9
+
10
+ // target に addEventListener / removeEventListener / dispatchEvent を設置する。
11
+ void InstallEventTarget(v8::Isolate* isolate, v8::Local<v8::Object> target);
12
+
13
+ // target の on<type> と __listeners[type] を発火する。event は {type, ...} を持つ JS オブジェクト。
14
+ void DispatchEvent(v8::Isolate* isolate, v8::Local<v8::Object> target,
15
+ v8::Local<v8::Object> event);
16
+
17
+ } // namespace next2d
@@ -0,0 +1,149 @@
1
+ #include "Bindings.h"
2
+
3
+ #include "HostContext.h"
4
+ #include "AssetLoader.h"
5
+ #include "v8/V8Util.h"
6
+
7
+ #include <cstring>
8
+ #include <vector>
9
+
10
+ namespace next2d {
11
+
12
+ using v8util::Str;
13
+ using v8util::ToStdString;
14
+
15
+ namespace {
16
+
17
+ // Response.arrayBuffer(): 内部データ(External の std::vector) から ArrayBuffer を作る。
18
+ void ResponseArrayBuffer(const v8::FunctionCallbackInfo<v8::Value>& args)
19
+ {
20
+ v8::Isolate* isolate = args.GetIsolate();
21
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
22
+
23
+ v8::Local<v8::Object> self = args.This();
24
+ v8::Local<v8::Value> ext =
25
+ self->GetInternalField(0).As<v8::Value>();
26
+ auto* data = static_cast<std::vector<uint8_t>*>(ext.As<v8::External>()->Value());
27
+
28
+ std::unique_ptr<v8::BackingStore> store =
29
+ v8::ArrayBuffer::NewBackingStore(isolate, data->size());
30
+ if (!data->empty()) {
31
+ std::memcpy(store->Data(), data->data(), data->size());
32
+ }
33
+ v8::Local<v8::ArrayBuffer> buffer =
34
+ v8::ArrayBuffer::New(isolate, std::move(store));
35
+
36
+ v8::Local<v8::Promise::Resolver> resolver =
37
+ v8::Promise::Resolver::New(ctx).ToLocalChecked();
38
+ resolver->Resolve(ctx, buffer).Check();
39
+ args.GetReturnValue().Set(resolver->GetPromise());
40
+ }
41
+
42
+ void ResponseText(const v8::FunctionCallbackInfo<v8::Value>& args)
43
+ {
44
+ v8::Isolate* isolate = args.GetIsolate();
45
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
46
+
47
+ v8::Local<v8::Object> self = args.This();
48
+ auto* data = static_cast<std::vector<uint8_t>*>(
49
+ self->GetInternalField(0).As<v8::External>()->Value());
50
+
51
+ v8::Local<v8::String> text = v8::String::NewFromUtf8(
52
+ isolate, reinterpret_cast<const char*>(data->data()),
53
+ v8::NewStringType::kNormal, static_cast<int>(data->size())
54
+ ).ToLocalChecked();
55
+
56
+ v8::Local<v8::Promise::Resolver> resolver =
57
+ v8::Promise::Resolver::New(ctx).ToLocalChecked();
58
+ resolver->Resolve(ctx, text).Check();
59
+ args.GetReturnValue().Set(resolver->GetPromise());
60
+ }
61
+
62
+ void ResponseJson(const v8::FunctionCallbackInfo<v8::Value>& args)
63
+ {
64
+ v8::Isolate* isolate = args.GetIsolate();
65
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
66
+
67
+ v8::Local<v8::Object> self = args.This();
68
+ auto* data = static_cast<std::vector<uint8_t>*>(
69
+ self->GetInternalField(0).As<v8::External>()->Value());
70
+
71
+ v8::Local<v8::String> text = v8::String::NewFromUtf8(
72
+ isolate, reinterpret_cast<const char*>(data->data()),
73
+ v8::NewStringType::kNormal, static_cast<int>(data->size())
74
+ ).ToLocalChecked();
75
+
76
+ v8::Local<v8::Promise::Resolver> resolver =
77
+ v8::Promise::Resolver::New(ctx).ToLocalChecked();
78
+ v8::Local<v8::Value> parsed;
79
+ if (v8::JSON::Parse(ctx, text).ToLocal(&parsed)) {
80
+ resolver->Resolve(ctx, parsed).Check();
81
+ } else {
82
+ resolver->Reject(ctx, v8::Exception::SyntaxError(Str(isolate, "Invalid JSON"))).Check();
83
+ }
84
+ args.GetReturnValue().Set(resolver->GetPromise());
85
+ }
86
+
87
+ // External に持たせた vector を解放するための弱参照コールバック
88
+ void ReleaseResponseData(const v8::WeakCallbackInfo<std::vector<uint8_t>>& info)
89
+ {
90
+ delete info.GetParameter();
91
+ }
92
+
93
+ v8::Local<v8::Object> MakeResponse(v8::Isolate* isolate, v8::Local<v8::Context> ctx,
94
+ std::vector<uint8_t>&& bytes, bool ok, int status)
95
+ {
96
+ v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
97
+ tmpl->SetInternalFieldCount(1);
98
+ v8::Local<v8::Object> response = tmpl->NewInstance(ctx).ToLocalChecked();
99
+
100
+ auto* data = new std::vector<uint8_t>(std::move(bytes));
101
+ response->SetInternalField(0, v8::External::New(isolate, data));
102
+
103
+ // GC 時に解放
104
+ auto* handle = new v8::Global<v8::Object>(isolate, response);
105
+ handle->SetWeak(data, ReleaseResponseData, v8::WeakCallbackType::kParameter);
106
+
107
+ v8util::SetValue(isolate, response, "ok", v8::Boolean::New(isolate, ok));
108
+ v8util::SetValue(isolate, response, "status", v8::Integer::New(isolate, status));
109
+ v8util::SetMethod(isolate, response, "arrayBuffer", ResponseArrayBuffer);
110
+ v8util::SetMethod(isolate, response, "text", ResponseText);
111
+ v8util::SetMethod(isolate, response, "json", ResponseJson);
112
+ return response;
113
+ }
114
+
115
+ // fetch(url) -> Promise<Response>
116
+ void Fetch(const v8::FunctionCallbackInfo<v8::Value>& args)
117
+ {
118
+ v8::Isolate* isolate = args.GetIsolate();
119
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
120
+ AssetLoader* assets = HostContext::From(isolate)->assets;
121
+
122
+ v8::Local<v8::Promise::Resolver> resolver =
123
+ v8::Promise::Resolver::New(ctx).ToLocalChecked();
124
+ args.GetReturnValue().Set(resolver->GetPromise());
125
+
126
+ if (args.Length() < 1) {
127
+ resolver->Reject(ctx, v8::Exception::TypeError(Str(isolate, "url required"))).Check();
128
+ return;
129
+ }
130
+
131
+ const std::string url = ToStdString(isolate, args[0]);
132
+ auto bytes = assets->ReadBinary(url);
133
+ if (!bytes) {
134
+ // 404 相当の Response を返す (fetch は存在しないリソースでも reject しない)
135
+ resolver->Resolve(ctx, MakeResponse(isolate, ctx, {}, false, 404)).Check();
136
+ return;
137
+ }
138
+
139
+ resolver->Resolve(ctx, MakeResponse(isolate, ctx, std::move(*bytes), true, 200)).Check();
140
+ }
141
+
142
+ } // namespace
143
+
144
+ void InstallFetch(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* /*host*/)
145
+ {
146
+ v8util::SetMethod(isolate, global, "fetch", Fetch);
147
+ }
148
+
149
+ } // namespace next2d
@@ -0,0 +1,79 @@
1
+ #include "Bindings.h"
2
+
3
+ #include "HostContext.h"
4
+ #include "platform/GamepadManager.h"
5
+ #include "v8/V8Util.h"
6
+
7
+ namespace next2d {
8
+
9
+ using v8util::Str;
10
+
11
+ namespace {
12
+
13
+ v8::Local<v8::Object> BuildGamepad(v8::Isolate* isolate, v8::Local<v8::Context> ctx,
14
+ const GamepadSnapshot& snap, int index)
15
+ {
16
+ v8::Local<v8::Object> pad = v8::Object::New(isolate);
17
+
18
+ v8util::SetValue(isolate, pad, "index", v8::Integer::New(isolate, index));
19
+ v8util::SetValue(isolate, pad, "id", Str(isolate, "Xbox Wireless Controller (STANDARD GAMEPAD)"));
20
+ v8util::SetValue(isolate, pad, "mapping", Str(isolate, "standard"));
21
+ v8util::SetValue(isolate, pad, "connected", v8::Boolean::New(isolate, snap.connected));
22
+ v8util::SetValue(isolate, pad, "timestamp", v8::Number::New(isolate, snap.timestamp));
23
+
24
+ // axes
25
+ v8::Local<v8::Array> axes = v8::Array::New(isolate, static_cast<int>(snap.axes.size()));
26
+ for (size_t i = 0; i < snap.axes.size(); ++i) {
27
+ axes->Set(ctx, static_cast<uint32_t>(i), v8::Number::New(isolate, snap.axes[i])).Check();
28
+ }
29
+ v8util::SetValue(isolate, pad, "axes", axes);
30
+
31
+ // buttons: { pressed, touched, value }
32
+ v8::Local<v8::Array> buttons = v8::Array::New(isolate, static_cast<int>(snap.buttons.size()));
33
+ for (size_t i = 0; i < snap.buttons.size(); ++i) {
34
+ v8::Local<v8::Object> b = v8::Object::New(isolate);
35
+ v8util::SetValue(isolate, b, "pressed", v8::Boolean::New(isolate, snap.pressed[i]));
36
+ v8util::SetValue(isolate, b, "touched", v8::Boolean::New(isolate, snap.pressed[i]));
37
+ v8util::SetValue(isolate, b, "value", v8::Number::New(isolate, snap.buttons[i]));
38
+ buttons->Set(ctx, static_cast<uint32_t>(i), b).Check();
39
+ }
40
+ v8util::SetValue(isolate, pad, "buttons", buttons);
41
+
42
+ return pad;
43
+ }
44
+
45
+ // navigator.getGamepads()
46
+ void GetGamepads(const v8::FunctionCallbackInfo<v8::Value>& args)
47
+ {
48
+ v8::Isolate* isolate = args.GetIsolate();
49
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
50
+ GamepadManager* mgr = HostContext::From(isolate)->gamepad;
51
+
52
+ const auto& snaps = mgr ? mgr->snapshots() : std::vector<GamepadSnapshot>{};
53
+ v8::Local<v8::Array> result = v8::Array::New(isolate, static_cast<int>(snaps.size()));
54
+ for (size_t i = 0; i < snaps.size(); ++i) {
55
+ if (snaps[i].connected) {
56
+ result->Set(ctx, static_cast<uint32_t>(i),
57
+ BuildGamepad(isolate, ctx, snaps[i], static_cast<int>(i))).Check();
58
+ } else {
59
+ result->Set(ctx, static_cast<uint32_t>(i), v8::Null(isolate)).Check();
60
+ }
61
+ }
62
+ args.GetReturnValue().Set(result);
63
+ }
64
+
65
+ } // namespace
66
+
67
+ // navigator は DomShims が生成するため、ここでは navigator.getGamepads を後付けする。
68
+ void InstallGamepad(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* /*host*/)
69
+ {
70
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
71
+ v8::Local<v8::Value> nav_val;
72
+ if (!global->Get(ctx, Str(isolate, "navigator")).ToLocal(&nav_val) || !nav_val->IsObject()) {
73
+ return;
74
+ }
75
+ v8::Local<v8::Object> navigator = nav_val.As<v8::Object>();
76
+ v8util::SetMethod(isolate, navigator, "getGamepads", GetGamepads);
77
+ }
78
+
79
+ } // namespace next2d