@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,160 @@
1
+ #include "Bindings.h"
2
+
3
+ #include "HostContext.h"
4
+ #include "AssetLoader.h"
5
+ #include "ImageSource.h"
6
+ #include "platform/WicDecoder.h"
7
+ #include "v8/V8Util.h"
8
+
9
+ #include <objbase.h>
10
+
11
+ #include <cstring>
12
+ #include <vector>
13
+
14
+ namespace next2d {
15
+
16
+ using v8util::Str;
17
+ using v8util::ToStdString;
18
+
19
+ namespace {
20
+
21
+ void ReleaseDecoded(const v8::WeakCallbackInfo<DecodedImage>& info)
22
+ {
23
+ delete info.GetParameter();
24
+ }
25
+
26
+ // Image コンストラクタ: src セッターで読み込み+デコードし onload を発火する。
27
+ void ImageConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
28
+ {
29
+ v8::Isolate* isolate = args.GetIsolate();
30
+ if (!args.IsConstructCall()) {
31
+ v8util::ThrowTypeError(isolate, "Image must be called with new");
32
+ return;
33
+ }
34
+ // 実体は通常オブジェクト。src セッターで decode をトリガする。
35
+ args.This()->Set(isolate->GetCurrentContext(),
36
+ Str(isolate, "complete"),
37
+ v8::Boolean::New(isolate, false)).Check();
38
+ args.GetReturnValue().Set(args.This());
39
+ }
40
+
41
+ // createImageBitmap(source) -> Promise<ImageBitmap>
42
+ // source は Blob / Response.arrayBuffer 結果(ArrayBuffer/TypedArray) を想定。
43
+ void CreateImageBitmap(const v8::FunctionCallbackInfo<v8::Value>& args)
44
+ {
45
+ v8::Isolate* isolate = args.GetIsolate();
46
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
47
+
48
+ v8::Local<v8::Promise::Resolver> resolver =
49
+ v8::Promise::Resolver::New(ctx).ToLocalChecked();
50
+ args.GetReturnValue().Set(resolver->GetPromise());
51
+
52
+ if (args.Length() < 1) {
53
+ resolver->Reject(ctx, v8::Exception::TypeError(Str(isolate, "source required"))).Check();
54
+ return;
55
+ }
56
+
57
+ std::vector<uint8_t> input;
58
+ if (args[0]->IsArrayBuffer()) {
59
+ auto ab = args[0].As<v8::ArrayBuffer>();
60
+ auto store = ab->GetBackingStore();
61
+ input.assign(static_cast<uint8_t*>(store->Data()),
62
+ static_cast<uint8_t*>(store->Data()) + store->ByteLength());
63
+ } else if (args[0]->IsArrayBufferView()) {
64
+ auto view = args[0].As<v8::ArrayBufferView>();
65
+ input.resize(view->ByteLength());
66
+ view->CopyContents(input.data(), input.size());
67
+ } else if (args[0]->IsString()) {
68
+ // URL 文字列: assets から読み込む
69
+ AssetLoader* assets = HostContext::From(isolate)->assets;
70
+ auto bytes = assets->ReadBinary(ToStdString(isolate, args[0]));
71
+ if (bytes) {
72
+ input = std::move(*bytes);
73
+ }
74
+ }
75
+
76
+ auto* img = new DecodedImage();
77
+ if (input.empty() || !DecodeImageWithWIC(input, *img)) {
78
+ delete img;
79
+ resolver->Reject(ctx, v8::Exception::Error(Str(isolate, "Image decode failed"))).Check();
80
+ return;
81
+ }
82
+
83
+ resolver->Resolve(ctx, WrapImageBitmap(isolate, img)).Check();
84
+ }
85
+
86
+ } // namespace
87
+
88
+ // ImageBitmap をラップ (内部フィールド0=External<DecodedImage>, __isImageBitmap=true)。
89
+ v8::Local<v8::Object> WrapImageBitmap(v8::Isolate* isolate, DecodedImage* image)
90
+ {
91
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
92
+ v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
93
+ tmpl->SetInternalFieldCount(1);
94
+ v8::Local<v8::Object> obj = tmpl->NewInstance(ctx).ToLocalChecked();
95
+ obj->SetInternalField(0, v8::External::New(isolate, image));
96
+
97
+ v8util::SetValue(isolate, obj, "__isImageBitmap", v8::Boolean::New(isolate, true));
98
+ v8util::SetValue(isolate, obj, "width", v8::Integer::NewFromUnsigned(isolate, image->width));
99
+ v8util::SetValue(isolate, obj, "height", v8::Integer::NewFromUnsigned(isolate, image->height));
100
+ v8util::SetMethod(isolate, obj, "close", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
101
+
102
+ auto* handle = new v8::Global<v8::Object>(isolate, obj);
103
+ handle->SetWeak(image, ReleaseDecoded, v8::WeakCallbackType::kParameter);
104
+ return obj;
105
+ }
106
+
107
+ // 画像ソース(ImageBitmap / 2Dコンテキストを持つ canvas) から RGBA を取得する。
108
+ bool GetImageSourcePixels(v8::Isolate* isolate, v8::Local<v8::Value> source,
109
+ const uint8_t** out_rgba, uint32_t* out_width, uint32_t* out_height)
110
+ {
111
+ if (!source->IsObject()) {
112
+ return false;
113
+ }
114
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
115
+ v8::Local<v8::Object> obj = source.As<v8::Object>();
116
+
117
+ // ImageBitmap
118
+ v8::Local<v8::Value> is_bitmap;
119
+ if (obj->Get(ctx, Str(isolate, "__isImageBitmap")).ToLocal(&is_bitmap) &&
120
+ is_bitmap->IsBoolean() && is_bitmap.As<v8::Boolean>()->Value()) {
121
+ auto* img = static_cast<DecodedImage*>(
122
+ obj->GetInternalField(0).As<v8::External>()->Value());
123
+ *out_rgba = img->rgba.data();
124
+ *out_width = img->width;
125
+ *out_height = img->height;
126
+ return true;
127
+ }
128
+
129
+ // video 要素: 現在フレームを返す
130
+ v8::Local<v8::Value> is_video;
131
+ if (obj->Get(ctx, Str(isolate, "__isVideoElement")).ToLocal(&is_video) &&
132
+ is_video->IsBoolean() && is_video.As<v8::Boolean>()->Value()) {
133
+ return GetVideoFramePixels(isolate, obj, out_rgba, out_width, out_height);
134
+ }
135
+
136
+ // canvas / OffscreenCanvas: getContext('2d') 済みなら __ctx2d を持つ
137
+ v8::Local<v8::Value> ctx2d;
138
+ if (obj->Get(ctx, Str(isolate, "__ctx2d")).ToLocal(&ctx2d) && ctx2d->IsObject()) {
139
+ return GetCanvas2DPixels(ctx2d.As<v8::Object>(), out_rgba, out_width, out_height);
140
+ }
141
+ return false;
142
+ }
143
+
144
+ void InstallImage(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* /*host*/)
145
+ {
146
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
147
+
148
+ // COM (WIC 用) 初期化
149
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
150
+
151
+ v8::Local<v8::FunctionTemplate> image_tmpl =
152
+ v8::FunctionTemplate::New(isolate, ImageConstructor);
153
+ image_tmpl->SetClassName(Str(isolate, "Image"));
154
+ global->Set(ctx, Str(isolate, "Image"),
155
+ image_tmpl->GetFunction(ctx).ToLocalChecked()).Check();
156
+
157
+ v8util::SetMethod(isolate, global, "createImageBitmap", CreateImageBitmap);
158
+ }
159
+
160
+ } // namespace next2d
@@ -0,0 +1,26 @@
1
+ // 画像ソース(ImageBitmap / OffscreenCanvas・Canvas の 2D 内容)の RGBA ピクセルへ
2
+ // 統一アクセスするための基盤。queue.copyExternalImageToTexture / Canvas2D.drawImage /
3
+ // transferToImageBitmap が参照する。
4
+ #pragma once
5
+
6
+ #include "../platform/ImageTypes.h"
7
+
8
+ #include <v8.h>
9
+ #include <cstdint>
10
+ #include <vector>
11
+
12
+ namespace next2d {
13
+
14
+ // ImageBitmap(JS) をラップして返す (内部フィールド0に External<DecodedImage>, __isImageBitmap=true)。
15
+ v8::Local<v8::Object> WrapImageBitmap(v8::Isolate* isolate, DecodedImage* image);
16
+
17
+ // 任意の画像ソース(ImageBitmap / '2d' コンテキストを持つ canvas / OffscreenCanvas) から
18
+ // RGBA ピクセルを取得する。成功時 true。out_rgba は呼び出し中のみ有効な参照。
19
+ bool GetImageSourcePixels(v8::Isolate* isolate, v8::Local<v8::Value> source,
20
+ const uint8_t** out_rgba, uint32_t* out_width, uint32_t* out_height);
21
+
22
+ // Canvas2D コンテキストオブジェクトから RGBA を取得する (Canvas2D.cpp が実装)。
23
+ bool GetCanvas2DPixels(v8::Local<v8::Object> context2d,
24
+ const uint8_t** out_rgba, uint32_t* out_width, uint32_t* out_height);
25
+
26
+ } // namespace next2d
@@ -0,0 +1,303 @@
1
+ // XMLHttpRequest / Blob / URL.createObjectURL / ImageData の最小実装。
2
+ //
3
+ // player は fetch ではなく XHR でアセットを読み込み(`DisplayObjectUtil`/`MediaUtil`)、
4
+ // Worker を Vite の `?worker&inline`(= URL.createObjectURL(new Blob([...]))) で生成する。
5
+ // ここではローカル(assets)読み込みを同期的に行い、onload をマイクロタスクで発火する。
6
+ #include "Bindings.h"
7
+
8
+ #include "HostContext.h"
9
+ #include "AssetLoader.h"
10
+ #include "v8/V8Util.h"
11
+
12
+ #include <cstring>
13
+ #include <map>
14
+ #include <string>
15
+ #include <vector>
16
+
17
+ namespace next2d {
18
+
19
+ using v8util::Str;
20
+ using v8util::SetMethod;
21
+ using v8util::SetValue;
22
+ using v8util::ToStdString;
23
+
24
+ namespace {
25
+
26
+ // object URL レジストリ (createObjectURL で登録、Worker/XHR/Image が参照)
27
+ std::map<std::string, std::vector<uint8_t>>& ObjectURLs()
28
+ {
29
+ static std::map<std::string, std::vector<uint8_t>> registry;
30
+ return registry;
31
+ }
32
+ int g_object_url_seq = 0;
33
+
34
+ std::vector<uint8_t> ValueToBytes(v8::Isolate* isolate, v8::Local<v8::Value> v)
35
+ {
36
+ std::vector<uint8_t> out;
37
+ if (v->IsArrayBuffer()) {
38
+ auto store = v.As<v8::ArrayBuffer>()->GetBackingStore();
39
+ out.assign(static_cast<uint8_t*>(store->Data()),
40
+ static_cast<uint8_t*>(store->Data()) + store->ByteLength());
41
+ } else if (v->IsArrayBufferView()) {
42
+ auto view = v.As<v8::ArrayBufferView>();
43
+ out.resize(view->ByteLength());
44
+ view->CopyContents(out.data(), out.size());
45
+ } else if (v->IsString()) {
46
+ const std::string s = ToStdString(isolate, v);
47
+ out.assign(s.begin(), s.end());
48
+ }
49
+ return out;
50
+ }
51
+
52
+ v8::Local<v8::ArrayBuffer> BytesToArrayBuffer(v8::Isolate* isolate, const std::vector<uint8_t>& bytes)
53
+ {
54
+ auto store = v8::ArrayBuffer::NewBackingStore(isolate, bytes.size());
55
+ if (!bytes.empty()) std::memcpy(store->Data(), bytes.data(), bytes.size());
56
+ return v8::ArrayBuffer::New(isolate, std::move(store));
57
+ }
58
+
59
+ // --- Blob ----------------------------------------------------------------
60
+ // new Blob(parts[], options?) → { size, type, __bytes(External は使わず配列保持) }
61
+ void BlobConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
62
+ {
63
+ v8::Isolate* isolate = args.GetIsolate();
64
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
65
+ if (!args.IsConstructCall()) { v8util::ThrowTypeError(isolate, "Blob requires new"); return; }
66
+
67
+ std::vector<uint8_t> bytes;
68
+ if (args.Length() > 0 && args[0]->IsArray()) {
69
+ auto arr = args[0].As<v8::Array>();
70
+ for (uint32_t i = 0; i < arr->Length(); ++i) {
71
+ v8::Local<v8::Value> part;
72
+ if (arr->Get(ctx, i).ToLocal(&part)) {
73
+ auto b = ValueToBytes(isolate, part);
74
+ bytes.insert(bytes.end(), b.begin(), b.end());
75
+ }
76
+ }
77
+ }
78
+ v8::Local<v8::Object> self = args.This();
79
+ // バイト列は base64 化せず ArrayBuffer プロパティで保持
80
+ SetValue(isolate, self, "size", v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(bytes.size())));
81
+ SetValue(isolate, self, "__blobData", BytesToArrayBuffer(isolate, bytes));
82
+ SetMethod(isolate, self, "arrayBuffer", [](const v8::FunctionCallbackInfo<v8::Value>& a){
83
+ v8::Isolate* iso = a.GetIsolate();
84
+ v8::Local<v8::Context> c = iso->GetCurrentContext();
85
+ auto r = v8::Promise::Resolver::New(c).ToLocalChecked();
86
+ v8::Local<v8::Value> d;
87
+ a.This()->Get(c, Str(iso, "__blobData")).ToLocal(&d);
88
+ r->Resolve(c, d).Check();
89
+ a.GetReturnValue().Set(r->GetPromise());
90
+ });
91
+ args.GetReturnValue().Set(self);
92
+ }
93
+
94
+ // --- URL.createObjectURL / revokeObjectURL -------------------------------
95
+ void CreateObjectURL(const v8::FunctionCallbackInfo<v8::Value>& args)
96
+ {
97
+ v8::Isolate* isolate = args.GetIsolate();
98
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
99
+ std::vector<uint8_t> bytes;
100
+ if (args.Length() > 0 && args[0]->IsObject()) {
101
+ v8::Local<v8::Value> d;
102
+ if (args[0].As<v8::Object>()->Get(ctx, Str(isolate, "__blobData")).ToLocal(&d) &&
103
+ d->IsArrayBuffer()) {
104
+ bytes = ValueToBytes(isolate, d);
105
+ }
106
+ }
107
+ const std::string url = "blob:next2d/" + std::to_string(++g_object_url_seq);
108
+ ObjectURLs()[url] = std::move(bytes);
109
+ args.GetReturnValue().Set(Str(isolate, url));
110
+ }
111
+
112
+ void RevokeObjectURL(const v8::FunctionCallbackInfo<v8::Value>& args)
113
+ {
114
+ v8::Isolate* isolate = args.GetIsolate();
115
+ if (args.Length() > 0) ObjectURLs().erase(ToStdString(isolate, args[0]));
116
+ }
117
+
118
+ // --- ImageData -----------------------------------------------------------
119
+ // new ImageData(Uint8ClampedArray, w, h) | new ImageData(w, h)
120
+ void ImageDataConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
121
+ {
122
+ v8::Isolate* isolate = args.GetIsolate();
123
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
124
+ if (!args.IsConstructCall()) { v8util::ThrowTypeError(isolate, "ImageData requires new"); return; }
125
+
126
+ v8::Local<v8::Object> self = args.This();
127
+ if (args.Length() >= 3 && args[0]->IsArrayBufferView()) {
128
+ SetValue(isolate, self, "data", args[0]);
129
+ SetValue(isolate, self, "width", args[1]);
130
+ SetValue(isolate, self, "height", args[2]);
131
+ } else {
132
+ int w = args.Length() > 0 ? static_cast<int>(args[0].As<v8::Number>()->Value()) : 1;
133
+ int h = args.Length() > 1 ? static_cast<int>(args[1].As<v8::Number>()->Value()) : 1;
134
+ auto ab = v8::ArrayBuffer::New(isolate, static_cast<size_t>(w) * h * 4);
135
+ self->Set(ctx, Str(isolate, "data"),
136
+ v8::Uint8ClampedArray::New(ab, 0, static_cast<size_t>(w) * h * 4)).Check();
137
+ SetValue(isolate, self, "width", v8::Integer::New(isolate, w));
138
+ SetValue(isolate, self, "height", v8::Integer::New(isolate, h));
139
+ }
140
+ args.GetReturnValue().Set(self);
141
+ }
142
+
143
+ // --- XMLHttpRequest ------------------------------------------------------
144
+ // open/send/setRequestHeader/responseType/response/status + load/error イベント
145
+ void XHRConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
146
+ {
147
+ v8::Isolate* isolate = args.GetIsolate();
148
+ if (!args.IsConstructCall()) { v8util::ThrowTypeError(isolate, "XMLHttpRequest requires new"); return; }
149
+ v8::Local<v8::Object> self = args.This();
150
+ SetValue(isolate, self, "readyState", v8::Integer::New(isolate, 0));
151
+ SetValue(isolate, self, "status", v8::Integer::New(isolate, 0));
152
+ SetValue(isolate, self, "responseType", Str(isolate, ""));
153
+ SetValue(isolate, self, "__listeners", v8::Object::New(isolate));
154
+
155
+ SetMethod(isolate, self, "open", [](const v8::FunctionCallbackInfo<v8::Value>& a){
156
+ v8::Isolate* iso = a.GetIsolate();
157
+ // open(method, url, async)
158
+ SetValue(iso, a.This(), "__url", a.Length() > 1 ? a[1] : v8::Undefined(iso).As<v8::Value>());
159
+ });
160
+ SetMethod(isolate, self, "setRequestHeader", [](const v8::FunctionCallbackInfo<v8::Value>&){});
161
+ SetMethod(isolate, self, "abort", [](const v8::FunctionCallbackInfo<v8::Value>&){});
162
+ SetMethod(isolate, self, "getAllResponseHeaders", [](const v8::FunctionCallbackInfo<v8::Value>& a){
163
+ a.GetReturnValue().Set(Str(a.GetIsolate(), ""));
164
+ });
165
+ // addEventListener(type, fn): __listeners[type] へ配列で保持
166
+ SetMethod(isolate, self, "addEventListener", [](const v8::FunctionCallbackInfo<v8::Value>& a){
167
+ v8::Isolate* iso = a.GetIsolate();
168
+ v8::Local<v8::Context> c = iso->GetCurrentContext();
169
+ if (a.Length() < 2 || !a[1]->IsFunction()) return;
170
+ const std::string type = v8util::ToStdString(iso, a[0]);
171
+ v8::Local<v8::Value> lv;
172
+ a.This()->Get(c, Str(iso, "__listeners")).ToLocal(&lv);
173
+ v8::Local<v8::Object> listeners = lv.As<v8::Object>();
174
+ v8::Local<v8::Value> arrv;
175
+ v8::Local<v8::Array> arr;
176
+ if (listeners->Get(c, Str(iso, type.c_str())).ToLocal(&arrv) && arrv->IsArray()) {
177
+ arr = arrv.As<v8::Array>();
178
+ } else {
179
+ arr = v8::Array::New(iso, 0);
180
+ listeners->Set(c, Str(iso, type.c_str()), arr).Check();
181
+ }
182
+ arr->Set(c, arr->Length(), a[1]).Check();
183
+ });
184
+ SetMethod(isolate, self, "removeEventListener", [](const v8::FunctionCallbackInfo<v8::Value>&){});
185
+
186
+ // send(): assets/blob から同期読込 → response 準備 → load をマイクロタスクで発火
187
+ SetMethod(isolate, self, "send", [](const v8::FunctionCallbackInfo<v8::Value>& a){
188
+ v8::Isolate* iso = a.GetIsolate();
189
+ v8::Local<v8::Context> c = iso->GetCurrentContext();
190
+ v8::Local<v8::Object> self = a.This();
191
+ HostContext* host = HostContext::From(iso);
192
+
193
+ std::string url;
194
+ v8::Local<v8::Value> uv;
195
+ if (self->Get(c, Str(iso, "__url")).ToLocal(&uv)) url = ToStdString(iso, uv);
196
+
197
+ std::vector<uint8_t> bytes;
198
+ bool ok = false;
199
+ auto it = ObjectURLs().find(url);
200
+ if (it != ObjectURLs().end()) { bytes = it->second; ok = true; }
201
+ else if (host->assets) {
202
+ auto b = host->assets->ReadBinary(url);
203
+ if (b) { bytes = std::move(*b); ok = true; }
204
+ }
205
+
206
+ SetValue(iso, self, "status", v8::Integer::New(iso, ok ? 200 : 404));
207
+ SetValue(iso, self, "readyState", v8::Integer::New(iso, 4));
208
+
209
+ // responseType に応じて response をセット
210
+ const std::string rt = [&]{ v8::Local<v8::Value> v;
211
+ return self->Get(c, Str(iso, "responseType")).ToLocal(&v) ? ToStdString(iso, v) : std::string(); }();
212
+ v8::Local<v8::Value> response = v8::Null(iso);
213
+ if (ok) {
214
+ if (rt == "arraybuffer") {
215
+ response = BytesToArrayBuffer(iso, bytes);
216
+ } else {
217
+ v8::Local<v8::String> s = v8::String::NewFromUtf8(
218
+ iso, reinterpret_cast<const char*>(bytes.data()),
219
+ v8::NewStringType::kNormal, static_cast<int>(bytes.size())).ToLocalChecked();
220
+ if (rt == "json") {
221
+ v8::Local<v8::Value> parsed;
222
+ if (v8::JSON::Parse(c, s).ToLocal(&parsed)) response = parsed;
223
+ } else {
224
+ response = s;
225
+ SetValue(iso, self, "responseText", s);
226
+ }
227
+ }
228
+ }
229
+ SetValue(iso, self, "response", response);
230
+
231
+ // load / error イベントを発火 (on* + addEventListener)
232
+ auto fire = [&](const char* type){
233
+ v8::Local<v8::Object> ev = v8::Object::New(iso);
234
+ SetValue(iso, ev, "type", Str(iso, type));
235
+ SetValue(iso, ev, "target", self);
236
+ v8::Local<v8::Value> args1[1] = { ev };
237
+ std::string onname = std::string("on") + type;
238
+ v8::Local<v8::Value> on;
239
+ if (self->Get(c, Str(iso, onname.c_str())).ToLocal(&on) && on->IsFunction()) {
240
+ v8::TryCatch tc(iso); (void) on.As<v8::Function>()->Call(c, self, 1, args1);
241
+ }
242
+ v8::Local<v8::Value> lv;
243
+ self->Get(c, Str(iso, "__listeners")).ToLocal(&lv);
244
+ v8::Local<v8::Value> arrv;
245
+ if (lv->IsObject() && lv.As<v8::Object>()->Get(c, Str(iso, type)).ToLocal(&arrv) && arrv->IsArray()) {
246
+ auto arr = arrv.As<v8::Array>();
247
+ for (uint32_t i = 0; i < arr->Length(); ++i) {
248
+ v8::Local<v8::Value> fn;
249
+ if (arr->Get(c, i).ToLocal(&fn) && fn->IsFunction()) {
250
+ v8::TryCatch tc(iso); (void) fn.As<v8::Function>()->Call(c, self, 1, args1);
251
+ }
252
+ }
253
+ }
254
+ };
255
+ fire(ok ? "load" : "error");
256
+ fire("loadend");
257
+ });
258
+
259
+ args.GetReturnValue().Set(self);
260
+ }
261
+
262
+ void InstallCtor(v8::Isolate* isolate, v8::Local<v8::Object> global,
263
+ const char* name, v8::FunctionCallback ctor)
264
+ {
265
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
266
+ v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, ctor);
267
+ t->SetClassName(Str(isolate, name));
268
+ global->Set(ctx, Str(isolate, name), t->GetFunction(ctx).ToLocalChecked()).Check();
269
+ }
270
+
271
+ } // namespace
272
+
273
+ // blob: URL のバイト列を取得する (WorkerRuntime が inline worker の起動に使用)。
274
+ bool ResolveObjectURL(const std::string& url, std::string* out_text)
275
+ {
276
+ auto it = ObjectURLs().find(url);
277
+ if (it == ObjectURLs().end()) return false;
278
+ out_text->assign(it->second.begin(), it->second.end());
279
+ return true;
280
+ }
281
+
282
+ void InstallNetwork(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContext* /*host*/)
283
+ {
284
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
285
+
286
+ InstallCtor(isolate, global, "XMLHttpRequest", XHRConstructor);
287
+ InstallCtor(isolate, global, "Blob", BlobConstructor);
288
+ InstallCtor(isolate, global, "ImageData", ImageDataConstructor);
289
+
290
+ // URL: createObjectURL/revokeObjectURL を追加 (bootstrap.js の URL があれば拡張)
291
+ v8::Local<v8::Value> url_val;
292
+ v8::Local<v8::Object> url_obj;
293
+ if (global->Get(ctx, Str(isolate, "URL")).ToLocal(&url_val) && url_val->IsObject()) {
294
+ url_obj = url_val.As<v8::Object>();
295
+ } else {
296
+ url_obj = v8::Object::New(isolate);
297
+ SetValue(isolate, global, "URL", url_obj);
298
+ }
299
+ SetMethod(isolate, url_obj, "createObjectURL", CreateObjectURL);
300
+ SetMethod(isolate, url_obj, "revokeObjectURL", RevokeObjectURL);
301
+ }
302
+
303
+ } // namespace next2d