Skip to content

Commit

Permalink
Split BigOperatorAtom.CreateBoxCore into smaller methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Lehonti Ramos committed Sep 28, 2023
1 parent 8a93f60 commit b9cadf6
Showing 1 changed file with 92 additions and 52 deletions.
144 changes: 92 additions & 52 deletions src/XamlMath.Shared/Atoms/BigOperatorAtom.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using XamlMath.Boxes;
using XamlMath.Fonts;

namespace XamlMath.Atoms;

Expand All @@ -23,91 +24,130 @@ private static Box ChangeWidth(Box box, double maxWidth)

protected override Box CreateBoxCore(TexEnvironment environment)
{
var texFont = environment.MathFont;
var style = environment.Style;

if ((this.UseVerticalLimits.HasValue && !this.UseVerticalLimits.Value) ||
(!this.UseVerticalLimits.HasValue && style >= TexStyle.Text))
(!this.UseVerticalLimits.HasValue && environment.Style >= TexStyle.Text))
// Attach atoms for limits as scripts.
return new ScriptsAtom(this.Source, this.BaseAtom, this.LowerLimitAtom, this.UpperLimitAtom)
.CreateBox(environment);

// Create box for base atom.
Box baseBox;
double delta;
BoxForBaseAtom boxForBaseAtom = CreateBoxForBaseAtom(environment);
BoxesForUpperAndLowerLimits limits = CreateBoxesForUpperAndLowerLimits(environment);
FontStyleBundle fontStyleBundle = CreateFontStyleBundle(environment);

if (this.BaseAtom is SymbolAtom && this.BaseAtom.Type == TexAtomType.BigOperator)
{
// Find character of best scale for operator symbol.
var opChar = texFont.GetCharInfo(((SymbolAtom)this.BaseAtom).Name, style).Value;
if (style < TexStyle.Text && texFont.HasNextLarger(opChar))
opChar = texFont.GetNextLargerCharInfo(opChar, style);
var charBox = new CharBox(environment, opChar) { Source = this.BaseAtom.Source };
charBox.Shift = -(charBox.Height + charBox.Depth) / 2 -
environment.MathFont.GetAxisHeight(environment.Style);
baseBox = new HorizontalBox(charBox);

delta = opChar.Metrics.Italic;
if (delta > TexUtilities.FloatPrecision)
baseBox.Add(new StrutBox(delta, 0, 0, 0));
}
else
{
baseBox = new HorizontalBox(this.BaseAtom == null ? StrutBox.Empty : this.BaseAtom.CreateBox(environment));
delta = 0;
}
// Make all component boxes equally wide.
var maxWidth = GetMaxWidth(boxForBaseAtom, limits);
var adjustedBoxForBaseAtom = boxForBaseAtom.AdjustedToMaxWidth(maxWidth);
var adjustedLimits = limits.AdjustedToMaxWidth(maxWidth);

// Create boxes for upper and lower limits.
Box? upperLimitBox = this.UpperLimitAtom == null ? null : this.UpperLimitAtom.CreateBox(
environment.GetSuperscriptStyle());
Box? lowerLimitBox = this.LowerLimitAtom == null ? null : this.LowerLimitAtom.CreateBox(
environment.GetSubscriptStyle());
return CreateResultBox(fontStyleBundle, adjustedBoxForBaseAtom, adjustedLimits);
}

// Make all component boxes equally wide.
var maxWidth = Math.Max(Math.Max(baseBox.Width, upperLimitBox == null ? 0 : upperLimitBox.Width),
lowerLimitBox == null ? 0 : lowerLimitBox.Width);
baseBox = ChangeWidth(baseBox, maxWidth);
if (upperLimitBox != null)
upperLimitBox = ChangeWidth(upperLimitBox, maxWidth);
if (lowerLimitBox != null)
lowerLimitBox = ChangeWidth(lowerLimitBox, maxWidth);
private Box CreateResultBox(FontStyleBundle fontStyleBundle, BoxForBaseAtom boxForBaseAtom, BoxesForUpperAndLowerLimits limits)
{
var texFont = fontStyleBundle.TexFont;
var style = fontStyleBundle.Syle;

var resultBox = new VerticalBox();
var opSpacing5 = texFont.GetBigOpSpacing5(style);
var kern = 0d;

// Create and add box for upper limit.
if (this.UpperLimitAtom != null)
if (UpperLimitAtom != null)
{
resultBox.Add(new StrutBox(0, opSpacing5, 0, 0));
upperLimitBox!.Shift = delta / 2;
resultBox.Add(upperLimitBox);
limits.UpperLimitBox!.Shift = boxForBaseAtom.Delta / 2;
resultBox.Add(limits.UpperLimitBox);
kern = Math.Max(texFont.GetBigOpSpacing1(style), texFont.GetBigOpSpacing3(style) -
upperLimitBox.Depth);
limits.UpperLimitBox.Depth);
resultBox.Add(new StrutBox(0, kern, 0, 0));
}

// Add box for base atom.
resultBox.Add(baseBox);
resultBox.Add(boxForBaseAtom.BaseBox);

// Create and add box for lower limit.
if (this.LowerLimitAtom != null)
if (LowerLimitAtom != null)
{
resultBox.Add(new StrutBox(0, Math.Max(texFont.GetBigOpSpacing2(style), texFont.GetBigOpSpacing4(style) -
lowerLimitBox!.Height), 0, 0));
lowerLimitBox.Shift = -delta / 2;
resultBox.Add(lowerLimitBox);
limits.LowerLimitBox!.Height), 0, 0));
limits.LowerLimitBox.Shift = -boxForBaseAtom.Delta / 2;
resultBox.Add(limits.LowerLimitBox);
resultBox.Add(new StrutBox(0, opSpacing5, 0, 0));
}

// Adjust height and depth of result box.
var baseBoxHeight = baseBox.Height;
var baseBoxHeight = boxForBaseAtom.BaseBox.Height;
var totalHeight = resultBox.Height + resultBox.Depth;
if (upperLimitBox != null)
baseBoxHeight += opSpacing5 + kern + upperLimitBox.Height + upperLimitBox.Depth;
if (limits.UpperLimitBox != null)
baseBoxHeight += opSpacing5 + kern + limits.UpperLimitBox.Height + limits.UpperLimitBox.Depth;
resultBox.Height = baseBoxHeight;
resultBox.Depth = totalHeight - baseBoxHeight;

return resultBox;
}

private readonly record struct FontStyleBundle(ITeXFont TexFont, TexStyle Syle);
private static FontStyleBundle CreateFontStyleBundle(TexEnvironment environment) => new(environment.MathFont, environment.Style);

private static double GetMaxWidth(BoxForBaseAtom boxForBaseAtom, BoxesForUpperAndLowerLimits limits)
{
var val1 = Math.Max(boxForBaseAtom.BaseBox.Width, limits.UpperLimitBox == null ? 0 : limits.UpperLimitBox.Width);
var val2 = limits.LowerLimitBox == null ? 0 : limits.LowerLimitBox.Width;
return Math.Max(val1, val2);
}

private readonly record struct BoxesForUpperAndLowerLimits(Box? UpperLimitBox, Box? LowerLimitBox)
{
internal BoxesForUpperAndLowerLimits AdjustedToMaxWidth(double maxWidth)
{
Box? newUpperLimitBox = UpperLimitBox == null ? null : ChangeWidth(UpperLimitBox, maxWidth);
Box? newLowerLimitBox = LowerLimitBox == null ? null : ChangeWidth(LowerLimitBox, maxWidth);
return new(newUpperLimitBox, newLowerLimitBox);
}
}
private BoxesForUpperAndLowerLimits CreateBoxesForUpperAndLowerLimits(TexEnvironment environment)
{
Box? upperLimitBox = (this.UpperLimitAtom == null)
? null
: this.UpperLimitAtom.CreateBox(environment.GetSuperscriptStyle());
Box? lowerLimitBox = (this.LowerLimitAtom == null)
? null
: this.LowerLimitAtom.CreateBox(environment.GetSubscriptStyle());
return new(upperLimitBox, lowerLimitBox);
}

private readonly record struct BoxForBaseAtom(Box BaseBox, double Delta)
{
internal BoxForBaseAtom AdjustedToMaxWidth(double maxWidth) =>
this with { BaseBox = ChangeWidth(BaseBox, maxWidth) };
}
private BoxForBaseAtom CreateBoxForBaseAtom(TexEnvironment environment)
{
if (BaseAtom is not SymbolAtom symbolAtom || BaseAtom.Type != TexAtomType.BigOperator)
{
Box baseBox = new HorizontalBox(BaseAtom == null ? StrutBox.Empty : BaseAtom.CreateBox(environment));
double delta = 0;
return new(baseBox, delta);
}
else
{
var texFont = environment.MathFont;
var style = environment.Style;

// Find character of best scale for operator symbol.
var opChar = texFont.GetCharInfo(symbolAtom.Name, style).Value;
if (style < TexStyle.Text && texFont.HasNextLarger(opChar))
opChar = texFont.GetNextLargerCharInfo(opChar, style);
var charBox = new CharBox(environment, opChar) { Source = BaseAtom.Source };
charBox.Shift = -(charBox.Height + charBox.Depth) / 2 -
environment.MathFont.GetAxisHeight(environment.Style);
Box baseBox = new HorizontalBox(charBox);

double delta = opChar.Metrics.Italic;
if (delta > TexUtilities.FloatPrecision)
baseBox.Add(new StrutBox(delta, 0, 0, 0));
return new(baseBox, delta);
}

}
}

0 comments on commit b9cadf6

Please sign in to comment.