diff --git a/src/Runtime/Runtime/Core/Other/INTERNAL_FontsHelper.cs b/src/Runtime/Runtime/Core/Other/INTERNAL_FontsHelper.cs deleted file mode 100644 index 9a25b0d32..000000000 --- a/src/Runtime/Runtime/Core/Other/INTERNAL_FontsHelper.cs +++ /dev/null @@ -1,113 +0,0 @@ - - -/*=================================================================================== -* -* Copyright (c) Userware/OpenSilver.net -* -* This file is part of the OpenSilver Runtime (https://opensilver.net), which is -* licensed under the MIT license: https://opensource.org/licenses/MIT -* -* As stated in the MIT license, "the above copyright notice and this permission -* notice shall be included in all copies or substantial portions of the Software." -* -\*====================================================================================*/ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -#if MIGRATION -using System.Windows; -#else -using Windows.UI.Xaml; -#endif - -namespace CSHTML5.Internal -{ - internal static class INTERNAL_FontsHelper - { - static Dictionary _loadedFonts = new Dictionary(); - static int _suffixesUsed = 0; //this counts the amount of fonts we added (the name comes from the fact that this is what we use as a suffix for the names to use for the fonts). - static public string DefaultCssFontFamily; - - /// - /// Creates a css style with @font-face for the given font, then returns the name to use as the font-family. This name is actually the relative path to the file containing the font. - /// - /// The path to the font. - /// This is an optional parameter that is helpful - /// in case of relative URI's. In fact, when an URI is relative, we need to transform it into an - /// absolute URI in order to locate the resources. A relative URI is usually relative to the place - /// where the .XAML file is located. For example, when using an Image control, relative image paths - /// are relative to the location of the .XAML file that contains the Image control. - /// The name to use to set the font-family property, a.k.a: the relative path to the font. - internal static string LoadFont(string fontPath, UIElement elementThatARelativeUriIsRelativeTo = null) - { - fontPath = fontPath.Trim(); //Todo-perf: this is probably negligible in most cases but ensuring that the _source of the FontFamily the fontPath comes from is trimmed will allow us to only call Trim() once per FontFamily instead of every time we add a Control to the Visual tree. - if(!fontPath.Contains('.')) //Note: if the path does not contain the character '.', then it means that there is no specified file. It is therefore a default font or thet path to a folder containing fonts, which we cannot handle so we simply return the font as is. - { - if (fontPath == "Portable User Interface") - return INTERNAL_FontsHelper.DefaultCssFontFamily; - return fontPath; - } - string fontPathWithoutCustomName = fontPath; - int indexOfHashTag = fontPath.IndexOf('#'); - if(indexOfHashTag != -1) - { - fontPathWithoutCustomName = fontPath.Substring(0, indexOfHashTag); - } - - string lowerCasePathWithoutCustomName = fontPathWithoutCustomName.ToLower(); - - //we try to make the path fit by considering that it is the startup assembly if not specifically defined otherwise: (basically add a prefix ms-appx if there is none) - //Note: we should not enter the "if" below if the path was defined in xaml. This cas is already handled during compilation. - if (!(lowerCasePathWithoutCustomName.StartsWith(@"ms-appx:/") - || lowerCasePathWithoutCustomName.StartsWith(@"http://") - || lowerCasePathWithoutCustomName.StartsWith(@"https://") - || fontPathWithoutCustomName.Contains(@";component/"))) - { - fontPathWithoutCustomName = "ms-appx:/" + fontPathWithoutCustomName; - } - - //Get a path that will lead to the position of the file: - string relativeFontPath = INTERNAL_UriHelper.ConvertToHtml5Path(fontPathWithoutCustomName, elementThatARelativeUriIsRelativeTo); - - if (_loadedFonts.ContainsKey(relativeFontPath)) - { - return _loadedFonts[relativeFontPath]; - } - return CreateFontInJS(relativeFontPath); //note: this adds the relativeFontPath to _loadedFonts. - } - - static string CreateFontInJS(string fontUri) - { - string fontName = GetNewFontName(); - fontUri = fontUri.Replace('\\', '/'); //this is required. - if (fontUri.StartsWith("/")) //this breaks it for some reason. - { - fontUri = fontUri.Substring(1); - } - CSHTML5.Interop.ExecuteJavaScript(@"var newStyle = document.createElement('style'); -newStyle.appendChild(document.createTextNode(""\ -@font-face {\ - font-family: '"" + $1 + ""';\ - src: url('"" + $0 + ""')\ -}}\ -"")); -document.body.appendChild(newStyle);", fontUri, fontName); //Note: we used src: url(...) because src: local(...) does not seem to work. Also, we added the css style to the body instead of the header (which is what I found everywhere non the internet) because it didn't seem to work for me. - - _loadedFonts.Add(fontUri, fontName); - return fontName; - } - - static string GetNewFontName() - { - //generate a string with a suffix and return it: - string suffixesUsedAsString = _suffixesUsed.ToString(); - ++_suffixesUsed; - return "fontName" + suffixesUsedAsString; - } - } -} diff --git a/src/Runtime/Runtime/OpenSilver/Internal/Media/FontFace.cs b/src/Runtime/Runtime/OpenSilver/Internal/Media/FontFace.cs new file mode 100644 index 000000000..f2fc9da8b --- /dev/null +++ b/src/Runtime/Runtime/OpenSilver/Internal/Media/FontFace.cs @@ -0,0 +1,199 @@ + +/*=================================================================================== +* +* Copyright (c) Userware/OpenSilver.net +* +* This file is part of the OpenSilver Runtime (https://opensilver.net), which is +* licensed under the MIT license: https://opensource.org/licenses/MIT +* +* As stated in the MIT license, "the above copyright notice and this permission +* notice shall be included in all copies or substantial portions of the Software." +* +\*====================================================================================*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using CSHTML5.Internal; + +#if MIGRATION +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +#endif + +namespace OpenSilver.Internal.Media; + +internal sealed class FontFace +{ + private static readonly Dictionary _fontFacesCache = new(); + private static readonly Dictionary _fontSourceToFamilyCache = new(); + private static readonly ReferenceIDGenerator _idGenerator = new(); + private static string _defaultCssFontFamily; + + private TaskCompletionSource _loadOperation; + private List> _measureList; + + internal static string DefaultCssFontFamily + { + get + { + if (_defaultCssFontFamily is null) + { + var rootDiv = Application.Current?.GetRootDiv(); + if (rootDiv is not null) + { + string sDiv = CSHTML5.INTERNAL_InteropImplementation.GetVariableStringForJS(rootDiv); + _defaultCssFontFamily = Interop.ExecuteJavaScriptString( + $"window.getComputedStyle({sDiv}).getPropertyValue('font-family');"); + } + } + + return _defaultCssFontFamily ?? string.Empty; + } + } + + internal static FontFace GetFontFace(string source, UIElement relativeTo) + { + (string fontName, string fontUrl) = ParseFontSource(source, relativeTo); + + if (!_fontFacesCache.TryGetValue(fontName, out FontFace face)) + { + face = new FontFace(fontName, fontUrl); + _fontFacesCache.Add(fontName, face); + } + + return face; + } + + private FontFace(string fontName, string fontUrl) + { + CssFontName = fontName; + CssFontUrl = fontUrl; + IsLoaded = string.IsNullOrEmpty(fontUrl); + } + + public string CssFontName { get; } + + public string CssFontUrl { get; } + + public bool IsLoaded { get; private set; } + + internal void RegisterForMeasure(UIElement uie) + { + if (IsLoaded) return; + + _measureList ??= new List>(); + _measureList.Add(new WeakReference(uie)); + } + + internal async Task LoadAsync() + { + if (IsLoaded) return true; + + if (_loadOperation is null) + { + _loadOperation = new TaskCompletionSource(); + + var loadCallback = JavaScriptCallbackHelper.CreateSelfDisposedJavaScriptCallback(OnFontLoaded); + + string uriEscaped = CSHTML5.INTERNAL_InteropImplementation.GetVariableStringForJS(CssFontUrl); + string sCallback = CSHTML5.INTERNAL_InteropImplementation.GetVariableStringForJS(loadCallback); + Interop.ExecuteJavaScriptVoid( + $"document.loadFont('{CssFontName}', 'url({uriEscaped})', {sCallback});"); + } + + return await _loadOperation.Task; + } + + private void OnFontLoaded(bool success) + { + IsLoaded = true; + _loadOperation?.TrySetResult(success); + _loadOperation = null; + + if (success) + { + if (_measureList is null) + { + return; + } + + foreach (var weakRef in _measureList) + { + if (!weakRef.TryGetTarget(out UIElement uie)) + { + continue; + } + + switch (uie) + { + case TextBlock tb: + tb.InvalidateCacheAndMeasure(); + break; + default: + uie.InvalidateMeasure(); + break; + } + } + } + + _measureList = null; + } + + private static (string CssFontName, string CssFontUrl) ParseFontSource(string fontSource, UIElement relativeTo) + { + string fontPath = fontSource.Trim().ToLower(); + + // Note: if the path does not contain the character '.', then it means that there is no + // specified file. It is therefore a default font or thet path to a folder containing + // fonts, which we cannot handle so we simply return the font as is. + if (fontPath.IndexOf('.') == -1) + { + if (fontPath == "portable user interface") + { + fontPath = DefaultCssFontFamily; + } + + return (fontPath, null); + } + + int index = fontPath.IndexOf('#'); + string fontUrl = index != -1 ? fontPath.Substring(0, index) : fontPath; + + // we try to make the path fit by considering that it is the startup assembly if not + // specifically defined otherwise: (basically add a prefix ms-appx if there is none) + // Note: we should not enter the "if" below if the path was defined in xaml. This cas + // is already handled during compilation. + if (!fontUrl.StartsWith(@"ms-appx:/") && + !fontUrl.StartsWith(@"http://") && + !fontUrl.StartsWith(@"https://") && + !fontUrl.Contains(@";component/")) + { + fontUrl = $"ms-appx:/{fontUrl}"; + } + + // Get a path that will lead to the position of the file + string relativeFontPath = INTERNAL_UriHelper.ConvertToHtml5Path(fontUrl, relativeTo); + relativeFontPath = relativeFontPath.Replace('\\', '/'); + if (relativeFontPath.StartsWith("/")) + { + relativeFontPath = relativeFontPath.Substring(1); + } + + if (!_fontSourceToFamilyCache.TryGetValue(relativeFontPath, out string fontName)) + { + fontName = GenerateFontName(); + _fontSourceToFamilyCache.Add(relativeFontPath, fontName); + } + + return (fontName, relativeFontPath); + } + + private static string GenerateFontName() => $"fontName{_idGenerator.NewId()}"; +} diff --git a/src/Runtime/Runtime/Runtime.OpenSilver.csproj b/src/Runtime/Runtime/Runtime.OpenSilver.csproj index c5814fd6c..ab5b4b892 100644 --- a/src/Runtime/Runtime/Runtime.OpenSilver.csproj +++ b/src/Runtime/Runtime/Runtime.OpenSilver.csproj @@ -288,6 +288,7 @@ + @@ -647,7 +648,6 @@ - diff --git a/src/Runtime/Runtime/System.Windows.Controls/Control.cs b/src/Runtime/Runtime/System.Windows.Controls/Control.cs index a4872b878..d7f741e5d 100644 --- a/src/Runtime/Runtime/System.Windows.Controls/Control.cs +++ b/src/Runtime/Runtime/System.Windows.Controls/Control.cs @@ -296,21 +296,7 @@ public FontFamily FontFamily /// Identifies the dependency property. /// public static readonly DependencyProperty FontFamilyProperty = - DependencyProperty.Register( - nameof(FontFamily), - typeof(FontFamily), - typeof(Control), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure) - { - MethodToUpdateDom2 = static (d, oldValue, newValue) => - { - var c = (Control)d; - var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(c.INTERNAL_OuterDomElement); - style.fontFamily = newValue is FontFamily ff ? - INTERNAL_FontsHelper.LoadFont(ff.Source, c) : - string.Empty; - }, - }); + TextElementProperties.FontFamilyProperty.AddOwner(typeof(Control)); //----------------------- // FONTSIZE diff --git a/src/Runtime/Runtime/System.Windows.Controls/RichTextBlock.cs b/src/Runtime/Runtime/System.Windows.Controls/RichTextBlock.cs index f459f98f4..c78781115 100644 --- a/src/Runtime/Runtime/System.Windows.Controls/RichTextBlock.cs +++ b/src/Runtime/Runtime/System.Windows.Controls/RichTextBlock.cs @@ -189,17 +189,15 @@ public FontStyle FontStyle /// Identifies the dependency property. /// public static readonly DependencyProperty FontFamilyProperty = - DependencyProperty.Register( - nameof(FontFamily), - typeof(FontFamily), + TextElementProperties.FontFamilyProperty.AddOwner( typeof(RichTextBlock), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure) + new FrameworkPropertyMetadata(FontFamily.Default, FrameworkPropertyMetadataOptions.Inherits, OnFontFamilyChanged) { MethodToUpdateDom2 = static (d, oldValue, newValue) => { var rtb = (RichTextBlock)d; var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(rtb.INTERNAL_OuterDomElement); - style.fontFamily = newValue is FontFamily ff ? INTERNAL_FontsHelper.LoadFont(ff.Source, rtb) : string.Empty; + style.fontFamily = ((FontFamily)newValue).GetFontFace(rtb).CssFontName; }, }); @@ -213,6 +211,11 @@ public FontFamily FontFamily set => SetValue(FontFamilyProperty, value); } + private static void OnFontFamilyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextElementProperties.InvalidateMeasureOnFontFamilyChanged((RichTextBlock)d, (FontFamily)e.NewValue); + } + /// /// Identifies the dependency /// diff --git a/src/Runtime/Runtime/System.Windows.Controls/RichTextBox/RichTextBoxView.cs b/src/Runtime/Runtime/System.Windows.Controls/RichTextBox/RichTextBoxView.cs index a7491982d..4370bf460 100644 --- a/src/Runtime/Runtime/System.Windows.Controls/RichTextBox/RichTextBoxView.cs +++ b/src/Runtime/Runtime/System.Windows.Controls/RichTextBox/RichTextBoxView.cs @@ -20,7 +20,7 @@ using System.Xml; using CSHTML5.Internal; using OpenSilver.Internal.Controls; -using OpenSilver.Internal; +using OpenSilver.Internal.Media; #if MIGRATION using System.Windows.Documents; @@ -392,7 +392,7 @@ private string GetXamlContents(string content) //if (!string.IsNullOrEmpty(delta.Attributes.FontName)) // run.SetAttribute("FontFamily", GetFontName(delta.Attributes.FontName)); - run.SetAttribute("FontFamily", !string.IsNullOrEmpty(delta.Attributes.FontName) ? GetFontName(delta.Attributes.FontName) : INTERNAL_FontsHelper.DefaultCssFontFamily); + run.SetAttribute("FontFamily", !string.IsNullOrEmpty(delta.Attributes.FontName) ? GetFontName(delta.Attributes.FontName) : FontFace.DefaultCssFontFamily); if (!string.IsNullOrEmpty(delta.Attributes.FontSize)) run.SetAttribute("FontSize", delta.Attributes.FontSize.Replace("px", "")); if (delta.Attributes.Color != null) @@ -402,7 +402,7 @@ private string GetXamlContents(string content) } else { - run.SetAttribute("FontFamily", INTERNAL_FontsHelper.DefaultCssFontFamily); + run.SetAttribute("FontFamily", FontFace.DefaultCssFontFamily); } paragraph.AppendChild(run); diff --git a/src/Runtime/Runtime/System.Windows.Controls/TextBlock.cs b/src/Runtime/Runtime/System.Windows.Controls/TextBlock.cs index 824e5f844..86ec3081e 100644 --- a/src/Runtime/Runtime/System.Windows.Controls/TextBlock.cs +++ b/src/Runtime/Runtime/System.Windows.Controls/TextBlock.cs @@ -21,11 +21,13 @@ using System.Windows.Automation.Peers; using System.Windows.Documents; using System.Windows.Input; +using System.Windows.Media; #else using Windows.Foundation; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Documents; using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; #endif #if MIGRATION @@ -46,7 +48,7 @@ namespace Windows.UI.Xaml.Controls /// /// [ContentProperty(nameof(Inlines))] - public partial class TextBlock : Control //todo: this is supposed to inherit from FrameworkElement but Control has the implementations of FontSize, FontWeight, Foreground, etc. Maybe use an intermediate class between FrameworkElement and Control or add the implementation here too. + public class TextBlock : Control //todo: this is supposed to inherit from FrameworkElement but Control has the implementations of FontSize, FontWeight, Foreground, etc. Maybe use an intermediate class between FrameworkElement and Control or add the implementation here too. { private bool _isTextChanging; private Size _noWrapSize = Size.Empty; @@ -77,8 +79,25 @@ static TextBlock() style.letterSpacing = $"{value.ToInvariantString()}em"; }, }); + + FontFamilyProperty.OverrideMetadata( + typeof(TextBlock), + new FrameworkPropertyMetadata(FontFamily.Default, FrameworkPropertyMetadataOptions.Inherits, OnFontFamilyChanged) + { + MethodToUpdateDom2 = static (d, oldValue, newValue) => + { + var tb = (TextBlock)d; + var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(tb.INTERNAL_OuterDomElement); + style.fontFamily = ((FontFamily)newValue).GetFontFace(tb).CssFontName; + }, + }); + } + + private static void OnFontFamilyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextElementProperties.InvalidateMeasureOnFontFamilyChanged((TextBlock)d, (FontFamily)e.NewValue); } - + public TextBlock() { IsTabStop = false; //we want to avoid stopping on this element's div when pressing tab. diff --git a/src/Runtime/Runtime/System.Windows.Controls/TextBox.cs b/src/Runtime/Runtime/System.Windows.Controls/TextBox.cs index b9317bee1..9528b4102 100644 --- a/src/Runtime/Runtime/System.Windows.Controls/TextBox.cs +++ b/src/Runtime/Runtime/System.Windows.Controls/TextBox.cs @@ -85,6 +85,23 @@ static TextBox() style.letterSpacing = $"{value.ToInvariantString()}em"; }, }); + + FontFamilyProperty.OverrideMetadata( + typeof(TextBox), + new FrameworkPropertyMetadata(FontFamily.Default, FrameworkPropertyMetadataOptions.Inherits, OnFontFamilyChanged) + { + MethodToUpdateDom2 = static (d, oldValue, newValue) => + { + var tb = (TextBox)d; + var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(tb.INTERNAL_OuterDomElement); + style.fontFamily = ((FontFamily)newValue).GetFontFace(tb).CssFontName; + }, + }); + } + + private static void OnFontFamilyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextElementProperties.InvalidateMeasureOnFontFamilyChanged((TextBox)d, (FontFamily)e.NewValue); } public TextBox() diff --git a/src/Runtime/Runtime/System.Windows.Documents/TextElement.cs b/src/Runtime/Runtime/System.Windows.Documents/TextElement.cs index 6279725aa..bce1bfe5b 100644 --- a/src/Runtime/Runtime/System.Windows.Documents/TextElement.cs +++ b/src/Runtime/Runtime/System.Windows.Documents/TextElement.cs @@ -34,6 +34,27 @@ namespace Windows.UI.Xaml.Documents /// public abstract class TextElement : Control { + static TextElement() + { + FontFamilyProperty.OverrideMetadata( + typeof(TextElement), + new FrameworkPropertyMetadata(FontFamily.Default, FrameworkPropertyMetadataOptions.Inherits, OnFontFamilyChanged) + { + MethodToUpdateDom2 = static (d, oldValue, newValue) => + { + var textElement = (TextElement)d; + var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(textElement.INTERNAL_OuterDomElement); + style.fontFamily = ((FontFamily)newValue).GetFontFace(textElement).CssFontName; + }, + }); + } + + private static void OnFontFamilyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var face = ((FontFamily)e.NewValue).GetFontFace((TextElement)d); + _ = face.LoadAsync(); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Runtime/Runtime/System.Windows.Documents/TextElementProperties.cs b/src/Runtime/Runtime/System.Windows.Documents/TextElementProperties.cs index 16d0b4e01..e17eed5f1 100644 --- a/src/Runtime/Runtime/System.Windows.Documents/TextElementProperties.cs +++ b/src/Runtime/Runtime/System.Windows.Documents/TextElementProperties.cs @@ -13,8 +13,13 @@ using System.Diagnostics; -#if !MIGRATION +#if MIGRATION +using System.Windows.Controls; +using System.Windows.Media; +#else using Windows.UI.Text; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; #endif #if MIGRATION @@ -46,6 +51,37 @@ internal static class TextElementProperties typeof(TextElementProperties), new PropertyMetadata(0) { Inherits = true, }); + public static readonly DependencyProperty FontFamilyProperty = + DependencyProperty.RegisterAttached( + "FontFamily", + typeof(FontFamily), + typeof(TextElementProperties), + new PropertyMetadata(FontFamily.Default) { Inherits = true, }, + IsValidFontFamily); + + private static bool IsValidFontFamily(object o) => o is FontFamily; + + internal static void InvalidateMeasureOnFontFamilyChanged(UIElement uie, FontFamily font) + { + var face = font.GetFontFace(uie); + if (face.IsLoaded) + { + if (uie is TextBlock tb) + { + tb.InvalidateCacheAndMeasure(); + } + else + { + uie.InvalidateMeasure(); + } + } + else + { + face.RegisterForMeasure(uie); + _ = face.LoadAsync(); + } + } + internal static double GetBaseLineOffsetNative(UIElement uie) { Debug.Assert(uie is not null); diff --git a/src/Runtime/Runtime/System.Windows.Media/FontFamily.cs b/src/Runtime/Runtime/System.Windows.Media/FontFamily.cs index 21a19e8aa..79a3a37bd 100644 --- a/src/Runtime/Runtime/System.Windows.Media/FontFamily.cs +++ b/src/Runtime/Runtime/System.Windows.Media/FontFamily.cs @@ -12,6 +12,9 @@ \*====================================================================================*/ using System; +using System.ComponentModel; +using System.Threading.Tasks; +using OpenSilver.Internal.Media; #if MIGRATION namespace System.Windows.Media @@ -22,34 +25,90 @@ namespace Windows.UI.Xaml.Media /// /// Represents a family of related fonts. /// - public partial class FontFamily + public class FontFamily { - // Parameters: - // familyName: - // The family name of the font to represent. This can include a hashed suffix. /// - /// Initializes a new instance of the FontFamily class from the specified font - /// family string. + /// Initializes a new instance of the class from + /// the specified font family string. /// - /// The family name of the font to represent. This can include a hashed suffix. - public FontFamily(string familyName) - { - Source = familyName; + /// + /// The family name or names that comprise the new . + /// + public FontFamily(string familyName) + { + Source = familyName; + } + + internal static FontFamily Default { get; } = new FontFamily("Portable User Interface"); + + /// + /// Gets the font family name that is used to construct the object. + /// + public string Source { get; } + + /// + /// Gets a value that indicates whether the current font family object and the specified + /// font family object are the same. + /// + /// + /// The object to compare. + /// + /// + /// true if o is equal to the current object; otherwise, + /// false. If o is not a object, false is returned. + /// + public override bool Equals(object o) + { + if (o is FontFamily ff) + { + return ReferenceEquals(this, ff) || + (Source is not null && ff.Source is not null && + string.Equals(Source, ff.Source, StringComparison.OrdinalIgnoreCase)); + } + + return false; } /// - /// Gets the font family name that is used to construct the FontFamily object. + /// Serves as a hash function for . + /// + /// + /// An integer hash value. + /// + public override int GetHashCode() => Source?.ToLower().GetHashCode() ?? base.GetHashCode(); + + /// + /// Returns a string representation of this . /// - public string Source { get; private set; } + /// + /// The input font family string. + /// + public override string ToString() => Source ?? string.Empty; - internal string INTERNAL_ToHtmlString() + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static Task LoadFontAsync(FontFamily font) { - return Source; + if (font is null) + { + throw new ArgumentNullException(nameof(font)); + } + + return LoadFontAsync(font.Source); } - public override string ToString() + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static Task LoadFontAsync(string fontSource) { - return Source; + if (string.IsNullOrEmpty(fontSource)) + { + return Task.FromResult(true); + } + + return FontFace.GetFontFace(fontSource, null).LoadAsync(); } + + internal FontFace GetFontFace(UIElement relativeTo) => _face ??= FontFace.GetFontFace(Source, relativeTo); + + private FontFace _face; } } diff --git a/src/Runtime/Runtime/System.Windows/Application.cs b/src/Runtime/Runtime/System.Windows/Application.cs index 28980dafc..067398bc4 100644 --- a/src/Runtime/Runtime/System.Windows/Application.cs +++ b/src/Runtime/Runtime/System.Windows/Application.cs @@ -121,10 +121,6 @@ public Application(string rootDivId) OpenSilver.Interop.ExecuteJavaScriptVoid(@"document.isSLMigration = false", false); #endif - // Get default font-family from css - INTERNAL_FontsHelper.DefaultCssFontFamily = OpenSilver.Interop.ExecuteJavaScriptString( - "window.getComputedStyle(document.getElementsByTagName('body')[0]).getPropertyValue(\"font-family\")"); - Window.Current = _mainWindow = new Window(true); _mainWindow.AttachToDomElement(_rootDiv); diff --git a/src/Runtime/Scripts/cshtml5.js b/src/Runtime/Scripts/cshtml5.js index 5d5261d32..3176759d3 100644 --- a/src/Runtime/Scripts/cshtml5.js +++ b/src/Runtime/Scripts/cshtml5.js @@ -1179,7 +1179,18 @@ const isTouchDevice = () => { return (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)); -} +}; + +document.loadFont = async function (family, source, loadedCallback) { + try { + const font = new FontFace(family, source); + await font.load(); + document.fonts.add(font); + loadedCallback(true); + } catch (error) { + loadedCallback(false); + } +}; document.textboxHelpers = (function () { function getSelectionLength(view) {