diff --git a/CSharpMath.Apple/Drawing/AttributedStrings/AppleAttributedStringFactory.cs b/CSharpMath.Apple/Drawing/AttributedStrings/AppleAttributedStringFactory.cs index 7bd5d0b7..11d10ca3 100644 --- a/CSharpMath.Apple/Drawing/AttributedStrings/AppleAttributedStringFactory.cs +++ b/CSharpMath.Apple/Drawing/AttributedStrings/AppleAttributedStringFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using CoreText; using CSharpMath.Display.Text; @@ -12,7 +12,7 @@ public static class AppleAttributedStringFactory { public static NSMutableAttributedString ToNsAttributedString(this AttributedGlyphRun glyphRun) { var font = glyphRun.Font; - var text = glyphRun.Text; + var text = glyphRun.Text.ToString(); var unicodeIndexes = StringInfo.ParseCombiningCharacters(text); var attributes = new CTStringAttributes { @@ -21,7 +21,7 @@ public static NSMutableAttributedString ToNsAttributedString(this AttributedGlyp }; var attributedString = new NSMutableAttributedString(text, attributes); var kernedGlyphs = glyphRun.KernedGlyphs; - for (int i = 0; i < kernedGlyphs.Length; i++) { + for (int i = 0; i < kernedGlyphs.Count; i++) { var kern = kernedGlyphs[i].KernAfterGlyph; if (kern!=0) { var endIndex = (i < unicodeIndexes.Length - 1) ? unicodeIndexes[i + 1] : text.Length; diff --git a/CSharpMath.Apple/Font/AppleMathFont.cs b/CSharpMath.Apple/Font/AppleMathFont.cs index ccd11340..41d4b9f8 100644 --- a/CSharpMath.Apple/Font/AppleMathFont.cs +++ b/CSharpMath.Apple/Font/AppleMathFont.cs @@ -1,4 +1,4 @@ -using TGlyph = System.UInt16; +using TGlyph = System.UInt16; using Foundation; using CoreGraphics; using CoreText; @@ -8,21 +8,21 @@ namespace CSharpMath.Apple { /// Corresponds to MTFont in iosMath. - public class AppleMathFont: MathFont - { + public struct AppleMathFont: IMathFont { + public float PointSize { get; } public CGFont CgFont { get; private set; } public CTFont CtFont { get; private set; } public string Name { get; private set; } - private AppleMathFont(float pointSize): base(pointSize){} - internal AppleMathFont(string name, CGFont cgFont, float size): this(size) + internal AppleMathFont(string name, CGFont cgFont, float size) { + PointSize = size; Name = name; CgFont = cgFont; - var transform = CGAffineTransform.MakeIdentity(); - CtFont = new CTFont(CgFont, size, transform); + CtFont = new CTFont(CgFont, size, CGAffineTransform.MakeIdentity()); } - public AppleMathFont(AppleMathFont cloneMe, float pointSize): this(pointSize) { + public AppleMathFont(AppleMathFont cloneMe, float pointSize) { + PointSize = pointSize; Name = cloneMe.Name; CgFont= cloneMe.CgFont; CtFont = new CTFont(CgFont, pointSize, CGAffineTransform.MakeIdentity()); diff --git a/CSharpMath.Apple/Font/CtFontGlyphFinder.cs b/CSharpMath.Apple/Font/CtFontGlyphFinder.cs index b64ea81f..492bbf45 100644 --- a/CSharpMath.Apple/Font/CtFontGlyphFinder.cs +++ b/CSharpMath.Apple/Font/CtFontGlyphFinder.cs @@ -38,7 +38,7 @@ public byte[] ToByteArray(TGlyph[] glyphs) { return r; } - private IEnumerable FindGlyphsInternal(TFont font, string str) { + public IEnumerable FindGlyphs(TFont font, string str) { // not completely sure this is correct. Need an actual // example of a composed character sequence coming from LaTeX. var unicodeIndexes = StringInfo.ParseCombiningCharacters(str); @@ -71,9 +71,5 @@ public TGlyph FindGlyphForCharacterAtIndex(TFont font, int index, string str) { font.CtFont.GetGlyphsForCharacters(chars, glyphs, length); return glyphs[0]; } - - public TGlyph[] FindGlyphs(TFont font, string str) - => FindGlyphsInternal(font, str).ToArray(); - } } diff --git a/CSharpMath.Apple/Interfaces/IFontMeasurer.cs b/CSharpMath.Apple/Interfaces/IFontMeasurer.cs index ad8292db..ea0cda62 100644 --- a/CSharpMath.Apple/Interfaces/IFontMeasurer.cs +++ b/CSharpMath.Apple/Interfaces/IFontMeasurer.cs @@ -7,7 +7,7 @@ namespace CSharpMath.FrontEnd { public interface IFontMeasurer - where TFont: MathFont { + where TFont: IMathFont { /// A proportionality constant that is applied when /// reading from the Json table. int GetUnitsPerEm(TFont font); diff --git a/CSharpMath.Apple/Typesetting/JsonMathTable.cs b/CSharpMath.Apple/Typesetting/JsonMathTable.cs index d808059f..302350e2 100644 --- a/CSharpMath.Apple/Typesetting/JsonMathTable.cs +++ b/CSharpMath.Apple/Typesetting/JsonMathTable.cs @@ -8,7 +8,7 @@ namespace CSharpMath.Apple { /// Holds lots of constants for spacing between various visible elements by reading a JSON file. public class JsonMathTable : FontMathTable - where TFont : MathFont { + where TFont : IMathFont { /// Dictionary object containing a zillion constants, /// typically loaded from a .json file. private readonly JToken _mathTable; diff --git a/CSharpMath.Rendering/Drawing/GraphicsContext.cs b/CSharpMath.Rendering/Drawing/GraphicsContext.cs index 5617fa27..7952c602 100644 --- a/CSharpMath.Rendering/Drawing/GraphicsContext.cs +++ b/CSharpMath.Rendering/Drawing/GraphicsContext.cs @@ -65,7 +65,7 @@ public void DrawGlyphRunWithOffset(Display.Text.AttributedGlyphRun, IEnumerable { + public struct Fonts : IMathFont, IEnumerable { static Fonts() { var reader = new OpenFontReader(); var latinMathTypeface = reader.Read(new MemoryStream(Resources.LatinModernMath, false)); @@ -19,20 +19,24 @@ static Fonts() { GlobalTypefaces.AddStart(amsBlackboardBoldTypeface); } - public static Typefaces GlobalTypefaces { get; } - - public Fonts(IList localTypefaces, float pointSize) : base(pointSize) { + public Fonts(IList localTypefaces, float pointSize) { + PointSize = pointSize; var typefaces = localTypefaces.Concat(GlobalTypefaces); Typefaces = typefaces; MathTypeface = typefaces.First(t => t.HasMathTable()); } - public Fonts(Fonts cloneMe, float pointSize) : base(pointSize) { + public Fonts(Fonts cloneMe, float pointSize) { + PointSize = pointSize; Typefaces = cloneMe.Typefaces; MathTypeface = cloneMe.MathTypeface; } + public static Typefaces GlobalTypefaces { get; } + + public float PointSize { get; } public IEnumerable Typefaces { get; } public Typeface MathTypeface { get; } + public Typography.OpenFont.MathGlyphs.MathConstants MathConsts => MathTypeface.MathConsts; public IEnumerator GetEnumerator() => Typefaces.GetEnumerator(); diff --git a/CSharpMath.Rendering/Font/GlyphFinder.cs b/CSharpMath.Rendering/Font/GlyphFinder.cs index 9225ea00..4b156ea6 100644 --- a/CSharpMath.Rendering/Font/GlyphFinder.cs +++ b/CSharpMath.Rendering/Font/GlyphFinder.cs @@ -20,14 +20,14 @@ public Glyph Lookup(Fonts fonts, int codepoint) { return new Glyph(fonts.MathTypeface, fonts.MathTypeface.Lookup(GlyphNotFound)); } - public int GetCodepoint(string str, int index) => char.ConvertToUtf32(str, index - (char.IsLowSurrogate(str[index]) ? 1 : 0)); + public int GetCodepoint(string str, int index) => + char.ConvertToUtf32(str, index - (char.IsLowSurrogate(str[index]) ? 1 : 0)); - public Glyph FindGlyphForCharacterAtIndex(Fonts fonts, int index, string str) { - return Lookup(fonts, GetCodepoint(str, index)); - } + public Glyph FindGlyphForCharacterAtIndex(Fonts fonts, int index, string str) => + Lookup(fonts, GetCodepoint(str, index)); - public Glyph[] FindGlyphs(Fonts fonts, string str) => - Typography.OpenFont.StringUtils.GetCodepoints(str.ToCharArray()).Select(c => Lookup(fonts, c)).ToArray(); + public System.Collections.Generic.IEnumerable FindGlyphs(Fonts fonts, string str) => + Typography.OpenFont.StringUtils.GetCodepoints(str.ToCharArray()).Select(c => Lookup(fonts, c)); public bool GlyphIsEmpty(Glyph glyph) => glyph.IsEmpty; diff --git a/CSharpMath.Rendering/Settings.cs b/CSharpMath.Rendering/Settings.cs index 77ecc1a4..44187c4d 100644 --- a/CSharpMath.Rendering/Settings.cs +++ b/CSharpMath.Rendering/Settings.cs @@ -6,8 +6,8 @@ public static bool DisableEnhancedTextPainterColors { set => Rendering.TextBuilder.NoEnhancedColors = value; } public static bool DisableWarnings { - get => WarningException.DisableWarnings; - set => WarningException.DisableWarnings = value; + get => Warnings.DisableWarnings; + set => Warnings.DisableWarnings = value; } public static Rendering.Typefaces GlobalTypefaces => Rendering.Fonts.GlobalTypefaces; diff --git a/CSharpMath.Rendering/Text/TextAtoms.cs b/CSharpMath.Rendering/Text/TextAtoms.cs index 7a2076a9..f0dc5c84 100644 --- a/CSharpMath.Rendering/Text/TextAtoms.cs +++ b/CSharpMath.Rendering/Text/TextAtoms.cs @@ -46,7 +46,7 @@ public static class TextAtoms { { "textordfeminine" , "ª" }, { "textasteriskcentered" , "∗" }, { "textordmasculine" , "º" }, - { "textbackslash" , "∖" }, + { "textbackslash" , "\\" }, //originally was ∖ { "P", "textparagraph" , "¶" }, { "textbar" , "|" }, { "textperiodcentered" , "·" }, diff --git a/CSharpMath.Rendering/Text/TextBuilder.cs b/CSharpMath.Rendering/Text/TextBuilder.cs index 382d539d..83514e78 100644 --- a/CSharpMath.Rendering/Text/TextBuilder.cs +++ b/CSharpMath.Rendering/Text/TextBuilder.cs @@ -50,7 +50,7 @@ public static Result Build(string latex) { var breaker = new CustomBreaker { BreakNumberAfterText = true, ThrowIfCharOutOfRange = false }; var breakList = new List(); breaker.BreakWords(latex); - breaker.LoadBreakAtList(breakList); + breaker.CopyBreakResults(breakList); Result CheckDollarCount(TextAtomListBuilder atoms) { switch (dollarCount) { case 0: diff --git a/CSharpMath.Rendering/Text/TextLayoutter.cs b/CSharpMath.Rendering/Text/TextLayoutter.cs index baeca0d0..59ec9d71 100644 --- a/CSharpMath.Rendering/Text/TextLayoutter.cs +++ b/CSharpMath.Rendering/Text/TextLayoutter.cs @@ -83,9 +83,9 @@ void FinalizeInlineDisplay(float ascender, float rawDescender, float lineGap, bo var glyphs = GlyphFinder.Instance.FindGlyphs(fonts, content); //Calling Select(g => g.Typeface).Distinct() speeds up query up to 10 times, //Calling Max(Func<,>) instead of Select(Func<,>).Max() speeds up query 2 times - var typefaces = glyphs.Select(g => g.Typeface).Distinct(); - WarningException.WarnIfAny(typefaces, - tf => !Typography.OpenFont.Extensions.TypefaceExtensions.RecommendToUseTypoMetricsForLineSpacing(tf), + var typefaces = glyphs.Select(g => g.Typeface).Distinct().ToList(); + Warnings.AssertAll(typefaces, + tf => Typography.OpenFont.Extensions.TypefaceExtensions.RecommendToUseTypoMetricsForLineSpacing(tf), "This font file is too old. Only font files that support standard typographical metrics are supported."); display = new TextRunDisplay(Display.Text.AttributedGlyphRuns.Create(content, glyphs, fonts, false), t.Range, TypesettingContext.Instance); FinalizeInlineDisplay( @@ -116,7 +116,7 @@ void FinalizeInlineDisplay(float ascender, float rawDescender, float lineGap, bo AddDisplaysWithLineBreaks(a.Content, fonts, accentDisplayLine, accenteeDisplayList, invalidDisplayMaths, style, color); float _ = default; accentDisplayLine.Clear(0, 0, accenteeDisplayList, ref _, false, false, additionalLineSpacing); - WarningException.WarnIf(invalidDisplayMaths.Count > 0, "Display maths inside an accentee is unsupported -- ignoring display maths"); + Warnings.Assert(invalidDisplayMaths.Count == 0, "Display maths inside an accentee is unsupported -- ignoring display maths"); var accentee = new Displays(accenteeDisplayList); var accenteeCodepoint = a.Content.SingleChar(style); Glyph accenteeSingleGlyph = accenteeCodepoint.HasValue ? GlyphFinder.Instance.Lookup(fonts, accenteeCodepoint.Value) : GlyphFinder.Instance.EmptyGlyph; diff --git a/CSharpMath.Rendering/Text/TextSource.cs b/CSharpMath.Rendering/Text/TextSource.cs index 85ccc391..29ecdfea 100644 --- a/CSharpMath.Rendering/Text/TextSource.cs +++ b/CSharpMath.Rendering/Text/TextSource.cs @@ -1,4 +1,5 @@ namespace CSharpMath.Rendering { + public readonly struct TextSource : ISource { public TextSource(string latex) { LaTeX = latex; diff --git a/CSharpMath.SkiaSharp/SkiaPath.cs b/CSharpMath.SkiaSharp/SkiaPath.cs index 28664255..1a130e32 100644 --- a/CSharpMath.SkiaSharp/SkiaPath.cs +++ b/CSharpMath.SkiaSharp/SkiaPath.cs @@ -13,6 +13,7 @@ public void EndRead() { _owner.Canvas.DrawPath(_path, _owner.Paint); _path.Dispose(); _path = null; + _owner = null; } public void CloseContour() => _path.Close(); public void Curve3(float x1, float y1, float x2, float y2) => _path.QuadTo(x1, y1, x2, y2); diff --git a/CSharpMath.Tests/Extensions/IDisplayTestExtensions.cs b/CSharpMath.Tests/Extensions/IDisplayTestExtensions.cs index 6bd4c003..77940d00 100644 --- a/CSharpMath.Tests/Extensions/IDisplayTestExtensions.cs +++ b/CSharpMath.Tests/Extensions/IDisplayTestExtensions.cs @@ -1,4 +1,4 @@ -using CSharpMath.Display; +using CSharpMath.Display; using System; using System.Collections.Generic; using System.Linq; @@ -8,7 +8,7 @@ namespace CSharpMath.Tests { public static class IDisplayTestExtensions { - public static string StringText(this TextLineDisplay, char> display) + public static string StringText(this TextLineDisplay display) => new string(display.Text.ToArray()); } } diff --git a/CSharpMath.Tests/FrontEnd/TestFont.cs b/CSharpMath.Tests/FrontEnd/TestFont.cs new file mode 100644 index 00000000..c7491b47 --- /dev/null +++ b/CSharpMath.Tests/FrontEnd/TestFont.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CSharpMath.Enumerations; + +namespace CSharpMath.Tests.FrontEnd { + public struct TestMathFont : Display.IMathFont { + public TestMathFont(float pointSize) => PointSize = pointSize; + public float PointSize { get; } + } +} diff --git a/CSharpMath.Tests/FrontEnd/TestFontMeasurer.cs b/CSharpMath.Tests/FrontEnd/TestFontMeasurer.cs index 8b0cf7b2..f4fc5776 100644 --- a/CSharpMath.Tests/FrontEnd/TestFontMeasurer.cs +++ b/CSharpMath.Tests/FrontEnd/TestFontMeasurer.cs @@ -1,4 +1,4 @@ -using CSharpMath.FrontEnd; +using CSharpMath.FrontEnd; using System; using System.Collections.Generic; using System.Linq; @@ -7,7 +7,7 @@ using CSharpMath.Display; namespace CSharpMath.Tests.FrontEnd { - public class TestFontMeasurer : IFontMeasurer, char> { - public int GetUnitsPerEm(MathFont font) => 1000; + public class TestFontMeasurer : IFontMeasurer { + public int GetUnitsPerEm(TestMathFont font) => 1000; } } diff --git a/CSharpMath.Tests/FrontEnd/TestGlyphBoundsProvider.cs b/CSharpMath.Tests/FrontEnd/TestGlyphBoundsProvider.cs index a45ae24e..bf9d952f 100644 --- a/CSharpMath.Tests/FrontEnd/TestGlyphBoundsProvider.cs +++ b/CSharpMath.Tests/FrontEnd/TestGlyphBoundsProvider.cs @@ -1,4 +1,4 @@ -using CSharpMath.FrontEnd; +using CSharpMath.FrontEnd; using System; using System.Collections.Generic; using System.Linq; @@ -7,11 +7,10 @@ using CSharpMath.Display; using System.Drawing; using TGlyph = System.Char; -using TFont = CSharpMath.Display.MathFont; using CSharpMath.Display.Text; namespace CSharpMath.Tests.FrontEnd { - public class TestGlyphBoundsProvider : IGlyphBoundsProvider, TGlyph> { + public class TestGlyphBoundsProvider : IGlyphBoundsProvider { private const float WidthPerCharacterPerFontSize = 0.5f; // "m" and "M" get double width. private const float AscentPerFontSize = 0.7f; private const float DescentPerFontSize = 0.2f; // all constants were chosen to bear some resemblance to a real font. @@ -27,14 +26,14 @@ private int GetEffectiveLength(TGlyph[] glyphs) { return effectiveLength; } - public float GetTypographicWidth(MathFont font, AttributedGlyphRun run) { + public float GetTypographicWidth(TestMathFont font, AttributedGlyphRun run) { int effectiveLength = GetEffectiveLength(run.Glyphs.ToArray()); float width = font.PointSize * effectiveLength * WidthPerCharacterPerFontSize + run.KernedGlyphs.Sum(g => g.KernAfterGlyph); return width; } - public RectangleF[] GetBoundingRectsForGlyphs(TFont font, TGlyph[] glyphs) { + public RectangleF[] GetBoundingRectsForGlyphs(TestMathFont font, TGlyph[] glyphs) { RectangleF[] r = new RectangleF[glyphs.Length]; for (int i = 0; i < glyphs.Length; i++) { var glyph = glyphs[i]; @@ -49,7 +48,7 @@ public RectangleF[] GetBoundingRectsForGlyphs(TFont font, TGlyph[] glyphs) { return r; } - public (float[] Advances, float Total) GetAdvancesForGlyphs(MathFont font, TGlyph[] glyphs) { + public (float[] Advances, float Total) GetAdvancesForGlyphs(TestMathFont font, TGlyph[] glyphs) { var r = new float[glyphs.Length]; var total = 0f; for (int i = 0; i < glyphs.Length; i++) { diff --git a/CSharpMath.Tests/FrontEnd/TestGlyphFinder.cs b/CSharpMath.Tests/FrontEnd/TestGlyphFinder.cs index a0ca66be..83f91510 100644 --- a/CSharpMath.Tests/FrontEnd/TestGlyphFinder.cs +++ b/CSharpMath.Tests/FrontEnd/TestGlyphFinder.cs @@ -8,16 +8,16 @@ namespace CSharpMath.Tests.FrontEnd { - class TestGlyphFinder : IGlyphFinder, char> { - public char FindGlyphForCharacterAtIndex(MathFont font, int index, string str) { + class TestGlyphFinder : IGlyphFinder { + public char FindGlyphForCharacterAtIndex(TestMathFont font, int index, string str) { return str[index]; } - public char[] FindGlyphs(MathFont font, string str) => str.ToArray(); + public IEnumerable FindGlyphs(TestMathFont font, string str) => str; public string FindStringDebugPurposesOnly(char[] glyphs) => new string(glyphs); public bool GlyphIsEmpty(char glyph) - => glyph == '\0'; + => glyph is '\0'; public char EmptyGlyph => '\0'; } } diff --git a/CSharpMath.Tests/FrontEnd/TestTypesettingContext.cs b/CSharpMath.Tests/FrontEnd/TestTypesettingContext.cs index 430f13d9..253b7e6e 100644 --- a/CSharpMath.Tests/FrontEnd/TestTypesettingContext.cs +++ b/CSharpMath.Tests/FrontEnd/TestTypesettingContext.cs @@ -6,14 +6,14 @@ namespace CSharpMath.Tests.FrontEnd { public static class TestTypesettingContexts { - public static TypesettingContext, char> Create() { + public static TypesettingContext Create() { var boundsProvider = new TestGlyphBoundsProvider(); - return new TypesettingContext, char>( - (font, size) => new MathFont(size, font.Style), + return new TypesettingContext( + (font, size) => new TestMathFont(size), boundsProvider, new TestGlyphFinder(), new DoNothingFontChanger(), - new Apple.JsonMathTable, char>(new TestFontMeasurer(), TestResources.LatinMath, new TestGlyphNameProvider(), boundsProvider) + new Apple.JsonMathTable(new TestFontMeasurer(), TestResources.LatinMath, new TestGlyphNameProvider(), boundsProvider) ); } } diff --git a/CSharpMath.Tests/MockTests.cs b/CSharpMath.Tests/MockTests.cs index 20f87d7f..b99ecadf 100644 --- a/CSharpMath.Tests/MockTests.cs +++ b/CSharpMath.Tests/MockTests.cs @@ -1,4 +1,4 @@ -using CSharpMath.Display; +using CSharpMath.Display; using CSharpMath.Tests.FrontEnd; using System; using System.Drawing; @@ -13,12 +13,12 @@ public class MockTests { [Fact] public void TestGlyphBoundsWithoutM() { string hello = "Hello"; - MathFont font = new MathFont(10); + TestMathFont font = new TestMathFont(10); var provider = new TestGlyphBoundsProvider(); - var glyphRun = new AttributedGlyphRun, TGlyph> + var glyphRun = new AttributedGlyphRun { Font = font, - KernedGlyphs = hello.ToCharArray().Select(c => new KernedGlyph(c)).ToArray(), + KernedGlyphs = hello.Select(c => new KernedGlyph(c)).ToList(), }; var width = provider.GetTypographicWidth(font, glyphRun); Assertions.ApproximatelyEqual(width, 25, 0.01); @@ -27,12 +27,12 @@ public void TestGlyphBoundsWithoutM() { [Fact] public void TestGlyphBoundsWithM() { string america = "America"; - MathFont font = new MathFont(10); + TestMathFont font = new TestMathFont(10); var provider = new TestGlyphBoundsProvider(); - var glyphRun = new AttributedGlyphRun, TGlyph> + var glyphRun = new AttributedGlyphRun { Font = font, - KernedGlyphs = america.ToCharArray().Select(c => new KernedGlyph(c)).ToArray(), + KernedGlyphs = america.Select(c => new KernedGlyph(c)).ToList(), }; var width = provider.GetTypographicWidth(font, glyphRun); Assertions.ApproximatelyEqual(width, 40, 0.01); diff --git a/CSharpMath.Tests/PreTypesetting/MathListBuilderTest.cs b/CSharpMath.Tests/PreTypesetting/MathListBuilderTest.cs index 80ddbe49..b36dc4bf 100644 --- a/CSharpMath.Tests/PreTypesetting/MathListBuilderTest.cs +++ b/CSharpMath.Tests/PreTypesetting/MathListBuilderTest.cs @@ -300,9 +300,9 @@ public void TestRadical() { // nested yield return (@"\left[ 2 + \left|\frac{-x}{2}\right| \right]", singletonList, 0, new MathAtomType[] { MathAtomType.Number, MathAtomType.BinaryOperator, MathAtomType.Inner }, @"[", @"]", @"\left[ 2+\left| \frac{-x}{2}\right| \right] "); // With scripts - yield return (@"\left( 2 \right)^2", singletonList, 0, singletonNumber, @"(", @")", @"\left( 2\right) ^{2}"); + yield return (@"\left( 2 \right)^2", singletonList, 0, singletonNumber, @"(", @")", @"\left( 2\right) ^2"); // Scripts on left - yield return (@"\left(^2 \right )", singletonList, 0, new MathAtomType[] { MathAtomType.Ordinary }, @"(", @")", @"\left( {}^{2}\right) "); + yield return (@"\left(^2 \right )", singletonList, 0, new MathAtomType[] { MathAtomType.Ordinary }, @"(", @")", @"\left( {}^2\right) "); // Dot yield return (@"\left( 2 \right.", singletonList, 0, singletonNumber, @"(", @"", @"\left( 2\right. "); diff --git a/CSharpMath.Tests/TypesettingTests.cs b/CSharpMath.Tests/TypesettingTests.cs index a87bc2eb..26ac30b8 100644 --- a/CSharpMath.Tests/TypesettingTests.cs +++ b/CSharpMath.Tests/TypesettingTests.cs @@ -1,4 +1,4 @@ -using CSharpMath.Atoms; +using CSharpMath.Atoms; using CSharpMath.Display; using CSharpMath.Display.Text; using CSharpMath.Enumerations; @@ -8,7 +8,7 @@ using System.Linq; using Xunit; using TGlyph = System.Char; -using TFont = CSharpMath.Display.MathFont; +using TFont = CSharpMath.Tests.FrontEnd.TestMathFont; namespace CSharpMath.Tests { public class TypesettingTests { @@ -65,7 +65,7 @@ public void TestMultipleVariables() { var subDisplay = display.Displays[0]; var line = subDisplay as TextLineDisplay; Assert.NotNull(line); - Assert.Equal(4, line.Atoms.Count); + Assert.Equal(4, line.Atoms.Length); Assert.Equal("xyzw", line.StringText()); Assert.Equal(new PointF(), line.Position); @@ -96,7 +96,7 @@ public void TestVariablesAndNumbers() { var sub0 = display.Displays[0]; var line = sub0 as TextLineDisplay; Assert.NotNull(line); - Assert.Equal(4, line.Atoms.Count); + Assert.Equal(4, line.Atoms.Length); Assert.Equal("xy2w", line.StringText()); Assert.Equal(new PointF(), line.Position); Assert.Equal(new Range(0, 4), line.Range); @@ -300,7 +300,7 @@ public void TestBinomial() { Assert.Equal(new Range(0, 1), display.Range); Assert.False(display0.HasScript); Assert.Equal(Range.UndefinedInt, display0.IndexInParent); - Assert.Equal(3, display0.Displays.Count()); + Assert.Equal(3, display0.Displays.Count); var glyph = display0.Displays[0] as GlyphDisplay; Assert.Equal(new PointF(), glyph.Position); @@ -426,7 +426,7 @@ public void TestEquationWithOperatorsAndRelations() { Assert.Single(display.Displays); var line = display.Displays[0] as TextLineDisplay; - Assert.Equal(6, line.Atoms.Count); + Assert.Equal(6, line.Atoms.Length); Assert.Equal("2x+3=y", line.StringText()); Assert.Equal(new PointF(), line.Position); Assert.Equal(new Range(0, 6), line.Range); @@ -483,7 +483,7 @@ public void TestAtop() { Assert.Equal(new Range(0, 1), subNumerator.Range); Assert.False(subNumerator.HasScript); - var denominator = fraction.Numerator as ListDisplay; + var denominator = fraction.Denominator as ListDisplay; Assert.NotNull(denominator); Assert.Equal(LinePosition.Regular, denominator.MyLinePosition); Assertions.ApproximatePoint(0, -13.73, denominator.Position, 0.01); @@ -529,7 +529,7 @@ public void TestInner() { Assert.Equal(new Range(0, 1), display2.Range); Assert.False(display2.HasScript); Assert.Equal(Range.UndefinedInt, display2.IndexInParent); - Assert.Equal(3, display2.Displays.Count()); + Assert.Equal(3, display2.Displays.Count); var glyph = display2.Displays[0] as GlyphDisplay; Assert.Equal(new PointF(), glyph.Position); @@ -609,5 +609,42 @@ public void TestRadical() { Assertions.ApproximatelyEqual(4, display.Descent, 0.01); Assertions.ApproximatelyEqual(20, display.Width, 0.01); } + + [Fact] + public void TestRaiseBox() { + var mathList = new MathList { + new Atoms.Extension.RaiseBox { + InnerList = new MathList{ + MathAtoms.ForCharacter('r') + }, + Raise = new Space(3 * Structures.Space.Point) + } + }; + + var display = Typesetter.CreateLine(mathList, _font, _context, LineStyle.Display); + Assert.Equal(LinePosition.Regular, display.MyLinePosition); + Assert.Equal(new Range(0, 1), display.Range); + Assert.False(display.HasScript); + Assert.Equal(Range.UndefinedInt, display.IndexInParent); + Assert.Single(display.Displays); + + var display2 = display.Displays[0] as ListDisplay; + Assert.Equal(LinePosition.Regular, display2.MyLinePosition); + Assert.Equal(new PointF(0, 3), display2.Position); + Assert.Equal(new Range(0, 1), display2.Range); + Assert.False(display2.HasScript); + Assert.Equal(Range.UndefinedInt, display2.IndexInParent); + Assert.Equal(1, display2.Displays.Count); + + var line = display2.Displays[0] as TextLineDisplay; + Assert.Single(line.Atoms); + Assert.Equal("r", line.StringText()); + Assert.Equal(new PointF(), line.Position); + Assert.False(line.HasScript); + + Assertions.ApproximatelyEqual(17, display.Ascent, 0.01); + Assertions.ApproximatelyEqual(1, display.Descent, 0.01); + Assertions.ApproximatelyEqual(10, display.Width, 0.01); + } } } diff --git a/CSharpMath.Utils.NuGet/Editor.xaml.cs b/CSharpMath.Utils.NuGet/Editor.xaml.cs index 5d925167..8c78ea27 100644 --- a/CSharpMath.Utils.NuGet/Editor.xaml.cs +++ b/CSharpMath.Utils.NuGet/Editor.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Windows; @@ -16,8 +16,7 @@ namespace CSharpMath.Utils.NuGet { /// Interaction logic for MainWindow.xaml /// public partial class Editor : Window { - public Editor() { + public Editor() => InitializeComponent(); - } } } diff --git a/CSharpMath.Utils.NuGet/Editor2.xaml b/CSharpMath.Utils.NuGet/Editor2.xaml index 499ffec0..9c728c42 100644 --- a/CSharpMath.Utils.NuGet/Editor2.xaml +++ b/CSharpMath.Utils.NuGet/Editor2.xaml @@ -36,7 +36,7 @@ - + diff --git a/CSharpMath.Utils.NuGet/Editor2.xaml.cs b/CSharpMath.Utils.NuGet/Editor2.xaml.cs index 4c7a1d7c..8d0f9393 100644 --- a/CSharpMath.Utils.NuGet/Editor2.xaml.cs +++ b/CSharpMath.Utils.NuGet/Editor2.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -16,8 +16,7 @@ namespace CSharpMath.Utils.NuGet { /// Interaction logic for Editor2.xaml /// public partial class Editor2 : Window { - public Editor2() { + public Editor2() => InitializeComponent(); - } } } diff --git a/CSharpMath.Utils/CSharpMath.Utils.csproj b/CSharpMath.Utils/CSharpMath.Utils.csproj index 0ae0221a..6c7e64a9 100644 --- a/CSharpMath.Utils/CSharpMath.Utils.csproj +++ b/CSharpMath.Utils/CSharpMath.Utils.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp2.1 CSharpMath.DevUtils @@ -18,4 +18,5 @@ + diff --git a/CSharpMath.Utils/Program.cs b/CSharpMath.Utils/Program.cs index 7ee745e2..6828085a 100644 --- a/CSharpMath.Utils/Program.cs +++ b/CSharpMath.Utils/Program.cs @@ -11,7 +11,10 @@ static void Main(string[] args) { //iosMathDemo.Builder.Build(); //CSharpMathExamples.MirrorFromIos.Do(); - Rendering.FontReferenceCodeBuilder.Build(); + //Rendering.FontReferenceCodeBuilder.Build(); + Type.GetType("System.ThrowHelper").GetMethod("ThrowArgumentException_OverlapAlignmentMismatch", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, new object[0]); + //unsafe { new Span((void*)3456, 10).Overlaps(new Span((void*)3456, 10)); } + Console.WriteLine(); Console.WriteLine("Finished executing the method(s) requested."); diff --git a/CSharpMath.Utils/TypographyTest/BreakString.cs b/CSharpMath.Utils/TypographyTest/BreakString.cs new file mode 100644 index 00000000..bc4ca99f --- /dev/null +++ b/CSharpMath.Utils/TypographyTest/BreakString.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CSharpMath.DevUtils.TypographyTest { + internal static class BreakString { + public static void Benchmark() { + Console.OutputEncoding = Encoding.Unicode; + const int length = 100; + var s = new System.Diagnostics.Stopwatch(); + var b = new Typography.TextBreak.CustomBreaker(); + b.BreakWords("Initialize"); //Don't measure startup costs + void TestChar(char c) { + { + s.Restart(); + b.BreakWords(new string(c, length)); + s.Stop(); + Console.WriteLine("'{0}': {1}", c, s.Elapsed); + } + GC.Collect(); + } + foreach (var c in new[] { '0', '3', ' ', 'a', 'r', '#', '.', '%', '\r', '\u3232' }) + TestChar(c); + } + } +} diff --git a/CSharpMath/Atoms/Atom/MathAtom.cs b/CSharpMath/Atoms/Atom/MathAtom.cs index 7f45dc17..d4270a4d 100644 --- a/CSharpMath/Atoms/Atom/MathAtom.cs +++ b/CSharpMath/Atoms/Atom/MathAtom.cs @@ -108,8 +108,9 @@ public override int GetHashCode() { AtomType.GetHashCode() + 3 * ((Superscript == null) ? 0 : Superscript.GetHashCode()) + 5 * ((Subscript == null) ? 0 : Subscript.GetHashCode()) - + 7 * IndexRange.GetHashCode() - + 13 * FontStyle.GetHashCode(); + //+ 7 * IndexRange.GetHashCode() + //+ 13 * FontStyle.GetHashCode() + + 307 * Nucleus.GetHashCode(); } } } diff --git a/CSharpMath/Atoms/Atom/Space.cs b/CSharpMath/Atoms/Atom/Space.cs index 1dd909e0..7eaa3bd1 100644 --- a/CSharpMath/Atoms/Atom/Space.cs +++ b/CSharpMath/Atoms/Atom/Space.cs @@ -19,7 +19,7 @@ public Space(Space cloneMe, bool finalize) : base(cloneMe, finalize) => _space = cloneMe._space; public float ActualLength(FrontEnd.FontMathTable mathTable, TFont font) - where TFont : Display.MathFont => _space.ActualLength(mathTable, font); + where TFont : Display.IMathFont => _space.ActualLength(mathTable, font); public override string StringValue => " "; diff --git a/CSharpMath/Atoms/Factories/MathListBuilder.cs b/CSharpMath/Atoms/Factories/MathListBuilder.cs index da04b6ed..3d728fd2 100644 --- a/CSharpMath/Atoms/Factories/MathListBuilder.cs +++ b/CSharpMath/Atoms/Factories/MathListBuilder.cs @@ -104,7 +104,7 @@ internal IMathList BuildInternal(bool oneCharOnly, char stopChar) { r.Append(sublist); return r; } - //TODO +#warning TODO Example //https://phabricator.wikimedia.org/T99369 //https://phab.wmfusercontent.org/file/data/xsimlcnvo42siudvwuzk/PHID-FILE-bdcqexocj5b57tj2oezn/math_rendering.png //dt, \text{d}t, \partial t, \nabla\psi \\ \underline\overline{dy/dx, \text{d}y/\text{d}x, \frac{dy}{dx}, \frac{\text{d}y}{\text{d}x}, \frac{\partial^2}{\partial x_1\partial x_2}y} \\ \prime, @@ -112,7 +112,7 @@ internal IMathList BuildInternal(bool oneCharOnly, char stopChar) { break; case '}': if (oneCharOnly || stopChar != 0) { - throw new InvalidOperationException("This should have been handled before."); + throw new InvalidCodePathException("This should have been handled before."); } SetError("Missing opening brace"); return null; @@ -214,7 +214,7 @@ internal string ReadString() { } internal string ReadColor() { - if (!(ExpectCharacter('{'))) { + if (!ExpectCharacter('{')) { SetError("Missing {"); return null; } @@ -222,7 +222,7 @@ internal string ReadColor() { var builder = new StringBuilder(); while (HasCharacters) { var ch = GetNextCharacter(); - if (ch == '#' || (ch >= 'A' && ch <= 'F') || (ch >= 'A' && ch <= 'f') || (ch >= '0' && ch <= '9')) { + if (char.IsLetterOrDigit(ch) || ch == '#') { builder.Append(ch); } else { // we went too far diff --git a/CSharpMath/Atoms/Ranges/RangeExtensions.cs b/CSharpMath/Atoms/Ranges/RangeExtensions.cs index ab3ed42a..587bc841 100644 --- a/CSharpMath/Atoms/Ranges/RangeExtensions.cs +++ b/CSharpMath/Atoms/Ranges/RangeExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,8 +11,8 @@ public static class RangeExtensions { /// /// public static Range Combine(IEnumerable ranges) { - var trimRanges = ranges.Where(r => !(r.IsNotFound())); - if (trimRanges.IsEmpty()) { + var trimRanges = ranges.Where(r => !r.IsNotFound()).ToList(); + if (trimRanges.Count == 0) { return Ranges.NotFound; } int start = trimRanges.Min(r => r.Location); diff --git a/CSharpMath/CSharpMath.csproj b/CSharpMath/CSharpMath.csproj index c5bad511..ae20de09 100644 --- a/CSharpMath/CSharpMath.csproj +++ b/CSharpMath/CSharpMath.csproj @@ -23,6 +23,9 @@ 0.1.0.0 Debug;Release;Release-iOS + + DEBUG + @@ -34,6 +37,7 @@ + \ No newline at end of file diff --git a/CSharpMath/Display.Extension/_Typesetter.cs b/CSharpMath/Display.Extension/_Typesetter.cs index 75c4881b..94059e6e 100644 --- a/CSharpMath/Display.Extension/_Typesetter.cs +++ b/CSharpMath/Display.Extension/_Typesetter.cs @@ -8,7 +8,7 @@ namespace CSharpMath.Display.Extension { internal static class _Typesetter { internal static void CreateDisplayAtom(Typesetter t, I_ExtensionAtom atom) - where TFont : MathFont { + where TFont : IMathFont { switch (atom.AtomType) { case MathAtomType.RaiseBox: t.AddDisplayLine(false); diff --git a/CSharpMath/Display/AccentDisplay.cs b/CSharpMath/Display/AccentDisplay.cs index 04c072e9..e8dc2f9d 100644 --- a/CSharpMath/Display/AccentDisplay.cs +++ b/CSharpMath/Display/AccentDisplay.cs @@ -8,7 +8,7 @@ namespace CSharpMath.Display { public class AccentDisplay : IDisplay - where TFont : MathFont { + where TFont : IMathFont { public AccentDisplay(GlyphDisplay accentGlyphDisplay, IDisplay accentee) { diff --git a/CSharpMath/Display/FractionDisplay.cs b/CSharpMath/Display/FractionDisplay.cs index 9488656d..5bb5b559 100644 --- a/CSharpMath/Display/FractionDisplay.cs +++ b/CSharpMath/Display/FractionDisplay.cs @@ -8,7 +8,7 @@ namespace CSharpMath.Display { public class FractionDisplay : IDisplay - where TFont : MathFont { + where TFont : IMathFont { private PointF _position; // A display representing the numerator of the fraction. Its position is relative diff --git a/CSharpMath/Display/LargeOpLimitsDisplay.cs b/CSharpMath/Display/LargeOpLimitsDisplay.cs index 7487dddc..89cb22f5 100644 --- a/CSharpMath/Display/LargeOpLimitsDisplay.cs +++ b/CSharpMath/Display/LargeOpLimitsDisplay.cs @@ -8,7 +8,7 @@ namespace CSharpMath.Display { public class LargeOpLimitsDisplay : IDisplay - where TFont : MathFont { + where TFont : IMathFont { private IDisplay _nucleusDisplay; private readonly float _limitShift; private readonly int _extraPadding; diff --git a/CSharpMath/Display/LinesAndRuns/TextLineDisplay.cs b/CSharpMath/Display/LinesAndRuns/TextLineDisplay.cs index 87e77c53..d880b6aa 100644 --- a/CSharpMath/Display/LinesAndRuns/TextLineDisplay.cs +++ b/CSharpMath/Display/LinesAndRuns/TextLineDisplay.cs @@ -1,4 +1,4 @@ -using CSharpMath.Atoms; +using CSharpMath.Atoms; using CSharpMath.Display.Text; using CSharpMath.FrontEnd; using CSharpMath.Interfaces; @@ -10,27 +10,20 @@ using System.Text; namespace CSharpMath.Display { - public class TextLineDisplay : IDisplay where TFont: MathFont { - public TextLineDisplay(List> runs, - IEnumerable atoms) { + public class TextLineDisplay : IDisplay where TFont: IMathFont { + public TextLineDisplay(List> runs, List atoms) { Runs = runs; - Atoms = atoms.ToList(); + Atoms = new IMathAtom[atoms.Count]; + atoms.CopyTo(Atoms); } // We don't implement count as it's not clear if it would refer to runs or atoms. public List> Runs { get; } - public List Atoms { get; } - public List Text { - get { - List r = new List(); - foreach (var run in Runs) { - r.AddRange(run.Run.KernedGlyphs.Select(g => g.Glyph).ToArray()); - } - return r; - } - } + public IMathAtom[] Atoms { get; } + public IEnumerable Text => + Runs.SelectMany(run => run.Run.KernedGlyphs.Select(g => g.Glyph)); - public RectangleF DisplayBounds - => this.ComputeDisplayBounds(); + public RectangleF DisplayBounds => + this.ComputeDisplayBounds(); public void Draw(IGraphicsContext context) { context.SaveState(); diff --git a/CSharpMath/Display/LinesAndRuns/TextLineDisplays.cs b/CSharpMath/Display/LinesAndRuns/TextLineDisplays.cs index d58361b7..696e774e 100644 --- a/CSharpMath/Display/LinesAndRuns/TextLineDisplays.cs +++ b/CSharpMath/Display/LinesAndRuns/TextLineDisplays.cs @@ -1,4 +1,4 @@ -using CSharpMath.Atoms; +using CSharpMath.Atoms; using CSharpMath.Display.Text; using CSharpMath.FrontEnd; using CSharpMath.Interfaces; @@ -13,9 +13,9 @@ public static TextLineDisplay Create( AttributedString text, Range range, TypesettingContext context, - IEnumerable atoms + List atoms ) - where TFont: MathFont { + where TFont: IMathFont { int index = range.Location; List> textRuns = new List>(); foreach (var run in text.Runs) { diff --git a/CSharpMath/Display/LinesAndRuns/TextRunDisplay.cs b/CSharpMath/Display/LinesAndRuns/TextRunDisplay.cs index 7008e8aa..37dc6ec6 100644 --- a/CSharpMath/Display/LinesAndRuns/TextRunDisplay.cs +++ b/CSharpMath/Display/LinesAndRuns/TextRunDisplay.cs @@ -11,7 +11,7 @@ namespace CSharpMath.Display { /// Corresponds to MTCTLineDisplay in iOSMath. - public class TextRunDisplay : IDisplay where TFont : MathFont { + public class TextRunDisplay : IDisplay where TFont : IMathFont { public AttributedGlyphRun Run { get; private set; } public TextRunDisplay( diff --git a/CSharpMath/Display/MathListDisplay.cs b/CSharpMath/Display/MathListDisplay.cs index 791f2cc5..0bd3b9a3 100644 --- a/CSharpMath/Display/MathListDisplay.cs +++ b/CSharpMath/Display/MathListDisplay.cs @@ -13,7 +13,7 @@ namespace CSharpMath.Display { /// Corresponds to MTMathListDisplay in iosMath. /// public class ListDisplay: IDisplay - where TFont : MathFont { + where TFont : IMathFont { public IReadOnlyList> Displays { get; set; } public Enumerations.LinePosition MyLinePosition { get; set; } public Color? TextColor { get; set; } @@ -51,7 +51,7 @@ public void Draw(IGraphicsContext context) { context.Translate(this.Position); context.SetTextPosition(new PointF()); foreach (var displayAtom in Displays) { - displayAtom.Draw(context); + if(displayAtom != null) displayAtom.Draw(context); } context.RestoreState(); } diff --git a/CSharpMath/Display/OverUnderLineDisplay.cs b/CSharpMath/Display/OverUnderLineDisplay.cs index b3aa4ea2..8d37f5ed 100644 --- a/CSharpMath/Display/OverUnderLineDisplay.cs +++ b/CSharpMath/Display/OverUnderLineDisplay.cs @@ -9,7 +9,7 @@ namespace CSharpMath.Display { /// Corresponds to MTLineDisplay in iosMath. public class OverOrUnderlineDisplay : IDisplay - where TFont : MathFont { + where TFont : IMathFont { public OverOrUnderlineDisplay(IDisplay inner, PointF position) { Inner = inner; diff --git a/CSharpMath/Display/RadicalDisplay.cs b/CSharpMath/Display/RadicalDisplay.cs index 90392aa1..aed8f23d 100644 --- a/CSharpMath/Display/RadicalDisplay.cs +++ b/CSharpMath/Display/RadicalDisplay.cs @@ -9,7 +9,7 @@ namespace CSharpMath.Display { public class RadicalDisplay : IDisplay - where TFont : MathFont + where TFont : IMathFont { // A display representing the numerator of the fraction. Its position is relative // to the parent and it is not treated as a sub-display. diff --git a/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRun.cs b/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRun.cs index ec99b449..41ffbb1a 100644 --- a/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRun.cs +++ b/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRun.cs @@ -9,23 +9,23 @@ namespace CSharpMath.Display.Text { /// over the whole string. We use KernedGlyph objects instead of Glyphs to /// allow us to set kern on a per-glyph basis. public class AttributedGlyphRun - where TFont : MathFont { + where TFont : IMathFont { public bool Placeholder { get; set; } public IEnumerable Glyphs => KernedGlyphs.Select(g => g.Glyph); - public KernedGlyph[] KernedGlyphs { get; set; } - public string Text { get; set; } + public List> KernedGlyphs { get; set; } + public System.Text.StringBuilder Text { get; set; } - public int Length => KernedGlyphs.Length; + public int Length => KernedGlyphs.Count; public TFont Font { get; set; } - public override string ToString() => $"AttributedGlyphRun {KernedGlyphs.Length} glyphs"; + public override string ToString() => $"AttributedGlyphRun {KernedGlyphs.Count} glyphs"; } public static class AttributedGlyphRunExtensions { public static bool AttributesMatch(this AttributedGlyphRun run1, AttributedGlyphRun run2) - where TFont: MathFont { + where TFont: IMathFont { if (run1 is null || run2 is null) { return false; } diff --git a/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRuns.cs b/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRuns.cs index b17eef43..33365455 100644 --- a/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRuns.cs +++ b/CSharpMath/Display/Text/AttributedStrings/AttributedGlyphRuns.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -9,14 +9,14 @@ namespace CSharpMath.Display.Text { public static class AttributedGlyphRuns { - public static AttributedGlyphRun Create(string text, TGlyph[] glyphs, TFont font, bool isPlaceHolder) - where TFont : MathFont + public static AttributedGlyphRun Create(string text, IEnumerable glyphs, TFont font, bool isPlaceHolder) + where TFont : IMathFont { - var kernedGlyphs = glyphs.Select(g => new KernedGlyph(g)).ToArray(); + var kernedGlyphs = glyphs.Select(g => new KernedGlyph(g)).ToList(); return new AttributedGlyphRun { Placeholder = isPlaceHolder, - Text = text, + Text = new StringBuilder(text), KernedGlyphs = kernedGlyphs, Font = font }; diff --git a/CSharpMath/Display/Text/AttributedStrings/AttributedString.cs b/CSharpMath/Display/Text/AttributedStrings/AttributedString.cs index 5b5d55df..5aace693 100644 --- a/CSharpMath/Display/Text/AttributedStrings/AttributedString.cs +++ b/CSharpMath/Display/Text/AttributedStrings/AttributedString.cs @@ -6,7 +6,7 @@ namespace CSharpMath.Display.Text { public class AttributedString - where TFont: MathFont { + where TFont: IMathFont { private List> _Runs { get; } public AttributedString(IEnumerable> runs = null) { _Runs = runs?.ToList() ?? new List>(); @@ -27,8 +27,8 @@ internal void FuseMatchingRuns() { } public bool TryFuseRunAt(int index) { if (index > 0 && _Runs[index].AttributesMatch(_Runs[index - 1])) { - _Runs[index - 1].KernedGlyphs = _Runs[index - 1].KernedGlyphs.Concat(_Runs[index].KernedGlyphs).ToArray(); - _Runs[index - 1].Text = _Runs[index - 1].Text + _Runs[index].Text; + _Runs[index - 1].KernedGlyphs.AddRange(_Runs[index].KernedGlyphs); + _Runs[index - 1].Text.Append(_Runs[index].Text); _Runs.RemoveAt(index); return true; } @@ -53,7 +53,7 @@ internal void AppendGlyphRun(AttributedGlyphRun run) { public static class AttributedStringExtensions { [Obsolete("Is any code using this?", true)] public static AttributedString Combine(AttributedString attr1, AttributedString attr2) - where TFont: MathFont { + where TFont: IMathFont { if (attr1 == null) { return attr2; } @@ -66,12 +66,12 @@ public static AttributedString Combine(AttributedS [Obsolete("Is any code using this?", true)] public static AttributedString Combine(AttributedGlyphRun run1, AttributedGlyphRun run2) - where TFont: MathFont + where TFont: IMathFont => AttributedStrings.FromGlyphRuns(run1, run2); [Obsolete("Is any code using this?", true)] public static AttributedString Combine(AttributedString aStr, AttributedGlyphRun run) - where TFont: MathFont { + where TFont: IMathFont { if (aStr == null) { return AttributedStrings.FromGlyphRuns(run); } else { diff --git a/CSharpMath/Display/Text/AttributedStrings/AttributedStrings.cs b/CSharpMath/Display/Text/AttributedStrings/AttributedStrings.cs index b76557bd..12cb6d0a 100644 --- a/CSharpMath/Display/Text/AttributedStrings/AttributedStrings.cs +++ b/CSharpMath/Display/Text/AttributedStrings/AttributedStrings.cs @@ -7,7 +7,7 @@ namespace CSharpMath.Display.Text { [Obsolete("Is any code using this?", true)] public static class AttributedStrings { public static AttributedString FromGlyphRuns(params AttributedGlyphRun[] runs) - where TFont: MathFont + where TFont: IMathFont => new AttributedString(runs); } } diff --git a/CSharpMath/Display/Text/Glyphs/GlyphConstructionDisplay.cs b/CSharpMath/Display/Text/Glyphs/GlyphConstructionDisplay.cs index 6df93709..36954d37 100644 --- a/CSharpMath/Display/Text/Glyphs/GlyphConstructionDisplay.cs +++ b/CSharpMath/Display/Text/Glyphs/GlyphConstructionDisplay.cs @@ -10,7 +10,7 @@ namespace CSharpMath.Display { class GlyphConstructionDisplay : IDownshiftableDisplay - where TFont : MathFont { + where TFont : IMathFont { private TGlyph[] _glyphs; private readonly PointF[] _glyphPositions; diff --git a/CSharpMath/Display/Text/Glyphs/GlyphDisplay.cs b/CSharpMath/Display/Text/Glyphs/GlyphDisplay.cs index a5d4e0c9..9f282d8d 100644 --- a/CSharpMath/Display/Text/Glyphs/GlyphDisplay.cs +++ b/CSharpMath/Display/Text/Glyphs/GlyphDisplay.cs @@ -9,7 +9,7 @@ namespace CSharpMath.Display { public class GlyphDisplay : IDownshiftableDisplay - where TFont : MathFont { + where TFont : IMathFont { public RectangleF DisplayBounds => this.ComputeDisplayBounds(); diff --git a/CSharpMath/Display/Text/MathFont.cs b/CSharpMath/Display/Text/MathFont.cs index 92577568..9d40fdb5 100644 --- a/CSharpMath/Display/Text/MathFont.cs +++ b/CSharpMath/Display/Text/MathFont.cs @@ -3,32 +3,7 @@ using System.Text; namespace CSharpMath.Display { - using Enumerations; - public class MathFont { - public MathFont(float pointSize) { - PointSize = pointSize; - } - public MathFont(float pointSize, FontStyle style) { - PointSize = pointSize; - Style = style; - } - public float PointSize { get; } - public FontStyle Style { get; } - public bool Equals(MathFont otherFont) => - PointSize.Equals(otherFont.PointSize) - && Style.Equals(otherFont.Style); - public override bool Equals(object obj) { - if (obj is MathFont font) { - return Equals(font); - } - return false; - } - public override int GetHashCode() { - unchecked { - return Style.GetHashCode() + 13 * PointSize.GetHashCode(); - } - } - - public override string ToString() => $"[{nameof(MathFont)}<{typeof(TGlyph).Name}>: {nameof(PointSize)}={PointSize}, {nameof(Style)}={Style}]"; + public interface IMathFont { + float PointSize { get; } } } diff --git a/CSharpMath/Extensions/StringBuilderExtensions.cs b/CSharpMath/Extensions/StringBuilderExtensions.cs index 52b70a0a..55e42999 100644 --- a/CSharpMath/Extensions/StringBuilderExtensions.cs +++ b/CSharpMath/Extensions/StringBuilderExtensions.cs @@ -5,6 +5,11 @@ namespace CSharpMath { using Enumerations; public static class StringBuilderExtensions { + public static StringBuilder Append(this StringBuilder sb1, StringBuilder sb2) { + sb1.EnsureCapacity(sb1.Length + sb2.Length); + for (int i = 0; i < sb2.Length; i++) sb1.Append(sb2[i]); + return sb1; + } public static StringBuilder AppendUnlessNull(this StringBuilder builder, string appendMe, string unlessNull) { if (unlessNull!=null) { return builder.Append(appendMe); diff --git a/CSharpMath/Extensions/TypesettingContextExtensions.cs b/CSharpMath/Extensions/TypesettingContextExtensions.cs index b12158b6..45dc86fd 100644 --- a/CSharpMath/Extensions/TypesettingContextExtensions.cs +++ b/CSharpMath/Extensions/TypesettingContextExtensions.cs @@ -9,11 +9,11 @@ namespace CSharpMath.FrontEnd { public static class TypesettingContextExtensions { public static ListDisplay CreateLine(this TypesettingContext context, IMathList list, TFont font, LineStyle style) - where TFont: MathFont { + where TFont: IMathFont { return Typesetter.CreateLine(list, font, context, style); } internal static string ChangeFont(this TypesettingContext context, string input, FontStyle outputFontStyle) - where TFont: MathFont { + where TFont: IMathFont { var changer = context.FontChanger; return changer.ChangeFont(input, outputFontStyle); } diff --git a/CSharpMath/FrontEnd/FontMathTable.cs b/CSharpMath/FrontEnd/FontMathTable.cs index 221b9e43..b47d3044 100644 --- a/CSharpMath/FrontEnd/FontMathTable.cs +++ b/CSharpMath/FrontEnd/FontMathTable.cs @@ -8,7 +8,7 @@ namespace CSharpMath.FrontEnd { /// Holds lots of constants for spacing between various visible elements. public abstract class FontMathTable - where TFont : MathFont { + where TFont : IMathFont { public float MuUnit(TFont font) => font.PointSize / 18f; diff --git a/CSharpMath/FrontEnd/IGlyphBoundsProvider.cs b/CSharpMath/FrontEnd/IGlyphBoundsProvider.cs index bba02aa4..dcacd550 100644 --- a/CSharpMath/FrontEnd/IGlyphBoundsProvider.cs +++ b/CSharpMath/FrontEnd/IGlyphBoundsProvider.cs @@ -7,7 +7,7 @@ namespace CSharpMath.FrontEnd { public interface IGlyphBoundsProvider - where TFont: MathFont { + where TFont: IMathFont { /// The width of the glyph run. float GetTypographicWidth(TFont font, AttributedGlyphRun run); /// This should treat the glyphs independently. In other words, diff --git a/CSharpMath/FrontEnd/IGlyphFinder.cs b/CSharpMath/FrontEnd/IGlyphFinder.cs index f539de62..3f533ea3 100644 --- a/CSharpMath/FrontEnd/IGlyphFinder.cs +++ b/CSharpMath/FrontEnd/IGlyphFinder.cs @@ -4,9 +4,9 @@ namespace CSharpMath.FrontEnd { /// For changing a string into glyphs which will appear on the page. - public interface IGlyphFinder where TFont : Display.MathFont { + public interface IGlyphFinder where TFont : Display.IMathFont { TGlyph FindGlyphForCharacterAtIndex(TFont font, int index, string str); - TGlyph[] FindGlyphs(TFont font, string str); + IEnumerable FindGlyphs(TFont font, string str); TGlyph EmptyGlyph { get; } bool GlyphIsEmpty(TGlyph glyph); } diff --git a/CSharpMath/FrontEnd/IGraphicsContext.cs b/CSharpMath/FrontEnd/IGraphicsContext.cs index 4a9fa8ee..1fbfe349 100644 --- a/CSharpMath/FrontEnd/IGraphicsContext.cs +++ b/CSharpMath/FrontEnd/IGraphicsContext.cs @@ -7,7 +7,7 @@ namespace CSharpMath.FrontEnd { /// Represents a front-end graphics context. Used for drawing. public interface IGraphicsContext - where TFont: MathFont { + where TFont: IMathFont { void DrawLine(float x1, float y1, float x2, float y2, float strokeWidth, Color? color); void DrawGlyphRunWithOffset(AttributedGlyphRun text, PointF point, Color? color); void DrawGlyphsAtPoints(TGlyph[] glyph, TFont font, PointF[] points, Color? color); diff --git a/CSharpMath/FrontEnd/TypesettingContext.cs b/CSharpMath/FrontEnd/TypesettingContext.cs index a35eb721..8c0647e9 100644 --- a/CSharpMath/FrontEnd/TypesettingContext.cs +++ b/CSharpMath/FrontEnd/TypesettingContext.cs @@ -7,7 +7,7 @@ namespace CSharpMath.FrontEnd { /// A wrapper class holding everything the core needs to have in order /// layout the LaTeX. public class TypesettingContext - where TFont: MathFont { + where TFont: IMathFont { public IGlyphBoundsProvider GlyphBoundsProvider { get; } public IGlyphFinder GlyphFinder { get; } diff --git a/CSharpMath/Generic/BiDictionary.cs b/CSharpMath/Generic/BiDictionary.cs index e2b09d7a..f6a9b96a 100644 --- a/CSharpMath/Generic/BiDictionary.cs +++ b/CSharpMath/Generic/BiDictionary.cs @@ -21,27 +21,29 @@ public AliasDictionary(int capacity) { readonly BiDictionary main; #region AliasDictionary.Add - public void Add(IEnumerable keys, V value) { - if (main.Contains(value)) + public void Add(Span keys, V value) { + if (main.Contains(value)) { foreach (var key in keys) aliases.Add(key, value); - else if(keys.Any()) { - main.Add(keys.First(), value); - foreach (var key in keys.Skip(1)) + } else if (!keys.IsEmpty) { + main.Add(keys[0], value); + foreach (var key in keys.Slice(1)) aliases.Add(key, value); } } + //Array renting may result in larger arrays than normal -> the unused slots are nulls. + //Therefore, slicing prevents nulls from propagating through. public void Add(K mainKey, V value) { var array = ArrayPool.Shared.Rent(1); array[0] = mainKey; - Add(array, value); + Add(new Span(array, 0, 1), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey, V value) { var array = ArrayPool.Shared.Rent(2); array[0] = mainKey; array[1] = aliasKey; - Add(array, value); + Add(new Span(array, 0, 2), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, V value) { @@ -49,7 +51,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, V value) { array[0] = mainKey; array[1] = aliasKey1; array[2] = aliasKey2; - Add(array, value); + Add(new Span(array, 0, 3), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, V value) { @@ -58,7 +60,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, V value) { array[1] = aliasKey1; array[2] = aliasKey2; array[3] = aliasKey3; - Add(array, value); + Add(new Span(array, 0, 4), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, V value) { @@ -68,7 +70,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, V array[2] = aliasKey2; array[3] = aliasKey3; array[4] = aliasKey4; - Add(array, value); + Add(new Span(array, 0, 5), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K aliasKey5, V value) { @@ -79,7 +81,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K array[3] = aliasKey3; array[4] = aliasKey4; array[5] = aliasKey5; - Add(array, value); + Add(new Span(array, 0, 6), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K aliasKey5, K aliasKey6, V value) { @@ -91,7 +93,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K array[4] = aliasKey4; array[5] = aliasKey5; array[6] = aliasKey6; - Add(array, value); + Add(new Span(array, 0, 7), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K aliasKey5, K aliasKey6, K aliasKey7, V value) { @@ -104,7 +106,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K array[5] = aliasKey5; array[6] = aliasKey6; array[7] = aliasKey7; - Add(array, value); + Add(new Span(array, 0, 8), value); ArrayPool.Shared.Return(array); } public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K aliasKey5, K aliasKey6, K aliasKey7, K aliasKey8, V value) { @@ -118,7 +120,7 @@ public void Add(K mainKey, K aliasKey1, K aliasKey2, K aliasKey3, K aliasKey4, K array[6] = aliasKey6; array[7] = aliasKey7; array[8] = aliasKey8; - Add(array, value); + Add(new Span(array, 0, 9), value); ArrayPool.Shared.Return(array); } #endregion AliasDictionary.Add diff --git a/CSharpMath/Generic/WarningException.cs b/CSharpMath/Generic/WarningException.cs index 25e3f9db..d8d13066 100644 --- a/CSharpMath/Generic/WarningException.cs +++ b/CSharpMath/Generic/WarningException.cs @@ -1,38 +1,18 @@ namespace CSharpMath { - public class WarningException : System.Exception { - WarningException(string message) : base(message) => - System.Diagnostics.Debugger.Break(); - + using System.Diagnostics; + public static class Warnings { public static bool DisableWarnings { get; set; } - [System.Diagnostics.Conditional("DEBUG")] - public static void WarnIf(bool condition, string message) { - try { - if (condition && !DisableWarnings) - throw new WarningException(message); - } catch (WarningException) { } - } - - [System.Diagnostics.Conditional("DEBUG")] - public static void WarnIfAny(System.Collections.Generic.IEnumerable ie, - System.Func condition, string message) { - try { - if (!DisableWarnings) - foreach (var item in ie) - if (condition(item)) - throw new WarningException(message); - } catch (WarningException) { } - } + [Conditional("DEBUG")] + public static void Assert(bool condition, string message) => + Debug.Assert(!DisableWarnings && condition, message); - [System.Diagnostics.Conditional("DEBUG")] - public static void WarnIfAll(System.Collections.Generic.IEnumerable ie, + [Conditional("DEBUG")] + public static void AssertAll(System.Collections.Generic.IEnumerable ie, System.Func condition, string message) { - try { - if (DisableWarnings) return; + if (!DisableWarnings) foreach (var item in ie) - if (!condition(item)) return; - throw new WarningException(message); - } catch (WarningException) { } + Debug.Assert(condition(item), message); } } } diff --git a/CSharpMath/Interfaces/Display/DisplayEnumerableExtensions.cs b/CSharpMath/Interfaces/Display/DisplayEnumerableExtensions.cs index 7ccf8395..f6269017 100644 --- a/CSharpMath/Interfaces/Display/DisplayEnumerableExtensions.cs +++ b/CSharpMath/Interfaces/Display/DisplayEnumerableExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,24 +6,24 @@ namespace CSharpMath.Display { public static class DisplayEnumerableExtensions { public static float CollectionAscent(this IEnumerable> displays) - where TFont : MathFont { + where TFont : IMathFont { float r = 0; foreach (var display in displays) { - r = Math.Max(r, display.Ascent + display.Position.Y); + if (display != null) r = Math.Max(r, display.Ascent + display.Position.Y); } return r; } public static float CollectionDescent(this IEnumerable> displays) - where TFont : MathFont { + where TFont : IMathFont { float r = 0; foreach (var display in displays) { - r = Math.Max(r, display.Descent - display.Position.Y); + if(display != null) r = Math.Max(r, display.Descent - display.Position.Y); } return r; } public static float CollectionX(this IEnumerable> displays) - where TFont : MathFont + where TFont : IMathFont { float r = 0; if (displays.IsNonempty()) { @@ -32,7 +32,7 @@ public static float CollectionX(this IEnumerable(this IEnumerable> displays) - where TFont : MathFont + where TFont : IMathFont { float r = 0; if (displays.IsNonempty()) @@ -43,7 +43,7 @@ public static float CollectionMaxX(this IEnumerable(this IEnumerable> displays) - where TFont : MathFont + where TFont : IMathFont => displays.CollectionMaxX() - displays.CollectionX(); } } diff --git a/CSharpMath/Interfaces/Display/IDisplay.cs b/CSharpMath/Interfaces/Display/IDisplay.cs index 294ad3d8..258b81ef 100644 --- a/CSharpMath/Interfaces/Display/IDisplay.cs +++ b/CSharpMath/Interfaces/Display/IDisplay.cs @@ -6,7 +6,7 @@ namespace CSharpMath { public interface IDisplay - where TFont : MathFont { + where TFont : IMathFont { void Draw(IGraphicsContext context); /// The display's bounds, in its own coordinate system. RectangleF DisplayBounds { get; } @@ -29,11 +29,11 @@ public interface IDisplay public static class IDisplayExtensions { public static RectangleF ComputeDisplayBounds(this IDisplay display, bool invert = false) - where TFont : MathFont + where TFont : IMathFont => new RectangleF(0, invert ? display.Descent : -display.Ascent, display.Width, display.Ascent + display.Descent); /// Where the display is located, expressed in its parent's coordinate system. public static RectangleF Frame(this IDisplay display, bool invert = false) - where TFont : MathFont + where TFont : IMathFont => display.ComputeDisplayBounds(invert).Plus(display.Position); } } diff --git a/CSharpMath/Interfaces/Display/IDownshiftableDisplay.cs b/CSharpMath/Interfaces/Display/IDownshiftableDisplay.cs index 1396c2e0..ac08c437 100644 --- a/CSharpMath/Interfaces/Display/IDownshiftableDisplay.cs +++ b/CSharpMath/Interfaces/Display/IDownshiftableDisplay.cs @@ -5,6 +5,6 @@ namespace CSharpMath { public interface IDownshiftableDisplay: IDisplay, IDownShift - where TFont : MathFont{ + where TFont : IMathFont{ } } diff --git a/CSharpMath/Interfaces/ISpace.cs b/CSharpMath/Interfaces/ISpace.cs index 32afb451..cb65b772 100644 --- a/CSharpMath/Interfaces/ISpace.cs +++ b/CSharpMath/Interfaces/ISpace.cs @@ -7,6 +7,6 @@ public interface ISpace { float Length { get; } bool IsMu { get; } float ActualLength(FrontEnd.FontMathTable mathTable, TFont font) - where TFont : Display.MathFont; + where TFont : Display.IMathFont; } } diff --git a/CSharpMath/Structures/Space.cs b/CSharpMath/Structures/Space.cs index 9db209e3..d8f551d1 100644 --- a/CSharpMath/Structures/Space.cs +++ b/CSharpMath/Structures/Space.cs @@ -16,7 +16,7 @@ private Space(float length, bool isMu) { } public float ActualLength(FrontEnd.FontMathTable mathTable, TFont font) - where TFont : Display.MathFont => + where TFont : Display.IMathFont => IsMu ? Length * mathTable.MuUnit(font) : Length; public static Result Create(string length, string unit, bool useTextUnits) { diff --git a/CSharpMath/Typesetting/Typesetter.cs b/CSharpMath/Typesetting/Typesetter.cs index 4f36d66f..b040713c 100644 --- a/CSharpMath/Typesetting/Typesetter.cs +++ b/CSharpMath/Typesetting/Typesetter.cs @@ -13,7 +13,7 @@ namespace CSharpMath { public class Typesetter - where TFont: MathFont { + where TFont: IMathFont { internal readonly TFont _font; internal readonly TypesettingContext _context; internal FontMathTable _mathTable => _context.MathTable; @@ -745,7 +745,7 @@ private IDisplay MakeFraction(IFraction fraction) { var numeratorShiftUp = _NumeratorShiftUp(fraction.HasRule); var denominatorShiftDown = _DenominatorShiftDown(fraction.HasRule); var barLocation = _mathTable.AxisHeight(_styleFont); - var barThickness = (fraction.HasRule) ? _mathTable.FractionRuleThickness(_styleFont) : 0; + var barThickness = fraction.HasRule ? _mathTable.FractionRuleThickness(_styleFont) : 0; if (fraction.HasRule) { // this is the difference between the lowest portion of the numerator and the top edge of the fraction bar. diff --git a/Typography b/Typography index 972e433b..33a8fadc 160000 --- a/Typography +++ b/Typography @@ -1 +1 @@ -Subproject commit 972e433b9694356a36f46e99c132e21d6adc0f6b +Subproject commit 33a8fadc83e3f7f34615c9913a99558ec104f958