@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
@@ -51,7 +51,7 @@ C++ 実行ファイルをビルドします。Electron や WebView は使用し
51
51
  ### ランタイム環境の要点
52
52
 
53
53
  - **jitless V8**: Xbox/Switch のリテールは JIT(動的コード生成)を禁止するため、V8 は
54
- `--jitless`(Ignition インタプリタのみ)で起動する。WebAssembly も無効。
54
+ `--jitless --wasm-jitless` で起動する (JS=Ignition インタプリタ、wasm=DrumBrake インタープリタ)。
55
55
  - **Worker / OffscreenCanvas**: player はレンダラを Worker + `transferControlToOffscreen`
56
56
  で動かす。本ホストは **「同一 Isolate 内の別 Context を協調スケジューリングする単一スレッド
57
57
  Worker モデル」** を採用(`src/worker/WorkerRuntime`)。`postMessage` は V8 の
@@ -73,7 +73,7 @@ C++ 実行ファイルをビルドします。Electron や WebView は使用し
73
73
  |------|------|
74
74
  | OS | Windows 11 |
75
75
  | IDE | Visual Studio 2022 (v143, C++ Game development workload) |
76
- | GDK | Microsoft GDK (June 2024 以降) — ID@Xbox 登録が必要 |
76
+ | GDK | 公開版 GDK をインストール (`-A Gaming.Desktop.x64`)、**または** NuGet `Microsoft.GDK.Windows` を展開して `-A x64` + 環境変数/`-D` `GDK_ROOT=<pkg>/native/<edition>/windows`(インストーラ不要・CI 向け)。コンソール向け GDKX は ID@Xbox 登録が必要 |
77
77
  | CMake | 3.26 以降 |
78
78
  | V8 | 不要 (builder が prebuilt を自動ダウンロード)。自前ビルドは `--v8-root` で指定可 |
79
79
  | Dawn | CMake の FetchContent で自動取得(ネットワーク必須) |
@@ -120,9 +120,9 @@ set DEPOT_TOOLS_WIN_TOOLCHAIN=0
120
120
  fetch v8
121
121
  cd v8
122
122
  :: CI のコンパイル検証と同じバージョンに固定 (xbox-host-ci.yml の V8_TAG)
123
- git checkout 13.6.233.17
123
+ git checkout 13.7.152.19
124
124
  gclient sync
125
- gn gen out\x64.release --args="v8_monolithic=true v8_use_external_startup_data=false is_component_build=false use_custom_libcxx=false icu_use_data_file=false treat_warnings_as_errors=false v8_jitless=true v8_enable_turbofan=false v8_enable_webassembly=false target_cpu=\"x64\" is_debug=false v8_enable_pointer_compression=true v8_enable_sandbox=false"
125
+ gn gen out\x64.release --args="v8_monolithic=true v8_use_external_startup_data=false is_component_build=false use_custom_libcxx=false icu_use_data_file=false treat_warnings_as_errors=false v8_enable_drumbrake=true target_cpu=\"x64\" is_debug=false v8_enable_pointer_compression=true v8_enable_sandbox=false"
126
126
  ninja -C out\x64.release v8_monolith
127
127
  ```
128
128
 
@@ -142,9 +142,12 @@ ninja -C out\x64.release v8_monolith
142
142
  > - `treat_warnings_as_errors=false` を推奨。`use_custom_libcxx=false` では MSVC STL の
143
143
  > ヘッダ警告が -Werror で停止することがあります。**VS のバージョンは VS2022 (v143) を推奨**
144
144
  > (新しすぎる STL は V8 の clang が警告/エラーを出しやすい)。
145
- > - `v8_jitless=true` + `v8_enable_turbofan=false` + `v8_enable_webassembly=false` を推奨。
146
- > ホストは実行時 `--jitless` で動かすため (Xbox は JIT 禁止)、JIT/wasm をビルドから
147
- > 外すのが正しい構成です (BUILD.gn の assert もこの組み合わせを要求)。ビルドも大幅に速くなります。
145
+ > - `v8_enable_drumbrake=true` は必須 (r2)。**DrumBrake = V8 の wasm インタープリタ**で、
146
+ > JIT 禁止環境 (コンソール) でも wasm を解釈実行できます。wasm はビルド時に turbofan を
147
+ > 要求するため `v8_jitless` ビルドは使えません — JIT の無効化はホストが実行時フラグ
148
+ > `--jitless --wasm-jitless` で行います (JS=Ignition / wasm=DrumBrake)。
149
+ > 注意: DrumBrake は既定ビルド対象外のためタグによりコンパイル不能な場合があります
150
+ > (13.6.233.17 は不可 → 13.7.152.19 で修正済み)。
148
151
  > - pointer compression は `CMakeLists.txt` の `V8_COMPRESS_POINTERS` と一致させてください
149
152
  > (sandbox 無効に合わせ `V8_ENABLE_SANDBOX` は定義しません)。不一致は ABI 崩れの原因になります。
150
153
  > - 上記は PC (`Gaming.Desktop.x64`) 用。コンソール実機 (`Gaming.Xbox.*`) 向けは
@@ -210,7 +213,7 @@ macOS / Linux でそのまま実行できます:
210
213
  tests/check_local.sh
211
214
  ```
212
215
 
213
- 構文チェックは実 V8 ヘッダ (pin: `13.6.233.17`) に対して、Windows API 非依存の
216
+ 構文チェックは実 V8 ヘッダ (pin: `13.7.152.19`) に対して、Windows API 非依存の
214
217
  V8 バインディング 12 ファイルをコンパイル検証します (API 削除・型不整合を検出)。
215
218
 
216
219
  ### 2. GitHub Actions (windows-latest) — `.github/workflows/xbox-host-ci.yml`
@@ -302,6 +305,11 @@ player の実 API 使用を全面調査し、以下を実装済み。**この環
302
305
  | ポインタ/キーボード/ホイール入力 | ⚠️ 実装(要検証) | `WndProc`→`DispatchEvent`。配送先canvasの特定は実機検証 |
303
306
  | 動画 (HTMLVideoElement) | ⚠️ 実装(要検証) | `Video.cpp`(Media Foundation)。フレーム精度/音声同期は実機検証 |
304
307
  | クリップボード (`navigator.clipboard`) | ✅ 実装 | Win32 クリップボード (readText/writeText) |
308
+ | **JS エンジン/グローバル機能** (player 全数調査) | ✅ 実装 | Proxy=V8コア。`crypto.randomUUID`/`getRandomValues`(BCrypt)、`TextEncoder`/`TextDecoder`/`queueMicrotask`/`location`/`atob`/`btoa` は worker 含む全コンテキストへ注入。`createImageBitmap` は ImageData/ImageBitmap/canvas/Blob を受理 |
309
+ | **WebAssembly** | ✅ 実装 (要 V8 r2) | prebuilt V8 r2 = wasm + **DrumBrake**(V8 の wasm インタープリタ、JIT 禁止コンソール向け)。実行時 `--jitless --wasm-jitless` で JS=Ignition / wasm=DrumBrake 解釈実行 |
310
+ | **indexedDB** (最小実装) | ✅ 実装 | open/createObjectStore/transaction/get/put/delete/clear/getAll/count/keyPath。値は JSON 化可能なもの + ArrayBuffer/TypedArray(base64 永続化)。カーソル/インデックスは未対応。保存先 `%LOCALAPPDATA%\Next2D\idb_<db>.json` |
311
+ | **localStorage / sessionStorage** | ✅ 実装 | JS セマンティクス + ファイル永続化 (`%LOCALAPPDATA%\Next2D\`)。コンソール実機では XGameSave 化が必要 («EXTEND») |
312
+ | **Audio 要素** (`new Audio(url)`) | ✅ 実装 | play/pause/paused/loop/volume/currentTime/preload (pause→play は先頭から) |
305
313
 
306
314
  > player が使用する API はコード上すべて実装済み。残る唯一の障壁は
307
315
  > **GDK/devkit を要するコンパイル・実機検証**(この環境では物理的に不可)。
@@ -370,3 +378,21 @@ xbox/
370
378
  ├─ Gamepad.cpp DomShims.cpp
371
379
  └─ webgpu/{WebGPU.cpp,WebGPUCommon.h,WebGPUEnums.h}
372
380
  ```
381
+
382
+ ---
383
+
384
+ ## コンソール (Game Core OS) とテキスト描画・フォント
385
+
386
+ コンソールには DirectWrite / システムフォントが存在しないため、`fillText`/`measureText`
387
+ は同梱の stb_truetype 実装 (`platform/StbTextRasterizer`) が担う。フォントは実行時登録:
388
+
389
+ - **ゲーム資材に TTF/OTF を含める**(推奨): Web ビルドの資材 (`assets/app`) に
390
+ `*.ttf` / `*.otf` があれば起動時に自動登録される (vite の `public/` に置く等)。
391
+ 日本語テキストを使う場合は Noto Sans JP (OFL) などの同梱を推奨。
392
+ - 開発ビルド: exe 隣接の `fonts/` ディレクトリからも読み込む。
393
+ - フォント未登録の場合、テキストは近似メトリクスのみ (グリフ描画なし) になる。
394
+
395
+ デスクトップ (PC/GDK) は従来どおり DirectWrite が主経路のため、フォント同梱は不要。
396
+ 同様に、画像は stb_image、音声は dr_mp3/dr_wav/stb_vorbis が全プラットフォーム共通の
397
+ 第一経路で、WIC / Media Foundation はデスクトップ限定のフォールバック
398
+ (AAC/TIFF 等の非標準形式向け)。コンソールでの動画 (`<video>`) は未対応。
@@ -3,13 +3,18 @@
3
3
  # D3D12 バックエンドのみを有効化し、Xbox(GDK)/PC(GDK) で利用する。
4
4
  #
5
5
  # 注意:
6
- # - Dawn のビルドには depot_tools 由来の一部が不要になる CMake パスを使用する。
6
+ # - submodule はクローンしない (GIT_SUBMODULES "")。SwiftShader→LLVM まで再帰して
7
+ # 数 GB のクローン + Windows の MAX_PATH 超過 ("Filename too long") で失敗するため。
8
+ # 依存は Dawn 公式の DAWN_FETCH_DEPENDENCIES (python スクリプト) が必要分だけ取得する。
9
+ # - DAWN_FETCH_DEPENDENCIES には python3 が PATH に必要。
7
10
  # - 初回構成はネットワークとビルド時間を要する。CI ではキャッシュ推奨。
8
- # - DAWN_TAG は動作確認済みタグに固定すること (chromium ブランチに追従)。
11
+ # - DAWN_TAG はバインディング (bindings/webgpu/*) が使う API 世代と一致させること:
12
+ # wgpu::Limits / ShaderSourceWGSL / SurfaceSourceWindowsHWND / OptionalBool
13
+ # (いずれも 2025 以降の命名。古いタグでは SupportedLimits 等になりビルド不可)
9
14
  # =============================================================================
10
15
  include(FetchContent)
11
16
 
12
- set(DAWN_TAG "chromium/6478" CACHE STRING "Dawn のチェックアウトタグ")
17
+ set(DAWN_TAG "v20260402.171122" CACHE STRING "Dawn のチェックアウトタグ (github.com/google/dawn)")
13
18
 
14
19
  # Dawn のビルドオプション: 必要なものだけを有効化
15
20
  set(DAWN_FETCH_DEPENDENCIES ON CACHE BOOL "" FORCE)
@@ -24,14 +29,24 @@ set(DAWN_BUILD_SAMPLES OFF CACHE BOOL "" FORCE)
24
29
  set(TINT_BUILD_TESTS OFF CACHE BOOL "" FORCE)
25
30
  set(TINT_BUILD_CMD_TOOLS OFF CACHE BOOL "" FORCE)
26
31
 
27
- # webgpu_dawn: webgpu.h C-API を提供する統合ライブラリ (バインディング層はこれを叩く)
28
- set(DAWN_BUILD_MONOLITHIC_LIBRARY ON CACHE BOOL "" FORCE)
32
+ # webgpu_dawn: webgpu.h C-API を提供する統合ライブラリ (バインディング層はこれを叩く)。
33
+ # 2025 以降の Dawn では SHARED / STATIC / OFF の3値。
34
+ # SHARED (DLL) を選ぶ理由: V8 monolith と Dawn は双方が abseil を静的に内蔵しており、
35
+ # STATIC だと raw_hash_set 等の同名シンボルが LNK2005 で衝突する (しかも absl の
36
+ # バージョンが異なるため /FORCE:MULTIPLE は実行時破壊のリスクがある)。
37
+ # DLL にすれば公開されるのは WebGPU C API のみで、absl は DLL 内部に閉じる。
38
+ set(DAWN_BUILD_MONOLITHIC_LIBRARY SHARED CACHE STRING "" FORCE)
39
+ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
29
40
 
30
41
  FetchContent_Declare(
31
42
  dawn
32
- GIT_REPOSITORY https://dawn.googlesource.com/dawn
43
+ # GitHub ミラーの方が CI から高速・安定 (googlesource はレート制限がきつい)
44
+ GIT_REPOSITORY https://github.com/google/dawn.git
33
45
  GIT_TAG ${DAWN_TAG}
34
46
  GIT_SHALLOW TRUE
47
+ # submodule は取得しない (DAWN_FETCH_DEPENDENCIES が必要分を取得する)
48
+ GIT_SUBMODULES ""
49
+ GIT_SUBMODULES_RECURSE FALSE
35
50
  )
36
51
 
37
52
  FetchContent_MakeAvailable(dawn)
@@ -40,3 +55,29 @@ FetchContent_MakeAvailable(dawn)
40
55
  if(NOT TARGET dawn::webgpu_dawn AND TARGET webgpu_dawn)
41
56
  add_library(dawn::webgpu_dawn ALIAS webgpu_dawn)
42
57
  endif()
58
+
59
+ # -----------------------------------------------------------------------------
60
+ # CRT を静的 (/MT) へ強制統一する。
61
+ # CMAKE_MSVC_RUNTIME_LIBRARY 変数だけでは Dawn の third_party (fetch_dawn_dependencies
62
+ # が取得する abseil/protobuf 等) の一部に伝播せず /MD が混ざり、静的 CRT 固定の
63
+ # prebuilt V8 とのリンクで LNK2005/LNK2019 になる。全ターゲットへ再帰的に
64
+ # プロパティを直接設定して確実に揃える。
65
+ # -----------------------------------------------------------------------------
66
+ function(next2d_force_static_crt dir)
67
+ get_property(_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
68
+ foreach(_t IN LISTS _targets)
69
+ get_target_property(_type ${_t} TYPE)
70
+ if(NOT _type STREQUAL "INTERFACE_LIBRARY")
71
+ set_property(TARGET ${_t} PROPERTY
72
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
73
+ endif()
74
+ endforeach()
75
+ get_property(_subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)
76
+ foreach(_sd IN LISTS _subdirs)
77
+ next2d_force_static_crt("${_sd}")
78
+ endforeach()
79
+ endfunction()
80
+
81
+ if(MSVC)
82
+ next2d_force_static_crt("${dawn_SOURCE_DIR}")
83
+ endif()
@@ -40,6 +40,21 @@ if(NOT V8_ROOT OR NOT EXISTS "${V8_ROOT}")
40
40
  "詳細は README.md の『V8 の用意』を参照。")
41
41
  endif()
42
42
 
43
+ # find_path/find_library の結果は CMakeCache に永続化されるため、
44
+ # V8_ROOT の変更 (バージョン更新等) や参照先の消滅に追随しない。
45
+ # 古い/無効な検出結果はここで破棄して再探索させる。
46
+ if(DEFINED CACHE{NEXT2D_V8_ROOT_LAST} AND NOT "$CACHE{NEXT2D_V8_ROOT_LAST}" STREQUAL "${V8_ROOT}")
47
+ unset(V8_INCLUDE_DIR CACHE)
48
+ unset(V8_MONOLITH_LIB CACHE)
49
+ endif()
50
+ if(V8_INCLUDE_DIR AND NOT EXISTS "${V8_INCLUDE_DIR}/v8.h")
51
+ unset(V8_INCLUDE_DIR CACHE)
52
+ endif()
53
+ if(V8_MONOLITH_LIB AND NOT EXISTS "${V8_MONOLITH_LIB}")
54
+ unset(V8_MONOLITH_LIB CACHE)
55
+ endif()
56
+ set(NEXT2D_V8_ROOT_LAST "${V8_ROOT}" CACHE INTERNAL "直近の構成で使った V8_ROOT")
57
+
43
58
  find_path(V8_INCLUDE_DIR
44
59
  NAMES v8.h
45
60
  PATHS "${V8_ROOT}/include"
@@ -25,7 +25,7 @@
25
25
  // V8 単体には Web の Text* が含まれないため最小実装を提供する。
26
26
  if (typeof global.TextEncoder === "undefined") {
27
27
  global.TextEncoder = class TextEncoder {
28
- get encoding() { return "utf-8"; }
28
+ get encoding() { return "utf-8" }
29
29
  encode(str) {
30
30
  str = String(str);
31
31
  const out = [];
@@ -34,23 +34,23 @@
34
34
  if (code < 0x80) {
35
35
  out.push(code);
36
36
  } else if (code < 0x800) {
37
- out.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
37
+ out.push(0xc0 | code >> 6, 0x80 | code & 0x3f);
38
38
  } else if (code >= 0xd800 && code <= 0xdbff) {
39
39
  // サロゲートペア
40
40
  const hi = code;
41
41
  const lo = str.charCodeAt(++i);
42
- code = 0x10000 + ((hi - 0xd800) << 10) + (lo - 0xdc00);
42
+ code = 0x10000 + (hi - 0xd800 << 10) + (lo - 0xdc00);
43
43
  out.push(
44
- 0xf0 | (code >> 18),
45
- 0x80 | ((code >> 12) & 0x3f),
46
- 0x80 | ((code >> 6) & 0x3f),
47
- 0x80 | (code & 0x3f)
44
+ 0xf0 | code >> 18,
45
+ 0x80 | code >> 12 & 0x3f,
46
+ 0x80 | code >> 6 & 0x3f,
47
+ 0x80 | code & 0x3f
48
48
  );
49
49
  } else {
50
50
  out.push(
51
- 0xe0 | (code >> 12),
52
- 0x80 | ((code >> 6) & 0x3f),
53
- 0x80 | (code & 0x3f)
51
+ 0xe0 | code >> 12,
52
+ 0x80 | code >> 6 & 0x3f,
53
+ 0x80 | code & 0x3f
54
54
  );
55
55
  }
56
56
  }
@@ -61,10 +61,10 @@
61
61
 
62
62
  if (typeof global.TextDecoder === "undefined") {
63
63
  global.TextDecoder = class TextDecoder {
64
- constructor(label) { this._label = label || "utf-8"; }
65
- get encoding() { return "utf-8"; }
64
+ constructor(label) { this._label = label || "utf-8" }
65
+ get encoding() { return "utf-8" }
66
66
  decode(input) {
67
- if (!input) return "";
67
+ if (!input) { return "" }
68
68
  const bytes = input instanceof Uint8Array
69
69
  ? input
70
70
  : new Uint8Array(input.buffer || input);
@@ -75,14 +75,14 @@
75
75
  if (c < 0x80) {
76
76
  out += String.fromCharCode(c);
77
77
  } else if (c < 0xe0) {
78
- out += String.fromCharCode(((c & 0x1f) << 6) | (bytes[i++] & 0x3f));
78
+ out += String.fromCharCode((c & 0x1f) << 6 | bytes[i++] & 0x3f);
79
79
  } else if (c < 0xf0) {
80
80
  out += String.fromCharCode(
81
- ((c & 0x0f) << 12) | ((bytes[i++] & 0x3f) << 6) | (bytes[i++] & 0x3f)
81
+ (c & 0x0f) << 12 | (bytes[i++] & 0x3f) << 6 | bytes[i++] & 0x3f
82
82
  );
83
83
  } else {
84
- let code = ((c & 0x07) << 18) | ((bytes[i++] & 0x3f) << 12) |
85
- ((bytes[i++] & 0x3f) << 6) | (bytes[i++] & 0x3f);
84
+ let code = (c & 0x07) << 18 | (bytes[i++] & 0x3f) << 12 |
85
+ (bytes[i++] & 0x3f) << 6 | bytes[i++] & 0x3f;
86
86
  code -= 0x10000;
87
87
  out += String.fromCharCode(0xd800 + (code >> 10), 0xdc00 + (code & 0x3ff));
88
88
  }
@@ -97,28 +97,151 @@
97
97
  if (typeof global.URL === "undefined") {
98
98
  global.URL = class URL {
99
99
  constructor(url, base) {
100
- this.href = base ? (String(base).replace(/\/?$/, "/") + url) : String(url);
100
+ this.href = base ? String(base).replace(/\/?$/, "/") + url : String(url);
101
101
  this.pathname = this.href.replace(/^[a-z]+:\/\/[^/]*/i, "");
102
102
  this.search = "";
103
103
  this.hash = "";
104
104
  }
105
- toString() { return this.href; }
105
+ toString() { return this.href }
106
106
  };
107
- global.URL.createObjectURL = function () { return ""; };
107
+ global.URL.createObjectURL = function () { return "" };
108
+ // 意図的な no-op スタブ (ローカル実行では解放処理は不要)
109
+ // eslint-disable-next-line no-empty-function
108
110
  global.URL.revokeObjectURL = function () {};
109
111
  }
110
112
 
113
+ // --- URLSearchParams の最小補完 ----------------------------------------
114
+ // V8 単体には URLSearchParams が存在しないため補完する。
115
+ // Next2D アプリがクエリ文字列 (?mode=0 等) を解析する際に使用する。
116
+ if (typeof global.URLSearchParams === "undefined") {
117
+ global.URLSearchParams = class URLSearchParams {
118
+ constructor(init) {
119
+ this._list = [];
120
+ if (typeof init === "string") {
121
+ let query = init;
122
+ if (query.charAt(0) === "?") {
123
+ query = query.slice(1);
124
+ }
125
+ if (query.length) {
126
+ const pairs = query.split("&");
127
+ for (let i = 0; i < pairs.length; i++) {
128
+ const pair = pairs[i];
129
+ if (!pair) {
130
+ continue;
131
+ }
132
+ const index = pair.indexOf("=");
133
+ const decode = (value) => {
134
+ try {
135
+ return decodeURIComponent(value.replace(/\+/g, " "));
136
+ } catch {
137
+ return value;
138
+ }
139
+ };
140
+ if (index === -1) {
141
+ this._list.push([decode(pair), ""]);
142
+ } else {
143
+ this._list.push([decode(pair.slice(0, index)), decode(pair.slice(index + 1))]);
144
+ }
145
+ }
146
+ }
147
+ } else if (init && typeof init === "object") {
148
+ if (Array.isArray(init)) {
149
+ for (let i = 0; i < init.length; i++) {
150
+ this._list.push([String(init[i][0]), String(init[i][1])]);
151
+ }
152
+ } else if (typeof init.forEach === "function") {
153
+ init.forEach((value, key) => this._list.push([String(key), String(value)]));
154
+ } else {
155
+ for (const key in init) {
156
+ if (Object.prototype.hasOwnProperty.call(init, key)) {
157
+ this._list.push([key, String(init[key])]);
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ get(name) {
164
+ for (let i = 0; i < this._list.length; i++) {
165
+ if (this._list[i][0] === name) {
166
+ return this._list[i][1];
167
+ }
168
+ }
169
+ return null;
170
+ }
171
+ getAll(name) {
172
+ const result = [];
173
+ for (let i = 0; i < this._list.length; i++) {
174
+ if (this._list[i][0] === name) {
175
+ result.push(this._list[i][1]);
176
+ }
177
+ }
178
+ return result;
179
+ }
180
+ has(name) {
181
+ return this.get(name) !== null;
182
+ }
183
+ set(name, value) {
184
+ const text = String(value);
185
+ let done = false;
186
+ const next = [];
187
+ for (let i = 0; i < this._list.length; i++) {
188
+ if (this._list[i][0] === name) {
189
+ if (!done) {
190
+ next.push([name, text]);
191
+ done = true;
192
+ }
193
+ } else {
194
+ next.push(this._list[i]);
195
+ }
196
+ }
197
+ if (!done) {
198
+ next.push([name, text]);
199
+ }
200
+ this._list = next;
201
+ }
202
+ append(name, value) {
203
+ this._list.push([String(name), String(value)]);
204
+ }
205
+ delete(name) {
206
+ this._list = this._list.filter((pair) => pair[0] !== name);
207
+ }
208
+ forEach(callback, thisArg) {
209
+ for (let i = 0; i < this._list.length; i++) {
210
+ callback.call(thisArg, this._list[i][1], this._list[i][0], this);
211
+ }
212
+ }
213
+ keys() {
214
+ return this._list.map((pair) => pair[0])[Symbol.iterator]();
215
+ }
216
+ values() {
217
+ return this._list.map((pair) => pair[1])[Symbol.iterator]();
218
+ }
219
+ entries() {
220
+ return this._list.map((pair) => [pair[0], pair[1]])[Symbol.iterator]();
221
+ }
222
+ toString() {
223
+ return this._list
224
+ .map((pair) => encodeURIComponent(pair[0]) + "=" + encodeURIComponent(pair[1]))
225
+ .join("&");
226
+ }
227
+ [Symbol.iterator]() {
228
+ return this.entries();
229
+ }
230
+ };
231
+ }
232
+
111
233
  // --- location (Next2D が参照する場合の最小値) ---------------------------
112
234
  if (typeof global.location === "undefined") {
113
235
  global.location = {
114
- href: "app://local/",
115
- origin: "app://local",
116
- protocol: "app:",
117
- host: "local",
118
- hostname: "local",
119
- pathname: "/",
120
- search: "",
121
- hash: "",
236
+ "href": "app://local/",
237
+ "origin": "app://local",
238
+ "protocol": "app:",
239
+ "host": "local",
240
+ "hostname": "local",
241
+ "pathname": "/",
242
+ "search": "",
243
+ "hash": "",
244
+ // eslint-disable-next-line no-empty-function
122
245
  reload() {}
123
246
  };
124
247
  }