Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty Font Family Name Crashes App #17495

Open
projectinaadmin opened this issue Nov 13, 2024 · 2 comments
Open

Empty Font Family Name Crashes App #17495

projectinaadmin opened this issue Nov 13, 2024 · 2 comments
Labels
bug by-design The behavior reported in the issue is actually correct.

Comments

@projectinaadmin
Copy link

Describe the bug

Updated to Avalonia 11.2

I have a font that i embed in a Styles dictionary as follows

<FontFamily x:Key="AlternateFont">avares://MyUILibrary/Implementation/Fonts/Roboto#</FontFamily>

I then bind this to a Text Block as follows:

<!-- Base Text block style Title --> <Style Selector="TextBlock"> <Setter Property="Foreground" Value="{DynamicResource MainForegroundBrush}" /> <Setter Property="FontSize" Value="{DynamicResource DefaultFontSize}" /> <Setter Property="ToolTip.ShowDelay" Value="{DynamicResource TooltipDelay}" /> <Setter Property="FontFamily" Value="{DynamicResource AlternateFont}" /> </Style>
My understanding is that the # character will basically import all TTF files such as Roboto-Bold, Roboto-Italic etc.

In the new version I start the application and I get the following error:

Value cannot be null. (Parameter 'name')
at Avalonia.Media.FontFamily..ctor(Uri baseUri, String name) at Avalonia.Media.FontFamily..ctor(String name) at Avalonia.Media.Typeface..ctor(String fontFamilyName, FontStyle style, FontWeight weight, FontStretch stretch) at Avalonia.Media.Fonts.EmbeddedFontCollection.TryGetGlyphTypeface(String familyName, FontStyle style, FontWeight weight, FontStretch stretch, IGlyphTypeface& glyphTypeface) at Avalonia.Media.FontManager.TryGetGlyphTypefaceByKeyAndName(Typeface typeface, FontFamilyKey key, String familyName, IGlyphTypeface& glyphTypeface) at Avalonia.Media.FontManager.TryGetGlyphTypeface(Typeface typeface, IGlyphTypeface& glyphTypeface) at Avalonia.Media.Typeface.get_GlyphTypeface() at Avalonia.Media.TextFormatting.TextRunProperties.get_CachedGlyphTypeface() at Avalonia.Media.TextFormatting.TextCharacters.CreateShapeableRun(ReadOnlyMemory1 text, TextRunProperties defaultProperties, SByte biDiLevel, FontManager fontManager, TextRunProperties& previousProperties)
at Avalonia.Media.TextFormatting.TextCharacters.GetShapeableCharacters(ReadOnlyMemory1 text, SByte biDiLevel, FontManager fontManager, TextRunProperties& previousProperties, RentedList1 results)
at Avalonia.Media.TextFormatting.TextFormatterImpl.CoalesceLevels(IReadOnlyList1 textCharacters, ReadOnlySpan1 levels, FontManager fontManager, RentedList1 processedRuns) at Avalonia.Media.TextFormatting.TextFormatterImpl.ShapeTextRuns(IReadOnlyList1 textRuns, TextParagraphProperties paragraphProperties, FormattingObjectPool objectPool, FontManager fontManager, FlowDirection& resolvedFlowDirection)
at Avalonia.Media.TextFormatting.TextFormatterImpl.FormatLine(ITextSource textSource, Int32 firstTextSourceIndex, Double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak)
at Avalonia.Media.TextFormatting.TextLayout.CreateTextLines()
at Avalonia.Media.TextFormatting.TextLayout..ctor(ITextSource textSource, TextParagraphProperties paragraphProperties, TextTrimming textTrimming, Double maxWidth, Double maxHeight, Int32 maxLines)
at Avalonia.Controls.TextBlock.CreateTextLayout(String text)
at Avalonia.Controls.TextBlock.get_TextLayout()
at Avalonia.Controls.TextBlock.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at Avalonia.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
at Avalonia.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at Avalonia.Controls.Grid.MeasureOverride(Size constraint)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at Avalonia.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
at Avalonia.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at Avalonia.Controls.Grid.MeasureOverride(Size constraint)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.LayoutHelper.MeasureChild(Layoutable control, Size availableSize, Thickness padding, Thickness borderThickness)
at Avalonia.Controls.Presenters.ContentPresenter.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.LayoutHelper.MeasureChild(Layoutable control, Size availableSize, Thickness padding, Thickness borderThickness)
at Avalonia.Controls.Presenters.ContentPresenter.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.LayoutHelper.MeasureChild(Layoutable control, Size availableSize, Thickness padding)
at Avalonia.Controls.Decorator.MeasureOverride(Size availableSize)
at Avalonia.Controls.Primitives.VisualLayerManager.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureOverride(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.Layoutable.MeasureOverride(Size availableSize)
at Avalonia.Controls.Window.MeasureOverride(Size availableSize)
at Avalonia.Controls.WindowBase.MeasureCore(Size availableSize)
at Avalonia.Layout.Layoutable.Measure(Size availableSize)
at Avalonia.Layout.LayoutManager.Measure(Layoutable control)
at Avalonia.Layout.LayoutManager.ExecuteInitialLayoutPass()
at Avalonia.Controls.Window.ShowCore(Window owner)
at Avalonia.Controls.Window.Show()
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.ShowMainWindow()
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.StartCore(String[] args)
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args)
at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(AppBuilder builder, String[] args, Action1 lifetimeBuilder) at UILibraryBrowser.Desktop.Program.Main(String[] args) in C:\Users\woods\Documents\Work Folder\Source Code\UILibrary\Source\Applications\UILibraryBrowser.Desktop\Program.cs:line 49

I am pretty sure this is due to a change to the TypeFace.cs #16677

It seems that this now checks for NULL and replaces with the default. However the Font Family CTOR checks for String.IsNullOrEmpty, meaning that an Empty name will pass the first check and fail the second check

`
///


/// Initializes a new instance of the class.
///

/// The name of the font family.
/// The font style.
/// The font weight.
/// The font stretch.
public Typeface(string fontFamilyName,
FontStyle style = FontStyle.Normal,
FontWeight weight = FontWeight.Normal,
FontStretch stretch = FontStretch.Normal)
: this(fontFamilyName == null ? FontFamily.Default : new FontFamily(fontFamilyName), style, weight, stretch)
{
}

///


/// Initializes a new instance of the class.
///

/// Specifies the base uri that is used to resolve font family assets.
/// The name of the .
/// Base uri must be an absolute uri.
public FontFamily(Uri? baseUri, string name)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}

`

I fixed this by changing the imported Font resource to add the name after the # character

<FontFamily x:Key="MainFont">avares://Projectina.UILibrary/Implementation/Fonts/Roboto#Roboto</FontFamily>

So the bugs are:

  1. This should not crash when nothing is passed after the hash
  2. The documentation around fonts must be improved as this was not clear at all
  3. If the family name is required, there should be a more descriptive warning message (even an avalonia trace log would have helped)

To Reproduce

  1. Add resource

<FontFamily x:Key="MainFont">avares://Projectina.UILibrary/Implementation/Fonts/Roboto#</FontFamily>

  1. Bind Font Family

<!-- Base Text block style Title --> <Style Selector="TextBlock"> <Setter Property="Foreground" Value="{DynamicResource MainForegroundBrush}" /> <Setter Property="FontSize" Value="{DynamicResource DefaultFontSize}" /> <Setter Property="ToolTip.ShowDelay" Value="{DynamicResource TooltipDelay}" /> <Setter Property="FontFamily" Value="{DynamicResource AlternateFont}" /> </Style>

  1. Run App
  2. Crash

Expected behavior

No Crash and the Correct Font is applied

Avalonia version

11.2.0

OS

Windows

Additional context

No response

@Gillibald
Copy link
Contributor

Gillibald commented Nov 13, 2024

<FontFamily x:Key="MainFont">avares://Projectina.UILibrary/Implementation/Fonts/Roboto#Roboto</FontFamily> You can't leave the requested family name empty

@maxkatz6 maxkatz6 added the by-design The behavior reported in the issue is actually correct. label Nov 14, 2024
@maxkatz6
Copy link
Member

Error message can be improved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug by-design The behavior reported in the issue is actually correct.
Projects
None yet
Development

No branches or pull requests

3 participants