diff --git a/Documentation/input/_Head.cshtml b/Documentation/input/_Head.cshtml index 1c5145a73..588052125 100644 --- a/Documentation/input/_Head.cshtml +++ b/Documentation/input/_Head.cshtml @@ -1,3 +1,4 @@ + \ No newline at end of file diff --git a/Documentation/input/examples/render-customization/colors-fonts.cshtml b/Documentation/input/examples/render-customization/colors-fonts.cshtml index bf3560111..5723fff49 100644 --- a/Documentation/input/examples/render-customization/colors-fonts.cshtml +++ b/Documentation/input/examples/render-customization/colors-fonts.cshtml @@ -16,7 +16,7 @@ Order: 10 - copyrightFont Font Music copyright information in page layouts 12px Arial bold + copyrightFont Font Music copyright information in page layouts bold 12px Arial titleFont Font Title of the song in page layouts 32px Georgia subTitleFont Font Subtitle of the song in page layouts 20px Georgia wordsFont Font Lyrics information of the song in page layouts 15px Georgia @@ -26,7 +26,7 @@ Order: 10 graceFont Font The numbers grace notes in tablature staves 11px Arial barNumberFont Font The numbers above bars 11px Arial fingeringFont Font The numbers shown for fingering information14px Georgia - markerFont Font The section marker labels 14px Arial bold + markerFont Font The section marker labels bold 14px Arial staffLineColor Color The lines for all staves rgb(165,165,165) barSeparatorColor Color The lines for bar separators and repeat indicators rgb(34,34,17) @@ -44,7 +44,7 @@ Order: 10

Usage of different fonts

- The usage of other fonts can result in alignment or layouting issues and in a slighly worse performance. If such problems are detected, please inform us on GitHub. The format for fonts is similar to the CSS shorthand font declarations but with some limitations: Size Family Style. No relative font sizes are supported and every size beside px will be converted to px. For styles italic and bold are supported. + The usage of other fonts can result in alignment or layouting issues and in a slighly worse performance. If such problems are detected, please inform us on GitHub. The format for fonts is similar to the CSS shorthand font declarations but with some limitations: Style Size Family. No relative font sizes are supported and every size beside px will be converted to px. For styles italic and bold are supported.
@@ -76,7 +76,7 @@ Order: 10 $('#alphaTabScriptInit').alphaTab({ file: '@Context.GetLink("/assets/files/features/Skillet.gp5")', resources: { - copyrightFont: "12px Roboto bold", + copyrightFont: "bold 12px Roboto", titleFont: "32px 'Roboto Slab'", subTitleFont: "20px 'Roboto Slab'", wordsFont: "15px 'Roboto Slab'", @@ -86,7 +86,7 @@ Order: 10 graceFont: "11px Roboto", barNumberFont: "11px Roboto", fingeringFont: "14px 'Roboto Slab'", - markerFont: "14px Roboto bold", + markerFont: "bold 14px Roboto", staffLineColor: "rgba(255,255,255, 0.8)", barSeparatorColor: "rgb(255,255,255)", @@ -105,17 +105,17 @@ Order: 10 .alphaTabSurface { background: #000; }
Fonts

-For the .net platform any installed font on the system can be used. For JavaScript until this feature is implemented the 2 fonts "Arial" and "Georgia" are officially supported. Due to the nature of Web Workers, no font metrics are available which needs a custom solution for measuring texts. -
-On .net simply construct the Font object to configure your desired fonts. For JavaScript you can use any CSS font property compliant string. Relative font sizes with percentual values are not supported. +For the .net platform any installed font on the system can be used. Simply construct the Font object to configure your desired fonts. +

+

+For the JavaScript platform any font that might be installed on the client machines can be used. Any additional fonts can be added via WebFonts. The rendering of the score will be delayed until it is detected that the font was loaded. Simply use any CSS font property compliant string as configuration. Relative font sizes with percentual values are not supported, remaining values will be considered if supported.

diff --git a/Phase/Mscorlib/system/CsString.hx b/Phase/Mscorlib/system/CsString.hx index cc6ab031c..a56cabd0f 100644 --- a/Phase/Mscorlib/system/CsString.hx +++ b/Phase/Mscorlib/system/CsString.hx @@ -358,4 +358,5 @@ abstract CsString(String) from String to String @:op(A + B) public static inline function add16(lhs : system.CsString, rhs : system.Single) : system.CsString return lhs + rhs.toString(); @:op(A + B) public static inline function add17(lhs : system.CsString, rhs : system.Double) : system.CsString return lhs + rhs.toString(); @:op(A + B) public static inline function add18(lhs : system.CsString, rhs : system.CsString) : system.CsString return lhs.toHaxeString() + rhs.toHaxeString(); + @:op(A + B) public static inline function add19(lhs : system.CsString, rhs : system.Boolean) : system.CsString return lhs.toHaxeString() + Std.string(rhs); } \ No newline at end of file diff --git a/Samples/CSharp/AlphaTab.Samples.PngDump/Program.cs b/Samples/CSharp/AlphaTab.Samples.PngDump/Program.cs index 1cac59557..f1da2231c 100644 --- a/Samples/CSharp/AlphaTab.Samples.PngDump/Program.cs +++ b/Samples/CSharp/AlphaTab.Samples.PngDump/Program.cs @@ -52,7 +52,7 @@ private static void Main(string[] args) var info = new FileInfo(args[0]); var path = Path.Combine(info.DirectoryName, Path.GetFileNameWithoutExtension(info.Name) + "-" + i + ".png"); - using (var full = SKSurface.Create(totalWidth, totalHeight, SKImageInfo.PlatformColorType, SKAlphaType.Premul)) + using (var full = SKSurface.Create(new SKImageInfo(totalWidth, totalHeight, SKImageInfo.PlatformColorType, SKAlphaType.Premul))) { var y = 0; foreach (var image in images) diff --git a/Source/AlphaTab.CSharp/Platform/CSharp/ManagedUiFacade.cs b/Source/AlphaTab.CSharp/Platform/CSharp/ManagedUiFacade.cs index a7adc889f..05e2f641a 100644 --- a/Source/AlphaTab.CSharp/Platform/CSharp/ManagedUiFacade.cs +++ b/Source/AlphaTab.CSharp/Platform/CSharp/ManagedUiFacade.cs @@ -10,7 +10,7 @@ namespace AlphaTab.Platform.CSharp { - public abstract class ManagedUiFacade : IUiFacade + internal abstract class ManagedUiFacade : IUiFacade { protected ConcurrentQueue TotalResultCount { get; private set; } diff --git a/Source/AlphaTab.CSharp/Platform/Svg/FontSizes.cs b/Source/AlphaTab.CSharp/Platform/Svg/FontSizes.cs new file mode 100644 index 000000000..b7ab8f728 --- /dev/null +++ b/Source/AlphaTab.CSharp/Platform/Svg/FontSizes.cs @@ -0,0 +1,27 @@ +namespace AlphaTab.Platform.Svg +{ + /// + /// This public class stores text widths for several fonts and allows width calculation + /// + internal partial class FontSizes + { + public static void GenerateFontLookup(string family) + { + if (FontSizeLookupTables == null) + { + Init(); + } + + if (FontSizeLookupTables.ContainsKey(family)) + { + return; + } + + // TODO: maybe allow fallback to GDI/Skia based on availability? + FontSizeLookupTables[family] = new byte[] + { + 8 + }; + } + } +} diff --git a/Source/AlphaTab.JavaScript/Collections/FastDictionary.cs b/Source/AlphaTab.JavaScript/Collections/FastDictionary.cs index a1cfe8679..713b2ff02 100644 --- a/Source/AlphaTab.JavaScript/Collections/FastDictionary.cs +++ b/Source/AlphaTab.JavaScript/Collections/FastDictionary.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.Runtime.CompilerServices; using Phase; using Phase.Attributes; diff --git a/Source/AlphaTab.JavaScript/Environment.cs b/Source/AlphaTab.JavaScript/Environment.cs index fe8ffd375..c542800d5 100644 --- a/Source/AlphaTab.JavaScript/Environment.cs +++ b/Source/AlphaTab.JavaScript/Environment.cs @@ -6,6 +6,7 @@ using AlphaTab.Platform.Svg; using AlphaTab.Rendering.Glyphs; using AlphaTab.Util; +using AlphaTab.Utils; using Haxe; using Phase; using StringBuilder = AlphaTab.Collections.StringBuilder; @@ -20,17 +21,8 @@ namespace AlphaTab internal partial class Environment { public static string ScriptFile { get; set; } - public static bool IsFontLoaded { get; set; } - public static event Action FontLoaded; - private static void OnFontLoaded() - { - var handler = FontLoaded; - if (handler != null) - { - handler(); - } - } + public static FontLoadingChecker BravuraFontChecker { get; private set; } private static void PlatformInit() { @@ -133,7 +125,10 @@ private static void PlatformInit() } } - CheckForFontAvailability(); + BravuraFontChecker = new FontLoadingChecker("alphaTab", + "&#" + (int)MusicFontSymbol.ClefG + ";" + ); + BravuraFontChecker.CheckForFontAvailability(); } else { @@ -207,95 +202,5 @@ private static string ScriptFileFromStack(string stack) return matches[1]; } - - public static void CheckForFontAvailability() - { - var isWorker = - Script.Write( - "untyped __js__(\"typeof(WorkerGlobalScope) !== 'undefined' && self instanceof WorkerGlobalScope\")"); - if (isWorker) - { - // no web fonts in web worker - IsFontLoaded = false; - return; - } - - var cssFontLoadingModuleSupported = Browser.Document.Fonts.IsTruthy() && - Browser.Document.Fonts.Member("load").IsTruthy(); - if (cssFontLoadingModuleSupported) - { - Action checkFont = null; - checkFont = () => - { - Browser.Document.Fonts.Load("1em alphaTab").Then(_ => - { - if (Browser.Document.Fonts.Check("1em alphaTab")) - { - Logger.Info("Rendering", "Font available"); - IsFontLoaded = true; - OnFontLoaded(); - } - else - { - Browser.Window.SetTimeout((Action)(() => - { - checkFont(); - }), - 250); - } - - return true; - }); - }; - checkFont(); - } - else - { - Action checkFont = null; - checkFont = () => - { - var document = Browser.Document; - var testItem = document.GetElementById("alphaTabFontChecker"); - - if (testItem == null) - { - // create a hidden element with the font style set - testItem = document.CreateElement("div"); - testItem.SetAttribute("id", "alphaTabFontChecker"); - testItem.Style.Opacity = "0"; - testItem.Style.Position = "absolute"; - testItem.Style.Left = "0"; - testItem.Style.Top = "0"; - testItem.Style.FontSize = "100px"; - testItem.ClassList.Add("at"); - testItem.InnerHTML = "&#" + (int)MusicFontSymbol.ClefG + ";"; - - document.Body.AppendChild(testItem); - } - - // get width - var width = testItem.OffsetWidth; - if (width > 30 && width < 100) - { - IsFontLoaded = true; - document.Body.RemoveChild(testItem); - OnFontLoaded(); - } - else - { - Browser.Window.SetTimeout((Action)(() => - { - checkFont(); - }), - 250); - } - }; - Browser.Window.AddEventListener("DOMContentLoaded", - (Action)(() => - { - checkFont(); - })); - } - } } } diff --git a/Source/AlphaTab.JavaScript/Haxe/IO/HaxeBytesBuffer.cs b/Source/AlphaTab.JavaScript/Haxe/IO/HaxeBytesBuffer.cs index c13804122..500a360a4 100644 --- a/Source/AlphaTab.JavaScript/Haxe/IO/HaxeBytesBuffer.cs +++ b/Source/AlphaTab.JavaScript/Haxe/IO/HaxeBytesBuffer.cs @@ -1,5 +1,4 @@ -using Haxe; -using Phase.Attributes; +using Phase.Attributes; namespace Haxe.IO { diff --git a/Source/AlphaTab.JavaScript/Haxe/Js/Html/Blob.cs b/Source/AlphaTab.JavaScript/Haxe/Js/Html/Blob.cs index f7decba52..f478ada74 100644 --- a/Source/AlphaTab.JavaScript/Haxe/Js/Html/Blob.cs +++ b/Source/AlphaTab.JavaScript/Haxe/Js/Html/Blob.cs @@ -1,5 +1,4 @@ -using Haxe; -using Phase.Attributes; +using Phase.Attributes; namespace AlphaTab.Haxe.Js.Html { diff --git a/Source/AlphaTab.JavaScript/Haxe/Js/Html/CSSStyleDeclaration.cs b/Source/AlphaTab.JavaScript/Haxe/Js/Html/CSSStyleDeclaration.cs index 77dddd379..76ffdece9 100644 --- a/Source/AlphaTab.JavaScript/Haxe/Js/Html/CSSStyleDeclaration.cs +++ b/Source/AlphaTab.JavaScript/Haxe/Js/Html/CSSStyleDeclaration.cs @@ -57,5 +57,6 @@ public class CSSStyleDeclaration [Name("transitionDuration")] public HaxeString TransitionDuration { get; set; } + } } diff --git a/Source/AlphaTab.JavaScript/Haxe/Js/Html/DOMElement.cs b/Source/AlphaTab.JavaScript/Haxe/Js/Html/DOMElement.cs index 83ac99540..8e980567e 100644 --- a/Source/AlphaTab.JavaScript/Haxe/Js/Html/DOMElement.cs +++ b/Source/AlphaTab.JavaScript/Haxe/Js/Html/DOMElement.cs @@ -67,7 +67,6 @@ public class DOMElement : Node [Name("scrollLeft")] public HaxeInt ScrollLeft { get; set; } - [Name("querySelector")] public extern Element QuerySelector(HaxeString selectors); diff --git a/Source/AlphaTab.JavaScript/Haxe/Js/Navigator.cs b/Source/AlphaTab.JavaScript/Haxe/Js/Navigator.cs index bc8f1f0a5..ccc51165d 100644 --- a/Source/AlphaTab.JavaScript/Haxe/Js/Navigator.cs +++ b/Source/AlphaTab.JavaScript/Haxe/Js/Navigator.cs @@ -1,5 +1,4 @@ -using System; -using Haxe; +using Haxe; using Phase.Attributes; namespace AlphaTab.Haxe.Js diff --git a/Source/AlphaTab.JavaScript/Haxe/Zip/Reader.cs b/Source/AlphaTab.JavaScript/Haxe/Zip/Reader.cs index 7f74efd63..2f11442cd 100644 --- a/Source/AlphaTab.JavaScript/Haxe/Zip/Reader.cs +++ b/Source/AlphaTab.JavaScript/Haxe/Zip/Reader.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Haxe.IO; using Phase.Attributes; diff --git a/Source/AlphaTab.JavaScript/IO/ZipFile.cs b/Source/AlphaTab.JavaScript/IO/ZipFile.cs index 9e3f026c4..36bc4afd8 100644 --- a/Source/AlphaTab.JavaScript/IO/ZipFile.cs +++ b/Source/AlphaTab.JavaScript/IO/ZipFile.cs @@ -1,5 +1,4 @@ -using System; -using AlphaTab.Importer; +using AlphaTab.Importer; using Haxe.Zip; using Phase; diff --git a/Source/AlphaTab.JavaScript/Importer/ScoreLoader.cs b/Source/AlphaTab.JavaScript/Importer/ScoreLoader.cs index 72a3caadd..cd2f99172 100644 --- a/Source/AlphaTab.JavaScript/Importer/ScoreLoader.cs +++ b/Source/AlphaTab.JavaScript/Importer/ScoreLoader.cs @@ -4,7 +4,6 @@ using AlphaTab.Platform; using Haxe.Js.Html; using Phase; -using Phase.Attributes; namespace AlphaTab.Importer { diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthFlashOutput.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthFlashOutput.cs index 68dd07a8f..c5e9f3ebb 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthFlashOutput.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthFlashOutput.cs @@ -1,6 +1,5 @@ using System; using AlphaTab.Audio.Synth; -using AlphaTab.Audio.Synth.Ds; using AlphaTab.Collections; using AlphaTab.Haxe.Js; using AlphaTab.Haxe.Js.Html; diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebAudioOutput.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebAudioOutput.cs index 89700e896..eb5894393 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebAudioOutput.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebAudioOutput.cs @@ -4,8 +4,6 @@ using AlphaTab.Haxe.Js; using AlphaTab.Haxe.Js.Html; using AlphaTab.Haxe.Js.Html.Audio; -using AlphaTab.Util; -using Haxe; namespace AlphaTab.Platform.JavaScript { diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebWorkerApi.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebWorkerApi.cs index a0f6436b7..819333703 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebWorkerApi.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWebWorkerApi.cs @@ -2,7 +2,6 @@ using AlphaTab.Audio.Synth; using AlphaTab.Audio.Synth.Midi; using AlphaTab.Audio.Synth.Util; -using AlphaTab.Collections; using AlphaTab.Haxe.Js.Html; using AlphaTab.Model; using AlphaTab.Util; diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWorkerSynthOutput.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWorkerSynthOutput.cs index 9221fbb4a..23b8e157d 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWorkerSynthOutput.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaSynthWorkerSynthOutput.cs @@ -1,6 +1,5 @@ using System; using AlphaTab.Audio.Synth; -using AlphaTab.Audio.Synth.Ds; using AlphaTab.Haxe.Js; using AlphaTab.Haxe.Js.Html; using AlphaTab.Util; diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaTabApi.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaTabApi.cs index 114ed245f..6d13704b2 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaTabApi.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/AlphaTabApi.cs @@ -1,12 +1,10 @@ using System; -using System.Diagnostics.Contracts; using AlphaTab.Audio.Generator; using AlphaTab.Audio.Synth; using AlphaTab.Audio.Synth.Midi; using AlphaTab.Collections; using AlphaTab.Haxe.Js; using AlphaTab.Haxe.Js.Html; -using AlphaTab.Importer; using AlphaTab.Model; using AlphaTab.UI; using Haxe.Js.Html; diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/Html5Canvas.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/Html5Canvas.cs index 8aa3b1eb6..a852cbdbe 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/Html5Canvas.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/Html5Canvas.cs @@ -2,9 +2,7 @@ using AlphaTab.Haxe.Js; using AlphaTab.Haxe.Js.Html; using AlphaTab.Platform.Model; -using AlphaTab.Rendering; using AlphaTab.Rendering.Glyphs; -using Phase; using TextAlign = AlphaTab.Platform.Model.TextAlign; namespace AlphaTab.Platform.JavaScript diff --git a/Source/AlphaTab.JavaScript/Platform/JavaScript/JQueryAlphaTab.cs b/Source/AlphaTab.JavaScript/Platform/JavaScript/JQueryAlphaTab.cs index 495e4890a..ca8e7c454 100644 --- a/Source/AlphaTab.JavaScript/Platform/JavaScript/JQueryAlphaTab.cs +++ b/Source/AlphaTab.JavaScript/Platform/JavaScript/JQueryAlphaTab.cs @@ -6,7 +6,6 @@ using AlphaTab.Haxe.Js.Html; using AlphaTab.Model; using AlphaTab.Rendering; -using AlphaTab.UI; using AlphaTab.Util; using Phase; using Phase.Attributes; diff --git a/Source/AlphaTab.JavaScript/Platform/Platform.cs b/Source/AlphaTab.JavaScript/Platform/Platform.cs index a02ffe332..88db5c9ac 100644 --- a/Source/AlphaTab.JavaScript/Platform/Platform.cs +++ b/Source/AlphaTab.JavaScript/Platform/Platform.cs @@ -1,11 +1,7 @@ using System; -using AlphaTab.Audio.Synth; -using AlphaTab.Audio.Synth.Midi; -using AlphaTab.Audio.Synth.Midi.Event; using AlphaTab.Collections; using AlphaTab.Haxe.Js; using AlphaTab.IO; -using AlphaTab.Platform.JavaScript; using AlphaTab.Util; using Haxe; using Haxe.Js.Html; diff --git a/Source/AlphaTab.JavaScript/Platform/Svg/FontSizes.cs b/Source/AlphaTab.JavaScript/Platform/Svg/FontSizes.cs index 8d79bec2e..3c989a64c 100644 --- a/Source/AlphaTab.JavaScript/Platform/Svg/FontSizes.cs +++ b/Source/AlphaTab.JavaScript/Platform/Svg/FontSizes.cs @@ -5,36 +5,44 @@ namespace AlphaTab.Platform.Svg { /// - /// This public class stores text widths for several fonts and allows width calculation + /// This public class stores text widths for several fonts and allows width calculation /// internal partial class FontSizes { - public static byte[] GenerateFontLookup(string family) + public static void GenerateFontLookup(string family) { if (FontSizeLookupTables == null) { - FontSizeLookupTables = new FastDictionary(); + Init(); } - if (FontSizeLookupTables.ContainsKey(family)) { - return FontSizeLookupTables[family]; + return; } - var canvas = (CanvasElement)Browser.Document.CreateElement("canvas"); - var measureContext = (CanvasRenderingContext2D)canvas.GetContext("2d"); - measureContext.Font = "11px " + family; + if (Lib.Global.document) + { + var canvas = (CanvasElement)Browser.Document.CreateElement("canvas"); + var measureContext = (CanvasRenderingContext2D)canvas.GetContext("2d"); + measureContext.Font = "11px " + family; + + var sizes = new FastList(); + for (var i = 0x20; i < 255; i++) + { + var s = Platform.StringFromCharCode(i); + sizes.Add((byte)measureContext.MeasureText(s).Width); + } - var sizes = new FastList(); - for (var i = 0x20; i < 255; i++) + var data = sizes.ToArray(); + FontSizeLookupTables[family] = data; + } + else { - var s = Platform.StringFromCharCode(i); - sizes.Add((byte)measureContext.MeasureText(s).Width); + FontSizeLookupTables[family] = new byte[] + { + 8 + }; } - - var data = sizes.ToArray(); - FontSizeLookupTables[family] = data; - return data; } } } diff --git a/Source/AlphaTab.JavaScript/Rendering/Utils/BoundsLookup.cs b/Source/AlphaTab.JavaScript/Rendering/Utils/BoundsLookup.cs index afd55f27e..a3b22f563 100644 --- a/Source/AlphaTab.JavaScript/Rendering/Utils/BoundsLookup.cs +++ b/Source/AlphaTab.JavaScript/Rendering/Utils/BoundsLookup.cs @@ -1,5 +1,4 @@ using AlphaTab.Collections; -using AlphaTab.Haxe.Js.Html; using AlphaTab.Model; using AlphaTab.Platform; diff --git a/Source/AlphaTab.JavaScript/Settings.cs b/Source/AlphaTab.JavaScript/Settings.cs index f7aeffe78..94ebb3650 100644 --- a/Source/AlphaTab.JavaScript/Settings.cs +++ b/Source/AlphaTab.JavaScript/Settings.cs @@ -885,8 +885,6 @@ private static Font DecodeFont(object value, Font defaultFont) family = family.Substring(1, family.Length - 2); } - FontSizes.GenerateFontLookup(family); - string fontSizeString = style.FontSize.ToLowerCase(); float fontSize; // as per https://websemantics.uk/articles/font-size-conversion/ diff --git a/Source/AlphaTab.JavaScript/UI/BrowserUiFacade.cs b/Source/AlphaTab.JavaScript/UI/BrowserUiFacade.cs index d5b6ab53f..fd4cfe7eb 100644 --- a/Source/AlphaTab.JavaScript/UI/BrowserUiFacade.cs +++ b/Source/AlphaTab.JavaScript/UI/BrowserUiFacade.cs @@ -8,9 +8,12 @@ using AlphaTab.Model; using AlphaTab.Platform; using AlphaTab.Platform.JavaScript; +using AlphaTab.Platform.Model; +using AlphaTab.Platform.Svg; using AlphaTab.Rendering; using AlphaTab.Rendering.Utils; using AlphaTab.Util; +using AlphaTab.Utils; using Haxe; using Haxe.Js.Html; using Phase; @@ -21,6 +24,8 @@ internal class BrowserUiFacade : IUiFacade { private event Action _rootContainerBecameVisible; + private FastDictionary _fontCheckers; + private AlphaTabApi _api; private string _contents; private string _file; @@ -34,20 +39,52 @@ internal class BrowserUiFacade : IUiFacade public IContainer RootContainer { get; } public bool AreWorkersSupported { get; } - public bool CanRender => _api.Settings.Engine != "html5" || Environment.IsFontLoaded; + public bool CanRender => AreAllFontsLoaded(); + + private bool AreAllFontsLoaded() + { + if (!Environment.BravuraFontChecker.IsFontLoaded) + { + return false; + } + + foreach (var font in _fontCheckers) + { + var checker = _fontCheckers[font]; + if (!checker.IsFontLoaded) + { + return false; + } + } + + Logger.Debug("Font", "All fonts loaded: " + _fontCheckers.Count); - public event Action CanRenderChanged + return true; + } + + public event Action CanRenderChanged; + private void OnFontLoaded(string family) { - add => Environment.FontLoaded += value; - remove => Environment.FontLoaded += value; + FontSizes.GenerateFontLookup(family); + + if (AreAllFontsLoaded()) + { + var handler = CanRenderChanged; + if (handler != null) + { + handler(); + } + } } public BrowserUiFacade(Element rootElement) { + _fontCheckers = new FastDictionary(); rootElement.ClassList.Add("alphaTab"); RootContainer = new HtmlElementContainer(rootElement); var workersUnsupported = !Browser.Window.Member("Worker"); AreWorkersSupported = !workersUnsupported; + Environment.BravuraFontChecker.FontLoaded += OnFontLoaded; } public IScoreRenderer CreateWorkerRenderer() @@ -104,6 +141,8 @@ public void Initialize(AlphaTabApi api, object raw) api.Container.Resize += ShowSvgsInViewPort; } + SetupFontCheckers(settings); + #region build tracks array // get track data to parse @@ -129,7 +168,6 @@ public void Initialize(AlphaTabApi api, object raw) #endregion - _contents = ""; var element = ((HtmlElementContainer)api.Container); if (dataAttributes.ContainsKey("tex") && element.Element.InnerText.IsTruthy()) @@ -156,6 +194,32 @@ public void Initialize(AlphaTabApi api, object raw) } } + private void SetupFontCheckers(Settings settings) + { + RegisterFontChecker(settings.RenderingResources.CopyrightFont); + RegisterFontChecker(settings.RenderingResources.EffectFont); + RegisterFontChecker(settings.RenderingResources.FingeringFont); + RegisterFontChecker(settings.RenderingResources.GraceFont); + RegisterFontChecker(settings.RenderingResources.MarkerFont); + RegisterFontChecker(settings.RenderingResources.TablatureFont); + RegisterFontChecker(settings.RenderingResources.TitleFont); + RegisterFontChecker(settings.RenderingResources.WordsFont); + RegisterFontChecker(settings.RenderingResources.BarNumberFont); + RegisterFontChecker(settings.RenderingResources.FretboardNumberFont); + RegisterFontChecker(settings.RenderingResources.SubTitleFont); + } + + private void RegisterFontChecker(Font font) + { + if (!_fontCheckers.ContainsKey(font.Family)) + { + var checker = new FontLoadingChecker(font.Family); + _fontCheckers[font.Family] = checker; + checker.FontLoaded += OnFontLoaded; + checker.CheckForFontAvailability(); + } + } + public void Destroy() { ((HtmlElementContainer)RootContainer).Element.InnerHTML = ""; @@ -334,7 +398,7 @@ private void CreateStyleElement(Settings settings) css.AppendLine("}"); styleElement.InnerHTML = css.ToString(); elementDocument.GetElementsByTagName("head").Item(0).AppendChild(styleElement); - Environment.CheckForFontAvailability(); + Environment.BravuraFontChecker.CheckForFontAvailability(); } } diff --git a/Source/AlphaTab.JavaScript/Utils/FontLoadingChecker.cs b/Source/AlphaTab.JavaScript/Utils/FontLoadingChecker.cs new file mode 100644 index 000000000..b188a4dde --- /dev/null +++ b/Source/AlphaTab.JavaScript/Utils/FontLoadingChecker.cs @@ -0,0 +1,194 @@ +using System; +using AlphaTab.Haxe.Js; +using AlphaTab.Haxe.Js.Html; +using AlphaTab.Platform; +using AlphaTab.Util; +using Phase; + +namespace AlphaTab.Utils +{ + /// + /// This small utility helps to detect whether a particular font is already loaded. + /// + internal class FontLoadingChecker + { + private readonly string _family; + private readonly string _fallbackText; + private bool _isStarted; + public bool IsFontLoaded { get; set; } + public event Action FontLoaded; + + private void OnFontLoaded() + { + var handler = FontLoaded; + if (handler != null) + { + handler(_family); + } + } + + public FontLoadingChecker( + string family, + string fallbackText = null) + { + _family = family; + _fallbackText = fallbackText == null ? "BESbwy" : fallbackText; + } + + public void CheckForFontAvailability() + { + var isWorker = + Script.Write( + "untyped __js__(\"typeof(WorkerGlobalScope) !== 'undefined' && self instanceof WorkerGlobalScope\")"); + if (isWorker) + { + // no web fonts in web worker + IsFontLoaded = false; + return; + } + + if (_isStarted) + { + return; + } + + _isStarted = true; + var failCounter = 0; + var failCounterId = Browser.Window.SetInterval(new Action(() => + { + failCounter++; + Logger.Warning("Rendering", + "Could not load font '" + _family + "' within " + (failCounter * 5) + " seconds"); + }), + 5000); + + Logger.Debug("Font", "Start checking for font availablility: " + _family); + var cssFontLoadingModuleSupported = Browser.Document.Fonts.IsTruthy() && + Browser.Document.Fonts.Member("load").IsTruthy(); + if (cssFontLoadingModuleSupported) + { + Logger.Debug("Font", "[" + _family + "] Font API available"); + Action checkFont = null; + checkFont = () => + { + Browser.Document.Fonts.Load("1em " + _family).Then(_ => + { + Logger.Debug("Font", "[" + _family + "] Font API signaled loaded"); + if (Browser.Document.Fonts.Check("1em " + _family)) + { + Logger.Info("Rendering", "[" + _family + "] Font API signaled available"); + IsFontLoaded = true; + Browser.Window.ClearInterval(failCounterId); + OnFontLoaded(); + } + else + { + Logger.Debug("Font", + "[" + _family + + "] Font API loaded reported, but font not available, checking later again"); + Browser.Window.SetTimeout((Action)(() => + { + checkFont(); + }), + 250); + } + + return true; + }); + }; + checkFont(); + } + else + { + Logger.Debug("Font", "[" + _family + "] Font API not available, using resize trick"); + // based on the idea of https://www.bramstein.com/writing/detecting-system-fonts-without-flash.html + // simply create 3 elements with the 3 default font families and measure them + // then change to the desired font and expect a change on the width + + Element sans = null; + Element serif = null; + Element monospace = null; + + var initialSansWidth = -1; + var initialSerifWidth = -1; + var initialMonospaceWidth = -1; + + Action checkFont = null; + checkFont = () => + { + if (sans == null) + { + sans = CreateCheckerElement("sans-serif"); + serif = CreateCheckerElement("serif"); + monospace = CreateCheckerElement("monospace"); + + Browser.Document.Body.AppendChild(sans); + Browser.Document.Body.AppendChild(serif); + Browser.Document.Body.AppendChild(monospace); + + initialSansWidth = sans.OffsetWidth; + initialSerifWidth = serif.OffsetWidth; + initialMonospaceWidth = monospace.OffsetWidth; + + sans.Style.FontFamily = "'" + _family + "',sans-serif"; + serif.Style.FontFamily = "'" + _family + "',serif"; + monospace.Style.FontFamily = "'" + _family + "',monospace"; + + + } + + var sansWidth = sans.OffsetWidth; + var serifWidth = serif.OffsetWidth; + var monospaceWidth = monospace.OffsetWidth; + + if ((sansWidth != initialSansWidth && serifWidth != initialSerifWidth) || + (sansWidth != initialSansWidth && monospaceWidth != initialMonospaceWidth) || + (serifWidth != initialSerifWidth && monospaceWidth != initialMonospaceWidth)) + { + if (sansWidth == serifWidth || sansWidth == monospaceWidth || serifWidth == monospaceWidth) + { + Browser.Document.Body.RemoveChild(sans); + Browser.Document.Body.RemoveChild(serif); + Browser.Document.Body.RemoveChild(monospace); + IsFontLoaded = true; + Browser.Window.ClearInterval(failCounterId); + OnFontLoaded(); + } + else + { + Browser.Window.SetTimeout(checkFont, 250); + } + } + else + { + Browser.Window.SetTimeout(checkFont, 250); + } + }; + + Browser.Window.AddEventListener("DOMContentLoaded", + (Action)(() => + { + checkFont(); + })); + } + } + + private Element CreateCheckerElement(string family) + { + var document = Browser.Document; + var checkerElement = document.CreateElement("span"); + checkerElement.Style.Display = "inline-block"; + checkerElement.Style.Position = "absolute"; + checkerElement.Style.Overflow = "hidden"; + + checkerElement.Style.Top = "-1000px"; + + checkerElement.Style.FontSize = "100px"; + checkerElement.Style.FontFamily = family; + checkerElement.InnerHTML = _fallbackText; + + document.Body.AppendChild(checkerElement); + return checkerElement; + } + } +} diff --git a/Source/AlphaTab/AlphaTabApi.cs b/Source/AlphaTab/AlphaTabApi.cs index 144e97dc4..a1db98bb0 100644 --- a/Source/AlphaTab/AlphaTabApi.cs +++ b/Source/AlphaTab/AlphaTabApi.cs @@ -214,6 +214,10 @@ public void RenderScore(Score score, int[] trackIndexes = null) InternalRenderTracks(score, tracks.ToArray()); } + /// + /// Renders the given list of tracks. + /// + /// The tracks to render. They must all belong to the same score. public void RenderTracks(Track[] tracks) { if (tracks.Length > 0) diff --git a/Source/AlphaTab/Audio/Synth/ISynthOutput.cs b/Source/AlphaTab/Audio/Synth/ISynthOutput.cs index 38b68f95b..f9b3ebcc4 100644 --- a/Source/AlphaTab/Audio/Synth/ISynthOutput.cs +++ b/Source/AlphaTab/Audio/Synth/ISynthOutput.cs @@ -1,5 +1,4 @@ using System; -using AlphaTab.Audio.Synth.Ds; namespace AlphaTab.Audio.Synth { diff --git a/Source/AlphaTab/Platform/Svg/FontSizes.cs b/Source/AlphaTab/Platform/Svg/FontSizes.cs index f055a170b..b180d3c64 100644 --- a/Source/AlphaTab/Platform/Svg/FontSizes.cs +++ b/Source/AlphaTab/Platform/Svg/FontSizes.cs @@ -5,7 +5,7 @@ namespace AlphaTab.Platform.Svg { /// - /// This public class stores text widths for several fonts and allows width calculation + /// This public class stores text widths for several fonts and allows width calculation /// internal partial class FontSizes { @@ -57,18 +57,11 @@ public static float MeasureString(string s, string family, float size, FontStyle byte[] data; var dataSize = 11; - if (FontSizeLookupTables.ContainsKey(family)) + if (!FontSizeLookupTables.ContainsKey(family)) { - data = FontSizeLookupTables[family]; - } - else - { - // TODO: on-the-fly-generation for all canvas types - data = new byte[] - { - 8 - }; + GenerateFontLookup(family); } + data = FontSizeLookupTables[family]; float factor = 1; if ((style & FontStyle.Italic) != 0)