diff --git a/src/Core/src/Fonts/FontManager.Windows.cs b/src/Core/src/Fonts/FontManager.Windows.cs index 6973f61ea17e..5090dd7b0863 100644 --- a/src/Core/src/Fonts/FontManager.Windows.cs +++ b/src/Core/src/Fonts/FontManager.Windows.cs @@ -5,6 +5,8 @@ using System.IO; using Microsoft.Extensions.Logging; using Microsoft.Graphics.Canvas.Text; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Storage; using Microsoft.UI.Xaml.Media; namespace Microsoft.Maui @@ -146,16 +148,20 @@ IEnumerable GetAllFontPossibilities(string fontFamily) { var fontUri = new Uri(fontFile, UriKind.RelativeOrAbsolute); - // CanvasFontSet only supports ms-appx:// and ms-appdata:// font URIs - if (fontUri.IsAbsoluteUri && (fontUri.Scheme == "ms-appx" || fontUri.Scheme == "ms-appdata")) + // unpackaged apps can't load files using packaged schemes + if (!AppInfoUtils.IsPackagedApp) { - using (var fontSet = new CanvasFontSet(fontUri)) + var path = fontUri.AbsolutePath.TrimStart('/'); + if (FileSystemUtils.TryGetAppPackageFileUri(path, out var uri)) + fontUri = new Uri(uri, UriKind.RelativeOrAbsolute); + } + + using (var fontSet = new CanvasFontSet(fontUri)) + { + if (fontSet.Fonts.Count != 0) { - if (fontSet.Fonts.Count != 0) - { - var props = fontSet.GetPropertyValues(CanvasFontPropertyIdentifier.FamilyName); - return props.Length == 0 ? null : props[0].Value; - } + var props = fontSet.GetPropertyValues(CanvasFontPropertyIdentifier.FamilyName); + return props.Length == 0 ? null : props[0].Value; } } diff --git a/src/Core/tests/DeviceTests/Core.DeviceTests.csproj b/src/Core/tests/DeviceTests/Core.DeviceTests.csproj index 38b4ce0f3b8a..f9609cc3b58f 100644 --- a/src/Core/tests/DeviceTests/Core.DeviceTests.csproj +++ b/src/Core/tests/DeviceTests/Core.DeviceTests.csproj @@ -17,6 +17,15 @@ 1 + + + + + @@ -45,10 +54,10 @@ - + diff --git a/src/Core/tests/DeviceTests/Platforms/Windows/Assets/Fonts/insubfolder.ttf b/src/Core/tests/DeviceTests/Platforms/Windows/Assets/Fonts/insubfolder.ttf new file mode 100644 index 000000000000..051a88fe379a Binary files /dev/null and b/src/Core/tests/DeviceTests/Platforms/Windows/Assets/Fonts/insubfolder.ttf differ diff --git a/src/Core/tests/DeviceTests/Services/FontManagerTests.Windows.cs b/src/Core/tests/DeviceTests/Services/FontManagerTests.Windows.cs new file mode 100644 index 000000000000..75d75650c1a8 --- /dev/null +++ b/src/Core/tests/DeviceTests/Services/FontManagerTests.Windows.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Maui.DeviceTests; + +public partial class FontManagerTests : TestBase +{ + [Theory] + [InlineData("dokdo_regular", "ms-appx:///dokdo_regular.ttf#Dokdo")] + [InlineData("dokdo_regular.ttf", "ms-appx:///dokdo_regular.ttf#Dokdo")] + [InlineData("dokdo_regular#dokdo", "ms-appx:///dokdo_regular.ttf#Dokdo")] + [InlineData("dokdo_regular.ttf#dokdo", "ms-appx:///dokdo_regular.ttf#Dokdo")] + [InlineData("myalias", "ms-appx:///dokdo_regular.ttf#Dokdo")] + public Task CanLoadFonts(string fontName, string actualFontFamily) => + InvokeOnMainThreadAsync(() => + { + var registrar = new FontRegistrar(fontLoader: null); + registrar.Register("dokdo_regular.ttf", "myalias"); + var manager = new FontManager(registrar); + + var actual = manager.GetFontFamily(Font.OfSize(fontName, 12, FontWeight.Regular)); + + Assert.Equal(actualFontFamily, actual.Source); + }); + + // TODO: this is not going to work in unpackaged + [Fact] + public Task CanLoadEmbeddedFont() => + InvokeOnMainThreadAsync(() => + { + var registrar = new FontRegistrar(new EmbeddedFontLoader()); + registrar.Register("dokdo_regular.ttf", "myalias", GetType().Assembly); + var manager = new FontManager(registrar); + + var actual = manager.GetFontFamily(Font.OfSize("myalias", 12, FontWeight.Regular)); + + Assert.Equal("ms-appdata:///local/fonts/dokdo_regular.ttf#Dokdo", actual.Source); + }); +} diff --git a/src/Essentials/src/FileSystem/FileSystem.uwp.cs b/src/Essentials/src/FileSystem/FileSystem.uwp.cs index 9719ed661fef..9146e54fa71d 100644 --- a/src/Essentials/src/FileSystem/FileSystem.uwp.cs +++ b/src/Essentials/src/FileSystem/FileSystem.uwp.cs @@ -50,31 +50,6 @@ Task PlatformAppPackageFileExistsAsync(string filename) } } - static partial class FileSystemUtils - { - public static bool AppPackageFileExists(string filename) - { - var file = PlatformGetFullAppPackageFilePath(filename); - return File.Exists(file); - } - - public static string PlatformGetFullAppPackageFilePath(string filename) - { - if (filename == null) - throw new ArgumentNullException(nameof(filename)); - - filename = NormalizePath(filename); - - string root; - if (AppInfoUtils.IsPackagedApp) - root = Package.Current.InstalledLocation.Path; - else - root = AppContext.BaseDirectory; - - return Path.Combine(root, filename); - } - } - public partial class FileBase { internal FileBase(IStorageFile file) diff --git a/src/Essentials/src/FileSystem/FileSystemUtils.uwp.cs b/src/Essentials/src/FileSystem/FileSystemUtils.uwp.cs new file mode 100644 index 000000000000..9d2cd968f76d --- /dev/null +++ b/src/Essentials/src/FileSystem/FileSystemUtils.uwp.cs @@ -0,0 +1,52 @@ +#nullable enable +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Microsoft.Maui.ApplicationModel; +using Package = Windows.ApplicationModel.Package; + +namespace Microsoft.Maui.Storage +{ + static partial class FileSystemUtils + { + public static bool AppPackageFileExists(string filename) + { + var file = PlatformGetFullAppPackageFilePath(filename); + return File.Exists(file); + } + + public static string PlatformGetFullAppPackageFilePath(string filename) + { + if (filename is null) + throw new ArgumentNullException(nameof(filename)); + + filename = NormalizePath(filename); + + string root; + if (AppInfoUtils.IsPackagedApp) + root = Package.Current.InstalledLocation.Path; + else + root = AppContext.BaseDirectory; + + return Path.Combine(root, filename); + } + + public static bool TryGetAppPackageFileUri(string filename, [NotNullWhen(true)] out string? uri) + { + var path = PlatformGetFullAppPackageFilePath(filename); + + if (File.Exists(path)) + { + if (AppInfoUtils.IsPackagedApp) + uri = $"ms-appx:///{filename.Replace('\\', '/')}"; + else + uri = $"file:///{path.Replace('\\', '/')}"; + + return true; + } + + uri = null; + return false; + } + } +}