From c9a87af838429468c140cacfeb843701aee83ed8 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:43:32 +0100 Subject: [PATCH 1/3] Base64 Image support --- Polyfills/Canvas/CMakeLists.txt | 1 + Polyfills/Canvas/Source/Canvas.cpp | 4 ++ Polyfills/Canvas/Source/Image.cpp | 79 +++++++++++++++++++----------- Polyfills/Canvas/Source/Image.h | 1 + 4 files changed, 56 insertions(+), 29 deletions(-) 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 72858bfda..79d12dc04 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,42 +98,62 @@ namespace Babylon::Polyfills::Internal } } + bool NativeCanvasImage::SetBuffer(gsl::span buffer) + { + m_imageContainer = bimg::imageParse(&m_allocator, 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()}; 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) { - if (result.has_error()) - { - HandleLoadImageError(Napi::Error::New(env, result.error())); - return; - } - - Dispose(); - - auto buffer{request.ResponseBuffer()}; - if (buffer.data() == nullptr || buffer.size_bytes() == 0) - { - HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response.")); - return; - } - - m_imageContainer = bimg::imageParse(&m_allocator, 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()) + request.SendAsync().then(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, cancellationSource{m_cancellationSource}, request{std::move(request)}, text](arcana::expected result) { + if (!cancellationSource->cancelled()) { - m_onloadHandlerRef.Call({}); + if (result.has_error()) + { + HandleLoadImageError(Napi::Error::New(env, result.error())); + return; + } + + Dispose(); + + auto buffer{request.ResponseBuffer()}; + std::vector base64Buffer; + if (buffer.data() == nullptr || buffer.size_bytes() == 0) + { + // try with base64 + static const std::string base64{"base64,"}; + const auto pos = text.find(base64); + if (pos == std::string::npos) + { + HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response or invalid base64.")); + return; + } + bn::decode_b64(text.begin() + pos + base64.length(), text.end(), std::back_inserter(base64Buffer)); + buffer = {reinterpret_cast(base64Buffer.data()), base64Buffer.size()}; + } + if (!SetBuffer(buffer)) + { + HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided src.")); + return; + } } }); } diff --git a/Polyfills/Canvas/Source/Image.h b/Polyfills/Canvas/Source/Image.h index a4b41adb0..b6959004c 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}; From 313a0e60aa4f300d2790717eaab95fec584fbf0a Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:32:50 +0100 Subject: [PATCH 2/3] move code block --- Polyfills/Canvas/Source/Image.cpp | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/Polyfills/Canvas/Source/Image.cpp b/Polyfills/Canvas/Source/Image.cpp index 79d12dc04..5aeb390a5 100644 --- a/Polyfills/Canvas/Source/Image.cpp +++ b/Polyfills/Canvas/Source/Image.cpp @@ -124,36 +124,37 @@ namespace Babylon::Polyfills::Internal request.Open(UrlLib::UrlMethod::Get, text); request.ResponseType(UrlLib::UrlResponseType::Buffer); request.SendAsync().then(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, cancellationSource{m_cancellationSource}, request{std::move(request)}, text](arcana::expected result) { - if (!cancellationSource->cancelled()) + if (cancellationSource->cancelled()) { - if (result.has_error()) - { - HandleLoadImageError(Napi::Error::New(env, result.error())); - return; - } + return; + } + if (result.has_error()) + { + HandleLoadImageError(Napi::Error::New(env, result.error())); + return; + } - Dispose(); + Dispose(); - auto buffer{request.ResponseBuffer()}; - std::vector base64Buffer; - if (buffer.data() == nullptr || buffer.size_bytes() == 0) - { - // try with base64 - static const std::string base64{"base64,"}; - const auto pos = text.find(base64); - if (pos == std::string::npos) - { - HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response or invalid base64.")); - return; - } - bn::decode_b64(text.begin() + pos + base64.length(), text.end(), std::back_inserter(base64Buffer)); - buffer = {reinterpret_cast(base64Buffer.data()), base64Buffer.size()}; - } - if (!SetBuffer(buffer)) + auto buffer{request.ResponseBuffer()}; + std::vector base64Buffer; + if (buffer.data() == nullptr || buffer.size_bytes() == 0) + { + // try with base64 + static const std::string base64{"base64,"}; + const auto pos = text.find(base64); + if (pos == std::string::npos) { - HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided src.")); + HandleLoadImageError(Napi::Error::New(env, "Image with provided source returned empty response or invalid base64.")); return; } + bn::decode_b64(text.begin() + pos + base64.length(), text.end(), std::back_inserter(base64Buffer)); + buffer = {reinterpret_cast(base64Buffer.data()), base64Buffer.size()}; + } + if (!SetBuffer(buffer)) + { + HandleLoadImageError(Napi::Error::New(env, "Unable to decode image with provided src.")); + return; } }); } From c0934c954ad967fbf9e8cc1e48c8e8211752e40b Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Tue, 5 Dec 2023 10:07:24 +0100 Subject: [PATCH 3/3] removed cancellation check --- Polyfills/Canvas/Source/Image.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Polyfills/Canvas/Source/Image.cpp b/Polyfills/Canvas/Source/Image.cpp index 4004fedbd..9ec91a8c3 100644 --- a/Polyfills/Canvas/Source/Image.cpp +++ b/Polyfills/Canvas/Source/Image.cpp @@ -144,10 +144,6 @@ namespace Babylon::Polyfills::Internal request.Open(UrlLib::UrlMethod::Get, text); request.ResponseType(UrlLib::UrlResponseType::Buffer); request.SendAsync().then(m_runtimeScheduler, *m_cancellationSource, [env{info.Env()}, this, cancellationSource{m_cancellationSource}, request{std::move(request)}, text](arcana::expected result) { - if (cancellationSource->cancelled()) - { - return; - } if (result.has_error()) { HandleLoadImageError(Napi::Error::New(env, result.error()));