Add DOM globals polyfill + native AbortController for Playground#1708
Add DOM globals polyfill + native AbortController for Playground#1708bkaradzic-microsoft wants to merge 4 commits into
Conversation
…nt.createEvent) Playground tests that use modern browser APIs hit ReferenceErrors on the Chakra-based BN runtime because TextEncoder and PointerEvent are not part of older Chakra's built-ins. Several serializer tests also exercise document.createEvent + element.dispatchEvent shapes that the existing minimal document polyfill in validation_native.js did not cover. - Apps/Playground/Scripts/dom_polyfill.js: new self-detecting JS polyfills for TextEncoder (UTF-8 encode + encodeInto) and PointerEvent (constructor with the MouseEvent + PointerEvent surface). - Apps/Playground/Shared/AppContext.cpp + CMakeLists.txt: wire in the native AbortController polyfill from JsRuntimeHost and load dom_polyfill.js before ammo.js. - Apps/Playground/Scripts/validation_native.js: extend the existing document shim with createEvent, dispatchEvent, addEventListener and a generic-element fallback for createElement so click-event-based serializer tests can run. - Apps/Playground/Scripts/config.json: re-enable "Serialize scene without materials" (idx 342), which now validates with 248 px diff. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AppContext.cpp includes <Babylon/Polyfills/AbortController.h> and calls Babylon::Polyfills::AbortController::Initialize(env), but the Android- specific CMakeLists at Apps/Playground/Android/BabylonNative did not add AbortController to BabylonNativeJNI's PRIVATE link libraries. The header is published only by the AbortController target, so Android CI failed with 'fatal error: Babylon/Polyfills/AbortController.h file not found'. Linux/macOS/Windows builds were fine because they use the main Apps/Playground/CMakeLists.txt which already links AbortController. Mirror the change there so Android picks up the include directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds missing DOM-like globals to the Playground JS host and wires up native AbortController so DOM-dependent playgrounds/tests stop throwing ReferenceError.
Changes:
- Adds a self-detecting
TextEncoder+PointerEventpolyfill script and loads it in the Playground startup sequence. - Initializes and links the native
AbortControllerpolyfill in Playground (including Android JNI link fix). - Extends the validation runner’s
documentshim withcreateEvent/dispatchEventand re-enables one previously excluded test.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Apps/Playground/Shared/AppContext.cpp | Initializes native AbortController and loads dom_polyfill.js during startup. |
| Apps/Playground/Scripts/validation_native.js | Expands the document/element shims to support event creation/dispatch used by tests. |
| Apps/Playground/Scripts/dom_polyfill.js | New polyfills for TextEncoder and PointerEvent when absent. |
| Apps/Playground/Scripts/config.json | Re-enables one previously excluded serialization test. |
| Apps/Playground/CMakeLists.txt | Packages dom_polyfill.js and links AbortController into Playground. |
| Apps/Playground/Android/BabylonNative/CMakeLists.txt | Links AbortController into BabylonNativeJNI to fix Android builds. |
- Replace `new Function('return this')` with a non-eval globalThis/self/
window/global resolution chain; keep the Function-constructor trick
only as a last-resort fallback for runtimes that ship none of the
standard globals.
- TextEncoder.prototype.encodeInto: normalize `input` (undefined ->
empty string) before computing `read`, so the returned read count
stays consistent with the bytes written by `encode()` (previously
`String(undefined).length` returned 9 for a zero-byte write).
- PointerEvent.cancelable: default to `false` (DOM spec EventInit
default) instead of `true`; callers that need a cancelable event
must pass `cancelable: true` explicitly.
Refs PR BabylonJS#1708.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ryantrem
left a comment
There was a problem hiding this comment.
I guess this makes the tests work, but if a consumer tried to use the same things in their own app, they wouldn't work. Is that really the state we want to be in, or we want to know what things don't work because they aren't polyfilled? I would have thought we would either document these features don't work because we don't polyfill, or we add native polyfills for them.
Per-test PIL-composite triage of all 17 ``subtle pixel-diff`` tests. None of them are deterministic-cosmetic (no re-bakes possible - all show real visible regressions). Updates the `reason` field in `Apps/Playground/Scripts/config.json` for 17 tests with accurate symptom descriptions, classifying into recurring root-cause clusters: - 9 GUI green->red color regressions (idx 160, 174, 175, 196, 197, 370, 402, 566, 587) - 4 OpenPBR analytic-lights right-column red rendering (580, 584, 587, 592) - 1 instanced billboard foliage red (169) - 1 LineEdgesRenderer extra red lines (179) - 1 Background blur red splotches (602) - 1 Clip planes GUI sliders red (182) - 1 Instanced Bones edge-AA (256, borderline) **No source changes, no test re-enables, no PNGs.** Metadata-only correction so the issue tracker reflects actionable root causes. --- ## Landing context This PR is one of **7 splits** from the proven CI-green combined preview in **draft PR #1702** (see [#1702](#1702) for the full intended end-state and verified CI run [26044922430](https://github.com/BabylonJS/BabylonNative/actions/runs/26044922430)). > Note: the original split included an 8th PR (#1709, ES2020+ -> ES2019 syntax-repair polyfill for Chakra). It was closed in favour of investigating `@babel/standalone` properly (#1711). ### Recommended landing order **Tier 1 - parallel-reviewable, no source conflicts:** 1. #1703 - ExternalTexture C4702 build fix 2. #1704 - config.json `reason` rewrites (5 entries) 3. #1705 - config.json `reason` rewrites (17 entries) **Tier 2 - sequential, each touches `Apps/Playground/CMakeLists.txt` SCRIPTS list + `Apps/Playground/Shared/AppContext.cpp` LoadScript order; rebase the next branch after the previous merges:** 4. #1706 - File/Blob/FileReader polyfill (largest test impact: 19 re-enables) 5. #1707 - fetch polyfill 6. #1708 - DOM globals + native AbortController + Android CMake link 7. #1710 - Cubemap auto-expand polyfill (loaded after babylon.max.js) ### Reference policy reminder Reference PNGs across all 7 PRs come from Babylon.js; never re-baked by BN. Combined diff: **0 PNGs**.
Per-test triage of 5 post-#1695 pixel-diff fallouts. Updates the `reason` field in `Apps/Playground/Scripts/config.json` for 3 entries to name the real BN rendering regression instead of generic "Pixel comparison fails": - idx 363 SSR2 - SSR not rendering wet floor. - idx 369 Sprites Pixel Perfect - sprite alpha-blending broken. - idx 395 soft-transparent-shadows - soft-shadow filter precision degraded. **No source changes, no test re-enables, no PNGs.** Metadata-only correction so the issue tracker reflects actionable root causes for follow-up engineering work. --- ## Landing context This PR is one of **7 splits** from the proven CI-green combined preview in **draft PR #1702** (see [#1702](#1702) for the full intended end-state and verified CI run [26044922430](https://github.com/BabylonJS/BabylonNative/actions/runs/26044922430)). > Note: the original split included an 8th PR (#1709, ES2020+ -> ES2019 syntax-repair polyfill for Chakra). It was closed in favour of investigating `@babel/standalone` properly (#1711). ### Recommended landing order **Tier 1 - parallel-reviewable, no source conflicts:** 1. #1703 - ExternalTexture C4702 build fix 2. #1704 - config.json `reason` rewrites (5 entries) 3. #1705 - config.json `reason` rewrites (17 entries) **Tier 2 - sequential, each touches `Apps/Playground/CMakeLists.txt` SCRIPTS list + `Apps/Playground/Shared/AppContext.cpp` LoadScript order; rebase the next branch after the previous merges:** 4. #1706 - File/Blob/FileReader polyfill (largest test impact: 19 re-enables) 5. #1707 - fetch polyfill 6. #1708 - DOM globals + native AbortController + Android CMake link 7. #1710 - Cubemap auto-expand polyfill (loaded after babylon.max.js) ### Reference policy reminder Reference PNGs across all 7 PRs come from Babylon.js; never re-baked by BN. Combined diff: **0 PNGs**.
…interEvent polyfills Addresses Ryan's review (pullrequestreview-4312723810): > I would have thought we would either document these features don't > work because we don't polyfill, or we add native polyfills for them. The previous version of this PR added a Playground-only dom_polyfill.js that injected TextEncoder and PointerEvent shims onto the global object. That worked for the Playground but every other app embedding Babylon Native against Chakra would have had to independently re-discover and ship the same workaround. Move both into proper C++ polyfill libraries under Polyfills/ with the same Initialize(Napi::Env) shape as the existing Polyfills/TextDecoder (the canonical reference for the pattern in jsruntimehost). Now any BN consumer that links them and calls Initialize() gets the same behaviour for free. - Polyfills/TextEncoder/ - Napi::ObjectWrap implementation of the WHATWG Encoding Standard TextEncoder surface: encoding accessor (always utf-8), encode(input) returning a fresh Uint8Array of UTF-8 bytes via Napi::String::Utf8Value() (the engine does the UTF-16 to UTF-8 conversion natively, which is well-tested across all N-API surfaces), and encodeInto(source, destination) which walks the UTF-8 byte stream a code-point at a time, stops cleanly on a code-point boundary when the destination fills up, and derives the spec-required UTF-16 read code-unit count from the UTF-8 leading-byte bit pattern (1 code unit for 1/2/3-byte sequences, 2 for the surrogate pair encoded by a 4-byte sequence). Avoids Utf16Value() entirely to sidestep N-API shim quirks. - Polyfills/PointerEvent/ - Napi::ObjectWrap implementation of the W3C Pointer Events Level 3 surface. The constructor materialises the same ~35 MouseEvent + PointerEvent own properties on the receiver that the prior JS shim used (matching defaults: cancelable = false per DOM EventInit spec, pressure = 0.5, isPrimary = true unless explicitly disabled, etc.) and exposes preventDefault / stopPropagation / stopImmediatePropagation / getModifierState / getCoalescedEvents / getPredictedEvents as InstanceMethods. CMake / wiring: - Top-level CMakeLists.txt: add BABYLON_NATIVE_POLYFILL_TEXTENCODER and BABYLON_NATIVE_POLYFILL_POINTEREVENT options (default ON). - Polyfills/CMakeLists.txt: add_subdirectory for each, guarded by their option. - Apps/Playground/CMakeLists.txt and Apps/Playground/Android/BabylonNative/CMakeLists.txt: PRIVATE link TextEncoder + PointerEvent so AppContext.cpp can use the published headers on every platform. - Apps/Playground/Shared/AppContext.cpp: include the new headers, call TextEncoder::Initialize(env) and PointerEvent::Initialize(env) inside the runtime Dispatch lambda right after the existing TextDecoder::Initialize call (before Babylon.js scripts are loaded), and drop the LoadScript for dom_polyfill.js now that the shims are part of the runtime itself. - Delete Apps/Playground/Scripts/dom_polyfill.js (no longer used). Verified locally on Chakra build (build/win32 RelWithDebInfo, headless): - 'Serialize scene without materials' (the test the prior JS shim was added to re-enable) validates with 248 px diff - same as before. - 'GLTF Serializer multimaterial with raw texture' validates with 891 px diff (matches the JS-shim baseline exactly). - EXR Loader, Native Canvas, GUI Input Test all behave identically to the JS-shim baseline (validated / skipped same as before). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…interEvent polyfills Addresses Ryan's review (pullrequestreview-4312723810): > I would have thought we would either document these features don't > work because we don't polyfill, or we add native polyfills for them. The previous version of this PR added a Playground-only dom_polyfill.js that injected TextEncoder and PointerEvent shims onto the global object. That worked for the Playground but every other app embedding Babylon Native against Chakra would have had to independently re-discover and ship the same workaround. Move both into proper C++ polyfill libraries under Polyfills/ with the same Initialize(Napi::Env) shape as the existing Polyfills/TextDecoder (the canonical reference for the pattern in jsruntimehost). Now any BN consumer that links them and calls Initialize() gets the same behaviour for free. - Polyfills/TextEncoder/ - Napi::ObjectWrap implementation of the WHATWG Encoding Standard TextEncoder surface: encoding accessor (always utf-8), encode(input) returning a fresh Uint8Array of UTF-8 bytes via Napi::String::Utf8Value() (the engine does the UTF-16 to UTF-8 conversion natively, which is well-tested across all N-API surfaces), and encodeInto(source, destination) which walks the UTF-8 byte stream a code-point at a time, stops cleanly on a code-point boundary when the destination fills up, and derives the spec-required UTF-16 read code-unit count from the UTF-8 leading-byte bit pattern (1 code unit for 1/2/3-byte sequences, 2 for the surrogate pair encoded by a 4-byte sequence). Avoids Utf16Value() entirely to sidestep N-API shim quirks. - Polyfills/PointerEvent/ - Napi::ObjectWrap implementation of the W3C Pointer Events Level 3 surface. The constructor materialises the same ~35 MouseEvent + PointerEvent own properties on the receiver that the prior JS shim used (matching defaults: cancelable = false per DOM EventInit spec, pressure = 0.5, isPrimary = true unless explicitly disabled, etc.) and exposes preventDefault / stopPropagation / stopImmediatePropagation / getModifierState / getCoalescedEvents / getPredictedEvents as InstanceMethods. CMake / wiring: - Top-level CMakeLists.txt: add BABYLON_NATIVE_POLYFILL_TEXTENCODER and BABYLON_NATIVE_POLYFILL_POINTEREVENT options (default ON). - Polyfills/CMakeLists.txt: add_subdirectory for each, guarded by their option. - Apps/Playground/CMakeLists.txt and Apps/Playground/Android/BabylonNative/CMakeLists.txt: PRIVATE link TextEncoder + PointerEvent so AppContext.cpp can use the published headers on every platform. - Apps/Playground/Shared/AppContext.cpp: include the new headers, call TextEncoder::Initialize(env) and PointerEvent::Initialize(env) inside the runtime Dispatch lambda right after the existing TextDecoder::Initialize call (before Babylon.js scripts are loaded), and drop the LoadScript for dom_polyfill.js now that the shims are part of the runtime itself. - Delete Apps/Playground/Scripts/dom_polyfill.js (no longer used). Verified locally on Chakra build (build/win32 RelWithDebInfo, headless): - 'Serialize scene without materials' (the test the prior JS shim was added to re-enable) validates with 248 px diff - same as before. - 'GLTF Serializer multimaterial with raw texture' validates with 891 px diff (matches the JS-shim baseline exactly). - EXR Loader, Native Canvas, GUI Input Test all behave identically to the JS-shim baseline (validated / skipped same as before). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
c98d68d to
2101ef8
Compare
…1703) Fixes MSVC C4702 (unreachable code) under `/WX` in `Plugins/ExternalTexture/Source/ExternalTexture_OpenGL.cpp` so the OpenGL TU builds cleanly without the project-wide `/wd4702` workaround. ## What changed `Plugins/ExternalTexture/Source/ExternalTexture_OpenGL.cpp` keeps the unimplemented `Impl` stubs as `throw std::runtime_error{"not implemented"}` (so callers get an unambiguous diagnostic matching every other backend's unimplemented path) and wraps the `#include "ExternalTexture_Shared.h"` line in `#pragma warning(push)/(disable: 4702)/(pop)`. The shared dispatchers instantiated by that include unconditionally call the stubs, so MSVC's flow analysis flags the dispatcher's post-call code as unreachable; the pragma suppresses C4702 only for the dispatcher code instantiated in this translation unit. Any other code in this file is still subject to `/WX` C4702 enforcement. `Plugins/ExternalTexture/CMakeLists.txt` - drop the `/wd4702` target compile option, which previously silenced C4702 across the whole target. ## Alternatives considered - **`[[noreturn]]` on the stubs**: MSVC propagates "never returns" through the shared dispatcher, which flags *more* post-call statements as unreachable. Tried and rejected (it made the warning worse). - **TU-wide `/wd4702` via `target_compile_options`**: silences any future legitimate C4702 elsewhere in the same TU, defeating `/WX`. The current localized `#pragma warning(push/pop)` block keeps the rest of the TU under `/WX` enforcement. - **Replacing the throws with inert return-default stubs**: changes product behaviour (callers would silently receive a null texture instead of a clear "not implemented" error) to work around a compiler warning. Rejected on principle. ## Verified Clean under Debug + Release + RelWithDebInfo on OpenGL (`win32-gl`, `GRAPHICS_API=OpenGLWindowsDevOnly`) and D3D11 (`win32`). --- ## Landing context This PR is one of **7 splits** from the proven CI-green combined preview in **draft PR #1702** (see [#1702](#1702) for the full intended end-state and verified CI run [26044922430](https://github.com/BabylonJS/BabylonNative/actions/runs/26044922430)). > Note: the original split included an 8th PR (#1709, ES2020+ -> ES2019 syntax-repair polyfill for Chakra). It was closed in favour of investigating `@babel/standalone` properly (#1711). ### Recommended landing order **Tier 1 - parallel-reviewable, no source conflicts:** 1. #1703 - ExternalTexture C4702 build fix 2. #1704 - config.json `reason` rewrites (5 entries) 3. #1705 - config.json `reason` rewrites (17 entries) **Tier 2 - sequential, each touches `Apps/Playground/CMakeLists.txt` SCRIPTS list + `Apps/Playground/Shared/AppContext.cpp` LoadScript order; rebase the next branch after the previous merges:** 4. #1706 - File/Blob/FileReader polyfill (largest test impact: 19 re-enables) 5. #1707 - fetch polyfill 6. #1708 - DOM globals + native AbortController + Android CMake link 7. #1710 - Cubemap auto-expand polyfill (loaded after babylon.max.js) ### Reference policy reminder Reference PNGs across all 7 PRs come from Babylon.js; never re-baked by BN. Combined diff: **0 PNGs**. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| @@ -0,0 +1,17 @@ | |||
| #pragma once | |||
There was a problem hiding this comment.
TextEncoder belongs in JsRuntimeHost alongside TextDecoder (also WHATWG Encoding Standard). Splitting them across repos means non-BN consumers can't get TextEncoder without duplicating.
| @@ -0,0 +1,21 @@ | |||
| #pragma once | |||
There was a problem hiding this comment.
We shouldn't polyfill DOM types. BabylonNative isn't a browser; DeviceInputSystem already abstracts input. Let's discuss offline before adding this.
Wires up native
AbortControllerand adds JS polyfills forTextEncoder+PointerEventso playgrounds depending on DOM globals stop ReferenceError'ing.Changes:
Apps/Playground/Scripts/dom_polyfill.js- self-detectingTextEncoder+PointerEventpolyfills.Apps/Playground/Shared/AppContext.cpp- callsBabylon::Polyfills::AbortController::Initialize(env); loadsdom_polyfill.jsafterfile_polyfill.js.Apps/Playground/CMakeLists.txt- addsdom_polyfill.jsto SCRIPTS list; linksAbortControllerplugin.Apps/Playground/Android/BabylonNative/CMakeLists.txt- addsPRIVATE AbortControllertoBabylonNativeJNIlink list (without this, Android builds fail with missing header - verified via CI).Apps/Playground/Scripts/validation_native.js- extends document shim withcreateEvent+dispatchEvent.Apps/Playground/Scripts/config.json- re-enables 1 test (idx 342).Note: Polyfill foundation. Remaining affected playground tests need native
dispatchEventon canvas /Imagepolyfill / async-module support - out of scope here.Landing context
This PR is one of 7 splits from the proven CI-green combined preview in draft PR #1702 (see #1702 for the full intended end-state and verified CI run 26044922430).
Recommended landing order
Tier 1 - parallel-reviewable, no source conflicts:
reasonrewrites (5 entries)reasonrewrites (17 entries)Tier 2 - sequential, each touches
Apps/Playground/CMakeLists.txtSCRIPTS list +Apps/Playground/Shared/AppContext.cppLoadScript order; rebase the next branch after the previous merges:Reference policy reminder
Reference PNGs across all 7 PRs come from Babylon.js; never re-baked by BN. Combined diff: 0 PNGs.