diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Bold.ttf b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Bold.ttf
new file mode 100644
index 000000000000..98c74e0a4228
Binary files /dev/null and b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Bold.ttf differ
diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Regular.ttf b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Regular.ttf
new file mode 100644
index 000000000000..67803bb64274
Binary files /dev/null and b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans-Regular.ttf differ
diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans.ttf.manifest b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans.ttf.manifest
new file mode 100644
index 000000000000..83dfe2a21e03
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans.ttf.manifest
@@ -0,0 +1,34 @@
+ {
+ "fonts": [
+ {
+ "font_style": "italic",
+ "font_weight": 400,
+ "font_stretch": "Condensed",
+ "family_name": "ms-appx:///Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf"
+ },
+ {
+ "font_style": "normal",
+ "font_weight": 400,
+ "font_stretch": "SemiCondensed",
+ "family_name": "ms-appx:///Assets/Fonts/OpenSans/OpenSans_SemiCondensed-Regular.ttf"
+ },
+ {
+ "font_style": "normal",
+ "font_weight": 600,
+ "font_stretch": "SemiCondensed",
+ "family_name": "ms-appx:///Assets/Fonts/OpenSans/OpenSans_SemiCondensed-SemiBold.ttf"
+ },
+ {
+ "font_style": "normal",
+ "font_weight": 700,
+ "font_stretch": "Normal",
+ "family_name": "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Bold.ttf"
+ },
+ {
+ "font_style": "normal",
+ "font_weight": 400,
+ "font_stretch": "Normal",
+ "family_name": "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Regular.ttf"
+ },
+ ]
+}
diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf
new file mode 100644
index 000000000000..b43786bb5218
Binary files /dev/null and b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf differ
diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-Regular.ttf b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-Regular.ttf
new file mode 100644
index 000000000000..5b09b35bc1f0
Binary files /dev/null and b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-Regular.ttf differ
diff --git a/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-SemiBold.ttf b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-SemiBold.ttf
new file mode 100644
index 000000000000..fff3a37206bb
Binary files /dev/null and b/src/SamplesApp/UITests.Shared/Assets/Fonts/OpenSans/OpenSans_SemiCondensed-SemiBold.ttf differ
diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
index 72d474a795a4..6fe542f33c53 100644
--- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
+++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
@@ -9588,6 +9588,8 @@
+
+
diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs
index 39efe8efa592..c12c9d90facf 100644
--- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs
+++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs
@@ -35,6 +35,62 @@ namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls
[RunsOnUIThread]
public class Given_TextBlock
{
+ [TestMethod]
+ [DataRow((ushort)400, FontStyle.Italic, FontStretch.Condensed, "ms-appx:///Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf")]
+ [DataRow((ushort)400, FontStyle.Normal, FontStretch.SemiCondensed, "ms-appx:///Assets/Fonts/OpenSans/OpenSans_SemiCondensed-Regular.ttf")]
+ [DataRow((ushort)600, FontStyle.Normal, FontStretch.SemiCondensed, "ms-appx:///Assets/Fonts/OpenSans/OpenSans_SemiCondensed-SemiBold.ttf")]
+ [DataRow((ushort)700, FontStyle.Normal, FontStretch.Normal, "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Bold.ttf")]
+ [DataRow((ushort)400, FontStyle.Normal, FontStretch.Normal, "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Regular.ttf")]
+ public async Task When_Font_Has_Manifest(ushort weight, FontStyle style, FontStretch stretch, string ttfFile)
+ {
+ var SUT = new TextBlock
+ {
+ Text = "Hello World!",
+ FontSize = 18,
+ FontStyle = style,
+ FontStretch = stretch,
+ FontWeight = new FontWeight(weight),
+ FontFamily = new FontFamily("ms-appx:///Assets/Fonts/OpenSans/OpenSans.ttf"),
+ };
+
+ var expectedTB = new TextBlock
+ {
+ Text = "Hello World!",
+ FontSize = 18,
+ FontFamily = new FontFamily(ttfFile)
+ };
+
+ var differentTtf = "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Bold.ttf";
+ if (ttfFile == differentTtf)
+ {
+ differentTtf = "ms-appx:///Assets/Fonts/OpenSans/OpenSans-Regular.ttf";
+ }
+
+ var differentTB = new TextBlock
+ {
+ Text = "Hello World!",
+ FontSize = 18,
+ FontFamily = new FontFamily(differentTtf),
+ };
+
+ var sp = new StackPanel()
+ {
+ Children =
+ {
+ SUT,
+ expectedTB,
+ differentTB,
+ },
+ };
+
+ await UITestHelper.Load(sp);
+ var actual = await UITestHelper.ScreenShot(SUT);
+ var expected = await UITestHelper.ScreenShot(expectedTB);
+ var different = await UITestHelper.ScreenShot(differentTB);
+ await ImageAssert.AreEqualAsync(actual, expected);
+ await ImageAssert.AreNotEqualAsync(actual, different);
+ }
+
#if __SKIA__
[TestMethod]
// It looks like CI might not have any installed fonts with Chinese characters which could cause the test to fail
@@ -42,7 +98,7 @@ public class Given_TextBlock
public async Task Check_FontFallback()
{
var SUT = new TextBlock { Text = "示例文本", FontSize = 24 };
- var skFont = FontDetailsCache.GetFont(SUT.FontFamily?.Source, (float)SUT.FontSize, SUT.FontWeight, SUT.FontStyle).SKFont;
+ var skFont = FontDetailsCache.GetFont(SUT.FontFamily?.Source, (float)SUT.FontSize, SUT.FontWeight, SUT.FontStretch, SUT.FontStyle).SKFont;
Assert.IsFalse(skFont.ContainsGlyph(SUT.Text[0]));
var fallbackFont = SKFontManager.Default.MatchCharacter(SUT.Text[0]);
diff --git a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/ContentPresenter.cs b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/ContentPresenter.cs
index f0c46fb28a4b..b59b855f8204 100644
--- a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/ContentPresenter.cs
+++ b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/ContentPresenter.cs
@@ -86,20 +86,7 @@ public bool IsTextScaleFactorEnabled
// Skipping already declared property Foreground
// Skipping already declared property FontWeight
// Skipping already declared property FontStyle
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public global::Windows.UI.Text.FontStretch FontStretch
- {
- get
- {
- return (global::Windows.UI.Text.FontStretch)this.GetValue(FontStretchProperty);
- }
- set
- {
- this.SetValue(FontStretchProperty, value);
- }
- }
-#endif
+ // Skipping already declared property FontStretch
// Skipping already declared property FontSize
// Skipping already declared property FontFamily
// Skipping already declared property CornerRadius
@@ -158,14 +145,7 @@ public int CharacterSpacing
// Skipping already declared property CornerRadiusProperty
// Skipping already declared property FontFamilyProperty
// Skipping already declared property FontSizeProperty
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public static global::Microsoft.UI.Xaml.DependencyProperty FontStretchProperty { get; } =
- Microsoft.UI.Xaml.DependencyProperty.Register(
- nameof(FontStretch), typeof(global::Windows.UI.Text.FontStretch),
- typeof(global::Microsoft.UI.Xaml.Controls.ContentPresenter),
- new Microsoft.UI.Xaml.FrameworkPropertyMetadata(default(global::Windows.UI.Text.FontStretch)));
-#endif
+ // Skipping already declared property FontStretchProperty
// Skipping already declared property FontStyleProperty
// Skipping already declared property FontWeightProperty
// Skipping already declared property ForegroundProperty
diff --git a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/Control.cs b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/Control.cs
index f27a4632bcc2..1b1a8534797f 100644
--- a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/Control.cs
+++ b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/Control.cs
@@ -47,20 +47,7 @@ public bool IsTextScaleFactorEnabled
// Skipping already declared property Foreground
// Skipping already declared property FontWeight
// Skipping already declared property FontStyle
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public global::Windows.UI.Text.FontStretch FontStretch
- {
- get
- {
- return (global::Windows.UI.Text.FontStretch)this.GetValue(FontStretchProperty);
- }
- set
- {
- this.SetValue(FontStretchProperty, value);
- }
- }
-#endif
+ // Skipping already declared property FontStretch
// Skipping already declared property FontSize
// Skipping already declared property FontFamily
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
@@ -150,14 +137,7 @@ public int CharacterSpacing
#endif
// Skipping already declared property FontFamilyProperty
// Skipping already declared property FontSizeProperty
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public static global::Microsoft.UI.Xaml.DependencyProperty FontStretchProperty { get; } =
- Microsoft.UI.Xaml.DependencyProperty.Register(
- nameof(FontStretch), typeof(global::Windows.UI.Text.FontStretch),
- typeof(global::Microsoft.UI.Xaml.Controls.Control),
- new Microsoft.UI.Xaml.FrameworkPropertyMetadata(default(global::Windows.UI.Text.FontStretch)));
-#endif
+ // Skipping already declared property FontStretchProperty
// Skipping already declared property FontStyleProperty
// Skipping already declared property FontWeightProperty
// Skipping already declared property ForegroundProperty
diff --git a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/TextBlock.cs b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/TextBlock.cs
index 01fc37d24043..f0516127ec68 100644
--- a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/TextBlock.cs
+++ b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls/TextBlock.cs
@@ -27,20 +27,7 @@ public bool IsColorFontEnabled
// Skipping already declared property Foreground
// Skipping already declared property FontWeight
// Skipping already declared property FontStyle
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public global::Windows.UI.Text.FontStretch FontStretch
- {
- get
- {
- return (global::Windows.UI.Text.FontStretch)this.GetValue(FontStretchProperty);
- }
- set
- {
- this.SetValue(FontStretchProperty, value);
- }
- }
-#endif
+ // Skipping already declared property FontStretch
// Skipping already declared property FontSize
// Skipping already declared property FontFamily
// Skipping already declared property IsTextSelectionEnabled
@@ -212,14 +199,7 @@ public double BaselineOffset
// Skipping already declared property CharacterSpacingProperty
// Skipping already declared property FontFamilyProperty
// Skipping already declared property FontSizeProperty
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public static global::Microsoft.UI.Xaml.DependencyProperty FontStretchProperty { get; } =
- Microsoft.UI.Xaml.DependencyProperty.Register(
- nameof(FontStretch), typeof(global::Windows.UI.Text.FontStretch),
- typeof(global::Microsoft.UI.Xaml.Controls.TextBlock),
- new Microsoft.UI.Xaml.FrameworkPropertyMetadata(default(global::Windows.UI.Text.FontStretch)));
-#endif
+ // Skipping already declared property FontStretchProperty
// Skipping already declared property FontStyleProperty
// Skipping already declared property FontWeightProperty
// Skipping already declared property ForegroundProperty
diff --git a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Documents/TextElement.cs b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Documents/TextElement.cs
index fa6ea7d4fc68..d45fd2719951 100644
--- a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Documents/TextElement.cs
+++ b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Documents/TextElement.cs
@@ -97,20 +97,7 @@ public bool IsAccessKeyScope
// Skipping already declared property Foreground
// Skipping already declared property FontWeight
// Skipping already declared property FontStyle
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public global::Windows.UI.Text.FontStretch FontStretch
- {
- get
- {
- return (global::Windows.UI.Text.FontStretch)this.GetValue(FontStretchProperty);
- }
- set
- {
- this.SetValue(FontStretchProperty, value);
- }
- }
-#endif
+ // Skipping already declared property FontStretch
// Skipping already declared property FontSize
// Skipping already declared property FontFamily
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
@@ -226,14 +213,7 @@ public string AccessKey
#endif
// Skipping already declared property FontFamilyProperty
// Skipping already declared property FontSizeProperty
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
- [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
- public static global::Microsoft.UI.Xaml.DependencyProperty FontStretchProperty { get; } =
- Microsoft.UI.Xaml.DependencyProperty.Register(
- nameof(FontStretch), typeof(global::Windows.UI.Text.FontStretch),
- typeof(global::Microsoft.UI.Xaml.Documents.TextElement),
- new Microsoft.UI.Xaml.FrameworkPropertyMetadata(default(global::Windows.UI.Text.FontStretch)));
-#endif
+ // Skipping already declared property FontStretchProperty
// Skipping already declared property FontStyleProperty
// Skipping already declared property FontWeightProperty
// Skipping already declared property ForegroundProperty
diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs
index a6f0419df23b..8ef7379f3de5 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs
@@ -330,6 +330,27 @@ public FontStyle FontStyle
);
#endregion
+ #region FontStretch
+
+ public FontStretch FontStretch
+ {
+ get => (FontStretch)this.GetValue(FontStretchProperty);
+ set => this.SetValue(FontStretchProperty, value);
+ }
+
+ public static DependencyProperty FontStretchProperty { get; } =
+ DependencyProperty.Register(
+ nameof(FontStretch),
+ typeof(FontStretch),
+ typeof(ContentPresenter),
+ new FrameworkPropertyMetadata(
+ FontStretch.Normal,
+ FrameworkPropertyMetadataOptions.Inherits,
+ (s, e) => ((ContentPresenter)s)?.OnFontStretchChanged((FontStretch)e.OldValue, (FontStretch)e.NewValue)
+ )
+ );
+ #endregion
+
#region TextWrapping Dependency Property
public TextWrapping TextWrapping
@@ -746,6 +767,13 @@ protected virtual void OnFontStyleChanged(FontStyle oldValue, FontStyle newValue
partial void OnFontStyleChangedPartial(FontStyle oldValue, FontStyle newValue);
+ private protected virtual void OnFontStretchChanged(FontStretch oldValue, FontStretch newValue)
+ {
+ OnFontStretchChangedPartial(oldValue, newValue);
+ }
+
+ partial void OnFontStretchChangedPartial(FontStretch oldValue, FontStretch newValue);
+
protected virtual void OnContentChanged(object oldValue, object newValue)
{
if (oldValue is View || newValue is View)
diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs
index 3de76a4a9060..5de274f51250 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs
@@ -706,6 +706,27 @@ public FontStyle FontStyle
);
#endregion
+ #region FontStretch
+
+ public FontStretch FontStretch
+ {
+ get => (FontStretch)this.GetValue(FontStretchProperty);
+ set => this.SetValue(FontStretchProperty, value);
+ }
+
+ public static DependencyProperty FontStretchProperty { get; } =
+ DependencyProperty.Register(
+ nameof(FontStretch),
+ typeof(FontStretch),
+ typeof(Control),
+ new FrameworkPropertyMetadata(
+ FontStretch.Normal,
+ FrameworkPropertyMetadataOptions.Inherits,
+ (s, e) => ((Control)s)?.OnFontStretchChanged((FontStretch)e.OldValue, (FontStretch)e.NewValue)
+ )
+ );
+ #endregion
+
#region Padding DependencyProperty
public Thickness Padding
@@ -965,6 +986,13 @@ protected virtual void OnFontStyleChanged(FontStyle oldValue, FontStyle newValue
partial void OnFontStyleChangedPartial(FontStyle oldValue, FontStyle newValue);
+ private protected virtual void OnFontStretchChanged(FontStretch oldValue, FontStretch newValue)
+ {
+ OnFontStretchChangedPartial(oldValue, newValue);
+ }
+
+ partial void OnFontStretchChangedPartial(FontStretch oldValue, FontStretch newValue);
+
protected virtual void OnPaddingChanged(Thickness oldValue, Thickness newValue)
{
OnPaddingChangedPartial(oldValue, newValue);
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Android.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Android.cs
index f254cf7b2d9d..a454ecb3fa71 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Android.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Android.cs
@@ -144,6 +144,7 @@ partial void OnTextChangedPartial()
// Invalidate _paint
partial void OnFontWeightChangedPartial() => _paint = null;
partial void OnFontStyleChangedPartial() => _paint = null;
+ // TODO: FontStretch?
partial void OnFontFamilyChangedPartial() => _paint = null;
partial void OnFontSizeChangedPartial() => _paint = null;
partial void OnCharacterSpacingChangedPartial() => _paint = null;
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs
index 36c42de9ecab..d1a63f4d415d 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs
@@ -185,6 +185,36 @@ private void OnFontStyleChanged()
#endregion
+ #region FontStretch Dependency Property
+
+ public FontStretch FontStretch
+ {
+ get => (FontStretch)GetValue(FontStretchProperty);
+ set => SetValue(FontStretchProperty, value);
+ }
+
+ public static DependencyProperty FontStretchProperty { get; } =
+ DependencyProperty.Register(
+ nameof(FontStretch),
+ typeof(FontStretch),
+ typeof(TextBlock),
+ new FrameworkPropertyMetadata(
+ defaultValue: FontStretch.Normal,
+ options: FrameworkPropertyMetadataOptions.Inherits,
+ propertyChangedCallback: (s, e) => ((TextBlock)s).OnFontStretchChanged()
+ )
+ );
+
+ private void OnFontStretchChanged()
+ {
+ OnFontStretchChangedPartial();
+ InvalidateTextBlock();
+ }
+
+ partial void OnFontStretchChangedPartial();
+
+ #endregion
+
#region TextWrapping Dependency Property
public TextWrapping TextWrapping
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.skia.cs
index a6376cca7711..d688b8e6c48d 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.skia.cs
@@ -150,7 +150,14 @@ internal float GetComputedLineHeight()
}
else
{
- var font = FontDetailsCache.GetFont(FontFamily?.Source, (float)FontSize, FontWeight, FontStyle);
+ var font = FontDetailsCache.GetFont(FontFamily?.Source, (float)FontSize, FontWeight, FontStretch, FontStyle);
+ if (font.CanChange)
+ {
+ // While font family itself didn't change, OnFontFamilyChanged will invalidate whatever
+ // needed for the rendering to happen correct on the next frame.
+ font.FontUpdated += OnFontFamilyChanged;
+ }
+
return font.LineHeight;
}
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.wasm.cs
index 45a19607e13c..01de39a412e5 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.wasm.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.wasm.cs
@@ -177,6 +177,8 @@ internal override void AfterArrange()
partial void OnFontWeightChangedPartial() => _fontWeightChanged = true;
+ // TODO: FontStretch?
+
partial void OnIsTextSelectionEnabledChangedPartial()
{
if (IsTextSelectionEnabled)
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
index 735c2e79f75e..1b2c8fabb492 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
@@ -492,6 +492,12 @@ protected override void OnFontStyleChanged(FontStyle oldValue, FontStyle newValu
UpdateFontPartial();
}
+ private protected override void OnFontStretchChanged(FontStretch oldValue, FontStretch newValue)
+ {
+ base.OnFontStretchChanged(oldValue, newValue);
+ UpdateFontPartial();
+ }
+
protected override void OnFontWeightChanged(FontWeight oldValue, FontWeight newValue)
{
base.OnFontWeightChanged(oldValue, newValue);
diff --git a/src/Uno.UI/UI/Xaml/Documents/Inline.skia.cs b/src/Uno.UI/UI/Xaml/Documents/Inline.skia.cs
index caa4c7cbb163..725c8f857098 100644
--- a/src/Uno.UI/UI/Xaml/Documents/Inline.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/Inline.skia.cs
@@ -27,7 +27,22 @@ internal SKPaint Paint
}
}
- internal FontDetails FontInfo => _fontInfo ??= FontDetailsCache.GetFont(FontFamily?.Source, (float)FontSize, FontWeight, FontStyle);
+ internal FontDetails FontInfo
+ {
+ get
+ {
+ _fontInfo ??= FontDetailsCache.GetFont(FontFamily?.Source, (float)FontSize, FontWeight, FontStretch, FontStyle);
+
+ if (_fontInfo.CanChange)
+ {
+ // While font family itself didn't change, OnFontFamilyChanged will invalidate whatever
+ // needed for the rendering to happen correct on the next frame.
+ _fontInfo.FontUpdated += OnFontFamilyChanged;
+ }
+
+ return _fontInfo;
+ }
+ }
internal float LineHeight => FontInfo.LineHeight;
@@ -47,6 +62,12 @@ protected override void OnFontStyleChanged()
InvalidateFontInfo();
}
+ protected override void OnFontStretchChanged()
+ {
+ base.OnFontStretchChanged();
+ InvalidateFontInfo();
+ }
+
protected override void OnFontWeightChanged()
{
base.OnFontWeightChanged();
diff --git a/src/Uno.UI/UI/Xaml/Documents/Run.cs b/src/Uno.UI/UI/Xaml/Documents/Run.cs
index 4a7aa985ffd5..09831b59add9 100644
--- a/src/Uno.UI/UI/Xaml/Documents/Run.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/Run.cs
@@ -68,6 +68,13 @@ protected override void OnFontStyleChanged()
InvalidateSegmentsPartial();
}
+ protected override void OnFontStretchChanged()
+ {
+ base.OnFontStretchChanged();
+ InvalidateInlines(false);
+ InvalidateSegmentsPartial();
+ }
+
protected override void OnFontWeightChanged()
{
base.OnFontWeightChanged();
diff --git a/src/Uno.UI/UI/Xaml/Documents/Run.skia.cs b/src/Uno.UI/UI/Xaml/Documents/Run.skia.cs
index 17d27a5dcbbb..84093103f391 100644
--- a/src/Uno.UI/UI/Xaml/Documents/Run.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/Run.skia.cs
@@ -17,7 +17,7 @@ partial class Run
{
private List? _segments;
- internal IReadOnlyList Segments => _segments ??= _segments = GetSegments();
+ internal IReadOnlyList Segments => _segments ??= GetSegments();
private List GetSegments()
{
@@ -56,7 +56,14 @@ private List GetSegments()
if (symbolTypeface is { })
{
- var fi = FontDetailsCache.GetFont(symbolTypeface.FamilyName, (float)FontSize, FontWeight, FontStyle);
+ var fi = FontDetailsCache.GetFont(symbolTypeface.FamilyName, (float)FontSize, FontWeight, FontStretch, FontStyle);
+ if (fi.CanChange)
+ {
+ // While font family itself didn't change, OnFontFamilyChanged will invalidate whatever
+ // needed for the rendering to happen correct on the next frame.
+ fi.FontUpdated += OnFontFamilyChanged;
+ }
+
font = fi.Font;
wordBreakAfter = Unicode.HasWordBreakOpportunityAfter(text, i) || (i + 1 < text.Length && Unicode.HasWordBreakOpportunityBefore(text, i + 1));
font.GetScale(out fontScale, out _);
diff --git a/src/Uno.UI/UI/Xaml/Documents/TextElement.cs b/src/Uno.UI/UI/Xaml/Documents/TextElement.cs
index c4eac593aaf7..b0a11c57025f 100644
--- a/src/Uno.UI/UI/Xaml/Documents/TextElement.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/TextElement.cs
@@ -110,6 +110,35 @@ protected virtual void OnFontStyleChanged()
#endregion
+ #region FontStretch Dependency Property
+
+ public FontStretch FontStretch
+ {
+ get => (FontStretch)this.GetValue(FontStretchProperty);
+ set => this.SetValue(FontStyleProperty, value);
+ }
+
+ public static DependencyProperty FontStretchProperty { get; } =
+ DependencyProperty.Register(
+ nameof(FontStretch),
+ typeof(FontStretch),
+ typeof(TextElement),
+ new FrameworkPropertyMetadata(
+ defaultValue: FontStretch.Normal,
+ options: FrameworkPropertyMetadataOptions.Inherits,
+ propertyChangedCallback: (s, e) => ((TextElement)s).OnFontStretchChanged()
+ )
+ );
+
+ protected virtual void OnFontStretchChanged()
+ {
+ OnFontStretchChangedPartial();
+ }
+
+ partial void OnFontStretchChangedPartial();
+
+ #endregion
+
#region FontSize Dependency Property
public double FontSize
diff --git a/src/Uno.UI/UI/Xaml/Documents/TextElement.wasm.cs b/src/Uno.UI/UI/Xaml/Documents/TextElement.wasm.cs
index d9a5c4df3398..c14db3123d69 100644
--- a/src/Uno.UI/UI/Xaml/Documents/TextElement.wasm.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/TextElement.wasm.cs
@@ -21,6 +21,8 @@ partial void OnFontStyleChangedPartial()
this.SetFontStyle(ReadLocalValue(FontStyleProperty));
}
+ // TODO: FontStretch
+
partial void OnFontSizeChangedPartial()
{
this.SetFontSize(ReadLocalValue(FontSizeProperty));
diff --git a/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetails.skia.cs b/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetails.skia.cs
index 792e5ff8435c..234fceca9c16 100644
--- a/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetails.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetails.skia.cs
@@ -1,10 +1,18 @@
-using HarfBuzzSharp;
+#nullable enable
+
+using System;
+using System.Runtime.InteropServices;
+using HarfBuzzSharp;
using SkiaSharp;
namespace Microsoft.UI.Xaml.Documents.TextFormatting;
-internal record FontDetails(SKFont SKFont, float SKFontSize, float SKFontScaleX, SKFontMetrics SKFontMetrics, SKTypeface SKTypeface, Font Font, Face Face)
+internal record FontDetails(SKFont SKFont, float SKFontSize, float SKFontScaleX, SKFontMetrics SKFontMetrics, Font Font, bool CanChange)
{
+ // TODO: Investigate best value to use here. SKShaper uses a constant 512 scale, Avalonia uses default font scale. Not 100% sure how much difference it
+ // makes here but it affects subpixel rendering accuracy. Performance does not seem to be affected by changing this value.
+ private const int FontScale = 512;
+
internal float LineHeight
{
get
@@ -13,4 +21,77 @@ internal float LineHeight
return metrics.Descent - metrics.Ascent;
}
}
+
+ internal SKFont SKFont { get; private set; } = SKFont;
+ internal float SKFontScaleX { get; private set; } = SKFontScaleX;
+ internal SKFontMetrics SKFontMetrics { get; private set; } = SKFontMetrics;
+ internal Font Font { get; private set; } = Font;
+ internal bool CanChange { get; private set; } = CanChange;
+
+ internal event Action? FontUpdated;
+
+ internal static Blob? GetTable(Tag tag, SKTypeface skTypeFace)
+ {
+ var size = skTypeFace.GetTableSize(tag);
+
+ if (size == 0)
+ {
+ return null;
+ }
+
+ var data = Marshal.AllocHGlobal(size);
+
+ var releaseDelegate = new ReleaseDelegate(() => Marshal.FreeHGlobal(data));
+
+ var value = skTypeFace.TryGetTableData(tag, 0, size, data) ?
+ new Blob(data, size, MemoryMode.Writeable, releaseDelegate) : null;
+
+ return value;
+ }
+
+ internal void Update(SKTypeface skTypeFace)
+ {
+ SKFont = CreateSKFont(skTypeFace, SKFontSize);
+ SKFontScaleX = SKFont.ScaleX;
+ SKFontMetrics = SKFont.Metrics;
+ Font = CreateHarfBuzzFont(skTypeFace);
+
+ FontUpdated?.Invoke();
+ FontUpdated = null;
+ CanChange = false;
+ }
+
+ internal void LoadFailed()
+ {
+ FontUpdated = null;
+ CanChange = false;
+ }
+
+ internal static FontDetails Create(SKTypeface skTypeFace, float fontSize, bool canChange)
+ {
+ var skFont = CreateSKFont(skTypeFace, fontSize);
+ var hbFont = CreateHarfBuzzFont(skTypeFace);
+
+ return new(skFont, skFont.Size, skFont.ScaleX, skFont.Metrics, hbFont, canChange);
+ }
+
+ private static SKFont CreateSKFont(SKTypeface skTypeFace, float fontSize)
+ {
+ var skFont = new SKFont(skTypeFace, fontSize);
+ skFont.Edging = SKFontEdging.SubpixelAntialias;
+ skFont.Subpixel = true;
+ return skFont;
+ }
+
+ private static Font CreateHarfBuzzFont(SKTypeface skTypeFace)
+ {
+ var hbFace = new Face((_, tag) => GetTable(tag, skTypeFace));
+ hbFace.UnitsPerEm = skTypeFace.UnitsPerEm;
+
+ var hbFont = new Font(hbFace);
+ hbFont.SetScale(FontScale, FontScale);
+ hbFont.SetFunctionsOpenType();
+
+ return hbFont;
+ }
}
diff --git a/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetailsCache.skia.cs b/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetailsCache.skia.cs
index d1de58c01028..cd8d15a9e7ac 100644
--- a/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetailsCache.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Documents/TextFormatting/FontDetailsCache.skia.cs
@@ -1,60 +1,205 @@
#nullable enable
using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
using HarfBuzzSharp;
using SkiaSharp;
-using Uno;
using Uno.Foundation.Logging;
+using Uno.UI;
using Uno.UI.Xaml;
+using Uno.UI.Xaml.Media;
using Windows.ApplicationModel;
+using Windows.Storage;
using Windows.UI.Text;
-using Uno.UI;
namespace Microsoft.UI.Xaml.Documents.TextFormatting;
internal static class FontDetailsCache
{
- // TODO: Investigate best value to use here. SKShaper uses a constant 512 scale, Avalonia uses default font scale. Not 100% sure how much difference it
- // makes here but it affects subpixel rendering accuracy. Performance does not seem to be affected by changing this value.
- private const int FontScale = 512;
+ private record struct FontCacheEntry(
+ string? Name,
+ float FontSize,
+ FontWeight Weight,
+ FontStretch Stretch,
+ FontStyle Style);
+
+ private static readonly ConcurrentDictionary _typefaceCache = new();
+ private static Dictionary _fontCache = new();
+ private static object _fontCacheGate = new();
+
+ private static JsonSerializerOptions _options = new JsonSerializerOptions()
+ {
+ AllowTrailingCommas = true,
+ PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
+ ReadCommentHandling = JsonCommentHandling.Skip,
+ Converters =
+ {
+ new JsonStringEnumConverter(),
+ },
+ };
+
+ internal static void OnFontLoaded(string font, SKTypeface? typeface)
+ {
+ _typefaceCache[font] = typeface;
+ lock (_fontCacheGate)
+ {
+ foreach (var key in _fontCache.Keys)
+ {
+ if (key.Name == font)
+ {
+ if (_fontCache.TryGetValue(key, out var details))
+ {
+ if (typeface is null)
+ {
+ // font load failed.
+ details.LoadFailed();
+ }
+ else
+ {
+ details.Update(typeface);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static string GetFamilyNameFromManifest(Stream jsonStream, FontWeight weight, FontStyle style, FontStretch stretch)
+ {
+ /*
+ {
+ "fonts": [
+ {
+ "font_style": "normal",
+ "font_weight": 400,
+ "font_stretch": "normal",
+ "family_name": "ms-appx:///path/to/ExampleFontFamily-Regular.ttf"
+ },
+ {
+ "font_style": "italic",
+ "font_weight": "Normal",
+ "font_stretch": "normal",
+ "family_name": "ms-appx:///path/to/ExampleFontFamily-Italic.ttf"
+ },
+ {
+ "font_style": "normal",
+ "font_weight": 700,
+ "font_stretch": "normal",
+ "family_name": "ms-appx:///path/to/ExampleFontFamily-Bold.ttf"
+ }
+ ]
+ }
+ */
+ var manifest = JsonSerializer.Deserialize(jsonStream, _options);
+ if (manifest?.Fonts is null || manifest.Fonts.Length == 0)
+ {
+ throw new ArgumentException("Font manifest file is incorrect.");
+ }
+
+ var bestSoFar = manifest.Fonts[0];
+ for (int i = 1; i < manifest.Fonts.Length; i++)
+ {
+ var candidateMatch = manifest.Fonts[i];
+ if (candidateMatch.FontWeight != bestSoFar.FontWeight && Math.Abs(candidateMatch.FontWeight - weight.Weight) < Math.Abs(bestSoFar.FontWeight - weight.Weight))
+ {
+ // candidateMatch is a better match than bestSoFar. So it's now our new bestSoFar.
+ bestSoFar = candidateMatch;
+ }
+ else if (candidateMatch.FontStyle != bestSoFar.FontStyle && candidateMatch.FontStyle == style)
+ {
+ // The current bestSoFar
+ bestSoFar = candidateMatch;
+ }
+ else if (stretch != FontStretch.Undefined && candidateMatch.FontStretch != bestSoFar.FontStretch && Math.Abs(candidateMatch.FontStretch - stretch) < Math.Abs(bestSoFar.FontStretch - stretch))
+ {
+ // candidateMatch is a better match than bestSoFar. So it's now our new bestSoFar.
+ bestSoFar = candidateMatch;
+ }
+ }
+
+ return bestSoFar.FamilyName;
+ }
+
+ private static async Task LoadTypefaceFromApplicationUriAsync(Uri uri, FontWeight weight, FontStyle style, FontStretch stretch)
+ {
+ try
+ {
+ // TODO (This comment should be resolved during code review):
+ // Should the user be responsible for adding ".manifest" to the ms-appx path himself?
+ // The benefit of the user doing so is that we will not have to first check if a manifest exists.
+ var manifestUri = new Uri(uri.OriginalString + ".manifest");
+ var manifestFile = await StorageFile.GetFileFromApplicationUriAsync(manifestUri);
+ var manifestStream = await manifestFile.OpenStreamForReadAsync();
+ uri = new Uri(GetFamilyNameFromManifest(manifestStream, weight, style, stretch));
+ }
+ catch
+ {
+ // manifest file is not found or cannot be read. Ignore it.
+ }
- private static readonly Func _getFont =
- Funcs.CreateMemoized(
- (nm, sz, wt, sl) => GetFontInternal(nm, sz, wt, sl));
+ var file = await StorageFile.GetFileFromApplicationUriAsync(uri);
+ var stream = await file.OpenStreamForReadAsync();
+ return stream is null ? null : SKTypeface.FromStream(stream);
+ }
private static FontDetails GetFontInternal(
- string? name,
- float fontSize,
- FontWeight weight,
- FontStyle style)
+ string? name,
+ float fontSize,
+ FontWeight weight,
+ FontStretch stretch,
+ FontStyle style)
{
var skWeight = weight.ToSkiaWeight();
- // TODO: FontStretch not supported by Uno yet
- // var skWidth = FontStretch.ToSkiaWidth();
- var skWidth = SKFontStyleWidth.Normal;
+ var skWidth = stretch.ToSkiaWidth();
var skSlant = style.ToSkiaSlant();
SKTypeface? skTypeFace;
-
- SKTypeface GetDefaultTypeFace()
- {
- return SKTypeface.FromFamilyName(FeatureConfiguration.Font.DefaultTextFontFamily, skWeight, skWidth, skSlant)
- ?? SKTypeface.FromFamilyName(null, skWeight, skWidth, skSlant)
- ?? SKTypeface.FromFamilyName(null);
- }
+ bool temporaryDefaultFont = false;
if (name == null || string.Equals(name, "XamlAutoFontFamily", StringComparison.OrdinalIgnoreCase))
{
- skTypeFace = GetDefaultTypeFace();
+ name = FeatureConfiguration.Font.DefaultTextFontFamily;
}
- else if (XamlFilePathHelper.TryGetMsAppxAssetPath(name, out var path))
- {
- var filePath = global::System.IO.Path.Combine(
- Package.Current.InstalledLocation.Path
- , path.Replace('/', global::System.IO.Path.DirectorySeparatorChar));
- // SKTypeface.FromFile may return null if the file is not found (SkiaSharp is not yet nullable attributed)
- skTypeFace = SKTypeface.FromFile(filePath);
+ if (Uri.TryCreate(name, UriKind.Absolute, out var uri) && uri.Scheme == "ms-appx")
+ {
+ var task = LoadTypefaceFromApplicationUriAsync(uri, weight, style, stretch);
+ if (task.IsCompleted)
+ {
+ if (task.IsCompletedSuccessfully)
+ {
+ skTypeFace = task.Result;
+ }
+ else
+ {
+ // Load failed.
+ OnFontLoaded(name, null);
+ skTypeFace = null;
+ }
+ }
+ else
+ {
+ temporaryDefaultFont = true;
+ skTypeFace = null;
+ task.ContinueWith(task =>
+ {
+ if (task.IsCompletedSuccessfully)
+ {
+ OnFontLoaded(name, task.Result);
+ }
+ else
+ {
+ // Load failed.
+ OnFontLoaded(name, null);
+ }
+ });
+ }
}
else
{
@@ -69,46 +214,30 @@ SKTypeface GetDefaultTypeFace()
typeof(Inline).Log().LogWarning($"The font {name} could not be found, using system default");
}
- skTypeFace = GetDefaultTypeFace();
+ skTypeFace = SKTypeface.FromFamilyName(FeatureConfiguration.Font.DefaultTextFontFamily, skWeight, skWidth, skSlant)
+ ?? SKTypeface.FromFamilyName(null, skWeight, skWidth, skSlant)
+ ?? SKTypeface.FromFamilyName(null);
}
- Blob? GetTable(Face face, Tag tag)
- {
- var size = skTypeFace.GetTableSize(tag);
+ return FontDetails.Create(skTypeFace, fontSize, temporaryDefaultFont);
+ }
+
+ public static FontDetails GetFont(
+ string? name,
+ float fontSize,
+ FontWeight weight,
+ FontStretch stretch,
+ FontStyle style)
+ {
+ var key = new FontCacheEntry(name, fontSize, weight, stretch, style);
- if (size == 0)
+ lock (_fontCacheGate)
+ {
+ if (!_fontCache.TryGetValue(key, out var value))
{
- return null;
+ _fontCache[key] = value = GetFontInternal(name, fontSize, weight, stretch, style);
}
-
- var data = Marshal.AllocHGlobal(size);
-
- var releaseDelegate = new ReleaseDelegate(() => Marshal.FreeHGlobal(data));
-
- var value = skTypeFace.TryGetTableData(tag, 0, size, data) ?
- new Blob(data, size, MemoryMode.Writeable, releaseDelegate) : null;
-
return value;
}
-
- var skFont = new SKFont(skTypeFace, fontSize);
- skFont.Edging = SKFontEdging.SubpixelAntialias;
- skFont.Subpixel = true;
-
- var hbFace = new Face(GetTable);
- hbFace.UnitsPerEm = skTypeFace.UnitsPerEm;
-
- var hbFont = new Font(hbFace);
- hbFont.SetScale(FontScale, FontScale);
- hbFont.SetFunctionsOpenType();
-
- return new(skFont, skFont.Size, skFont.ScaleX, skFont.Metrics, skTypeFace, hbFont, hbFace);
}
-
- public static FontDetails GetFont(
- string? name,
- float fontSize,
- FontWeight weight,
- FontStyle style
- ) => _getFont(name, fontSize, weight, style);
}
diff --git a/src/Uno.UI/UI/Xaml/FontInfo.cs b/src/Uno.UI/UI/Xaml/FontInfo.cs
new file mode 100644
index 000000000000..d5614888ee11
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/FontInfo.cs
@@ -0,0 +1,12 @@
+using System;
+using Windows.UI.Text;
+
+namespace Uno.UI.Xaml.Media;
+
+internal sealed class FontInfo
+{
+ public FontStyle FontStyle { get; set; }
+ public ushort FontWeight { get; set; }
+ public FontStretch FontStretch { get; set; }
+ public string FamilyName { get; set; }
+}
diff --git a/src/Uno.UI/UI/Xaml/FontManifest.cs b/src/Uno.UI/UI/Xaml/FontManifest.cs
new file mode 100644
index 000000000000..9f20bc93613e
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/FontManifest.cs
@@ -0,0 +1,6 @@
+namespace Uno.UI.Xaml.Media;
+
+internal sealed class FontManifest
+{
+ public FontInfo[] Fonts { get; set; }
+}
diff --git a/src/Uno.UWP/UI/Text/FontStyle.skia.cs b/src/Uno.UWP/UI/Text/FontStyle.skia.cs
index 97ad59fa3395..fc5362e05efc 100644
--- a/src/Uno.UWP/UI/Text/FontStyle.skia.cs
+++ b/src/Uno.UWP/UI/Text/FontStyle.skia.cs
@@ -12,5 +12,21 @@ public static SKFontStyleSlant ToSkiaSlant(this FontStyle style) =>
FontStyle.Oblique => SKFontStyleSlant.Oblique,
_ => SKFontStyleSlant.Upright
};
+
+ public static SKFontStyleWidth ToSkiaWidth(this FontStretch stretch) =>
+ stretch switch
+ {
+ FontStretch.Undefined => SKFontStyleWidth.Normal,
+ FontStretch.UltraCondensed => SKFontStyleWidth.UltraCondensed,
+ FontStretch.ExtraCondensed => SKFontStyleWidth.ExtraCondensed,
+ FontStretch.Condensed => SKFontStyleWidth.Condensed,
+ FontStretch.SemiCondensed => SKFontStyleWidth.SemiCondensed,
+ FontStretch.Normal => SKFontStyleWidth.Normal,
+ FontStretch.SemiExpanded => SKFontStyleWidth.SemiExpanded,
+ FontStretch.Expanded => SKFontStyleWidth.Expanded,
+ FontStretch.ExtraExpanded => SKFontStyleWidth.ExtraExpanded,
+ FontStretch.UltraExpanded => SKFontStyleWidth.UltraExpanded,
+ _ => SKFontStyleWidth.Normal,
+ };
}
}