From a55b27ec698758cfd2f1788b364e0208ba2323a0 Mon Sep 17 00:00:00 2001 From: Joseph Woo Date: Mon, 29 Apr 2024 16:12:23 -0700 Subject: [PATCH 1/5] refactor change size not working --- .../uwp/SharedRenderer/dll/CppWinRTIncludes.h | 1 + .../lib/AdaptiveImageRenderer.cpp | 542 ++++++------------ source/uwp/SharedRenderer/lib/XamlBuilder.h | 30 +- .../Renderer/AdaptiveCardRenderer.vcxproj | 3 - .../Properties/launchSettings.json | 3 +- .../Visualizer/Properties/launchSettings.json | 3 +- 6 files changed, 194 insertions(+), 388 deletions(-) diff --git a/source/uwp/SharedRenderer/dll/CppWinRTIncludes.h b/source/uwp/SharedRenderer/dll/CppWinRTIncludes.h index f90844d443..2b43d2924a 100644 --- a/source/uwp/SharedRenderer/dll/CppWinRTIncludes.h +++ b/source/uwp/SharedRenderer/dll/CppWinRTIncludes.h @@ -107,6 +107,7 @@ namespace winrt // using namespace winrt::Windows::Web::Http using HttpProgress = ::winrt::Windows::Web::Http::HttpProgress; using HttpClient = ::winrt::Windows::Web::Http::HttpClient; + using HttpResponseMessage = ::winrt::Windows::Web::Http::HttpResponseMessage; // using namespace winrt::Windows::Web::Http::HttpFilters using HttpBaseProtocolFilter = ::winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter; diff --git a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp index d7277deb6c..a585123a74 100644 --- a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp @@ -36,7 +36,7 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation namespace AdaptiveCards::Rendering::Xaml_Rendering { - auto inline GetDispatcher(winrt::SvgImageSource const &imageSource) + auto inline GetDispatcher(winrt::ImageSource const &imageSource) { #ifdef USE_WINUI3 return imageSource.DispatcherQueue(); @@ -289,74 +289,75 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering adaptiveCardElement, selectAction, renderContext, frameworkElement, XamlHelpers::SupportsInteractivity(hostConfig), true); } - template - winrt::ImageSource XamlBuilder::SetImageOnUIElement(winrt::Uri const& imageUrl, - winrt::AdaptiveCardResourceResolvers const& resolvers, - ImageProperties const& imgProperties) + winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageAsync(winrt::IRandomAccessStream const stream) { - bool mustHideElement = true; + co_await winrt::resume_background(); // Switch to a background thread - // Get the image url scheme - winrt::hstring schemeName = imageUrl.SchemeName(); + auto inputStream = stream.GetInputStreamAt(0); + auto dataReader = winrt::DataReader(inputStream); - // Get the resolver for the image - if (resolvers) + // Load the data from the stream + uint32_t numBytesLoaded = co_await dataReader.LoadAsync(static_cast(stream.Size())); + + // Read the data as a string + winrt::hstring svgString = dataReader.ReadString(numBytesLoaded); + + // Parse the size from the XamlDocument + winrt::XmlDocument xmlDoc; + + xmlDoc.LoadXml(svgString); + + if (xmlDoc) { - auto resolver = resolvers.Get(schemeName); - // If we have a resolver - if (resolver) + auto rootElement = xmlDoc.DocumentElement(); + + // Root element must be an SVG + if (winrt::operator==(rootElement.NodeName(), L"svg")) { - // Create a Image to hold the image data. We use BitmapImage & SvgImageSource in order to allow - // the tracker to subscribe to the ImageLoaded/Failed events - auto image = CreateImageSource(imgProperties.isImageSvg); + auto heightAttribute = rootElement.GetAttribute(L"height"); + auto widthAttribute = rootElement.GetAttribute(L"width"); + + double height{0.0}; + double width{0.0}; - if (!m_enableXamlImageHandling && (m_listeners.size() != 0)) + if (!heightAttribute.empty()) { - if (!imgProperties.isImageSvg) - { - image.as().CreateOptions(winrt::BitmapCreateOptions::None); - } - this->m_imageLoadTracker->TrackImage(image); + height = TryHStringToDouble(heightAttribute).value_or(0.0); } - // Create the arguments to pass to the resolver - auto args = winrt::make(imageUrl); + if (!widthAttribute.empty()) + { + width = TryHStringToDouble(widthAttribute).value_or(0.0); + } + + co_return {static_cast(width), static_cast(height)}; + } + } - // And call the resolver to get the image stream - auto getResourceStreamOperation = resolver.GetResourceStreamAsync(args); + co_return {}; + } - getResourceStreamOperation.Completed( - [this, weakThis = this->get_weak(), image, imgProperties]( - auto const& operation, auto status) -> void - { - if (status == winrt::AsyncStatus::Completed) - { - if (auto strongThis = weakThis.get()) - { - auto randomAccessStream = operation.GetResults(); - if (!randomAccessStream) - { - this->m_imageLoadTracker->MarkFailedLoadImage(image); - return; - } - strongThis->HandleAccessStreamForImageSource(imgProperties, randomAccessStream, image); - } - } - else - { - if (auto strongThis = weakThis.get()) - { - // Question: should we only mark as a failed image if (!m_enableXamlImageHandling && (m_listeners.size() != 0)) - this->m_imageLoadTracker->MarkFailedLoadImage(image); - } - } - }); - return image; + winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync(winrt::Uri const imageUrl, + winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg) + { + const auto weakThis = get_weak(); + const auto schemeName = imageUrl.SchemeName(); + + if (resolvers) + { + auto resolver = resolvers.Get(schemeName); + // If we have a resolver + if (resolver) + { + auto args = winrt::make(imageUrl); + auto stream = co_await resolver.GetResourceStreamAsync(args); + co_return stream; } } if (schemeName == L"data") { + co_await winrt::resume_background(); winrt::DataWriter dataWriter{winrt::InMemoryRandomAccessStream{}}; auto imagePath = HStringToUTF8(imageUrl.Path()); auto foundBase64 = imagePath.find("base64"); @@ -367,295 +368,177 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering std::vector decodedData = AdaptiveBase64Util::Decode(data); dataWriter.WriteBytes(std::vector{decodedData.begin(), decodedData.end()}); } - else if (imgProperties.isImageSvg) + else if (isImageSvg) { // Extract ... string std::string data = ExtractSvgDataFromUri(imageUrl); dataWriter.WriteBytes(std::vector{data.begin(), data.end()}); } - auto image = CreateImageSource(imgProperties.isImageSvg); + auto storeOp = dataWriter.StoreAsync(); - if (!imgProperties.isImageSvg) + if (const auto strongThis = weakThis.get()) { - image.as().CreateOptions(winrt::BitmapCreateOptions::IgnoreImageCache); + strongThis->m_writeAsyncOperations.push_back(storeOp); } - m_imageLoadTracker->TrackImage(image); - auto streamWriteOperation = dataWriter.StoreAsync(); + co_await storeOp; + + auto stream = dataWriter.DetachStream().try_as(); + stream.Seek(0); + + co_return stream; - streamWriteOperation.Completed( - [weakThis = this->get_weak(), dataWriter, image, imgProperties]( - auto const& /*operation*/, auto status) -> void - { - if (status == winrt::AsyncStatus::Completed) - { - if (auto strongThis = weakThis.get()) - { - if (const auto stream = dataWriter.DetachStream().try_as()) - { - stream.Seek(0); - strongThis->HandleAccessStreamForImageSource(imgProperties, stream, image); - } - } - } - }); - m_writeAsyncOperations.push_back(streamWriteOperation); - mustHideElement = false; - return image; } // Otherwise, no resolver... - if ((m_enableXamlImageHandling) || (m_listeners.size() == 0)) + if (const auto strongThis = weakThis.get()) { - // If we've been explicitly told to let Xaml handle the image loading, or there are - // no listeners waiting on the image load callbacks, use Xaml to load the images - auto image = CreateImageSource(imgProperties.isImageSvg); - - if (imgProperties.isImageSvg) + if ((!strongThis->m_enableXamlImageHandling) && (strongThis->m_listeners.size() != 0)) { - // If we have an SVG, we need to try to parse for the image size before setting the image source - auto svgDocumentLoadOperation = winrt::XmlDocument::LoadFromUriAsync(imageUrl); + winrt::HttpBaseProtocolFilter httpBaseProtocolFilter{}; + httpBaseProtocolFilter.AllowUI(false); - svgDocumentLoadOperation.Completed( - [weakThis = this->get_weak(), - weakImageSource = winrt::make_weak(image.as()), - imageUrl](auto const& operation, auto status) -> void - { - auto strongThis = weakThis.get(); - auto strongImageSource = weakImageSource.get(); + winrt::HttpClient httpClient{httpBaseProtocolFilter}; - if (strongThis && strongImageSource) - { - if (status == winrt::AsyncStatus::Completed) - { - auto success = strongThis->ParseXmlForHeightAndWidth(operation.GetResults(), strongImageSource); + auto httpStream = co_await httpClient.GetInputStreamAsync(imageUrl); + winrt::InMemoryRandomAccessStream randomAccessStream{}; + //auto copyStreamOperation = co_await winrt::RandomAccessStream::CopyAsync(httpStream, randomAccessStream); - if (success) - { - // Now that we've parsed the height and width successfully, we can set the image source - strongThis->SetSvgUriSource(strongImageSource, imageUrl); - } - } - else if (status == winrt::AsyncStatus::Error) - { - // Handle error - winrt::hresult error = operation.ErrorCode(); - } - } - }); - } - else - { - image.as().UriSource(imageUrl); - } + //strongThis->m_copyStreamOperations.push_back(copyStreamOperation); - SetImageSource(imgProperties.uiElement, image, imgProperties.stretch); + randomAccessStream.Seek(0); - // Issue #8126 - if (imgProperties.isAutoSize) - { - SetAutoSize(imgProperties.uiElement, - imgProperties.parentElement, - imgProperties.imageContainer, - imgProperties.isVisible, - true /* imageFiresOpenEvent */); + co_return randomAccessStream; } - - return image; - } - else - { - return PopulateImageFromUrlAsync(imageUrl, imgProperties); } + + co_return {}; } - winrt::ImageSource XamlBuilder::CreateImageSource(bool isImageSvg) + // Set the source of the image + winrt::IAsyncOperation XamlBuilder::SetImageSourceAsync(winrt::SvgImageSource imageSource, + winrt::IRandomAccessStream const stream) { - if (isImageSvg) - { - winrt::SvgImageSource svgImageSource{}; - return svgImageSource; - } - else - { - winrt::BitmapImage bitmapImage{}; - return bitmapImage; - } + imageSource.SetSourceAsync(stream); + co_return imageSource; } - // Issue #8127 template - winrt::ImageSource XamlBuilder::PopulateImageFromUrlAsync(winrt::Uri const& imageUrl, - ImageProperties const& imgProperties) + winrt::fire_and_forget XamlBuilder::ResolveImageAsync(winrt::Uri const uri, + winrt::AdaptiveCardResourceResolvers const resolvers, + winrt::ImageSource imageSource, + ImageProperties const properties) { - winrt::HttpBaseProtocolFilter httpBaseProtocolFilter{}; - httpBaseProtocolFilter.AllowUI(false); - - winrt::HttpClient httpClient{httpBaseProtocolFilter}; - - // Create an ImageSource to hold the image data. We use BitmapImage & SvgImageSource in order to allow - // the tracker to subscribe to the ImageLoaded/Failed events - auto image = CreateImageSource(imgProperties.isImageSvg); - this->m_imageLoadTracker->TrackImage(image); + auto weakThis{get_weak()}; + auto weakImageSource{winrt::make_weak(imageSource)}; + auto weakFrameworkElement = winrt::make_weak(properties.uiElement); - if (!imgProperties.isImageSvg) + try { - image.as().CreateOptions(winrt::BitmapCreateOptions::None); - } - - auto getStreamOperation = httpClient.GetInputStreamAsync(imageUrl); - getStreamOperation.Completed( - [this, weakThis = this->get_weak(), imgProperties, image]( - auto const& operation, auto status) -> void + // we can not do any works until stream is resolved + auto stream = co_await ResolveToStreamAsync(uri, resolvers, properties.isImageSvg); + if (auto strongImageSource = weakImageSource.get()) { - if (status == winrt::AsyncStatus::Completed) - { - if (auto strongThis = weakThis.get()) - { - auto imageStream = operation.GetResults(); - winrt::InMemoryRandomAccessStream randomAccessStream{}; - auto copyStreamOperation = winrt::RandomAccessStream::CopyAsync(imageStream, randomAccessStream); - - m_copyStreamOperations.push_back(copyStreamOperation); - - copyStreamOperation.Completed( - [randomAccessStream, weakThis, imgProperties, image]( - auto const& /*operation*/, auto status) - { - if (status == winrt::AsyncStatus::Completed) - { - randomAccessStream.Seek(0); - if (auto strongThis = weakThis.get()) - { - strongThis->HandleAccessStreamForImageSource( - imgProperties, randomAccessStream, image); - } - } - }); - } - } - }); - m_getStreamOperations.push_back(getStreamOperation); - - return image; - } - - template - void XamlBuilder::HandleAccessStreamForImageSource(ImageProperties const& imgProperties, - TStream const& stream, - winrt::ImageSource const& imageSource) - { - SetImageSource(imgProperties.uiElement, imageSource, imgProperties.stretch); - - if (imgProperties.isImageSvg) - { - // If we have an SVG, we need to try to parse for the image size before setting the image source - auto streamSize = stream.Size(); - auto inputStream = stream.GetInputStreamAt(0); - auto streamDataReader = winrt::DataReader(inputStream); - auto loadDataReaderOperation = streamDataReader.LoadAsync((uint32_t)streamSize); - - loadDataReaderOperation.Completed( - [weakThis = this->get_weak(), streamDataReader, streamRef = winrt::make_weak(stream), - imageSourceRef = winrt::make_weak(imageSource.as()), imgProperties]( - auto const& result, auto status) -> void + if (stream) { - auto strongThis = weakThis.get(); - auto strongImageSource = imageSourceRef.get(); - auto strongStream = streamRef.get(); - - if (strongThis && strongImageSource && strongStream) + // while image source is being set, we can do some other works + if (properties.isImageSvg) { - if (status == winrt::AsyncStatus::Completed) + // before setting the RasterizedPixelHeight and RasterizedPixelWidth, we need to switch to the + // UI thread and wait our turn for imageSource access + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + auto svgImageSource = strongImageSource.as(); + auto status = co_await svgImageSource.SetSourceAsync(stream); + auto size{ co_await ParseSizeOfSVGImageAsync(stream)}; + if (auto strongFrameworkElement = weakFrameworkElement.get()) { - auto bytes = result.GetResults(); - - try + if (status == winrt::SvgImageSourceLoadStatus::Success) { - auto svgText = streamDataReader.ReadString(bytes); + SetImageSource(strongFrameworkElement, svgImageSource, properties.stretch); + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + svgImageSource.RasterizePixelHeight(size.Height); + svgImageSource.RasterizePixelWidth(size.Width); - if (!svgText.empty()) - { - auto svgDocument = winrt::XmlDocument(); - svgDocument.LoadXml(svgText); - - auto success = strongThis->ParseXmlForHeightAndWidth(svgDocument, strongImageSource); - - if (success) - { - // Now that we've parsed the size, we can set the image source - strongThis->SetSvgImageSourceAsync(strongImageSource, strongStream, imgProperties); - } - } - } - catch (winrt::hresult_error) - { - // There was an error reading the streamDataReader or loading the xml } } } - }); - } - else - { - auto setSourceAction = imageSource.as().SetSourceAsync(stream); + else + { + auto bitmapImage = imageSource.as(); + bitmapImage.SetSource(stream); + } - setSourceAction.Completed([weakThis = this->get_weak(), imgProperties]( - auto const& /*operation*/, auto status) + // if (auto strongFrameworkElement = frameworkElement.get()) + //{ + // // Set the image source on the UI thread + // co_await winrt::resume_foreground(GetDispatcher(imageSource)); + // SetImageSource(strongFrameworkElement, imageSource, properties.stretch); + // } + } + else { - if (status == winrt::AsyncStatus::Completed && imgProperties.isAutoSize) + co_await wil::resume_foreground(GetDispatcher(imageSource)); + imageSource.as().UriSource(uri); + if (auto strongFrameworkElement = weakFrameworkElement.get()) { - if (auto strongThis = weakThis.get()) - { - strongThis->SetAutoSize(imgProperties.uiElement, - imgProperties.parentElement, - imgProperties.imageContainer, - imgProperties.isVisible, - false /* imageFiresOpenEvent */); - } + SetImageSource(strongFrameworkElement, imageSource, properties.stretch); } - }); + + // if (auto strongThis = weakThis.get()) + // { + // strongThis->m_imageLoadTracker->MarkFailedLoadImage(imageSource); + // // Otherwise, no resolver... + // if ((m_enableXamlImageHandling) || (m_listeners.size() == 0)) + // { + // // If we've been explicitly told to let Xaml handle the image loading, or there are + // // no listeners waiting on the image load callbacks, use Xaml to load the images + // image.as().UriSource(imageUrl); + // } + // } + } + } + } + catch (const std::exception& e) + { + (void)e; + } + catch (const winrt::hresult_error& e) + { + std::string message = HStringToUTF8(e.message()); + } + catch (...) + { + // Handle error + if (auto strongThis = weakThis.get()) + { + strongThis->m_imageLoadTracker->MarkFailedLoadImage(imageSource); + } } } - winrt::fire_and_forget XamlBuilder::SetSvgUriSource(winrt::SvgImageSource const imageSource, - winrt::Uri const uri) + template + winrt::ImageSource XamlBuilder::SetImageOnUIElement(winrt::Uri const& imageUrl, + winrt::AdaptiveCardResourceResolvers const& resolvers, + ImageProperties const& imgProperties) { - co_await wil::resume_foreground(GetDispatcher(imageSource)); - imageSource.UriSource(uri); + auto imageSource = CreateImageSource(imgProperties.isImageSvg); + ResolveImageAsync(imageUrl, resolvers, imageSource, imgProperties); + return imageSource; } - template - winrt::IAsyncAction XamlBuilder::SetSvgImageSourceAsync(winrt::SvgImageSource const imageSource, - TStream const stream, - ImageProperties const imgProperties) + winrt::ImageSource XamlBuilder::CreateImageSource(bool isImageSvg) { - auto weakThis = this->get_weak(); - - co_await wil::resume_foreground(GetDispatcher(imageSource)); - auto setSourceOperation = imageSource.SetSourceAsync(stream); - - setSourceOperation.Completed( - [weakThis, imgProperties]( - auto const& operation, auto status) - { - auto loadStatus = operation.GetResults(); - if (status == winrt::AsyncStatus::Completed && loadStatus == winrt::SvgImageSourceLoadStatus::Success) - { - if (auto strongThis = weakThis.get()) - { - if (imgProperties.isAutoSize) - { - strongThis->SetAutoSize(imgProperties.uiElement, - imgProperties.parentElement, - imgProperties.imageContainer, - imgProperties.isVisible, - false /* imageFiresOpenEvent */); - } - } - } - }); + if (isImageSvg) + { + winrt::SvgImageSource svgImageSource{}; + return svgImageSource; + } + else + { + winrt::BitmapImage bitmapImage{}; + return bitmapImage; + } } template @@ -780,84 +663,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering auto foundSvg = url.find("svg"); return !(foundSvg == std::string::npos); } - - bool XamlBuilder::ParseXmlForHeightAndWidth(winrt::XmlDocument const& xmlDoc, - winrt::SvgImageSource const& imageSource) - { - if (xmlDoc) - { - auto rootElement = xmlDoc.DocumentElement(); - - // Root element must be an SVG - if (winrt::operator==(rootElement.NodeName(), L"svg")) - { - auto height = rootElement.GetAttribute(L"height"); - auto width = rootElement.GetAttribute(L"width"); - - // We only need to set height or width, not both (fixes aspect ratio for person style) - bool isHeightSet = false; - - if (!height.empty()) - { - if (auto heightAsDouble = TryHStringToDouble(height)) - { - SetRasterizedPixelHeightAsync(imageSource, heightAsDouble.value()); - isHeightSet = true; - } - } - - if (!width.empty()) - { - if (auto widthAsDouble = TryHStringToDouble(width)) - { - SetRasterizedPixelWidthAsync(imageSource, widthAsDouble.value(), isHeightSet); - } - } - - return true; - } - } - return false; - } - - winrt::fire_and_forget XamlBuilder::SetRasterizedPixelHeightAsync(winrt::SvgImageSource const imageSource, - double const imageSize, - bool const dropIfUnset) - { - co_await wil::resume_foreground(GetDispatcher(imageSource)); - auto currentSize = imageSource.RasterizePixelHeight(); - bool sizeIsUnset = isinf(currentSize); - - // If the size has already been set explicitly, we need to update it with the correct value - // Ex: If `size: small`, the rasterize pixel size will be 40x40 at this point. - // If the actual image is 100x100, we cannot leave it as 100x40 and must set both height and width - bool dropHeight = sizeIsUnset && dropIfUnset; - - if (!dropHeight) - { - imageSource.RasterizePixelHeight(imageSize); - } - } - - winrt::fire_and_forget XamlBuilder::SetRasterizedPixelWidthAsync(winrt::SvgImageSource const imageSource, - double const imageSize, - bool const dropIfUnset) - { - co_await wil::resume_foreground(GetDispatcher(imageSource)); - auto currentSize = imageSource.RasterizePixelWidth(); - bool sizeIsUnset = isinf(currentSize); - - // If the size has already been set explicitly, we need to update it with the correct value - // Ex: If `size: small`, the rasterize pixel size will be 40x40 at this point. - // If the actual image is 100x100, we cannot leave it as 100x40 and must set both height and width - bool dropWidth = sizeIsUnset && dropIfUnset; - - if (!dropWidth) - { - imageSource.RasterizePixelWidth(imageSize); - } - } - + void XamlBuilder::SetRasterizedPixelHeight(winrt::ImageSource const& imageSource, double const& imageSize) { if (auto image = imageSource.try_as()) { diff --git a/source/uwp/SharedRenderer/lib/XamlBuilder.h b/source/uwp/SharedRenderer/lib/XamlBuilder.h index 0a65717491..8c9eae95ef 100644 --- a/source/uwp/SharedRenderer/lib/XamlBuilder.h +++ b/source/uwp/SharedRenderer/lib/XamlBuilder.h @@ -109,33 +109,33 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering winrt::fire_and_forget SetSvgUriSource(winrt::SvgImageSource const imageSourceRef, winrt::Uri const uriRef); - template - winrt::IAsyncAction SetSvgImageSourceAsync(winrt::SvgImageSource const imageSourceRef, - TStream const streamRef, - ImageProperties const imgProperties); + winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageAsync(winrt::IRandomAccessStream const stream); + + winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync( + winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg); + + winrt::IAsyncOperation XamlBuilder::SetImageSourceAsync( + winrt::SvgImageSource imageSource, winrt::IRandomAccessStream const stream); + + template + winrt::fire_and_forget ResolveImageAsync( + winrt::Uri const uri, + winrt::AdaptiveCardResourceResolvers const resolvers, + winrt::ImageSource imageSource, + ImageProperties const properties); boolean IsSvgImage(std::string url); void FireAllImagesLoaded(); void FireImagesLoadingHadError(); - bool ParseXmlForHeightAndWidth(winrt::XmlDocument const& xmlDoc, - winrt::SvgImageSource const& imageSourceRef); - - winrt::fire_and_forget SetRasterizedPixelHeightAsync(winrt::SvgImageSource const imageSourceRef, - double const imageSize, - bool const dropIfUnset = false); - winrt::fire_and_forget SetRasterizedPixelWidthAsync(winrt::SvgImageSource const imageSourceRef, - double const imageSize, - bool const dropIfUnset = false); - void SetRasterizedPixelHeight(winrt::ImageSource const& imageSource, double const& imageSize); void SetRasterizedPixelWidth(winrt::ImageSource const& imageSource, double const& imageSize); - static void ShouldFallback(winrt::IAdaptiveCardElement const& element, winrt::IAdaptiveElementRenderer const& elementRenderer, winrt::AdaptiveRenderArgs const& renderArgs, winrt::AdaptiveFeatureRegistration const& featureRegistration, boolean ancestorHasFallback); + static winrt::Windows::Foundation::Size ParseXmlForHeightAndWidth(winrt::hstring const& content); }; } diff --git a/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj b/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj index 31c01992be..0c5667a328 100644 --- a/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj +++ b/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj @@ -105,7 +105,6 @@ stdcpp17 Level4 true - Guard Console @@ -117,14 +116,12 @@ OleAut32.lib; %(AdditionalDependencies); - /profile /DEBUGTYPE:FIXUP %(AdditionalOptions) $(VC_LibraryPath_VC_OneCore_CurrentPlatform_spectre);%(AdditionalLibraryDirectories) _DEBUG;%(PreprocessorDefinitions) - ProgramDatabase diff --git a/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json b/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json index a014a9c463..34250bdbfd 100644 --- a/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json +++ b/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json @@ -4,7 +4,8 @@ "commandName": "MsixPackage" }, "SimpleVisualizer (Unpackaged)": { - "commandName": "Project" + "commandName": "Project", + "hotReloadEnabled": false } } } \ No newline at end of file diff --git a/source/uwp/winui3/Visualizer/Properties/launchSettings.json b/source/uwp/winui3/Visualizer/Properties/launchSettings.json index 98c20e9344..609a4a56c3 100644 --- a/source/uwp/winui3/Visualizer/Properties/launchSettings.json +++ b/source/uwp/winui3/Visualizer/Properties/launchSettings.json @@ -2,7 +2,8 @@ "profiles": { "AdaptiveCardVisualizer (Package)": { "commandName": "MsixPackage", - "nativeDebugging": true + "nativeDebugging": true, + "hotReloadEnabled": false }, "AdaptiveCardVisualizer (Unpackaged)": { "commandName": "Project" From 5375ed229880da3523e56e9977a812c2e00aa446 Mon Sep 17 00:00:00 2001 From: Joseph Woo Date: Mon, 29 Apr 2024 18:29:32 -0700 Subject: [PATCH 2/5] almost done --- .../lib/AdaptiveImageRenderer.cpp | 180 ++++++++---------- source/uwp/SharedRenderer/lib/XamlBuilder.h | 9 +- 2 files changed, 80 insertions(+), 109 deletions(-) diff --git a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp index a585123a74..cd9b032aec 100644 --- a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp @@ -289,23 +289,12 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering adaptiveCardElement, selectAction, renderContext, frameworkElement, XamlHelpers::SupportsInteractivity(hostConfig), true); } - winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageAsync(winrt::IRandomAccessStream const stream) + winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content) { - co_await winrt::resume_background(); // Switch to a background thread - - auto inputStream = stream.GetInputStreamAt(0); - auto dataReader = winrt::DataReader(inputStream); - - // Load the data from the stream - uint32_t numBytesLoaded = co_await dataReader.LoadAsync(static_cast(stream.Size())); - - // Read the data as a string - winrt::hstring svgString = dataReader.ReadString(numBytesLoaded); - // Parse the size from the XamlDocument winrt::XmlDocument xmlDoc; - xmlDoc.LoadXml(svgString); + xmlDoc.LoadXml(content); if (xmlDoc) { @@ -330,11 +319,25 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering width = TryHStringToDouble(widthAttribute).value_or(0.0); } - co_return {static_cast(width), static_cast(height)}; + return {static_cast(width), static_cast(height)}; } } - co_return {}; + return {}; + } + + winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream) + { + auto inputStream = stream.GetInputStreamAt(0); + auto dataReader = winrt::DataReader(inputStream); + + // Load the data from the stream + uint32_t numBytesLoaded = co_await dataReader.LoadAsync(static_cast(stream.Size())); + + // Read the data as a string + winrt::hstring svgString = dataReader.ReadString(numBytesLoaded); + + co_return ParseSizeOfSVGImageFromString(svgString); } winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync(winrt::Uri const imageUrl, @@ -380,134 +383,102 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering if (const auto strongThis = weakThis.get()) { strongThis->m_writeAsyncOperations.push_back(storeOp); - } - - co_await storeOp; - - auto stream = dataWriter.DetachStream().try_as(); - stream.Seek(0); - - co_return stream; - - } - // Otherwise, no resolver... - if (const auto strongThis = weakThis.get()) - { - if ((!strongThis->m_enableXamlImageHandling) && (strongThis->m_listeners.size() != 0)) - { - winrt::HttpBaseProtocolFilter httpBaseProtocolFilter{}; - httpBaseProtocolFilter.AllowUI(false); - - winrt::HttpClient httpClient{httpBaseProtocolFilter}; - - auto httpStream = co_await httpClient.GetInputStreamAsync(imageUrl); - winrt::InMemoryRandomAccessStream randomAccessStream{}; - //auto copyStreamOperation = co_await winrt::RandomAccessStream::CopyAsync(httpStream, randomAccessStream); + co_await storeOp; - //strongThis->m_copyStreamOperations.push_back(copyStreamOperation); + auto stream = dataWriter.DetachStream().try_as(); + stream.Seek(0); - randomAccessStream.Seek(0); - - co_return randomAccessStream; + co_return stream; } } co_return {}; } - // Set the source of the image - winrt::IAsyncOperation XamlBuilder::SetImageSourceAsync(winrt::SvgImageSource imageSource, - winrt::IRandomAccessStream const stream) - { - imageSource.SetSourceAsync(stream); - co_return imageSource; - } - template winrt::fire_and_forget XamlBuilder::ResolveImageAsync(winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, winrt::ImageSource imageSource, ImageProperties const properties) { + auto isAutoSize{properties.isAutoSize}; + auto isSVG{properties.isImageSvg}; auto weakThis{get_weak()}; auto weakImageSource{winrt::make_weak(imageSource)}; auto weakFrameworkElement = winrt::make_weak(properties.uiElement); try { + // if image loading is handled by Xaml, we set this to true; + auto imageFiresOpenEvent{true}; // we can not do any works until stream is resolved - auto stream = co_await ResolveToStreamAsync(uri, resolvers, properties.isImageSvg); + auto stream = co_await ResolveToStreamAsync(uri, resolvers, isSVG); if (auto strongImageSource = weakImageSource.get()) { if (stream) { - // while image source is being set, we can do some other works - if (properties.isImageSvg) + imageFiresOpenEvent = false; + + // the big differences between SVG and non-SVG images are: + // 1. SVG size needs to be parsed from its data source + // 2. SVG images need to be rasterized to a specific size + if (isSVG) { - // before setting the RasterizedPixelHeight and RasterizedPixelWidth, we need to switch to the - // UI thread and wait our turn for imageSource access + auto sizeParseOp {ParseSizeOfSVGImageFromStreamAsync(stream)}; + // as size is being parsed, we can switch to the UI thread to set the source co_await wil::resume_foreground(GetDispatcher(strongImageSource)); auto svgImageSource = strongImageSource.as(); - auto status = co_await svgImageSource.SetSourceAsync(stream); - auto size{ co_await ParseSizeOfSVGImageAsync(stream)}; - if (auto strongFrameworkElement = weakFrameworkElement.get()) - { - if (status == winrt::SvgImageSourceLoadStatus::Success) - { - SetImageSource(strongFrameworkElement, svgImageSource, properties.stretch); - co_await wil::resume_foreground(GetDispatcher(strongImageSource)); - svgImageSource.RasterizePixelHeight(size.Height); - svgImageSource.RasterizePixelWidth(size.Width); - - } - } + auto size = co_await sizeParseOp; + svgImageSource.RasterizePixelHeight(size.Height); + svgImageSource.RasterizePixelWidth(size.Width); + co_await svgImageSource.SetSourceAsync(stream); } else { auto bitmapImage = imageSource.as(); - bitmapImage.SetSource(stream); + co_await bitmapImage.SetSourceAsync(stream); } - - // if (auto strongFrameworkElement = frameworkElement.get()) - //{ - // // Set the image source on the UI thread - // co_await winrt::resume_foreground(GetDispatcher(imageSource)); - // SetImageSource(strongFrameworkElement, imageSource, properties.stretch); - // } } else { - co_await wil::resume_foreground(GetDispatcher(imageSource)); - imageSource.as().UriSource(uri); - if (auto strongFrameworkElement = weakFrameworkElement.get()) + // Otherwise, no resolver... + if (auto strongThis = weakThis.get(); + (strongThis->m_enableXamlImageHandling) || (strongThis->m_listeners.size() == 0)) { - SetImageSource(strongFrameworkElement, imageSource, properties.stretch); + // If we've been explicitly told to let Xaml handle the image loading, or there are + // no listeners waiting on the image load callbacks, use Xaml to load the images + if (isSVG) + { + winrt::HttpClient httpClient; + auto getOperation = co_await httpClient.GetAsync(uri); + auto readOperation = co_await getOperation.Content().ReadAsStringAsync(); + auto size{ParseSizeOfSVGImageFromString(readOperation)}; + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + auto svgImageSource = strongImageSource.as(); + svgImageSource.RasterizePixelHeight(size.Height); + svgImageSource.RasterizePixelWidth(size.Width); + svgImageSource.UriSource(uri); + } + else + { + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + strongImageSource.as().UriSource(uri); + } + } } - - // if (auto strongThis = weakThis.get()) - // { - // strongThis->m_imageLoadTracker->MarkFailedLoadImage(imageSource); - // // Otherwise, no resolver... - // if ((m_enableXamlImageHandling) || (m_listeners.size() == 0)) - // { - // // If we've been explicitly told to let Xaml handle the image loading, or there are - // // no listeners waiting on the image load callbacks, use Xaml to load the images - // image.as().UriSource(imageUrl); - // } - // } } - } - } - catch (const std::exception& e) - { - (void)e; - } - catch (const winrt::hresult_error& e) - { - std::string message = HStringToUTF8(e.message()); + + if (auto strongThis = weakThis.get(); isAutoSize) + { + strongThis->SetAutoSize(properties.uiElement, + properties.parentElement, + properties.imageContainer, + properties.isVisible, + imageFiresOpenEvent); + } } - catch (...) + catch (...) { // Handle error if (auto strongThis = weakThis.get()) @@ -523,6 +494,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering ImageProperties const& imgProperties) { auto imageSource = CreateImageSource(imgProperties.isImageSvg); + SetImageSourceToFrameworkElement(imgProperties.uiElement, imageSource, imgProperties.stretch); ResolveImageAsync(imageUrl, resolvers, imageSource, imgProperties); return imageSource; } @@ -542,13 +514,13 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering } template - void XamlBuilder::SetImageSource(TDest const& destination, winrt::ImageSource const& imageSource, winrt::Stretch /*stretch*/) + void XamlBuilder::SetImageSourceToFrameworkElement(TDest const& destination, winrt::ImageSource const& imageSource, winrt::Stretch /*stretch*/) { destination.Source(imageSource); }; template <> - void XamlBuilder::SetImageSource(winrt::Ellipse const& destination, winrt::ImageSource const& imageSource, winrt::Stretch stretch) + void XamlBuilder::SetImageSourceToFrameworkElement(winrt::Ellipse const& destination, winrt::ImageSource const& imageSource, winrt::Stretch stretch) { winrt::ImageBrush imageBrush{}; imageBrush.ImageSource(imageSource); diff --git a/source/uwp/SharedRenderer/lib/XamlBuilder.h b/source/uwp/SharedRenderer/lib/XamlBuilder.h index 8c9eae95ef..736ff3401e 100644 --- a/source/uwp/SharedRenderer/lib/XamlBuilder.h +++ b/source/uwp/SharedRenderer/lib/XamlBuilder.h @@ -88,7 +88,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering bool imageFiresOpenEvent); template - void SetImageSource(TDest const& destination, winrt::ImageSource const& imageSource, winrt::Stretch stretch = winrt::Stretch::UniformToFill); + void SetImageSourceToFrameworkElement(TDest const& destination, winrt::ImageSource const& imageSource, winrt::Stretch stretch = winrt::Stretch::UniformToFill); template winrt::ImageSource SetImageOnUIElement(winrt::Uri const& imageUrl, @@ -109,14 +109,13 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering winrt::fire_and_forget SetSvgUriSource(winrt::SvgImageSource const imageSourceRef, winrt::Uri const uriRef); - winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageAsync(winrt::IRandomAccessStream const stream); + winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content); + + winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream); winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync( winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg); - winrt::IAsyncOperation XamlBuilder::SetImageSourceAsync( - winrt::SvgImageSource imageSource, winrt::IRandomAccessStream const stream); - template winrt::fire_and_forget ResolveImageAsync( winrt::Uri const uri, From 7bc1a7160537ec69a1dfb1a4bac41b8f2a0cc5ee Mon Sep 17 00:00:00 2001 From: Joseph Woo Date: Mon, 29 Apr 2024 18:50:18 -0700 Subject: [PATCH 3/5] fixed the spacing --- .../lib/AdaptiveImageRenderer.cpp | 79 ++++++++++--------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp index cd9b032aec..e416dac0fa 100644 --- a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp @@ -384,12 +384,12 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering { strongThis->m_writeAsyncOperations.push_back(storeOp); - co_await storeOp; + co_await storeOp; - auto stream = dataWriter.DetachStream().try_as(); - stream.Seek(0); + auto stream = dataWriter.DetachStream().try_as(); + stream.Seek(0); - co_return stream; + co_return stream; } } @@ -429,9 +429,14 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering // as size is being parsed, we can switch to the UI thread to set the source co_await wil::resume_foreground(GetDispatcher(strongImageSource)); auto svgImageSource = strongImageSource.as(); - auto size = co_await sizeParseOp; - svgImageSource.RasterizePixelHeight(size.Height); - svgImageSource.RasterizePixelWidth(size.Width); + + if (!isAutoSize) + { + auto size = co_await sizeParseOp; + svgImageSource.RasterizePixelHeight(size.Height); + svgImageSource.RasterizePixelWidth(size.Width); + } + co_await svgImageSource.SetSourceAsync(stream); } else @@ -442,41 +447,41 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering } else { - // Otherwise, no resolver... + // Otherwise, no resolver... if (auto strongThis = weakThis.get(); (strongThis->m_enableXamlImageHandling) || (strongThis->m_listeners.size() == 0)) { - // If we've been explicitly told to let Xaml handle the image loading, or there are - // no listeners waiting on the image load callbacks, use Xaml to load the images - if (isSVG) - { - winrt::HttpClient httpClient; - auto getOperation = co_await httpClient.GetAsync(uri); - auto readOperation = co_await getOperation.Content().ReadAsStringAsync(); - auto size{ParseSizeOfSVGImageFromString(readOperation)}; - co_await wil::resume_foreground(GetDispatcher(strongImageSource)); - auto svgImageSource = strongImageSource.as(); - svgImageSource.RasterizePixelHeight(size.Height); - svgImageSource.RasterizePixelWidth(size.Width); - svgImageSource.UriSource(uri); - } - else - { - co_await wil::resume_foreground(GetDispatcher(strongImageSource)); - strongImageSource.as().UriSource(uri); - } - } + // If we've been explicitly told to let Xaml handle the image loading, or there are + // no listeners waiting on the image load callbacks, use Xaml to load the images + if (isSVG) + { + winrt::HttpClient httpClient; + auto getOperation = co_await httpClient.GetAsync(uri); + auto readOperation = co_await getOperation.Content().ReadAsStringAsync(); + auto size{ParseSizeOfSVGImageFromString(readOperation)}; + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + auto svgImageSource = strongImageSource.as(); + svgImageSource.RasterizePixelHeight(size.Height); + svgImageSource.RasterizePixelWidth(size.Width); + svgImageSource.UriSource(uri); + } + else + { + co_await wil::resume_foreground(GetDispatcher(strongImageSource)); + strongImageSource.as().UriSource(uri); + } + } } } - if (auto strongThis = weakThis.get(); isAutoSize) - { - strongThis->SetAutoSize(properties.uiElement, - properties.parentElement, - properties.imageContainer, - properties.isVisible, - imageFiresOpenEvent); - } + if (auto strongThis = weakThis.get(); isAutoSize) + { + strongThis->SetAutoSize(properties.uiElement, + properties.parentElement, + properties.imageContainer, + properties.isVisible, + imageFiresOpenEvent); + } } catch (...) { @@ -494,7 +499,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering ImageProperties const& imgProperties) { auto imageSource = CreateImageSource(imgProperties.isImageSvg); - SetImageSourceToFrameworkElement(imgProperties.uiElement, imageSource, imgProperties.stretch); + SetImageSourceToFrameworkElement(imgProperties.uiElement, imageSource, imgProperties.stretch); ResolveImageAsync(imageUrl, resolvers, imageSource, imgProperties); return imageSource; } From d0771d5546e444e99e47305de01fb850c59c8b50 Mon Sep 17 00:00:00 2001 From: Joseph Woo Date: Thu, 2 May 2024 16:21:08 -0700 Subject: [PATCH 4/5] completed refactoring work --- .../lib/AdaptiveImageRenderer.cpp | 37 +++++++++++-------- source/uwp/SharedRenderer/lib/XamlBuilder.h | 13 ++++--- .../Renderer/AdaptiveCardRenderer.vcxproj | 3 ++ .../Properties/launchSettings.json | 3 +- .../Visualizer/Properties/launchSettings.json | 3 +- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp index 29fb6f08ef..e93aa2e856 100644 --- a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp @@ -500,7 +500,11 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering if (auto strongThis = weakThis.get(); isAutoSize) { strongThis->SetAutoSize( - properties.uiElement, properties.parentElement, properties.imageContainer, properties.isVisible, imageFiresOpenEvent); + properties.uiElement, + properties.parentElement, + properties.imageContainer, + properties.isVisible, + imageFiresOpenEvent); } } } @@ -514,22 +518,31 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering } } - void XamlBuilder::CreateOptionsForBitmapImageSource(winrt::Uri const& imageUrl, - winrt::AdaptiveCardResourceResolvers const& resolvers, - winrt::ImageSource const& imageSource) + void XamlBuilder::ConfigureImageSource(winrt::Uri const& imageUrl, + winrt::AdaptiveCardResourceResolvers const& resolvers, + winrt::ImageSource const& imageSource, + bool isImageSvg) { winrt::hstring schemeName = imageUrl.SchemeName(); auto hasResolver = resolvers && resolvers.Get(schemeName) != nullptr; auto externalHandling = !(m_enableXamlImageHandling || (m_listeners.size() == 0)); auto schemeNameIsData = schemeName == L"data"; - if ((hasResolver || !schemeNameIsData) && externalHandling) + if (!isImageSvg) { - imageSource.as().CreateOptions(winrt::BitmapCreateOptions::None); + if ((hasResolver || !schemeNameIsData) && externalHandling) + { + imageSource.as().CreateOptions(winrt::BitmapCreateOptions::None); + } + else if (schemeNameIsData) + { + imageSource.as().CreateOptions(winrt::BitmapCreateOptions::IgnoreImageCache); + } } - else if (schemeNameIsData) + + if ((hasResolver && externalHandling) || schemeNameIsData) { - imageSource.as().CreateOptions(winrt::BitmapCreateOptions::IgnoreImageCache); + m_imageLoadTracker->TrackImage(imageSource); } } @@ -542,10 +555,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering SetImageSourceToFrameworkElement(imgProperties.uiElement, imageSource, imgProperties.stretch); - if (!imgProperties.isImageSvg) - { - CreateOptionsForBitmapImageSource(imageUrl, resolvers, imageSource); - } + ConfigureImageSource(imageUrl, resolvers, imageSource, imgProperties.isImageSvg); ResolveImageAsync(imageUrl, resolvers, imageSource, imgProperties); @@ -604,9 +614,6 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering // If the image hasn't loaded yet if (imageFiresOpenEvent) { - // Collapse the Ellipse while the image loads, so that resizing is not noticeable - ellipse.Visibility(winrt::Visibility::Collapsed); - // Handle ImageOpened event so we can check the imageSource's size to determine if it fits in its parent // Take a weak reference to the parent to avoid circular references (Parent->Ellipse->ImageBrush->Lambda->(Parent)) auto weakParent = winrt::make_weak(parentElement); diff --git a/source/uwp/SharedRenderer/lib/XamlBuilder.h b/source/uwp/SharedRenderer/lib/XamlBuilder.h index fc6fcbd280..a5ebb8b58d 100644 --- a/source/uwp/SharedRenderer/lib/XamlBuilder.h +++ b/source/uwp/SharedRenderer/lib/XamlBuilder.h @@ -97,18 +97,19 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering winrt::ImageSource CreateImageSource(bool isImageSvg); - winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content); + winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content); - winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream); + winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream); - winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync( + winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync( winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg); - void CreateOptionsForBitmapImageSource(winrt::Uri const& imageUrl, + void ConfigureImageSource(winrt::Uri const& imageUrl, winrt::AdaptiveCardResourceResolvers const& resolvers, - winrt::ImageSource const& imageSource); + winrt::ImageSource const& imageSource, + bool isImageSvg); - template + template winrt::fire_and_forget ResolveImageAsync( winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, diff --git a/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj b/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj index 0c5667a328..31c01992be 100644 --- a/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj +++ b/source/uwp/winui3/Renderer/AdaptiveCardRenderer.vcxproj @@ -105,6 +105,7 @@ stdcpp17 Level4 true + Guard Console @@ -116,12 +117,14 @@ OleAut32.lib; %(AdditionalDependencies); + /profile /DEBUGTYPE:FIXUP %(AdditionalOptions) $(VC_LibraryPath_VC_OneCore_CurrentPlatform_spectre);%(AdditionalLibraryDirectories) _DEBUG;%(PreprocessorDefinitions) + ProgramDatabase diff --git a/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json b/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json index 34250bdbfd..a014a9c463 100644 --- a/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json +++ b/source/uwp/winui3/SimpleVisualizer/Properties/launchSettings.json @@ -4,8 +4,7 @@ "commandName": "MsixPackage" }, "SimpleVisualizer (Unpackaged)": { - "commandName": "Project", - "hotReloadEnabled": false + "commandName": "Project" } } } \ No newline at end of file diff --git a/source/uwp/winui3/Visualizer/Properties/launchSettings.json b/source/uwp/winui3/Visualizer/Properties/launchSettings.json index 609a4a56c3..98c20e9344 100644 --- a/source/uwp/winui3/Visualizer/Properties/launchSettings.json +++ b/source/uwp/winui3/Visualizer/Properties/launchSettings.json @@ -2,8 +2,7 @@ "profiles": { "AdaptiveCardVisualizer (Package)": { "commandName": "MsixPackage", - "nativeDebugging": true, - "hotReloadEnabled": false + "nativeDebugging": true }, "AdaptiveCardVisualizer (Unpackaged)": { "commandName": "Project" From f4c9d42e6f800f62682025bfa885e2641e754b21 Mon Sep 17 00:00:00 2001 From: Joseph Woo Date: Fri, 3 May 2024 16:25:14 -0700 Subject: [PATCH 5/5] adressed CR comments --- .../uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp | 12 ++++++------ source/uwp/SharedRenderer/lib/XamlBuilder.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp index e93aa2e856..e39b3c66a1 100644 --- a/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/SharedRenderer/lib/AdaptiveImageRenderer.cpp @@ -289,9 +289,9 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering adaptiveCardElement, selectAction, renderContext, frameworkElement, XamlHelpers::SupportsInteractivity(hostConfig), true); } - winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content) + winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content) { - // Parse the size from the XamlDocument + // Parse the size from the XamlDocument as XML winrt::XmlDocument xmlDoc; xmlDoc.LoadXml(content); @@ -301,7 +301,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering auto rootElement = xmlDoc.DocumentElement(); // Root element must be an SVG - if (winrt::operator==(rootElement.NodeName(), L"svg")) + if (rootElement.NodeName() == L"svg") { auto heightAttribute = rootElement.GetAttribute(L"height"); auto widthAttribute = rootElement.GetAttribute(L"width"); @@ -337,7 +337,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering // Read the data as a string winrt::hstring svgString = dataReader.ReadString(numBytesLoaded); - co_return ParseSizeOfSVGImageFromString(svgString); + co_return ParseSizeOfSVGImageFromXmlString(svgString); } winrt::IAsyncOperation XamlBuilder::ResolveToStreamAsync(winrt::Uri const imageUrl, @@ -469,7 +469,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering } else { - // Otherwise, no resolver... + // Use Xaml to load the images if (auto strongThis = weakThis.get()) { if ((strongThis->m_enableXamlImageHandling) || (strongThis->m_listeners.size() == 0)) @@ -481,7 +481,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering winrt::HttpClient httpClient; auto getOperation = co_await httpClient.GetAsync(uri); auto readOperation = co_await getOperation.Content().ReadAsStringAsync(); - auto size{ParseSizeOfSVGImageFromString(readOperation)}; + auto size{ParseSizeOfSVGImageFromXmlString(readOperation)}; co_await wil::resume_foreground(GetDispatcher(strongImageSource)); auto svgImageSource = strongImageSource.as(); svgImageSource.RasterizePixelHeight(size.Height); diff --git a/source/uwp/SharedRenderer/lib/XamlBuilder.h b/source/uwp/SharedRenderer/lib/XamlBuilder.h index a5ebb8b58d..a7075f9326 100644 --- a/source/uwp/SharedRenderer/lib/XamlBuilder.h +++ b/source/uwp/SharedRenderer/lib/XamlBuilder.h @@ -97,7 +97,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering winrt::ImageSource CreateImageSource(bool isImageSvg); - winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromString(winrt::hstring const& content); + winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content); winrt::IAsyncOperation XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream);