From 33e195ac1c1b6c7d491e5e57163c1cd982570e45 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Fri, 30 Jan 2026 02:22:13 +0800 Subject: [PATCH] Fix issue #213 --- CSharpMath.Core.Tests/Atom/MathListTest.cs | 5 +- .../Display/TypesetterTests.cs | 101 ++++++++++++++++-- .../MathDisplay/Abs.png | Bin 9218 -> 9375 bytes CSharpMath.Rendering.Tests/MathInline/Abs.png | Bin 9218 -> 9375 bytes CSharpMath/Atom/MathAtom.cs | 3 +- CSharpMath/Atom/MathList.cs | 30 +++--- CSharpMath/Atom/Range.cs | 2 +- CSharpMath/Display/InterElementSpaces.cs | 2 +- CSharpMath/Display/Typesetter.cs | 6 +- 9 files changed, 114 insertions(+), 35 deletions(-) diff --git a/CSharpMath.Core.Tests/Atom/MathListTest.cs b/CSharpMath.Core.Tests/Atom/MathListTest.cs index 1e55a6bce..68de5ebb4 100644 --- a/CSharpMath.Core.Tests/Atom/MathListTest.cs +++ b/CSharpMath.Core.Tests/Atom/MathListTest.cs @@ -173,9 +173,8 @@ static void CheckListContents(MathList? list) { CheckAtomNucleusAndRange("", 13, 1), CheckAtomNucleusAndRange("∫", 14, 1), CheckAtomNucleusAndRange("θ", 15, 1), - // Comments are not given ranges as they won't affect typesetting - CheckAtomNucleusAndRange(":)", Range.UndefinedInt, Range.UndefinedInt), - CheckAtomNucleusAndRange(",", 16, 1) + CheckAtomNucleusAndRange(":)", 16, 1), + CheckAtomNucleusAndRange(",", 17, 1) ); Assert.Collection(list.Atoms[2].Superscript, CheckAtomNucleusAndRange("13", 0, 2), diff --git a/CSharpMath.Core.Tests/Display/TypesetterTests.cs b/CSharpMath.Core.Tests/Display/TypesetterTests.cs index fde7acae7..cd1b7ea4f 100644 --- a/CSharpMath.Core.Tests/Display/TypesetterTests.cs +++ b/CSharpMath.Core.Tests/Display/TypesetterTests.cs @@ -16,11 +16,11 @@ internal static ListDisplay ParseLaTeXToDisplay(string latex) => private static readonly TFont _font = new TFont(20); private static readonly TypesettingContext _context = BackEnd.TestTypesettingContext.Instance; - System.Action?> TestList(int rangeMax, double ascent, double descent, double width, double x, double y, + static System.Action?> TestList((int, int) range, double ascent, double descent, double width, double x, double y, LinePosition linePos, int indexInParent, params System.Action>[] inspectors) => d => { var list = Assert.IsType>(d); Assert.False(list.HasScript); - Assert.Equal(new Range(0, rangeMax), list.Range); + Assert.Equal(new Range(range.Item1, range.Item2), list.Range); Approximately.Equal(ascent, list.Ascent); Approximately.Equal(descent, list.Descent); Approximately.Equal(width, list.Width); @@ -29,10 +29,17 @@ internal static ListDisplay ParseLaTeXToDisplay(string latex) => Assert.Equal(indexInParent, list.IndexInParent); Assert.Collection(list.Displays, inspectors); }; - void TestOuter(string latex, int rangeMax, double ascent, double descent, double width, + static System.Action?> TestList(int rangeMax, double ascent, double descent, double width, double x, double y, + LinePosition linePos, int indexInParent, params System.Action>[] inspectors) => + TestList((0, rangeMax), ascent, descent, width, x, y, linePos, indexInParent, inspectors); + static void TestOuter(string latex, int rangeMax, double ascent, double descent, double width, params System.Action>[] inspectors) => TestList(rangeMax, ascent, descent, width, 0, 0, LinePosition.Regular, Range.UndefinedInt, inspectors) (ParseLaTeXToDisplay(latex)); + static void TestOuter(string latex, (int, int) range, double ascent, double descent, double width, + params System.Action>[] inspectors) => + TestList(range, ascent, descent, width, 0, 0, LinePosition.Regular, Range.UndefinedInt, inspectors) + (ParseLaTeXToDisplay(latex)); /// Makes sure that a single codepoint of various atom types have the same measured size. [Theory, InlineData("x"), InlineData("2"), InlineData(","), InlineData("+"), InlineData("Σ"), InlineData("𝑥")] @@ -67,18 +74,18 @@ public void TestVariablesNumbersAndOrdinaries(string latex) => Assert.Equal(40, line.Width); }); [Theory] - [InlineData("%\n1234", "1234")] - [InlineData("12.b% comment ", "12.𝑏")] - [InlineData("|`% \\notacommand \u2028@/", "|`@/")] - public void TestIgnoreComments(string latex, string text) => - TestOuter(latex, 4, 14, 4, 40, + [InlineData("%\n1234", "1234", 1, 4)] + [InlineData("12.b% comment ", "12.𝑏", 0, 4)] + [InlineData("|`% \\notacommand \u2028@/", "|`@/", 0, 5)] + public void TestIgnoreComments(string latex, string text, int rangeStart, int rangeEnd) => + TestOuter(latex, (rangeStart, rangeEnd), 14, 4, 40, d => { var line = Assert.IsType>(d); Assert.Equal(4, line.Atoms.Count); Assert.All(line.Atoms, Assert.IsNotType); Assert.Equal(text, string.Concat(line.Text)); Assert.Equal(new PointF(), line.Position); - Assert.Equal(new Range(0, 4), line.Range); + Assert.Equal(new Range(rangeStart, rangeEnd), line.Range); Assert.False(line.HasScript); Assert.Equal(14, line.Ascent); @@ -533,5 +540,81 @@ public void TestColor() => Assert.Null(line.TextColor); } ); + [Fact] + public void Issue213() { + float charWidth = 10; + float mathUnit = 20f / 18f; + foreach (var space in new[] { "", "\\," }) + // 5 mu spacing between = (Relation) and - (Unary Operator, aka Ordinary) + TestOuter($"{space}=-1", (space.Length / 2, 3), 14, 4, 3 * charWidth + 5 * mathUnit, // expected: - becomes UnaryOperator then typesetted as Ordinary + d => { + var textBefore = Assert.IsType>(d); + Assert.Equal(3 * charWidth + 5 * mathUnit, textBefore.Width); + Assert.Equal("=\u22121", string.Concat(textBefore.Text)); + Assert.Equal(new Range(space.Length / 2, 3), textBefore.Range); + Assert.Collection(textBefore.Atoms, + a => Assert.Equal("=", Assert.IsType(a).Nucleus), + a => Assert.Equal("\u2212", Assert.IsType(a).Nucleus), + a => Assert.Equal("1", Assert.IsType(a).Nucleus)); + }); + foreach (var (nonDisplayedAtomThatCreatesNewDisplayLine, additionalWidth) in new[] { (@"\, ", 3 * mathUnit), (@"\displaystyle ", 0) }) + TestOuter($@"={nonDisplayedAtomThatCreatesNewDisplayLine}-1", 4, 14, 4, 3 * charWidth + 5 * mathUnit + additionalWidth, // issue 213: inserting a space between them should still work + eq => { + var textBefore = Assert.IsType>(eq); + Assert.Equal(new PointF(), textBefore.Position); + Assert.Equal(charWidth, textBefore.Width); + Assert.Equal("=", string.Concat(textBefore.Text)); + Assert.Equal(new Range(0, 1), textBefore.Range); + Assert.Equal("=", Assert.IsType(Assert.Single(textBefore.Atoms)).Nucleus); + }, m1 => { + var textAfter = Assert.IsType>(m1); + Assert.Equal(new PointF(10 + 5 * mathUnit + additionalWidth, 0), textAfter.Position); + Assert.Equal(2 * charWidth, textAfter.Width); + Assert.Equal("\u22121", string.Concat(textAfter.Text)); + Assert.Equal(new Range(2, 2), textAfter.Range); + Assert.Collection(textAfter.Atoms, + a => Assert.Equal("\u2212", Assert.IsType(a).Nucleus), + a => Assert.Equal("1", Assert.IsType(a).Nucleus)); + }); + TestOuter("=%comment\n-1", 4, 14, 4, 3 * charWidth + 5 * mathUnit, // same should apply to Comment atoms + d => { + var textBefore = Assert.IsType>(d); + Assert.Equal(3 * charWidth + 5 * mathUnit, textBefore.Width); + Assert.Equal("=\u22121", string.Concat(textBefore.Text)); + Assert.Equal(new Range(0, 4), textBefore.Range); + Assert.Collection(textBefore.Atoms, + a => Assert.Equal("=", Assert.IsType(a).Nucleus), + a => Assert.Equal("\u2212", Assert.IsType(a).Nucleus), + a => Assert.Equal("1", Assert.IsType(a).Nucleus)); + }); + } + [Fact] + public void SpacingBetweenNumbers() { + // Numbers that have non-display atoms between them should not be fused together. + foreach (var (nonDisplayedAtomThatCreatesNewDisplayLine, additionalWidth) in new[] { (@"\quad ", 20), (@"\displaystyle ", 0) }) + TestOuter($"2{nonDisplayedAtomThatCreatesNewDisplayLine}3", 3, 14, 4, 10 + additionalWidth + 10, + d => { + var line = Assert.IsType>(d); + Assert.Equal(new PointF(), line.Position); + Assert.Equal("2", Assert.IsType(Assert.Single(line.Atoms)).Nucleus); + Assert.Equal("2", string.Concat(line.Text)); + Assert.Equal(new Range(0, 1), line.Range); + Assert.False(line.HasScript); + Assert.Equal(14, line.Ascent); + Assert.Equal(4, line.Descent); + Assert.Equal(10, line.Width); + }, + d => { + var line = Assert.IsType>(d); + Assert.Equal(new PointF(10 + additionalWidth, 0), line.Position); + Assert.Equal("3", Assert.IsType(Assert.Single(line.Atoms)).Nucleus); + Assert.Equal("3", string.Concat(line.Text)); + Assert.Equal(new Range(2, 1), line.Range); + Assert.False(line.HasScript); + Assert.Equal(14, line.Ascent); + Assert.Equal(4, line.Descent); + Assert.Equal(10, line.Width); + }); + } } } \ No newline at end of file diff --git a/CSharpMath.Rendering.Tests/MathDisplay/Abs.png b/CSharpMath.Rendering.Tests/MathDisplay/Abs.png index c00fd6cefdc1bd93e05bfe85c0502a1fac929ff7..f3369c8c1fe24d6869104d012fddd05a42c22a82 100644 GIT binary patch literal 9375 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 N!)fYkl&aq${U0YNn_2(> literal 9218 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 N!)fYkl&aq${U0YNn_2(> literal 9218 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 /// Corresponds to a range of s before finalization. /// This value is tracked in finalized s and s, - /// for utilization in CSharpMath.Editor to construct MathListIndexes from s. + /// for use in . /// public readonly struct Range : IEquatable { public const int UndefinedInt = int.MinValue; diff --git a/CSharpMath/Display/InterElementSpaces.cs b/CSharpMath/Display/InterElementSpaces.cs index b3d48d834..62808b9c1 100644 --- a/CSharpMath/Display/InterElementSpaces.cs +++ b/CSharpMath/Display/InterElementSpaces.cs @@ -52,7 +52,7 @@ static int GetInterElementSpaceArrayIndexForType(MathAtom atomType, bool row) => var multiplier = Spaces[leftIndex, rightIndex] switch { Invalid => throw new InvalidCodePathException - ($"Invalid space between {left.TypeName} and {right.TypeName}"), + ($"Invalid space between {left.TypeName} and {right.TypeName}. The {nameof(Atoms.BinaryOperator)} should have been converted to a {nameof(Atoms.UnaryOperator)} during {nameof(MathList)} {nameof(MathList.Clone)}, then converted to an {nameof(Atoms.Ordinary)} during {nameof(Typesetter)} preparation."), None => 0, Thin => 3, NsThin => style < LineStyle.Script ? 3 : 0, diff --git a/CSharpMath/Display/Typesetter.cs b/CSharpMath/Display/Typesetter.cs index 280e86bcb..6fb0b719a 100644 --- a/CSharpMath/Display/Typesetter.cs +++ b/CSharpMath/Display/Typesetter.cs @@ -125,6 +125,9 @@ internal Typesetter(TFont font, TypesettingContext context, internal static ListDisplay CreateLine( MathList list, TFont font, TypesettingContext context, LineStyle style, bool cramped, bool spaced = false) { + // NOTE: The 3 atom types that use continue; below, aka [Comment, Space, Style], correspond to non-displayed atom types + // in MathList.Clone(true). Update that if-condition and add a test in Issue213() if more such atom types are added. + // Otherwise, using these atoms between = (Relation) and - (BinaryOperator) will cause an exception from invalid spacing. List _PreprocessMathList() { MathAtom? prevAtom = null; @@ -338,8 +341,7 @@ private void CreateDisplayAtoms(List preprocessedAtoms) { if (_currentLineIndexRange.Location == Range.UndefinedInt) _currentLineIndexRange = atom.IndexRange; else - _currentLineIndexRange = new Range(_currentLineIndexRange.Location, - _currentLineIndexRange.Length + atom.IndexRange.Length); + _currentLineIndexRange += atom.IndexRange; // add the fused atoms if (atom.FusedAtoms != null) _currentAtoms.AddRange(atom.FusedAtoms);