@next2d/builder 0.1.7 → 0.1.10

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 (75) hide show
  1. package/dist/cli.d.ts +59 -0
  2. package/dist/cli.js +141 -0
  3. package/dist/constants.d.ts +53 -0
  4. package/dist/constants.js +64 -0
  5. package/dist/context.d.ts +29 -0
  6. package/dist/context.js +19 -0
  7. package/dist/electron.d.ts +10 -0
  8. package/dist/electron.js +142 -0
  9. package/dist/index.js +18 -754
  10. package/dist/native.d.ts +27 -0
  11. package/dist/native.js +123 -0
  12. package/dist/utils.d.ts +27 -0
  13. package/dist/utils.js +40 -0
  14. package/dist/web.d.ts +18 -0
  15. package/dist/web.js +70 -0
  16. package/dist/xbox.d.ts +62 -0
  17. package/dist/xbox.js +426 -0
  18. package/package.json +12 -9
  19. package/templates/xbox/CMakeLists.txt +116 -11
  20. package/templates/xbox/README.md +34 -8
  21. package/templates/xbox/cmake/FetchDawn.cmake +47 -6
  22. package/templates/xbox/cmake/FindV8.cmake +15 -0
  23. package/templates/xbox/js/bootstrap.js +151 -28
  24. package/templates/xbox/js/selftest.js +740 -90
  25. package/templates/xbox/src/AssetLoader.cpp +115 -12
  26. package/templates/xbox/src/AssetLoader.h +4 -0
  27. package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
  28. package/templates/xbox/src/EmbeddedAssets.h +60 -0
  29. package/templates/xbox/src/EventLoop.cpp +13 -1
  30. package/templates/xbox/src/EventLoop.h +12 -0
  31. package/templates/xbox/src/bindings/Audio.cpp +211 -31
  32. package/templates/xbox/src/bindings/Bindings.h +10 -0
  33. package/templates/xbox/src/bindings/Canvas.cpp +77 -2
  34. package/templates/xbox/src/bindings/Canvas2D.cpp +496 -43
  35. package/templates/xbox/src/bindings/Console.cpp +6 -1
  36. package/templates/xbox/src/bindings/DomShims.cpp +143 -0
  37. package/templates/xbox/src/bindings/EventTarget.cpp +11 -0
  38. package/templates/xbox/src/bindings/Fetch.cpp +2 -8
  39. package/templates/xbox/src/bindings/Image.cpp +243 -15
  40. package/templates/xbox/src/bindings/Polyfills.cpp +1226 -0
  41. package/templates/xbox/src/bindings/RasterCore.h +105 -1
  42. package/templates/xbox/src/bindings/Video.cpp +153 -10
  43. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +844 -18
  44. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +7 -9
  45. package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
  46. package/templates/xbox/src/gpu/DawnContext.cpp +245 -7
  47. package/templates/xbox/src/gpu/DawnContext.h +18 -0
  48. package/templates/xbox/src/main.cpp +459 -8
  49. package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
  50. package/templates/xbox/src/platform/AudioDecoder.h +18 -0
  51. package/templates/xbox/src/platform/AudioEngine.cpp +37 -6
  52. package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
  53. package/templates/xbox/src/platform/DecodeQueue.h +27 -0
  54. package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
  55. package/templates/xbox/src/platform/ImageDecoder.h +18 -0
  56. package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
  57. package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
  58. package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
  59. package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
  60. package/templates/xbox/src/v8/CodeCache.h +223 -0
  61. package/templates/xbox/src/v8/V8Runtime.cpp +76 -11
  62. package/templates/xbox/src/v8/V8Util.h +79 -0
  63. package/templates/xbox/src/v8/WeakHandle.h +45 -0
  64. package/templates/xbox/src/worker/WorkerRuntime.cpp +432 -48
  65. package/templates/xbox/src/worker/WorkerRuntime.h +43 -13
  66. package/templates/xbox/tests/check_local.sh +7 -2
  67. package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
  68. package/templates/xbox/tests/raster_test.cpp +50 -0
  69. package/templates/xbox/tests/windows_platform_test.cpp +75 -3
  70. package/templates/xbox/third_party/LICENSES.md +14 -0
  71. package/templates/xbox/third_party/dr_mp3.h +5412 -0
  72. package/templates/xbox/third_party/dr_wav.h +9131 -0
  73. package/templates/xbox/third_party/stb_image.h +7988 -0
  74. package/templates/xbox/third_party/stb_truetype.h +5079 -0
  75. package/templates/xbox/third_party/stb_vorbis.c +5584 -0
@@ -7,6 +7,7 @@
7
7
  #include <cctype>
8
8
  #include <cmath>
9
9
  #include <cstdint>
10
+ #include <memory>
10
11
  #include <string>
11
12
  #include <utility>
12
13
  #include <vector>
@@ -26,10 +27,18 @@ struct SubPath {
26
27
 
27
28
  struct RGBA { uint8_t r=0,g=0,b=0,a=255; };
28
29
 
29
- // クリップ矩形 (デバイス座標, [x0,x1) x [y0,y1))。active=false なら無制限。
30
+ // クリップ領域 (デバイス座標)。
31
+ // active=false … 無制限
32
+ // active=true, mask=null … 矩形クリップ [x0,x1) x [y0,y1) (厳密)
33
+ // mask!=null … 任意形状クリップ。x0..y1 は外接矩形 (高速リジェクト用)、
34
+ // mask は surface と同寸のカバレッジ (1=内側/0=外側)。
35
+ // mask は shared_ptr のため save()/restore() の state コピーで安価に共有される
36
+ // (clip() は既存 mask を破壊せず新しい mask を割り当てるので復元が壊れない)。
30
37
  struct ClipRect {
31
38
  bool active = false;
32
39
  double x0 = 0, y0 = 0, x1 = 0, y1 = 0;
40
+ std::shared_ptr<const std::vector<uint8_t>> mask;
41
+ int mask_w = 0, mask_h = 0;
33
42
  };
34
43
 
35
44
  // RGBA8 のピクセルバッファ。
@@ -101,6 +110,9 @@ inline void Blend(Surface& s, const ClipRect& clip, int x, int y, const RGBA& co
101
110
  {
102
111
  if (x < 0 || y < 0 || x >= s.width || y >= s.height) return;
103
112
  if (clip.active && (x < clip.x0 || x >= clip.x1 || y < clip.y0 || y >= clip.y1)) return;
113
+ // 任意形状クリップ: マスクの外なら書き込まない。
114
+ if (clip.mask && (x >= clip.mask_w || y >= clip.mask_h ||
115
+ (*clip.mask)[static_cast<size_t>(y) * clip.mask_w + x] == 0)) return;
104
116
  size_t i = (static_cast<size_t>(y) * s.width + x) * 4;
105
117
  double a = (col.a / 255.0) * alpha;
106
118
  s.pixels[i+0] = static_cast<uint8_t>(col.r * a + s.pixels[i+0] * (1 - a));
@@ -215,6 +227,98 @@ inline void IntersectClip(ClipRect& clip, double nx0, double ny0, double nx1, do
215
227
  }
216
228
  }
217
229
 
230
+ // パスが単一の軸並行矩形か判定する (矩形なら外接矩形クリップで厳密に足りる)。
231
+ // beginPath→rect() は 4 or 5 点 (閉路点重複) の矩形サブパスになる。
232
+ inline bool IsAxisAlignedRect(const std::vector<SubPath>& path)
233
+ {
234
+ if (path.size() != 1) return false;
235
+ const std::vector<Point>& p = path[0].pts;
236
+ // 末尾が始点と重複する 5 点表現も許容する
237
+ size_t n = p.size();
238
+ if (n == 5 && std::abs(p[4].x - p[0].x) < 1e-6 && std::abs(p[4].y - p[0].y) < 1e-6) {
239
+ n = 4;
240
+ }
241
+ if (n != 4) return false;
242
+ // 各辺が水平または垂直であること
243
+ for (size_t i = 0; i < 4; ++i) {
244
+ const Point& a = p[i];
245
+ const Point& b = p[(i + 1) % 4];
246
+ const bool horizontal = std::abs(a.y - b.y) < 1e-6;
247
+ const bool vertical = std::abs(a.x - b.x) < 1e-6;
248
+ if (!horizontal && !vertical) return false;
249
+ }
250
+ return true;
251
+ }
252
+
253
+ // パスを nonzero winding でカバレッジマスク (surface 同寸, 1=内側) にラスタライズする。
254
+ // スキャンライン規約は FillPath と一致させる (塗りと同じ形にクリップされる)。
255
+ inline std::shared_ptr<std::vector<uint8_t>> RasterizePathMask(
256
+ const std::vector<SubPath>& path, int width, int height)
257
+ {
258
+ auto mask = std::make_shared<std::vector<uint8_t>>(
259
+ static_cast<size_t>(width) * height, 0);
260
+ if (width <= 0 || height <= 0) return mask;
261
+
262
+ double miny = 1e18, maxy = -1e18;
263
+ for (auto& sp : path) for (auto& p : sp.pts) { miny = std::min(miny,p.y); maxy = std::max(maxy,p.y); }
264
+ if (maxy < miny) return mask;
265
+ int y0 = std::max(0, static_cast<int>(std::floor(miny)));
266
+ int y1 = std::min(height - 1, static_cast<int>(std::ceil(maxy)));
267
+ for (int y = y0; y <= y1; ++y) {
268
+ double sy = y + 0.5;
269
+ std::vector<std::pair<double,int>> xs;
270
+ for (auto& sp : path) {
271
+ size_t n = sp.pts.size();
272
+ if (n < 2) continue;
273
+ for (size_t i = 0; i < n; ++i) {
274
+ Point a = sp.pts[i];
275
+ Point b = sp.pts[(i+1) % n];
276
+ if ((a.y <= sy && b.y > sy) || (b.y <= sy && a.y > sy)) {
277
+ double t = (sy - a.y) / (b.y - a.y);
278
+ xs.push_back({a.x + t * (b.x - a.x), a.y < b.y ? 1 : -1});
279
+ }
280
+ }
281
+ }
282
+ std::sort(xs.begin(), xs.end());
283
+ int wind = 0;
284
+ for (size_t i = 0; i + 1 < xs.size(); ++i) {
285
+ wind += xs[i].second;
286
+ if (wind != 0) {
287
+ int xa = std::max(0, static_cast<int>(std::floor(xs[i].first)));
288
+ int xb = std::min(width - 1, static_cast<int>(std::ceil(xs[i+1].first)));
289
+ for (int x = xa; x <= xb; ++x) {
290
+ (*mask)[static_cast<size_t>(y) * width + x] = 1;
291
+ }
292
+ }
293
+ }
294
+ }
295
+ return mask;
296
+ }
297
+
298
+ // 任意形状パスをクリップへ積集合で反映する (非矩形 clip() の実体)。
299
+ // 外接矩形 (高速リジェクト) も同時に反映し、既存 mask があれば AND を取って
300
+ // 新しい mask を割り当てる (save/restore 安全)。
301
+ inline void IntersectClipMask(ClipRect& clip, const std::vector<SubPath>& path,
302
+ int width, int height)
303
+ {
304
+ double minx, miny, maxx, maxy;
305
+ if (PathBounds(path, &minx, &miny, &maxx, &maxy)) {
306
+ IntersectClip(clip, std::floor(minx), std::floor(miny),
307
+ std::ceil(maxx), std::ceil(maxy));
308
+ }
309
+ auto next = RasterizePathMask(path, width, height);
310
+ if (clip.mask) {
311
+ const std::vector<uint8_t>& prev = *clip.mask;
312
+ const size_t n = std::min(next->size(), prev.size());
313
+ for (size_t i = 0; i < n; ++i) {
314
+ if (prev[i] == 0) { (*next)[i] = 0; }
315
+ }
316
+ }
317
+ clip.mask = next;
318
+ clip.mask_w = width;
319
+ clip.mask_h = height;
320
+ }
321
+
218
322
  // 3次ベジェを現在サブパスへフラット化して追記する。p0 は変換済みの直前点。
219
323
  inline void FlattenCubic(std::vector<Point>& out,
220
324
  Point p0, Point p1, Point p2, Point p3, int steps = 16)
@@ -13,6 +13,15 @@
13
13
  #include "ImageSource.h"
14
14
  #include "EventTarget.h"
15
15
  #include "v8/V8Util.h"
16
+ #include "v8/WeakHandle.h"
17
+
18
+ #include <string>
19
+ #include <vector>
20
+
21
+ // Media Foundation はコンソール (Game Core OS) に無いデスクトップ専用 API。
22
+ // コンソールでは動画デコード未対応 (末尾の «CONSOLE» スタブ)。
23
+ // 実機での動画対応は devkit 段階の課題。
24
+ #if !NEXT2D_XBOX_CONSOLE
16
25
 
17
26
  #include <mfapi.h>
18
27
  #include <mfidl.h>
@@ -20,9 +29,6 @@
20
29
  #include <shlwapi.h>
21
30
  #include <wrl/client.h>
22
31
 
23
- #include <string>
24
- #include <vector>
25
-
26
32
  #pragma comment(lib, "mfplat.lib")
27
33
  #pragma comment(lib, "mfreadwrite.lib")
28
34
  #pragma comment(lib, "mfuuid.lib")
@@ -47,6 +53,24 @@ struct VideoDecoder {
47
53
  bool playing = false;
48
54
  bool ended = false;
49
55
  double duration = 0.0;
56
+ double position = 0.0; // 現在位置 (秒, サンプルタイムスタンプ由来)
57
+
58
+ // 先頭 (または指定秒) へシークする。loop 再生と currentTime 設定で使用。
59
+ bool Seek(double seconds)
60
+ {
61
+ if (!reader) return false;
62
+ PROPVARIANT var;
63
+ PropVariantInit(&var);
64
+ var.vt = VT_I8;
65
+ var.hVal.QuadPart = static_cast<LONGLONG>(seconds * 1e7); // s -> 100ns
66
+ const bool ok = SUCCEEDED(reader->SetCurrentPosition(GUID_NULL, var));
67
+ PropVariantClear(&var);
68
+ if (ok) {
69
+ ended = false;
70
+ position = seconds;
71
+ }
72
+ return ok;
73
+ }
50
74
 
51
75
  bool Open(const std::vector<uint8_t>& bytes)
52
76
  {
@@ -87,13 +111,15 @@ struct VideoDecoder {
87
111
  {
88
112
  if (!reader) return false;
89
113
  DWORD flags = 0;
114
+ LONGLONG timestamp = 0;
90
115
  ComPtr<IMFSample> sample;
91
116
  if (FAILED(reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0,
92
- nullptr, &flags, nullptr, &sample))) {
117
+ nullptr, &flags, &timestamp, &sample))) {
93
118
  return false;
94
119
  }
95
120
  if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { ended = true; return false; }
96
121
  if (!sample) return false;
122
+ position = static_cast<double>(timestamp) / 1e7; // 100ns -> s
97
123
 
98
124
  ComPtr<IMFMediaBuffer> buffer;
99
125
  sample->ConvertToContiguousBuffer(&buffer);
@@ -112,8 +138,6 @@ struct VideoDecoder {
112
138
  }
113
139
  };
114
140
 
115
- void ReleaseVideo(const v8::WeakCallbackInfo<VideoDecoder>& info) { delete info.GetParameter(); }
116
-
117
141
  VideoDecoder* Decoder(v8::Local<v8::Object> obj)
118
142
  {
119
143
  return static_cast<VideoDecoder*>(obj->GetInternalField(0).As<v8::External>()->Value());
@@ -144,7 +168,10 @@ void LoadVideo(v8::Isolate* isolate, v8::Local<v8::Object> self, const std::stri
144
168
  SetValue(isolate, self, "videoHeight", v8::Integer::NewFromUnsigned(isolate, dec->height));
145
169
  SetValue(isolate, self, "duration", v8::Number::New(isolate, dec->duration));
146
170
  SetValue(isolate, self, "readyState", v8::Integer::New(isolate, 4));
171
+ // player は loadedmetadata / progress / canplaythrough を購読する
172
+ // (VideoRegisterEventUseCase)。ローカル読み込みは即完了のため順に発火する。
147
173
  FireVideoEvent(isolate, self, "loadedmetadata");
174
+ FireVideoEvent(isolate, self, "progress");
148
175
  FireVideoEvent(isolate, self, "canplaythrough");
149
176
  } else {
150
177
  FireVideoEvent(isolate, self, "error");
@@ -162,7 +189,20 @@ bool GetVideoFramePixels(v8::Isolate* isolate, v8::Local<v8::Object> obj,
162
189
  if (dec->playing && !dec->ended) {
163
190
  dec->ReadNextFrame(); // 描画のたびに次フレームへ進める(簡易フレーム進行)
164
191
  if (dec->ended) {
165
- FireVideoEvent(isolate, obj, "ended");
192
+ // loop 指定時は先頭へ戻して継続、そうでなければ ended を通知
193
+ v8::Local<v8::Value> loop_v;
194
+ const bool loop =
195
+ obj->Get(isolate->GetCurrentContext(),
196
+ v8util::Str(isolate, "loop")).ToLocal(&loop_v) &&
197
+ loop_v->BooleanValue(isolate);
198
+ if (loop && dec->Seek(0.0)) {
199
+ dec->ReadNextFrame();
200
+ } else {
201
+ dec->playing = false;
202
+ SetValue(isolate, obj, "ended", v8::Boolean::New(isolate, true));
203
+ SetValue(isolate, obj, "paused", v8::Boolean::New(isolate, true));
204
+ FireVideoEvent(isolate, obj, "ended");
205
+ }
166
206
  }
167
207
  }
168
208
  *out_rgba = dec->frame.data();
@@ -180,19 +220,69 @@ v8::Local<v8::Object> CreateVideoElement(v8::Isolate* isolate, HostContext* /*ho
180
220
 
181
221
  auto* dec = new VideoDecoder();
182
222
  self->SetInternalField(0, v8::External::New(isolate, dec));
183
- auto* handle = new v8::Global<v8::Object>(isolate, self);
184
- handle->SetWeak(dec, ReleaseVideo, v8::WeakCallbackType::kParameter);
223
+ v8util::AttachWeak(isolate, self, dec);
185
224
 
186
225
  SetValue(isolate, self, "__isVideoElement", v8::Boolean::New(isolate, true));
187
226
  SetValue(isolate, self, "tagName", Str(isolate, "VIDEO"));
188
227
  SetValue(isolate, self, "videoWidth", v8::Integer::New(isolate, 0));
189
228
  SetValue(isolate, self, "videoHeight", v8::Integer::New(isolate, 0));
190
- SetValue(isolate, self, "currentTime", v8::Number::New(isolate, 0));
191
229
  SetValue(isolate, self, "readyState", v8::Integer::New(isolate, 0));
192
230
  SetValue(isolate, self, "loop", v8::Boolean::New(isolate, false));
231
+ SetValue(isolate, self, "paused", v8::Boolean::New(isolate, true));
232
+ SetValue(isolate, self, "ended", v8::Boolean::New(isolate, false));
233
+ SetValue(isolate, self, "muted", v8::Boolean::New(isolate, false));
234
+ SetValue(isolate, self, "volume", v8::Number::New(isolate, 1.0));
235
+ SetValue(isolate, self, "autoplay", v8::Boolean::New(isolate, false));
193
236
  SetValue(isolate, self, "style", v8::Object::New(isolate));
194
237
  InstallEventTarget(isolate, self);
195
238
 
239
+ // currentTime: 取得はデコーダの現在位置、設定はシーク
240
+ self->SetNativeDataProperty(ctx, Str(isolate, "currentTime"),
241
+ [](v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
242
+ VideoDecoder* d = Decoder(info.This());
243
+ info.GetReturnValue().Set(
244
+ v8::Number::New(info.GetIsolate(), d ? d->position : 0.0));
245
+ },
246
+ [](v8::Local<v8::Name>, v8::Local<v8::Value> value,
247
+ const v8::PropertyCallbackInfo<void>& info) {
248
+ if (!value->IsNumber()) return;
249
+ VideoDecoder* d = Decoder(info.This());
250
+ if (d) {
251
+ d->Seek(value.As<v8::Number>()->Value());
252
+ }
253
+ }).Check();
254
+
255
+ // setAttribute / getAttribute (player は playsinline を設定する)
256
+ SetMethod(isolate, self, "setAttribute",
257
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) {
258
+ if (a.Length() < 2) return;
259
+ v8::Isolate* iso = a.GetIsolate();
260
+ v8::Local<v8::Context> c = iso->GetCurrentContext();
261
+ v8::Local<v8::Value> attrs;
262
+ v8::Local<v8::Object> store;
263
+ if (a.This()->Get(c, v8util::Str(iso, "__attrs")).ToLocal(&attrs) && attrs->IsObject()) {
264
+ store = attrs.As<v8::Object>();
265
+ } else {
266
+ store = v8::Object::New(iso);
267
+ SetValue(iso, a.This(), "__attrs", store);
268
+ }
269
+ store->Set(c, a[0], a[1]).Check();
270
+ });
271
+ SetMethod(isolate, self, "getAttribute",
272
+ [](const v8::FunctionCallbackInfo<v8::Value>& a) {
273
+ a.GetReturnValue().SetNull();
274
+ if (a.Length() < 1) return;
275
+ v8::Isolate* iso = a.GetIsolate();
276
+ v8::Local<v8::Context> c = iso->GetCurrentContext();
277
+ v8::Local<v8::Value> attrs;
278
+ if (a.This()->Get(c, v8util::Str(iso, "__attrs")).ToLocal(&attrs) && attrs->IsObject()) {
279
+ v8::Local<v8::Value> v;
280
+ if (attrs.As<v8::Object>()->Get(c, a[0]).ToLocal(&v) && !v->IsUndefined()) {
281
+ a.GetReturnValue().Set(v);
282
+ }
283
+ }
284
+ });
285
+
196
286
  // src セッター: 代入で読み込み開始
197
287
  self->SetNativeDataProperty(ctx, Str(isolate, "src"),
198
288
  [](v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
@@ -218,12 +308,16 @@ v8::Local<v8::Object> CreateVideoElement(v8::Isolate* isolate, HostContext* /*ho
218
308
  SetMethod(isolate, self, "play", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
219
309
  v8::Isolate* iso = a.GetIsolate();
220
310
  Decoder(a.This())->playing = true;
311
+ SetValue(iso, a.This(), "paused", v8::Boolean::New(iso, false));
312
+ SetValue(iso, a.This(), "ended", v8::Boolean::New(iso, false));
221
313
  auto r = v8::Promise::Resolver::New(iso->GetCurrentContext()).ToLocalChecked();
222
314
  r->Resolve(iso->GetCurrentContext(), v8::Undefined(iso)).Check();
223
315
  a.GetReturnValue().Set(r->GetPromise());
224
316
  });
225
317
  SetMethod(isolate, self, "pause", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
318
+ v8::Isolate* iso = a.GetIsolate();
226
319
  Decoder(a.This())->playing = false;
320
+ SetValue(iso, a.This(), "paused", v8::Boolean::New(iso, true));
227
321
  });
228
322
  SetMethod(isolate, self, "canPlayType", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
229
323
  a.GetReturnValue().Set(Str(a.GetIsolate(), "maybe"));
@@ -233,3 +327,52 @@ v8::Local<v8::Object> CreateVideoElement(v8::Isolate* isolate, HostContext* /*ho
233
327
  }
234
328
 
235
329
  } // namespace next2d
330
+
331
+ #else // NEXT2D_XBOX_CONSOLE
332
+
333
+ // «CONSOLE» 動画デコード未対応スタブ。
334
+ // createElement('video') がクラッシュしないよう API 形状だけ提供する
335
+ // (フレーム取得は常に false、canPlayType は空 = 非対応を正しく通知)。
336
+ namespace next2d {
337
+
338
+ using v8util::Str;
339
+ using v8util::SetMethod;
340
+ using v8util::SetValue;
341
+
342
+ bool GetVideoFramePixels(v8::Isolate*, v8::Local<v8::Object>,
343
+ const uint8_t** out_rgba, uint32_t* out_width, uint32_t* out_height)
344
+ {
345
+ *out_rgba = nullptr;
346
+ *out_width = 0;
347
+ *out_height = 0;
348
+ return false;
349
+ }
350
+
351
+ v8::Local<v8::Object> CreateVideoElement(v8::Isolate* isolate, HostContext* /*host*/)
352
+ {
353
+ v8::Local<v8::Object> self = v8::Object::New(isolate);
354
+ SetValue(isolate, self, "__isVideoElement", v8::Boolean::New(isolate, true));
355
+ SetValue(isolate, self, "tagName", Str(isolate, "VIDEO"));
356
+ SetValue(isolate, self, "localName", Str(isolate, "video"));
357
+ SetValue(isolate, self, "videoWidth", v8::Integer::New(isolate, 0));
358
+ SetValue(isolate, self, "videoHeight", v8::Integer::New(isolate, 0));
359
+ SetValue(isolate, self, "paused", v8::Boolean::New(isolate, true));
360
+ SetValue(isolate, self, "ended", v8::Boolean::New(isolate, false));
361
+ InstallEventTarget(isolate, self);
362
+ SetMethod(isolate, self, "load", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
363
+ SetMethod(isolate, self, "play", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
364
+ v8::Isolate* iso = a.GetIsolate();
365
+ auto r = v8::Promise::Resolver::New(iso->GetCurrentContext()).ToLocalChecked();
366
+ r->Resolve(iso->GetCurrentContext(), v8::Undefined(iso)).Check();
367
+ a.GetReturnValue().Set(r->GetPromise());
368
+ });
369
+ SetMethod(isolate, self, "pause", [](const v8::FunctionCallbackInfo<v8::Value>&) {});
370
+ SetMethod(isolate, self, "canPlayType", [](const v8::FunctionCallbackInfo<v8::Value>& a) {
371
+ a.GetReturnValue().Set(Str(a.GetIsolate(), ""));
372
+ });
373
+ return self;
374
+ }
375
+
376
+ } // namespace next2d
377
+
378
+ #endif // !NEXT2D_XBOX_CONSOLE