@next2d/builder 0.1.6 → 0.1.8

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 (34) hide show
  1. package/README.md +5 -1
  2. package/dist/index.js +140 -36
  3. package/package.json +3 -2
  4. package/templates/xbox/CMakeLists.txt +74 -2
  5. package/templates/xbox/README.md +73 -12
  6. package/templates/xbox/cmake/FetchDawn.cmake +47 -6
  7. package/templates/xbox/cmake/FindV8.cmake +22 -1
  8. package/templates/xbox/js/bootstrap.js +31 -28
  9. package/templates/xbox/js/selftest.js +740 -90
  10. package/templates/xbox/src/EventLoop.cpp +28 -1
  11. package/templates/xbox/src/EventLoop.h +12 -0
  12. package/templates/xbox/src/bindings/Audio.cpp +99 -15
  13. package/templates/xbox/src/bindings/Bindings.h +10 -0
  14. package/templates/xbox/src/bindings/Canvas.cpp +45 -0
  15. package/templates/xbox/src/bindings/Canvas2D.cpp +2 -5
  16. package/templates/xbox/src/bindings/DomShims.cpp +127 -0
  17. package/templates/xbox/src/bindings/EventTarget.cpp +2 -0
  18. package/templates/xbox/src/bindings/Fetch.cpp +2 -8
  19. package/templates/xbox/src/bindings/Image.cpp +212 -10
  20. package/templates/xbox/src/bindings/Polyfills.cpp +791 -0
  21. package/templates/xbox/src/bindings/Video.cpp +96 -7
  22. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +815 -15
  23. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +3 -8
  24. package/templates/xbox/src/gpu/DawnContext.cpp +90 -3
  25. package/templates/xbox/src/gpu/DawnContext.h +18 -0
  26. package/templates/xbox/src/main.cpp +88 -6
  27. package/templates/xbox/src/platform/AudioEngine.cpp +9 -3
  28. package/templates/xbox/src/v8/V8Runtime.cpp +69 -4
  29. package/templates/xbox/src/v8/V8Util.h +29 -0
  30. package/templates/xbox/src/v8/WeakHandle.h +45 -0
  31. package/templates/xbox/src/worker/WorkerRuntime.cpp +325 -41
  32. package/templates/xbox/src/worker/WorkerRuntime.h +20 -10
  33. package/templates/xbox/tests/check_local.sh +3 -2
  34. package/templates/xbox/tests/raster_test.bin +0 -0
@@ -2,13 +2,16 @@
2
2
 
3
3
  #include "HostContext.h"
4
4
  #include "AssetLoader.h"
5
+ #include "EventTarget.h"
5
6
  #include "ImageSource.h"
6
7
  #include "platform/WicDecoder.h"
7
8
  #include "v8/V8Util.h"
9
+ #include "v8/WeakHandle.h"
8
10
 
9
11
  #include <objbase.h>
10
12
 
11
13
  #include <cstring>
14
+ #include <iostream>
12
15
  #include <vector>
13
16
 
14
17
  namespace next2d {
@@ -18,12 +21,110 @@ using v8util::ToStdString;
18
21
 
19
22
  namespace {
20
23
 
21
- void ReleaseDecoded(const v8::WeakCallbackInfo<DecodedImage>& info)
24
+ // base64 デコード (data: URL 用。Vite は小さい画像をインライン化する)
25
+ bool ImageDecodeBase64(const std::string& in, std::vector<uint8_t>* out)
22
26
  {
23
- delete info.GetParameter();
27
+ auto val = [](char c) -> int {
28
+ if (c >= 'A' && c <= 'Z') return c - 'A';
29
+ if (c >= 'a' && c <= 'z') return c - 'a' + 26;
30
+ if (c >= '0' && c <= '9') return c - '0' + 52;
31
+ if (c == '+') return 62;
32
+ if (c == '/') return 63;
33
+ return -1;
34
+ };
35
+ out->clear();
36
+ out->reserve(in.size() / 4 * 3);
37
+ int buf = 0, bits = 0;
38
+ for (char c : in) {
39
+ if (c == '=' || c == '\r' || c == '\n') continue;
40
+ const int v = val(c);
41
+ if (v < 0) return false;
42
+ buf = buf << 6 | v;
43
+ bits += 6;
44
+ if (bits >= 8) {
45
+ bits -= 8;
46
+ out->push_back(static_cast<uint8_t>(buf >> bits & 0xFF));
47
+ }
48
+ }
49
+ return true;
24
50
  }
25
51
 
26
- // Image コンストラクタ: src セッターで読み込み+デコードし onload を発火する。
52
+ // 遅延発火する load/error イベント (img.src = url; img.onload = fn の順でも拾えるよう
53
+ // microtask で発火する。メインループの PerformMicrotaskCheckpoint が実行する)
54
+ struct PendingImageEvent {
55
+ v8::Isolate* isolate;
56
+ v8::Global<v8::Object> image;
57
+ bool ok;
58
+ };
59
+
60
+ void FireImageEvent(void* data)
61
+ {
62
+ auto* p = static_cast<PendingImageEvent*>(data);
63
+ v8::Isolate* isolate = p->isolate;
64
+ v8::HandleScope hs(isolate);
65
+ v8::Local<v8::Object> img = p->image.Get(isolate);
66
+ v8::Local<v8::Context> ctx = img->GetCreationContextChecked();
67
+ v8::Context::Scope cs(ctx);
68
+
69
+ v8::Local<v8::Object> ev = v8::Object::New(isolate);
70
+ v8util::SetValue(isolate, ev, "type", Str(isolate, p->ok ? "load" : "error"));
71
+ v8util::SetValue(isolate, ev, "target", img);
72
+ DispatchEvent(isolate, img, ev);
73
+
74
+ p->image.Reset();
75
+ delete p;
76
+ }
77
+
78
+ // src に指定された URL (assets 相対 / data:) を読み込み WIC でデコードする。
79
+ // 成否イベントは microtask で発火する。
80
+ void LoadImageFromSrc(v8::Isolate* isolate, v8::Local<v8::Object> self, const std::string& url)
81
+ {
82
+ std::vector<uint8_t> input;
83
+ if (url.rfind("data:", 0) == 0) {
84
+ const auto comma = url.find(',');
85
+ if (comma != std::string::npos) {
86
+ const std::string meta = url.substr(5, comma - 5);
87
+ const std::string payload = url.substr(comma + 1);
88
+ if (meta.find(";base64") != std::string::npos) {
89
+ ImageDecodeBase64(payload, &input);
90
+ }
91
+ }
92
+ } else {
93
+ AssetLoader* assets = HostContext::From(isolate)->assets;
94
+ auto bytes = assets->ReadBinary(url);
95
+ if (bytes) {
96
+ input = std::move(*bytes);
97
+ }
98
+ }
99
+
100
+ auto* img = new DecodedImage();
101
+ const bool ok = !input.empty() && DecodeImageWithWIC(input, *img);
102
+ if (ok) {
103
+ self->SetInternalField(0, v8::External::New(isolate, img));
104
+ v8util::AttachWeak(isolate, self, img);
105
+ v8util::SetValue(isolate, self, "width",
106
+ v8::Integer::NewFromUnsigned(isolate, img->width));
107
+ v8util::SetValue(isolate, self, "height",
108
+ v8::Integer::NewFromUnsigned(isolate, img->height));
109
+ v8util::SetValue(isolate, self, "naturalWidth",
110
+ v8::Integer::NewFromUnsigned(isolate, img->width));
111
+ v8util::SetValue(isolate, self, "naturalHeight",
112
+ v8::Integer::NewFromUnsigned(isolate, img->height));
113
+ v8util::SetValue(isolate, self, "complete", v8::Boolean::New(isolate, true));
114
+ } else {
115
+ delete img;
116
+ std::cerr << "[Image] load failed: "
117
+ << (url.size() > 96 ? url.substr(0, 96) + "..." : url) << std::endl;
118
+ }
119
+
120
+ auto* pending = new PendingImageEvent();
121
+ pending->isolate = isolate;
122
+ pending->image.Reset(isolate, self);
123
+ pending->ok = ok;
124
+ isolate->EnqueueMicrotask(FireImageEvent, pending);
125
+ }
126
+
127
+ // Image コンストラクタ: src セッターで読み込み+デコードし load イベントを発火する。
27
128
  void ImageConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
28
129
  {
29
130
  v8::Isolate* isolate = args.GetIsolate();
@@ -31,11 +132,46 @@ void ImageConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
31
132
  v8util::ThrowTypeError(isolate, "Image must be called with new");
32
133
  return;
33
134
  }
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());
135
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
136
+ v8::Local<v8::Object> self = args.This();
137
+
138
+ v8util::SetValue(isolate, self, "__isImageElement", v8::Boolean::New(isolate, true));
139
+ v8util::SetValue(isolate, self, "tagName", Str(isolate, "IMG"));
140
+ v8util::SetValue(isolate, self, "localName", Str(isolate, "img"));
141
+ v8util::SetValue(isolate, self, "complete", v8::Boolean::New(isolate, false));
142
+ v8util::SetValue(isolate, self, "width", v8::Integer::New(isolate, 0));
143
+ v8util::SetValue(isolate, self, "height", v8::Integer::New(isolate, 0));
144
+ v8util::SetValue(isolate, self, "naturalWidth", v8::Integer::New(isolate, 0));
145
+ v8util::SetValue(isolate, self, "naturalHeight", v8::Integer::New(isolate, 0));
146
+ InstallEventTarget(isolate, self); // addEventListener("load"/"error")
147
+
148
+ self->SetNativeDataProperty(ctx, Str(isolate, "src"),
149
+ [](v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
150
+ v8::Local<v8::Value> v;
151
+ if (info.This()->Get(info.GetIsolate()->GetCurrentContext(),
152
+ Str(info.GetIsolate(), "__src")).ToLocal(&v) && !v->IsUndefined()) {
153
+ info.GetReturnValue().Set(v);
154
+ } else {
155
+ info.GetReturnValue().Set(Str(info.GetIsolate(), ""));
156
+ }
157
+ },
158
+ [](v8::Local<v8::Name>, v8::Local<v8::Value> value,
159
+ const v8::PropertyCallbackInfo<void>& info) {
160
+ v8::Isolate* iso = info.GetIsolate();
161
+ v8util::SetValue(iso, info.This(), "__src", value);
162
+ LoadImageFromSrc(iso, info.This(), ToStdString(iso, value));
163
+ }).Check();
164
+
165
+ // decode(): 読み込み済みなら resolve、未読み込みでも resolve (簡易)
166
+ v8util::SetMethod(isolate, self, "decode",
167
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) {
168
+ v8::Isolate* iso = a.GetIsolate();
169
+ auto r = v8::Promise::Resolver::New(iso->GetCurrentContext()).ToLocalChecked();
170
+ r->Resolve(iso->GetCurrentContext(), v8::Undefined(iso)).Check();
171
+ a.GetReturnValue().Set(r->GetPromise());
172
+ });
173
+
174
+ args.GetReturnValue().Set(self);
39
175
  }
40
176
 
41
177
  // createImageBitmap(source) -> Promise<ImageBitmap>
@@ -71,6 +207,52 @@ void CreateImageBitmap(const v8::FunctionCallbackInfo<v8::Value>& args)
71
207
  if (bytes) {
72
208
  input = std::move(*bytes);
73
209
  }
210
+ } else if (args[0]->IsObject()) {
211
+ v8::Local<v8::Object> obj = args[0].As<v8::Object>();
212
+
213
+ // 1) ImageData ({ data: Uint8ClampedArray, width, height }):
214
+ // デコード不要でそのまま RGBA として取り込む
215
+ // (webgpu レンダラのキャプチャ/フィルタ→ImageBitmap 化の経路)。
216
+ v8::Local<v8::Value> data_v, w_v, h_v;
217
+ if (obj->Get(ctx, Str(isolate, "data")).ToLocal(&data_v) && data_v->IsArrayBufferView() &&
218
+ obj->Get(ctx, Str(isolate, "width")).ToLocal(&w_v) && w_v->IsNumber() &&
219
+ obj->Get(ctx, Str(isolate, "height")).ToLocal(&h_v) && h_v->IsNumber()) {
220
+ const auto w = static_cast<uint32_t>(w_v.As<v8::Number>()->Value());
221
+ const auto h = static_cast<uint32_t>(h_v.As<v8::Number>()->Value());
222
+ auto view = data_v.As<v8::ArrayBufferView>();
223
+ if (view->ByteLength() < static_cast<size_t>(w) * h * 4) {
224
+ resolver->Reject(ctx, v8::Exception::TypeError(
225
+ Str(isolate, "ImageData size mismatch"))).Check();
226
+ return;
227
+ }
228
+ auto* raw = new DecodedImage();
229
+ raw->width = w;
230
+ raw->height = h;
231
+ raw->rgba.resize(static_cast<size_t>(w) * h * 4);
232
+ view->CopyContents(raw->rgba.data(), raw->rgba.size());
233
+ resolver->Resolve(ctx, WrapImageBitmap(isolate, raw)).Check();
234
+ return;
235
+ }
236
+
237
+ // 2) ImageBitmap / 2D 済み canvas / video: ピクセルを複製して新規 ImageBitmap
238
+ const uint8_t* px = nullptr;
239
+ uint32_t sw = 0, sh = 0;
240
+ if (GetImageSourcePixels(isolate, obj, &px, &sw, &sh) && px) {
241
+ auto* raw = new DecodedImage();
242
+ raw->width = sw;
243
+ raw->height = sh;
244
+ raw->rgba.assign(px, px + static_cast<size_t>(sw) * sh * 4);
245
+ resolver->Resolve(ctx, WrapImageBitmap(isolate, raw)).Check();
246
+ return;
247
+ }
248
+
249
+ // 3) Blob: 内包バイト列 (エンコード済み画像) を WIC デコードへ回す
250
+ v8::Local<v8::Value> blob_v;
251
+ if (obj->Get(ctx, Str(isolate, "__blobData")).ToLocal(&blob_v) && blob_v->IsArrayBuffer()) {
252
+ auto store = blob_v.As<v8::ArrayBuffer>()->GetBackingStore();
253
+ input.assign(static_cast<uint8_t*>(store->Data()),
254
+ static_cast<uint8_t*>(store->Data()) + store->ByteLength());
255
+ }
74
256
  }
75
257
 
76
258
  auto* img = new DecodedImage();
@@ -99,8 +281,7 @@ v8::Local<v8::Object> WrapImageBitmap(v8::Isolate* isolate, DecodedImage* image)
99
281
  v8util::SetValue(isolate, obj, "height", v8::Integer::NewFromUnsigned(isolate, image->height));
100
282
  v8util::SetMethod(isolate, obj, "close", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
101
283
 
102
- auto* handle = new v8::Global<v8::Object>(isolate, obj);
103
- handle->SetWeak(image, ReleaseDecoded, v8::WeakCallbackType::kParameter);
284
+ v8util::AttachWeak(isolate, obj, image);
104
285
  return obj;
105
286
  }
106
287
 
@@ -126,6 +307,25 @@ bool GetImageSourcePixels(v8::Isolate* isolate, v8::Local<v8::Value> source,
126
307
  return true;
127
308
  }
128
309
 
310
+ // Image 要素 (new Image() + src): 読み込み完了後は内部フィールドに DecodedImage
311
+ v8::Local<v8::Value> is_image;
312
+ if (obj->Get(ctx, Str(isolate, "__isImageElement")).ToLocal(&is_image) &&
313
+ is_image->IsBoolean() && is_image.As<v8::Boolean>()->Value()) {
314
+ if (obj->InternalFieldCount() < 1) {
315
+ return false;
316
+ }
317
+ v8::Local<v8::Data> field = obj->GetInternalField(0);
318
+ if (!field->IsValue() || !field.As<v8::Value>()->IsExternal()) {
319
+ return false; // 未読み込み
320
+ }
321
+ auto* img = static_cast<DecodedImage*>(
322
+ field.As<v8::Value>().As<v8::External>()->Value());
323
+ *out_rgba = img->rgba.data();
324
+ *out_width = img->width;
325
+ *out_height = img->height;
326
+ return true;
327
+ }
328
+
129
329
  // video 要素: 現在フレームを返す
130
330
  v8::Local<v8::Value> is_video;
131
331
  if (obj->Get(ctx, Str(isolate, "__isVideoElement")).ToLocal(&is_video) &&
@@ -151,6 +351,8 @@ void InstallImage(v8::Isolate* isolate, v8::Local<v8::Object> global, HostContex
151
351
  v8::Local<v8::FunctionTemplate> image_tmpl =
152
352
  v8::FunctionTemplate::New(isolate, ImageConstructor);
153
353
  image_tmpl->SetClassName(Str(isolate, "Image"));
354
+ // 内部フィールド0: デコード済み DecodedImage* (src セッターが設定)
355
+ image_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
154
356
  global->Set(ctx, Str(isolate, "Image"),
155
357
  image_tmpl->GetFunction(ctx).ToLocalChecked()).Check();
156
358