@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
@@ -0,0 +1,791 @@
1
+ // 全コンテキスト (メイン + 各 worker) に必要な JS ポリフィルを評価する。
2
+ //
3
+ // bootstrap.js はメインコンテキストでのみ実行されるため、worker コンテキストには
4
+ // TextEncoder/TextDecoder 等が存在せず、Vite がバンドルした worker スクリプトが
5
+ // 評価時に ReferenceError で落ちる。ここで C++ から全コンテキストに注入する。
6
+ // (bootstrap.js 側は typeof ガード付きなので二重定義にはならない)
7
+ //
8
+ // NOTE: MSVC は 1 つの文字列リテラルが約 16KB までのため (C2026)、
9
+ // ポリフィルは独立した IIFE のセクション配列に分割して順に評価する。
10
+ #include "Bindings.h"
11
+
12
+ #include "v8/V8Util.h"
13
+
14
+ namespace next2d {
15
+
16
+ namespace {
17
+
18
+ // section 1: base (queueMicrotask)
19
+ const char kPolyfills1[] = R"JS(
20
+ (function (global) {
21
+ "use strict";
22
+
23
+
24
+ if (typeof global.queueMicrotask !== "function") {
25
+ global.queueMicrotask = function (callback) {
26
+ Promise.resolve().then(callback);
27
+ };
28
+ }
29
+ })(globalThis);
30
+ )JS";
31
+
32
+ // section 2: TextEncoder / location
33
+ const char kPolyfills2[] = R"JS(
34
+ (function (global) {
35
+ "use strict";
36
+ if (typeof global.TextEncoder === "undefined") {
37
+ global.TextEncoder = class TextEncoder {
38
+ get encoding() { return "utf-8"; }
39
+ encode(str) {
40
+ str = String(str);
41
+ const out = [];
42
+ for (let i = 0; i < str.length; i++) {
43
+ let code = str.charCodeAt(i);
44
+ if (code < 0x80) {
45
+ out.push(code);
46
+ } else if (code < 0x800) {
47
+ out.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
48
+ } else if (code >= 0xd800 && code <= 0xdbff) {
49
+ const hi = code;
50
+ const lo = str.charCodeAt(++i);
51
+ code = 0x10000 + ((hi - 0xd800) << 10) + (lo - 0xdc00);
52
+ out.push(
53
+ 0xf0 | (code >> 18),
54
+ 0x80 | ((code >> 12) & 0x3f),
55
+ 0x80 | ((code >> 6) & 0x3f),
56
+ 0x80 | (code & 0x3f)
57
+ );
58
+ } else {
59
+ out.push(
60
+ 0xe0 | (code >> 12),
61
+ 0x80 | ((code >> 6) & 0x3f),
62
+ 0x80 | (code & 0x3f)
63
+ );
64
+ }
65
+ }
66
+ return new Uint8Array(out);
67
+ }
68
+ };
69
+ }
70
+
71
+ // location (worker を含む全コンテキストで参照可能にする。
72
+ // player の LoadUseCase が location.origin で URL を解決する)
73
+ if (typeof global.location === "undefined") {
74
+ global.location = {
75
+ "href": "app://local/",
76
+ "origin": "app://local",
77
+ "protocol": "app:",
78
+ "host": "local",
79
+ "hostname": "local",
80
+ "pathname": "/",
81
+ "search": "",
82
+ "hash": "",
83
+ reload() { /* no-op */ }
84
+ };
85
+ }
86
+
87
+ // history (framework の gotoView が SPA 設定時に history.pushState を呼ぶ)。
88
+ // pushState/replaceState は location の pathname/search/hash にも反映する
89
+ if (typeof global.history === "undefined") {
90
+ const applyUrl = (url) => {
91
+ if (typeof url !== "string" || url === "") {
92
+ return;
93
+ }
94
+ let rest = url;
95
+ const origin = global.location.origin;
96
+ if (rest.indexOf(origin) === 0) {
97
+ rest = rest.slice(origin.length);
98
+ }
99
+ if (rest === "" || rest[0] !== "/") {
100
+ rest = "/" + rest;
101
+ }
102
+ let hash = "";
103
+ const hi = rest.indexOf("#");
104
+ if (hi >= 0) {
105
+ hash = rest.slice(hi);
106
+ rest = rest.slice(0, hi);
107
+ }
108
+ let search = "";
109
+ const qi = rest.indexOf("?");
110
+ if (qi >= 0) {
111
+ search = rest.slice(qi);
112
+ rest = rest.slice(0, qi);
113
+ }
114
+ global.location.pathname = rest;
115
+ global.location.search = search;
116
+ global.location.hash = hash;
117
+ global.location.href = origin + rest + search + hash;
118
+ };
119
+ global.history = {
120
+ "state": null,
121
+ "length": 1,
122
+ pushState(state, _title, url) {
123
+ this.state = state;
124
+ this.length++;
125
+ applyUrl(url);
126
+ },
127
+ replaceState(state, _title, url) {
128
+ this.state = state;
129
+ applyUrl(url);
130
+ },
131
+ back() { /* no-op */ },
132
+ forward() { /* no-op */ },
133
+ go() { /* no-op */ }
134
+ };
135
+ }
136
+ })(globalThis);
137
+ )JS";
138
+
139
+ // section 3: atob / btoa
140
+ const char kPolyfills3[] = R"JS(
141
+ (function (global) {
142
+ "use strict";
143
+ // atob / btoa (indexedDB のバイナリ値永続化にも使用)
144
+ const B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
145
+ if (typeof global.btoa !== "function") {
146
+ global.btoa = function (bin) {
147
+ bin = String(bin);
148
+ let out = "";
149
+ for (let i = 0; i < bin.length; i += 3) {
150
+ const a = bin.charCodeAt(i);
151
+ const b = i + 1 < bin.length ? bin.charCodeAt(i + 1) : NaN;
152
+ const c = i + 2 < bin.length ? bin.charCodeAt(i + 2) : NaN;
153
+ if (a > 255 || b > 255 || c > 255) {
154
+ throw new Error("btoa: character out of range");
155
+ }
156
+ out += B64[a >> 2];
157
+ out += B64[((a & 3) << 4) | (isNaN(b) ? 0 : b >> 4)];
158
+ out += isNaN(b) ? "=" : B64[((b & 15) << 2) | (isNaN(c) ? 0 : c >> 6)];
159
+ out += isNaN(c) ? "=" : B64[c & 63];
160
+ }
161
+ return out;
162
+ };
163
+ }
164
+ if (typeof global.atob !== "function") {
165
+ global.atob = function (b64) {
166
+ b64 = String(b64).replace(/[=\s]+$/, "");
167
+ let out = "";
168
+ let buffer = 0;
169
+ let bits = 0;
170
+ for (let i = 0; i < b64.length; i++) {
171
+ const v = B64.indexOf(b64[i]);
172
+ if (v < 0) { continue; }
173
+ buffer = (buffer << 6) | v;
174
+ bits += 6;
175
+ if (bits >= 8) {
176
+ bits -= 8;
177
+ out += String.fromCharCode((buffer >> bits) & 0xff);
178
+ }
179
+ }
180
+ return out;
181
+ };
182
+ }
183
+ })(globalThis);
184
+ )JS";
185
+
186
+ // section 4: localStorage / sessionStorage / alert / confirm
187
+ const char kPolyfills4[] = R"JS(
188
+ (function (global) {
189
+ "use strict";
190
+ // localStorage / sessionStorage。
191
+ // 永続化はホストの __next2d_storage_load/save (名前付きファイル I/O) に委ねる。
192
+ if (typeof global.localStorage === "undefined") {
193
+ const makeStorage = function (persistent) {
194
+ let data = {};
195
+ if (persistent && typeof global.__next2d_storage_load === "function") {
196
+ try {
197
+ const raw = global.__next2d_storage_load("localStorage");
198
+ if (raw) { data = JSON.parse(raw) || {}; }
199
+ } catch (e) { data = {}; }
200
+ }
201
+ const persist = function () {
202
+ if (persistent && typeof global.__next2d_storage_save === "function") {
203
+ try { global.__next2d_storage_save("localStorage", JSON.stringify(data)); } catch (e) { /* 保存失敗は無視 */ }
204
+ }
205
+ };
206
+ return {
207
+ getItem(k) {
208
+ k = String(k);
209
+ return Object.prototype.hasOwnProperty.call(data, k) ? data[k] : null;
210
+ },
211
+ setItem(k, v) { data[String(k)] = String(v); persist(); },
212
+ removeItem(k) { delete data[String(k)]; persist(); },
213
+ clear() { data = {}; persist(); },
214
+ key(i) {
215
+ const ks = Object.keys(data);
216
+ return i >= 0 && i < ks.length ? ks[i] : null;
217
+ },
218
+ get length() { return Object.keys(data).length; }
219
+ };
220
+ };
221
+ global.localStorage = makeStorage(true);
222
+ global.sessionStorage = makeStorage(false);
223
+ }
224
+
225
+ // alert / confirm (ダイアログの無い環境向け。confirm は肯定を返す)
226
+ if (typeof global.alert !== "function") {
227
+ global.alert = function () { /* no-op */ };
228
+ }
229
+ if (typeof global.confirm !== "function") {
230
+ global.confirm = function () { return true; };
231
+ }
232
+ })(globalThis);
233
+ )JS";
234
+
235
+ // section 5: indexedDB / TextDecoder
236
+ const char kPolyfills5[] = R"JS(
237
+ (function (global) {
238
+ "use strict";
239
+ // indexedDB (最小実装・ファイル永続化)。
240
+ // ゲームの典型用途 (open → objectStore → get/put/delete/getAll) をカバーする。
241
+ // 値は JSON 化可能なもの + ArrayBuffer/TypedArray (base64 でタグ付け永続化)。
242
+ // カーソル/インデックス/複合キーは未対応 («EXTEND»)。
243
+ if (typeof global.indexedDB === "undefined" &&
244
+ typeof global.__next2d_storage_load === "function") {
245
+
246
+ const TYPED = {
247
+ "Int8Array": Int8Array, "Uint8Array": Uint8Array,
248
+ "Uint8ClampedArray": Uint8ClampedArray,
249
+ "Int16Array": Int16Array, "Uint16Array": Uint16Array,
250
+ "Int32Array": Int32Array, "Uint32Array": Uint32Array,
251
+ "Float32Array": Float32Array, "Float64Array": Float64Array
252
+ };
253
+
254
+ const bytesToB64 = function (u8) {
255
+ let bin = "";
256
+ for (let i = 0; i < u8.length; i += 0x8000) {
257
+ bin += String.fromCharCode.apply(null, u8.subarray(i, i + 0x8000));
258
+ }
259
+ return global.btoa(bin);
260
+ };
261
+ const b64ToBytes = function (b64) {
262
+ const bin = global.atob(b64);
263
+ const u8 = new Uint8Array(bin.length);
264
+ for (let i = 0; i < bin.length; i++) { u8[i] = bin.charCodeAt(i); }
265
+ return u8;
266
+ };
267
+
268
+ const encodeValue = function (v) {
269
+ if (v instanceof ArrayBuffer) {
270
+ return { "__n2d_bin": bytesToB64(new Uint8Array(v)), "__n2d_type": "ArrayBuffer" };
271
+ }
272
+ if (ArrayBuffer.isView(v)) {
273
+ const name = v.constructor && v.constructor.name;
274
+ if (TYPED[name]) {
275
+ return {
276
+ "__n2d_bin": bytesToB64(new Uint8Array(v.buffer, v.byteOffset, v.byteLength)),
277
+ "__n2d_type": name
278
+ };
279
+ }
280
+ }
281
+ if (Array.isArray(v)) { return v.map(encodeValue); }
282
+ if (v && typeof v === "object") {
283
+ const out = {};
284
+ for (const k of Object.keys(v)) { out[k] = encodeValue(v[k]); }
285
+ return out;
286
+ }
287
+ return v;
288
+ };
289
+ const decodeValue = function (v) {
290
+ if (v && typeof v === "object") {
291
+ if (typeof v.__n2d_bin === "string") {
292
+ const u8 = b64ToBytes(v.__n2d_bin);
293
+ if (v.__n2d_type === "ArrayBuffer") { return u8.buffer; }
294
+ const Ctor = TYPED[v.__n2d_type] || Uint8Array;
295
+ return new Ctor(u8.buffer, 0, u8.byteLength / Ctor.BYTES_PER_ELEMENT);
296
+ }
297
+ if (Array.isArray(v)) { return v.map(decodeValue); }
298
+ const out = {};
299
+ for (const k of Object.keys(v)) { out[k] = decodeValue(v[k]); }
300
+ return out;
301
+ }
302
+ return v;
303
+ };
304
+
305
+ const loadDb = function (name) {
306
+ try {
307
+ const raw = global.__next2d_storage_load("idb_" + name);
308
+ if (raw) { return JSON.parse(raw); }
309
+ } catch (e) { /* 破損時は初期化 */ }
310
+ return { "version": 0, "stores": {} };
311
+ };
312
+ const saveDb = function (name, db) {
313
+ try { global.__next2d_storage_save("idb_" + name, JSON.stringify(db)); } catch (e) { /* 無視 */ }
314
+ };
315
+
316
+ const makeRequest = function () {
317
+ return { "onsuccess": null, "onerror": null, "result": undefined, "error": null };
318
+ };
319
+ const fireSuccess = function (r) {
320
+ global.queueMicrotask(function () {
321
+ if (typeof r.onsuccess === "function") { r.onsuccess({ "target": r }); }
322
+ });
323
+ };
324
+ const fireError = function (r, e) {
325
+ r.error = e;
326
+ global.queueMicrotask(function () {
327
+ if (typeof r.onerror === "function") { r.onerror({ "target": r }); }
328
+ });
329
+ };
330
+
331
+ global.indexedDB = {
332
+ open(name, version) {
333
+ const req = makeRequest();
334
+ req.onupgradeneeded = null;
335
+ req.onblocked = null;
336
+ global.queueMicrotask(function () {
337
+ const data = loadDb(name);
338
+
339
+ const storeApi = function (storeName) {
340
+ const entry = data.stores[storeName] ||
341
+ (data.stores[storeName] = { "keyPath": null, "data": {} });
342
+ const run = function (fn) {
343
+ const r = makeRequest();
344
+ global.queueMicrotask(function () {
345
+ try { r.result = fn(); fireSuccess(r); }
346
+ catch (e) { fireError(r, e); }
347
+ });
348
+ return r;
349
+ };
350
+ return {
351
+ "keyPath": entry.keyPath,
352
+ get(key) {
353
+ return run(function () {
354
+ const raw = entry.data[String(key)];
355
+ return raw === undefined ? undefined : decodeValue(raw);
356
+ });
357
+ },
358
+ put(value, key) {
359
+ return run(function () {
360
+ let k = key;
361
+ if (k === undefined && entry.keyPath && value &&
362
+ typeof value === "object") {
363
+ k = value[entry.keyPath];
364
+ }
365
+ if (k === undefined) { throw new Error("key required"); }
366
+ entry.data[String(k)] = encodeValue(value);
367
+ saveDb(name, data);
368
+ return k;
369
+ });
370
+ },
371
+ add(value, key) { return this.put(value, key); },
372
+ "delete": function (key) {
373
+ return run(function () {
374
+ delete entry.data[String(key)];
375
+ saveDb(name, data);
376
+ });
377
+ },
378
+ clear() {
379
+ return run(function () {
380
+ entry.data = {};
381
+ saveDb(name, data);
382
+ });
383
+ },
384
+ count() { return run(function () { return Object.keys(entry.data).length; }); },
385
+ getAll() {
386
+ return run(function () {
387
+ return Object.keys(entry.data).map(function (k) {
388
+ return decodeValue(entry.data[k]);
389
+ });
390
+ });
391
+ },
392
+ getAllKeys() { return run(function () { return Object.keys(entry.data); }); }
393
+ };
394
+ };
395
+
396
+ const dbObj = {
397
+ "name": name,
398
+ "objectStoreNames": {
399
+ contains(s) { return Object.prototype.hasOwnProperty.call(data.stores, s); },
400
+ get length() { return Object.keys(data.stores).length; }
401
+ },
402
+ createObjectStore(storeName, options) {
403
+ if (!data.stores[storeName]) {
404
+ data.stores[storeName] = {
405
+ "keyPath": options && options.keyPath ? options.keyPath : null,
406
+ "data": {}
407
+ };
408
+ saveDb(name, data);
409
+ }
410
+ return storeApi(storeName);
411
+ },
412
+ deleteObjectStore(storeName) {
413
+ delete data.stores[storeName];
414
+ saveDb(name, data);
415
+ },
416
+ transaction(_names, _mode) {
417
+ const tx = {
418
+ "oncomplete": null, "onerror": null, "onabort": null,
419
+ objectStore(s) { return storeApi(s); },
420
+ abort() { /* 未対応 */ },
421
+ commit() { /* 自動コミット */ }
422
+ };
423
+ // 全リクエストのマイクロタスク消化後に complete を発火
424
+ global.queueMicrotask(function () {
425
+ global.queueMicrotask(function () {
426
+ global.queueMicrotask(function () {
427
+ if (typeof tx.oncomplete === "function") {
428
+ tx.oncomplete({ "target": tx });
429
+ }
430
+ });
431
+ });
432
+ });
433
+ return tx;
434
+ },
435
+ close() { /* no-op */ },
436
+ "onversionchange": null
437
+ };
438
+
439
+ const oldVersion = data.version || 0;
440
+ const newVersion = typeof version === "number" ? version : Math.max(1, oldVersion);
441
+ req.result = dbObj;
442
+ if (newVersion > oldVersion) {
443
+ data.version = newVersion;
444
+ if (typeof req.onupgradeneeded === "function") {
445
+ req.onupgradeneeded({
446
+ "target": req,
447
+ "oldVersion": oldVersion,
448
+ "newVersion": newVersion
449
+ });
450
+ }
451
+ saveDb(name, data);
452
+ }
453
+ if (typeof req.onsuccess === "function") {
454
+ req.onsuccess({ "target": req });
455
+ }
456
+ });
457
+ return req;
458
+ },
459
+ deleteDatabase(name) {
460
+ const req = makeRequest();
461
+ global.queueMicrotask(function () {
462
+ try {
463
+ global.__next2d_storage_save("idb_" + name, "");
464
+ fireSuccess(req);
465
+ } catch (e) {
466
+ fireError(req, e);
467
+ }
468
+ });
469
+ return req;
470
+ }
471
+ };
472
+ }
473
+
474
+ if (typeof global.TextDecoder === "undefined") {
475
+ global.TextDecoder = class TextDecoder {
476
+ constructor(label) { this._label = label || "utf-8"; }
477
+ get encoding() { return "utf-8"; }
478
+ decode(input) {
479
+ if (!input) { return ""; }
480
+ const bytes = input instanceof Uint8Array
481
+ ? input
482
+ : new Uint8Array(input.buffer || input);
483
+ let out = "";
484
+ let i = 0;
485
+ while (i < bytes.length) {
486
+ const c = bytes[i++];
487
+ if (c < 0x80) {
488
+ out += String.fromCharCode(c);
489
+ } else if (c < 0xe0) {
490
+ out += String.fromCharCode(((c & 0x1f) << 6) | (bytes[i++] & 0x3f));
491
+ } else if (c < 0xf0) {
492
+ out += String.fromCharCode(
493
+ ((c & 0x0f) << 12) | ((bytes[i++] & 0x3f) << 6) | (bytes[i++] & 0x3f)
494
+ );
495
+ } else {
496
+ let code = ((c & 0x07) << 18) | ((bytes[i++] & 0x3f) << 12) |
497
+ ((bytes[i++] & 0x3f) << 6) | (bytes[i++] & 0x3f);
498
+ code -= 0x10000;
499
+ out += String.fromCharCode(0xd800 + (code >> 10), 0xdc00 + (code & 0x3ff));
500
+ }
501
+ }
502
+ return out;
503
+ }
504
+ };
505
+ }
506
+ })(globalThis);
507
+ )JS";
508
+
509
+ // section 6: DOM 要素ツリー (parentElement / children / getElementById / Event)。
510
+ // player の boot は document.body.appendChild(div) 後に div.parentElement.tagName を
511
+ // 参照し、無いと throw する (async 起動フロー内のため無報告で停止していた)。
512
+ // canvas/video はネイティブ実装 (C++) をそのまま使い、他タグを JS で本格化する。
513
+ const char kPolyfills6[] = R"JS(
514
+ (function (global) {
515
+ "use strict";
516
+ var doc = global.document;
517
+ if (!doc || doc.__domUpgraded) {
518
+ return;
519
+ }
520
+ doc.__domUpgraded = true;
521
+
522
+ if (typeof global.Event !== "function") {
523
+ var Ev = function (type, init) {
524
+ init = init || {};
525
+ this.type = String(type);
526
+ this.bubbles = !!init.bubbles;
527
+ this.cancelable = !!init.cancelable;
528
+ this.defaultPrevented = false;
529
+ this.target = null;
530
+ this.currentTarget = null;
531
+ };
532
+ Ev.prototype.preventDefault = function () {
533
+ if (this.cancelable) { this.defaultPrevented = true; }
534
+ };
535
+ Ev.prototype.stopPropagation = function () {};
536
+ Ev.prototype.stopImmediatePropagation = function () {};
537
+ global.Event = Ev;
538
+ }
539
+ if (typeof global.CustomEvent !== "function") {
540
+ global.CustomEvent = function (type, init) {
541
+ var e = new global.Event(type, init);
542
+ e.detail = init && init.detail !== undefined ? init.detail : null;
543
+ return e;
544
+ };
545
+ }
546
+
547
+ function styleSize(el, key) {
548
+ var v = el.style && el.style[key];
549
+ var n = parseFloat(v);
550
+ if (isFinite(n) && n > 0) { return n; }
551
+ var attrs = el.__attrs;
552
+ if (attrs && typeof attrs.style === "string") {
553
+ var m = attrs.style.match(
554
+ new RegExp("(?:^|;)\\s*" + key + "\\s*:\\s*([0-9.]+)px")
555
+ );
556
+ if (m) { return parseFloat(m[1]); }
557
+ }
558
+ if (el.tagName === "BODY" || el.tagName === "HTML") {
559
+ return key === "width" ? global.innerWidth : global.innerHeight;
560
+ }
561
+ return 0;
562
+ }
563
+
564
+ // el を DOM 要素相当へ拡張する。addEventListener はネイティブ実装
565
+ // (__listeners: ホストの入力配送先) が既にある場合は温存する。
566
+ function upgrade(el, tag) {
567
+ tag = String(tag || "div").toLowerCase();
568
+ el.tagName = tag.toUpperCase();
569
+ el.localName = tag;
570
+ if (el.id === undefined) { el.id = ""; }
571
+ if (!el.style) { el.style = {}; }
572
+ if (!el.__attrs) { el.__attrs = {}; }
573
+ el.children = [];
574
+ el.childNodes = el.children;
575
+ el.parentElement = null;
576
+ el.parentNode = null;
577
+ el.dataset = {};
578
+
579
+ Object.defineProperty(el, "firstChild", {
580
+ get: function () { return this.children.length ? this.children[0] : null; },
581
+ configurable: true
582
+ });
583
+ Object.defineProperty(el, "lastChild", {
584
+ get: function () {
585
+ var c = this.children;
586
+ return c.length ? c[c.length - 1] : null;
587
+ },
588
+ configurable: true
589
+ });
590
+ Object.defineProperty(el, "clientWidth", {
591
+ get: function () { return styleSize(this, "width"); },
592
+ configurable: true
593
+ });
594
+ Object.defineProperty(el, "clientHeight", {
595
+ get: function () { return styleSize(this, "height"); },
596
+ configurable: true
597
+ });
598
+
599
+ var html = "";
600
+ Object.defineProperty(el, "innerHTML", {
601
+ get: function () { return html; },
602
+ set: function (v) { html = String(v); this.children.length = 0; },
603
+ configurable: true
604
+ });
605
+
606
+ el.appendChild = function (child) {
607
+ if (child.parentElement && child.parentElement.children) {
608
+ var cs = child.parentElement.children;
609
+ var i = cs.indexOf(child);
610
+ if (i >= 0) { cs.splice(i, 1); }
611
+ }
612
+ this.children.push(child);
613
+ child.parentElement = this;
614
+ child.parentNode = this;
615
+ return child;
616
+ };
617
+ el.removeChild = function (child) {
618
+ var i = this.children.indexOf(child);
619
+ if (i >= 0) { this.children.splice(i, 1); }
620
+ child.parentElement = null;
621
+ child.parentNode = null;
622
+ return child;
623
+ };
624
+ el.insertBefore = function (child, ref) {
625
+ var i = ref ? this.children.indexOf(ref) : -1;
626
+ if (i < 0) { return this.appendChild(child); }
627
+ this.children.splice(i, 0, child);
628
+ child.parentElement = this;
629
+ child.parentNode = this;
630
+ return child;
631
+ };
632
+ el.contains = function (node) {
633
+ if (node === this) { return true; }
634
+ for (var i = 0; i < this.children.length; i++) {
635
+ var c = this.children[i];
636
+ if (c === node || (c.contains && c.contains(node))) { return true; }
637
+ }
638
+ return false;
639
+ };
640
+ el.remove = function () {
641
+ if (this.parentElement) { this.parentElement.removeChild(this); }
642
+ };
643
+ el.setAttribute = function (name, value) {
644
+ this.__attrs[name] = String(value);
645
+ if (name === "id") { this.id = String(value); }
646
+ };
647
+ el.getAttribute = function (name) {
648
+ return this.__attrs[name] !== undefined ? this.__attrs[name] : null;
649
+ };
650
+ el.removeAttribute = function (name) { delete this.__attrs[name]; };
651
+ el.getBoundingClientRect = function () {
652
+ var w = this.clientWidth;
653
+ var h = this.clientHeight;
654
+ return { x: 0, y: 0, top: 0, left: 0, right: w, bottom: h, width: w, height: h };
655
+ };
656
+ el.focus = function () {};
657
+ el.blur = function () {};
658
+
659
+ if (typeof el.addEventListener !== "function") {
660
+ var listeners = {};
661
+ el.addEventListener = function (type, fn) {
662
+ (listeners[type] || (listeners[type] = [])).push(fn);
663
+ };
664
+ el.removeEventListener = function (type, fn) {
665
+ var a = listeners[type];
666
+ if (!a) { return; }
667
+ var i = a.indexOf(fn);
668
+ if (i >= 0) { a.splice(i, 1); }
669
+ };
670
+ el.dispatchEvent = function (ev) {
671
+ ev.target = ev.target || this;
672
+ ev.currentTarget = this;
673
+ var a = listeners[ev.type];
674
+ if (a) {
675
+ for (var i = 0; i < a.length; i++) {
676
+ try { a[i].call(this, ev); } catch (e) {
677
+ if (global.console) { global.console.error(e); }
678
+ }
679
+ }
680
+ }
681
+ var on = this["on" + ev.type];
682
+ if (typeof on === "function") {
683
+ try { on.call(this, ev); } catch (e2) {
684
+ if (global.console) { global.console.error(e2); }
685
+ }
686
+ }
687
+ return !ev.defaultPrevented;
688
+ };
689
+ }
690
+ return el;
691
+ }
692
+
693
+ var nativeCreate = doc.createElement.bind(doc);
694
+ doc.createElement = function (tag) {
695
+ var t = String(tag).toLowerCase();
696
+ if (t === "canvas" || t === "video") {
697
+ var n = nativeCreate(t);
698
+ if (!n.localName) {
699
+ n.localName = t;
700
+ n.tagName = t.toUpperCase();
701
+ }
702
+ if (n.parentElement === undefined) {
703
+ n.parentElement = null;
704
+ n.parentNode = null;
705
+ }
706
+ return n;
707
+ }
708
+ return upgrade({}, t);
709
+ };
710
+
711
+ // body / documentElement (同一オブジェクト)。ネイティブの addEventListener
712
+ // は upgrade 内で温存される。
713
+ var body = doc.body;
714
+ if (body) {
715
+ upgrade(body, "body");
716
+ Object.defineProperty(body, "clientWidth", {
717
+ get: function () { return global.innerWidth; },
718
+ configurable: true
719
+ });
720
+ Object.defineProperty(body, "clientHeight", {
721
+ get: function () { return global.innerHeight; },
722
+ configurable: true
723
+ });
724
+ }
725
+
726
+ doc.getElementById = function (id) {
727
+ id = String(id);
728
+ var find = function (el) {
729
+ if (el.id === id) { return el; }
730
+ var cs = el.children || [];
731
+ for (var i = 0; i < cs.length; i++) {
732
+ var r = find(cs[i]);
733
+ if (r) { return r; }
734
+ }
735
+ return null;
736
+ };
737
+ return body ? find(body) : null;
738
+ };
739
+
740
+ // window.addEventListener("resize", ...) 用 (main コンテキストの global)
741
+ if (typeof global.addEventListener !== "function") {
742
+ var winListeners = {};
743
+ global.addEventListener = function (type, fn) {
744
+ (winListeners[type] || (winListeners[type] = [])).push(fn);
745
+ };
746
+ global.removeEventListener = function (type, fn) {
747
+ var a = winListeners[type];
748
+ if (!a) { return; }
749
+ var i = a.indexOf(fn);
750
+ if (i >= 0) { a.splice(i, 1); }
751
+ };
752
+ global.dispatchEvent = function (ev) {
753
+ var a = winListeners[ev.type];
754
+ if (a) {
755
+ for (var i = 0; i < a.length; i++) {
756
+ try { a[i].call(global, ev); } catch (e) {
757
+ if (global.console) { global.console.error(e); }
758
+ }
759
+ }
760
+ }
761
+ return true;
762
+ };
763
+ }
764
+ })(globalThis);
765
+ )JS";
766
+
767
+ const char* const kPolyfillSections[] = {
768
+ kPolyfills1,
769
+ kPolyfills2,
770
+ kPolyfills3,
771
+ kPolyfills4,
772
+ kPolyfills5,
773
+ kPolyfills6,
774
+ };
775
+
776
+ } // namespace
777
+
778
+ void InstallPolyfills(v8::Isolate* isolate, v8::Local<v8::Context> context)
779
+ {
780
+ v8::Context::Scope cs(context);
781
+ for (const char* source : kPolyfillSections) {
782
+ v8::TryCatch tc(isolate);
783
+ v8::Local<v8::String> src = v8util::Str(isolate, source);
784
+ v8::Local<v8::Script> script;
785
+ if (v8::Script::Compile(context, src).ToLocal(&script)) {
786
+ (void) script->Run(context);
787
+ }
788
+ }
789
+ }
790
+
791
+ } // namespace next2d