Skip to content

Commit

Permalink
[UWP/WinUI3 Renderer]: Discard Background Image if URI is not valid (#…
Browse files Browse the repository at this point in the history
…8968)

* ignore background image

* remove new line

* add warning to text sources load

* address pr feedback
  • Loading branch information
beervoley authored Jul 24, 2024
1 parent 4745cb6 commit 728044c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 48 deletions.
53 changes: 30 additions & 23 deletions source/uwp/SharedRenderer/lib/MediaHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,36 +192,43 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::MediaHelpers
if (const auto search = supportedCaptionTypes.find(captionSource.MimeType());
search != supportedCaptionTypes.end())
{
const auto timedTextURL = GetUrlFromString(renderContext.HostConfig(), captionSource.Url());

winrt::IAdaptiveCardResourceResolver resourceResolver{nullptr};
if (const auto resourceResolvers = renderContext.ResourceResolvers())
if (const auto timedTextURL = GetUrlFromString(renderContext.HostConfig(), captionSource.Url()))
{
resourceResolver = resourceResolvers.Get(timedTextURL.SchemeName());
}

const auto timedTextSrcResolvedHelper =
[label = captionSource.Label()](winrt::TimedTextSource const& /*sender*/,
winrt::TimedTextSourceResolveResultEventArgs const& args)
{
if (!args.Error())
winrt::IAdaptiveCardResourceResolver resourceResolver{ nullptr };
if (const auto resourceResolvers = renderContext.ResourceResolvers())
{
args.Tracks().GetAt(0).Label(label);
resourceResolver = resourceResolvers.Get(timedTextURL.SchemeName());
}

const auto timedTextSrcResolvedHelper =
[label = captionSource.Label()](winrt::TimedTextSource const& /*sender*/,
winrt::TimedTextSourceResolveResultEventArgs const& args)
{
if (!args.Error())
{
args.Tracks().GetAt(0).Label(label);
}
};
if (!resourceResolver)
{
const auto timedTextSrc = winrt::TimedTextSource::CreateFromUri(timedTextURL);
timedTextSrc.Resolved(timedTextSrcResolvedHelper);
mediaSrc.ExternalTimedTextSources().Append(timedTextSrc);
}
else
{
auto args = winrt::make<winrt::implementation::AdaptiveCardGetResourceStreamArgs>(timedTextURL);
const auto randomAccessStream = resourceResolver.GetResourceStreamAsync(args);
auto timedTextSrc = winrt::TimedTextSource::CreateFromStream(randomAccessStream.get());
timedTextSrc.Resolved(timedTextSrcResolvedHelper);
mediaSrc.ExternalTimedTextSources().Append(timedTextSrc);
}
};
if (!resourceResolver)
{
const auto timedTextSrc = winrt::TimedTextSource::CreateFromUri(timedTextURL);
timedTextSrc.Resolved(timedTextSrcResolvedHelper);
mediaSrc.ExternalTimedTextSources().Append(timedTextSrc);
}
else
{
auto args = winrt::make<winrt::implementation::AdaptiveCardGetResourceStreamArgs>(timedTextURL);
const auto randomAccessStream = resourceResolver.GetResourceStreamAsync(args);
auto timedTextSrc = winrt::TimedTextSource::CreateFromStream(randomAccessStream.get());
timedTextSrc.Resolved(timedTextSrcResolvedHelper);
mediaSrc.ExternalTimedTextSources().Append(timedTextSrc);
renderContext.AddWarning(winrt::WarningStatusCode::AssetLoadFailed,
L"Specified URI:" + captionSource.Url() + L" for Media Text Sources is not valid. Text sources loading has failed.");
}
}
}
Expand Down
35 changes: 33 additions & 2 deletions source/uwp/SharedRenderer/lib/Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "AdaptiveSubmitActionRenderer.h"
#include "AdaptiveToggleVisibilityActionRenderer.h"
#include "AdaptiveExecuteActionRenderer.h"
#include <windows.foundation.h>

std::string WStringToString(std::wstring_view in)
{
Expand Down Expand Up @@ -535,19 +536,49 @@ bool IsBackgroundImageValid(winrt::AdaptiveBackgroundImage const& backgroundImag
return false;
}

winrt::Uri UriTryCreate(winrt::hstring const &uriString, winrt::hstring const& baseUriString = L"")
{
auto factory = winrt::
get_activation_factory<winrt::Windows::Foundation::Uri, winrt::Windows::Foundation::IUriRuntimeClassFactory>();
auto abiFactory = static_cast<ABI::Windows::Foundation::IUriRuntimeClassFactory *>(winrt::get_abi(factory));

winrt::Windows::Foundation::Uri uri{nullptr};
HRESULT hr = S_OK;
if (baseUriString.empty())
{
hr = abiFactory->CreateUri(
static_cast<HSTRING>(winrt::get_abi(uriString)),
reinterpret_cast<ABI::Windows::Foundation::IUriRuntimeClass**>(winrt::put_abi(uri)));
}
else
{
hr = abiFactory->CreateWithRelativeUri(
static_cast<HSTRING>(winrt::get_abi(baseUriString)),
static_cast<HSTRING>(winrt::get_abi(uriString)),
reinterpret_cast<ABI::Windows::Foundation::IUriRuntimeClass**>(winrt::put_abi(uri)));
}

if (FAILED(hr))
{
return winrt::Windows::Foundation::Uri { nullptr };
}

return uri;
}

winrt::Uri GetUrlFromString(winrt::AdaptiveHostConfig const& hostConfig, winrt::hstring const& urlString)
{
winrt::Uri uri{nullptr};

if (const auto uriFromAbsoluteUri = winrt::Uri{urlString})
if (const auto uriFromAbsoluteUri = UriTryCreate(urlString))
{
return uriFromAbsoluteUri;
}
else
{
winrt::hstring imageBaseUrl = hostConfig.ImageBaseUrl();

if (const auto uriFromRelativeUri = winrt::Uri{imageBaseUrl, urlString})
if (const auto uriFromRelativeUri = UriTryCreate(urlString, imageBaseUrl))
{
return uriFromRelativeUri;
}
Expand Down
53 changes: 30 additions & 23 deletions source/uwp/SharedRenderer/lib/XamlHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,37 +358,44 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
winrt::AdaptiveRenderContext const& renderContext)
{
// Creates the background image for all fill modes
auto tileControl = winrt::make<winrt::implementation::TileControl>();
auto imageUrl = GetUrlFromString(renderContext.HostConfig(), adaptiveBackgroundImage.Url());
bool IsSvg = IsSvgImage(imageUrl);

// In order to reuse the image creation code paths, we simply create an adaptive card
// image element and then build that into xaml and apply to the root.
if (const auto backgroundImage = CreateBackgroundImage(renderContext, tileControl, IsSvg, imageUrl))
if (const auto imageUrl = GetUrlFromString(renderContext.HostConfig(), adaptiveBackgroundImage.Url()))
{
// Set IsEnabled to false to avoid generating a tab stop for the background image tile control
tileControl.IsEnabled(false);
tileControl.BackgroundImage(adaptiveBackgroundImage);
if (!IsSvg)
auto tileControl = winrt::make<winrt::implementation::TileControl>();
bool IsSvg = IsSvgImage(imageUrl);

// In order to reuse the image creation code paths, we simply create an adaptive card
// image element and then build that into xaml and apply to the root.
if (const auto backgroundImage = CreateBackgroundImage(renderContext, tileControl, IsSvg, imageUrl))
{
tileControl.LoadImageBrush(backgroundImage);
}
// Set IsEnabled to false to avoid generating a tab stop for the background image tile control
tileControl.IsEnabled(false);
tileControl.BackgroundImage(adaptiveBackgroundImage);
if (!IsSvg)
{
tileControl.LoadImageBrush(backgroundImage);
}

XamlHelpers::AppendXamlElementToPanel(tileControl, rootPanel);
XamlHelpers::AppendXamlElementToPanel(tileControl, rootPanel);

// The overlay applied to the background image is determined by a resouce, so create
// the overlay if that resources exists
auto resourceDictionary = renderContext.OverrideStyles();
if (const auto backgroundOverlayBrush =
// The overlay applied to the background image is determined by a resouce, so create
// the overlay if that resources exists
auto resourceDictionary = renderContext.OverrideStyles();
if (const auto backgroundOverlayBrush =
XamlHelpers::TryGetResourceFromResourceDictionaries(resourceDictionary, c_BackgroundImageOverlayBrushKey)
.try_as<winrt::Brush>())
{
winrt::Rectangle overlayRectangle;
overlayRectangle.Fill(backgroundOverlayBrush);
.try_as<winrt::Brush>())
{
winrt::Rectangle overlayRectangle;
overlayRectangle.Fill(backgroundOverlayBrush);

XamlHelpers::AppendXamlElementToPanel(overlayRectangle, rootPanel);
XamlHelpers::AppendXamlElementToPanel(overlayRectangle, rootPanel);
}
}
}
else
{
renderContext.AddWarning(winrt::WarningStatusCode::AssetLoadFailed,
L"Specified URI:" + adaptiveBackgroundImage.Url() + L" for background image is not valid. Image loading has failed.");
}
}

std::tuple<winrt::UIElement, winrt::IAdaptiveCardElement> RenderFallback(winrt::IAdaptiveCardElement const& currentElement,
Expand Down
12 changes: 12 additions & 0 deletions source/uwp/UWPUnitTests/RenderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,18 @@ public async Task MaxActionsWarnings()
Assert.AreEqual("Some actions were moved to an overflow menu due to exceeding the maximum number of actions allowed", renderedCard.Warnings[0].Message);

}
[TestMethod]
public async Task FaultyBackgroundImageRenderTest()
{
AdaptiveCard card = new AdaptiveCard();
AdaptiveBackgroundImage backgroundImage = new AdaptiveBackgroundImage();
backgroundImage.Url = "${myBackgroundImage}";
card.BackgroundImage = backgroundImage;
var renderedCard = await RenderOnUIThread(card);
Assert.AreEqual(0, renderedCard.Errors.Count);
Assert.AreEqual(1, renderedCard.Warnings.Count);
Assert.AreEqual("Specified URI:${myBackgroundImage} for background image is not valid. Image loading has failed.", renderedCard.Warnings[0].Message);
}

public async Task<RenderedAdaptiveCard> RenderOnUIThread(AdaptiveCard card, AdaptiveHostConfig hostConfig = null, bool overflowMaxActions = false)
{
Expand Down

0 comments on commit 728044c

Please sign in to comment.