@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.
- package/README.md +5 -1
- package/dist/index.js +140 -36
- package/package.json +3 -2
- package/templates/xbox/CMakeLists.txt +74 -2
- package/templates/xbox/README.md +73 -12
- package/templates/xbox/cmake/FetchDawn.cmake +47 -6
- package/templates/xbox/cmake/FindV8.cmake +22 -1
- package/templates/xbox/js/bootstrap.js +31 -28
- package/templates/xbox/js/selftest.js +740 -90
- package/templates/xbox/src/EventLoop.cpp +28 -1
- package/templates/xbox/src/EventLoop.h +12 -0
- package/templates/xbox/src/bindings/Audio.cpp +99 -15
- package/templates/xbox/src/bindings/Bindings.h +10 -0
- package/templates/xbox/src/bindings/Canvas.cpp +45 -0
- package/templates/xbox/src/bindings/Canvas2D.cpp +2 -5
- package/templates/xbox/src/bindings/DomShims.cpp +127 -0
- package/templates/xbox/src/bindings/EventTarget.cpp +2 -0
- package/templates/xbox/src/bindings/Fetch.cpp +2 -8
- package/templates/xbox/src/bindings/Image.cpp +212 -10
- package/templates/xbox/src/bindings/Polyfills.cpp +791 -0
- package/templates/xbox/src/bindings/Video.cpp +96 -7
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +815 -15
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +3 -8
- package/templates/xbox/src/gpu/DawnContext.cpp +90 -3
- package/templates/xbox/src/gpu/DawnContext.h +18 -0
- package/templates/xbox/src/main.cpp +88 -6
- package/templates/xbox/src/platform/AudioEngine.cpp +9 -3
- package/templates/xbox/src/v8/V8Runtime.cpp +69 -4
- package/templates/xbox/src/v8/V8Util.h +29 -0
- package/templates/xbox/src/v8/WeakHandle.h +45 -0
- package/templates/xbox/src/worker/WorkerRuntime.cpp +325 -41
- package/templates/xbox/src/worker/WorkerRuntime.h +20 -10
- package/templates/xbox/tests/check_local.sh +3 -2
- 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
|
-
|
|
24
|
+
// base64 デコード (data: URL 用。Vite は小さい画像をインライン化する)
|
|
25
|
+
bool ImageDecodeBase64(const std::string& in, std::vector<uint8_t>* out)
|
|
22
26
|
{
|
|
23
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
35
|
-
args.This()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
|