Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

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

Merged
merged 4 commits into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 ...
activa marked this conversation as resolved.
Show resolved Hide resolved
{
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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
23 changes: 19 additions & 4 deletions Xamarin.Forms.Platform.UAP/FontExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,27 @@ public static FontFamily ToFontFamily(this string fontFamily)

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
activa marked this conversation as resolved.
Show resolved Hide resolved
Internals.Log.Warning("Font",$"Error loading font {fontFile}: {ex.Message}");
return null;
activa marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
26 changes: 18 additions & 8 deletions Xamarin.Forms.Platform.UAP/FontImageSourceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,19 @@ public sealed class FontImageSourceHandler : IImageSourceHandler, IIconElementHa
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,
Expand All @@ -44,7 +54,7 @@ public sealed class FontImageSourceHandler : IImageSourceHandler, IIconElementHa

// offset by 1 as we added a 1 inset
var x = (float)layout.DrawBounds.X * -1;

ds.DrawTextLayout(layout, x, 1f, iconcolor);
}

Expand All @@ -65,10 +75,10 @@ public Task<Microsoft.UI.Xaml.Controls.IconSource> LoadIconSourceAsync(ImageSour
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);
Expand All @@ -87,10 +97,10 @@ public Task<IconElement> LoadIconElementAsync(ImageSource imagesource, Cancellat
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);
Expand Down