diff --git a/Polyfills/Canvas/CMakeLists.txt b/Polyfills/Canvas/CMakeLists.txt index f9b394c1c..ab9704cbd 100644 --- a/Polyfills/Canvas/CMakeLists.txt +++ b/Polyfills/Canvas/CMakeLists.txt @@ -35,6 +35,7 @@ target_link_libraries(Canvas PRIVATE JsRuntimeInternal PRIVATE GraphicsDeviceContext PRIVATE UrlLib + PRIVATE base-n PRIVATE napi_extensions) set_property(TARGET Canvas PROPERTY FOLDER Polyfills) diff --git a/Polyfills/Canvas/Source/Canvas.cpp b/Polyfills/Canvas/Source/Canvas.cpp index df8ed9836..7a0a7862d 100644 --- a/Polyfills/Canvas/Source/Canvas.cpp +++ b/Polyfills/Canvas/Source/Canvas.cpp @@ -195,6 +195,10 @@ namespace Babylon::Polyfills void Canvas::Impl::RemoveMonitoredResource(MonitoredResource* monitoredResource) { + if (m_monitoredResources.empty()) + { + return; + } auto iter = std::find(m_monitoredResources.begin(), m_monitoredResources.end(), monitoredResource); if (iter != m_monitoredResources.end()) { diff --git a/Polyfills/Canvas/Source/Image.cpp b/Polyfills/Canvas/Source/Image.cpp index 34299142f..9ec91a8c3 100644 --- a/Polyfills/Canvas/Source/Image.cpp +++ b/Polyfills/Canvas/Source/Image.cpp @@ -11,6 +11,7 @@ #include "nanovg.h" #include #include +#include namespace Babylon::Polyfills::Internal { @@ -97,13 +98,52 @@ namespace Babylon::Polyfills::Internal } } + bool NativeCanvasImage::SetBuffer(gsl::span buffer) + { + m_imageContainer = bimg::imageParse(&Graphics::DeviceContext::GetDefaultAllocator(), buffer.data(), static_cast(buffer.size_bytes()), bimg::TextureFormat::RGBA8); + + if (m_imageContainer == nullptr) + { + return false; + } + + m_width = m_imageContainer->m_width; + m_height = m_imageContainer->m_height; + + if (!m_onloadHandlerRef.IsEmpty()) + { + m_onloadHandlerRef.Call({}); + } + return true; + } + void NativeCanvasImage::SetSrc(const Napi::CallbackInfo& info, const Napi::Value& value) { auto text{value.As().Utf8Value()}; + + // try with base64 + static const std::string base64{"base64,"}; + const auto pos = text.find(base64); + if (pos != std::string::npos) + { + arcana::make_task(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, text{std::move(text)}, pos]() { + std::vector base64Buffer; + bn::decode_b64(text.begin() + pos + base64.length(), text.end(), std::back_inserter(base64Buffer)); + gsl::span buffer = {reinterpret_cast(base64Buffer.data()), base64Buffer.size()}; + + if (!SetBuffer(buffer)) + { + HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided base64 source.")); + } + }); + return; + } + + // try with URL UrlLib::UrlRequest request{}; request.Open(UrlLib::UrlMethod::Get, text); request.ResponseType(UrlLib::UrlResponseType::Buffer); - request.SendAsync().then(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, request{std::move(request)}](arcana::expected result) { + request.SendAsync().then(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, cancellationSource{m_cancellationSource}, request{std::move(request)}, text](arcana::expected result) { if (result.has_error()) { HandleLoadImageError(Napi::Error::New(env, result.error())); @@ -115,24 +155,13 @@ namespace Babylon::Polyfills::Internal auto buffer{request.ResponseBuffer()}; if (buffer.data() == nullptr || buffer.size_bytes() == 0) { - HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response.")); + HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response or invalid base64.")); return; } - m_imageContainer = bimg::imageParse(&Graphics::DeviceContext::GetDefaultAllocator(), buffer.data(), static_cast(buffer.size_bytes()), bimg::TextureFormat::RGBA8); - - if (m_imageContainer == nullptr) - { - HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided src.")); - return; - } - - m_width = m_imageContainer->m_width; - m_height = m_imageContainer->m_height; - - if (!m_onloadHandlerRef.IsEmpty()) + if (!SetBuffer(buffer)) { - m_onloadHandlerRef.Call({}); + HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided source URL.")); } }); } diff --git a/Polyfills/Canvas/Source/Image.h b/Polyfills/Canvas/Source/Image.h index c4b1c0a57..5cd62aed0 100644 --- a/Polyfills/Canvas/Source/Image.h +++ b/Polyfills/Canvas/Source/Image.h @@ -36,6 +36,7 @@ namespace Babylon::Polyfills::Internal void SetOnload(const Napi::CallbackInfo&, const Napi::Value&); void SetOnerror(const Napi::CallbackInfo&, const Napi::Value&); void HandleLoadImageError(const Napi::Error& error); + bool SetBuffer(gsl::span buffer); void Dispose(); uint32_t m_width{1};