[UWP] Fix crash when specifying non-embedded font families (fixes #12153) (#12171)

* Fix crash on UWP when specifiying non-embedded font families

* Fix FontImageSourceHandler to handle non-embedded fonts

* Add logging when font fails to load on UWP

* - add ui test

Co-authored-by: Philippe Leybaert <pleybaert@agileassets.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
This commit is contained in:
Philippe Leybaert 2020-09-28 13:05:58 -05:00 коммит произвёл GitHub
Родитель 4e847ff3f1
Коммит 0be2136844
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 89 добавлений и 12 удалений

Просмотреть файл

@ -0,0 +1,51 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.ManualReview)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 12153, "Setting FontFamily to pre-installed fonts on UWP crashes", PlatformAffected.UWP)]
public class Issue12153 : TestContentPage // or TestMasterDetailPage, etc ...
{
protected override void Init()
{
Content = new StackLayout()
{
Children =
{
// Setting the font family to "Tahoma" or any other built-in Windows font would crash on UWP
new Label() { Text = "Four bell icons should be visible below and it shouldn't crash on UWP", FontFamily = "Tahoma", Margin = new Thickness(10), AutomationId = "Success"},
new Label { FontFamily = "FontAwesome", FontSize = 50, TextColor = Color.Black, Text = "\xf0f3" },
new Label { FontFamily = "fa-regular-400.ttf", FontSize = 50, TextColor = Color.Black, Text = "\xf0f3" },
new Image() { Source = new FontImageSource() { FontFamily = "FontAwesome", Glyph = "\xf0f3", Color = Color.Black, Size = 50}, HorizontalOptions = LayoutOptions.Start},
new Image() { Source = new FontImageSource() { FontFamily = "fa-regular-400.ttf", Glyph = "\xf0f3", Color = Color.Black, Size = 50}, HorizontalOptions = LayoutOptions.Start},
new Label() { Text = "This text should be shown using the Lobster font, which is included as an asset", FontFamily = "Lobster-Regular", Margin = new Thickness(10)},
new Label() { Text = "Below a PLAY icon should be visible (if the \"Segoe MDL2 Assets\" font is installed)", Margin = new Thickness(10)},
new Image() { Source = new FontImageSource{Glyph = "\xe102",FontFamily = "Segoe MDL2 Assets", Size = 50, Color = Color.Green}, HorizontalOptions = LayoutOptions.Start },
}
};
}
#if UITEST
[Test]
public void InvalidFontDoesntCauseAppToCrash()
{
RunningApp.WaitForElement("Success");
}
#endif
}
}

Просмотреть файл

@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12153.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10324.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Github9536.xaml.cs">
<DependentUpon>Github9536.xaml</DependentUpon>

Просмотреть файл

@ -109,12 +109,27 @@ namespace Xamarin.Forms.Platform.UWP
static string FindFontFamilyName(string fontFile)
{
using (var fontSet = new CanvasFontSet(new Uri(fontFile)))
try
{
if (fontSet.Fonts.Count == 0)
return null;
var fontUri = new Uri(fontFile, UriKind.RelativeOrAbsolute);
return fontSet.GetPropertyValues(CanvasFontPropertyIdentifier.FamilyName).FirstOrDefault().Value;
// CanvasFontSet only supports ms-appx:// and ms-appdata:// font URIs
if (fontUri.IsAbsoluteUri && (fontUri.Scheme == "ms-appx" || fontUri.Scheme == "ms-appdata"))
{
using (var fontSet = new CanvasFontSet(fontUri))
{
if (fontSet.Fonts.Count != 0)
return fontSet.GetPropertyValues(CanvasFontPropertyIdentifier.FamilyName).FirstOrDefault().Value;
}
}
return null;
}
catch(Exception ex)
{
// the CanvasFontSet constructor can throw an exception in case something's wrong with the font. It should not crash the app
Internals.Log.Warning("Font",$"Error loading font {fontFile}: {ex.Message}");
return null;
}
}

Просмотреть файл

@ -23,9 +23,19 @@ namespace Xamarin.Forms.Platform.UWP
var device = CanvasDevice.GetSharedDevice();
var dpi = Math.Max(_minimumDpi, Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi);
// There's really no perfect solution to handle font families with fallbacks (comma-separated)
// So if the font family has fallbacks, only the first one is taken, because CanvasTextFormat
// only supports one font family
var fontFamily = fontsource.FontFamily.ToFontFamily();
var allFamilies = fontFamily.Source.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (allFamilies.Length < 1)
return null;
var textFormat = new CanvasTextFormat
{
FontFamily = fontsource.FontFamily.ToFontFamily().Source,
FontFamily = allFamilies[0],
FontSize = (float)fontsource.Size,
HorizontalAlignment = CanvasHorizontalAlignment.Center,
VerticalAlignment = CanvasVerticalAlignment.Center,
@ -44,7 +54,7 @@ namespace Xamarin.Forms.Platform.UWP
// offset by 1 as we added a 1 inset
var x = (float)layout.DrawBounds.X * -1;
ds.DrawTextLayout(layout, x, 1f, iconcolor);
}
@ -65,10 +75,10 @@ namespace Xamarin.Forms.Platform.UWP
Foreground = fontImageSource.Color.ToBrush()
};
var uwpFontFamily = fontImageSource.FontFamily.ToFontFamily().Source;
var uwpFontFamily = fontImageSource.FontFamily.ToFontFamily();
if (!string.IsNullOrEmpty(uwpFontFamily))
((WFontIconSource)image).FontFamily = new FontFamily(uwpFontFamily);
if (!string.IsNullOrEmpty(uwpFontFamily.Source))
((WFontIconSource)image).FontFamily = uwpFontFamily;
}
return Task.FromResult(image);
@ -87,10 +97,10 @@ namespace Xamarin.Forms.Platform.UWP
Foreground = fontImageSource.Color.ToBrush()
};
var uwpFontFamily = fontImageSource.FontFamily.ToFontFamily().Source;
var uwpFontFamily = fontImageSource.FontFamily.ToFontFamily();
if (!string.IsNullOrEmpty(uwpFontFamily))
((FontIcon)image).FontFamily = new FontFamily(uwpFontFamily);
if (!string.IsNullOrEmpty(uwpFontFamily.Source))
((FontIcon)image).FontFamily = uwpFontFamily;
}
return Task.FromResult(image);