Skip to content

Commit

Permalink
feat(wasm): BitmapImage now supports scale qualifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
ebariche committed Aug 3, 2020
1 parent 091a465 commit b14ee4d
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 34 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 5 additions & 3 deletions src/SamplesApp/SamplesApp.Shared/SamplesApp.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
</Page>
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\FluentIcon_Medium.scale-100.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\FluentIcon_Medium.scale-150.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\FluentIcon_Medium.scale-200.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\FluentIcon_Medium.scale-300.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\FluentIcon_Medium.scale-400.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\home.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\Icons\play.png" />
<Content Include="$(MSBuildThisFileDirectory)Assets\lockscreenlogo.scale-200.png" />
Expand All @@ -65,7 +70,4 @@
<DependentUpon>HttpUnitTests.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)Assets\Icons\" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Private.Infrastructure;
using Windows.Foundation;
using Windows.Graphics.Display;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Foundation;

namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls
{
Expand Down Expand Up @@ -49,5 +50,49 @@ public async Task When_Fixed_Height_And_Stretch_Uniform()

TestServices.WindowHelper.WindowContent = null;
}

#if __WASM__
[TestMethod]
[RunsOnUIThread]
public async Task When_Resource_Has_Scale_Qualifier()
{
var scales = new List<ResolutionScale>()
{
ResolutionScale.Scale100Percent,
ResolutionScale.Scale150Percent,
ResolutionScale.Scale200Percent,
ResolutionScale.Scale300Percent,
ResolutionScale.Scale400Percent,
ResolutionScale.Scale500Percent,
};

try
{
foreach (var scale in scales)
{
var imageOpened = new TaskCompletionSource<bool>();

var source = new BitmapImage(new Uri("ms-appx:///Assets/Icons/FluentIcon_Medium.png"));
source.ScaleOverride = scale;

var image = new Image { Height = 24, Width = 24, Stretch = Stretch.Uniform, Source = source };
image.ImageOpened += (s, e) => imageOpened.TrySetResult(true);
image.ImageFailed += (s, e) => imageOpened.TrySetResult(false);

TestServices.WindowHelper.WindowContent = image;

await TestServices.WindowHelper.WaitForIdle();

var result = await imageOpened.Task;

Assert.IsTrue(result);
}
}
finally
{
TestServices.WindowHelper.WindowContent = null;
}
}
#endif
}
}
30 changes: 0 additions & 30 deletions src/Uno.UI/UI/Xaml/Media/ImageSource.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,36 +50,6 @@ private bool TryOpenSourceLegacy(out ImageData img)
return true;
}

var url = WebUri;
if (url != null)
{
string value;
if (url.IsAbsoluteUri)
{
value = url.Scheme switch
{
// Local files are assumed as coming from the remoter server
"file" when UNO_BOOTSTRAP_APP_BASE == null => url.PathAndQuery,
"file" => UNO_BOOTSTRAP_APP_BASE + "/" + url.PathAndQuery,
_ => url.AbsoluteUri
};
}
else
{
value = UNO_BOOTSTRAP_APP_BASE == null
? url.OriginalString
: UNO_BOOTSTRAP_APP_BASE + "/" + url.OriginalString;
}


img = new ImageData
{
Kind = ImageDataKind.Url,
Value = value
};
return true;
}

img = default;
return false;
}
Expand Down
142 changes: 142 additions & 0 deletions src/Uno.UI/UI/Xaml/Media/Imaging/BitmapImage.wasm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Uno.Foundation;
using Windows.Graphics.Display;

using Path = global::System.IO.Path;

namespace Windows.UI.Xaml.Media.Imaging
{
public sealed partial class BitmapImage : BitmapSource
{
private static readonly string UNO_BOOTSTRAP_APP_BASE = Environment.GetEnvironmentVariable(nameof(UNO_BOOTSTRAP_APP_BASE));

internal ResolutionScale? ScaleOverride { get; set; }

private protected override bool TryOpenSourceAsync(int? targetWidth, int? targetHeight, out Task<ImageData> asyncImage)
{
var uri = WebUri;

if (uri != null)
{
var hasFileScheme = uri.IsAbsoluteUri && uri.Scheme == "file";

// Local files are assumed as coming from the remote server
var newUri = hasFileScheme switch
{
true => new Uri(uri.PathAndQuery.TrimStart('/'), UriKind.Relative),
_ => uri
};

asyncImage = AssetResolver.ResolveImageAsync(newUri, ScaleOverride);
return true;
}

asyncImage = default;
return false;
}

internal static class AssetResolver
{
private static readonly Lazy<Task<HashSet<string>>> _assets = new Lazy<Task<HashSet<string>>>(() => GetAssets());

private static async Task<HashSet<string>> GetAssets()
{
var host = WebAssemblyRuntime.InvokeJS("window.location.host");
var scheme = WebAssemblyRuntime.InvokeJS("window.location.protocol");
var path = !string.IsNullOrEmpty(UNO_BOOTSTRAP_APP_BASE) ? $"{UNO_BOOTSTRAP_APP_BASE}/uno-assets.txt" : "uno-assets.txt";

var httpClient = new HttpClient();

var assets = await httpClient.GetStringAsync($"{scheme}//{host}/{path}");

return new HashSet<string>(Regex.Split(assets, "\r\n|\r|\n"));
}

public static async Task<ImageData> ResolveImageAsync(Uri uri, ResolutionScale? scaleOverride)
{
try
{
// ms-appx comes in as a relative path
if (uri.IsAbsoluteUri)
{
if (uri.Scheme == "http" || uri.Scheme == "https")
{
return new ImageData() { Kind = ImageDataKind.Url, Value = uri.AbsoluteUri };
}

// TODO: Implement ms-appdata
return new ImageData();
}
else
{
var assets = await _assets.Value;

return new ImageData() { Kind = ImageDataKind.Url, Value = GetScaledPath(uri.OriginalString, assets, scaleOverride) };
}
}
catch (Exception e)
{
return new ImageData() { Kind = ImageDataKind.Error, Error = e };
}
}

private static string GetScaledPath(string path, HashSet<string> assets, ResolutionScale? scaleOverride)
{
if (!string.IsNullOrEmpty(path))
{
var directory = Path.GetDirectoryName(path);
var filename = Path.GetFileNameWithoutExtension(path);
var extension = Path.GetExtension(path);

var resolutionScale = scaleOverride == null ? (int)DisplayInformation.GetForCurrentView().ResolutionScale : (int)scaleOverride;

for (var i = KnownScales.Length - 1; i >= 0; i--)
{
var probeScale = KnownScales[i];

if (resolutionScale >= probeScale)
{
var filePath = Path.Combine(directory, $"{filename}.scale-{probeScale}{extension}");

if (assets.Contains(filePath))
{
return !string.IsNullOrEmpty(UNO_BOOTSTRAP_APP_BASE) ?
$"{UNO_BOOTSTRAP_APP_BASE}/{filePath}" :
filePath;
}
}
}

return !string.IsNullOrEmpty(UNO_BOOTSTRAP_APP_BASE) ? $"{UNO_BOOTSTRAP_APP_BASE}/{path}" : path;
}

return path;
}

private static readonly int[] KnownScales =
{
(int)ResolutionScale.Scale100Percent,
(int)ResolutionScale.Scale120Percent,
(int)ResolutionScale.Scale125Percent,
(int)ResolutionScale.Scale140Percent,
(int)ResolutionScale.Scale150Percent,
(int)ResolutionScale.Scale160Percent,
(int)ResolutionScale.Scale175Percent,
(int)ResolutionScale.Scale180Percent,
(int)ResolutionScale.Scale200Percent,
(int)ResolutionScale.Scale225Percent,
(int)ResolutionScale.Scale250Percent,
(int)ResolutionScale.Scale300Percent,
(int)ResolutionScale.Scale350Percent,
(int)ResolutionScale.Scale400Percent,
(int)ResolutionScale.Scale450Percent,
(int)ResolutionScale.Scale500Percent
};
}
}
}

0 comments on commit b14ee4d

Please sign in to comment.