Skip to content

Commit

Permalink
Add CharSymbol.IsSupportedByFont API (ForNeVeR#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Apr 29, 2018
1 parent 62ce98b commit ab17032
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 60 deletions.
18 changes: 11 additions & 7 deletions src/WpfMath/CharAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public CharAtom(SourceSpan source, char character, string textStyle = null)
// Null means default text style.
public string TextStyle { get; }

private bool IsDefaultTextStyle => this.TextStyle == null;

protected override Box CreateBoxCore(TexEnvironment environment)
{
var font = GetStyledFont(environment);
Expand All @@ -25,13 +27,15 @@ protected override Box CreateBoxCore(TexEnvironment environment)
public override ITeXFont GetStyledFont(TexEnvironment environment) =>
TextStyle == TexUtilities.TextStyleName ? environment.TextFont : base.GetStyledFont(environment);

private CharInfo GetCharInfo(ITeXFont texFont, TexStyle style)
{
if (this.TextStyle == null)
return texFont.GetDefaultCharInfo(this.Character, style);
else
return texFont.GetCharInfo(this.Character, this.TextStyle, style);
}
public override bool IsSupportedByFont(ITeXFont font) =>
this.IsDefaultTextStyle
? font.SupportsDefaultCharacter(this.Character, TexStyle.Display)
: font.SupportsCharacter(this.Character, this.TextStyle, TexStyle.Display);

private CharInfo GetCharInfo(ITeXFont texFont, TexStyle style) =>
this.IsDefaultTextStyle
? texFont.GetDefaultCharInfo(this.Character, style)
: texFont.GetCharInfo(this.Character, this.TextStyle, style);

public override CharFont GetCharFont(ITeXFont texFont)
{
Expand Down
7 changes: 7 additions & 0 deletions src/WpfMath/CharSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ protected CharSymbol(SourceSpan source, TexAtomType type = TexAtomType.Ordinary)
/// <summary>Returns the preferred font to render this character.</summary>
public virtual ITeXFont GetStyledFont(TexEnvironment environment) => environment.MathFont;

/// <summary>Checks if the symbol can be rendered by font.</summary>
public abstract bool IsSupportedByFont(ITeXFont font);

/// <summary>
/// Returns the symbol rendered by font. Throws an exception if the symbol is not supported by font. Always
/// succeed if <see cref="IsSupportedByFont"/>.
/// </summary>
public abstract CharFont GetCharFont(ITeXFont texFont);
}
}
106 changes: 80 additions & 26 deletions src/WpfMath/DefaultTexFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public DefaultTexFont(double size)

public bool SupportsMetrics => true;

public bool SupportsSymbol(string name) => symbolMappings.ContainsKey(name);

public bool SupportsDefaultCharacter(char character, TexStyle style) =>
this.GetDefaultCharInfo(character, style, false) != null;

public bool SupportsCharacter(char character, string textStyle, TexStyle style) =>
this.GetCharInfo(character, textStyle, style, false) != null;

public double Size
{
get;
Expand All @@ -76,8 +84,12 @@ public ExtensionChar GetExtension(CharInfo charInfo, TexStyle style)
if (extension[i] == (int)TexCharKind.None)
parts[i] = null;
else
parts[i] = new CharInfo((char)extension[i], charInfo.Font, sizeFactor, charInfo.FontId,
GetMetrics(new CharFont((char)extension[i], charInfo.FontId), sizeFactor));
parts[i] = new CharInfo(
(char)extension[i],
charInfo.Font,
sizeFactor,
charInfo.FontId,
GetMetrics(new CharFont((char)extension[i], charInfo.FontId), sizeFactor, true));
}

return new ExtensionChar(parts[TexFontUtilities.ExtensionTop], parts[TexFontUtilities.ExtensionMiddle],
Expand All @@ -98,21 +110,33 @@ public CharInfo GetNextLargerCharInfo(CharInfo charInfo, TexStyle style)
var fontInfo = fontInfoList[charInfo.FontId];
var charFont = fontInfo.GetNextLarger(charInfo.Character);
var newFontInfo = fontInfoList[charFont.FontId];
return new CharInfo(charFont.Character, newFontInfo.Font, GetSizeFactor(style), charFont.FontId,
GetMetrics(charFont, GetSizeFactor(style)));
return new CharInfo(
charFont.Character,
newFontInfo.Font,
GetSizeFactor(style),
charFont.FontId,
GetMetrics(charFont, GetSizeFactor(style), true));
}

public CharInfo GetDefaultCharInfo(char character, TexStyle style)
private static string GetDefaultTextStyleMapping(char character)
{
if (character >= '0' && character <= '9')
return GetCharInfo(character, defaultTextStyleMappings[(int)TexCharKind.Numbers], style);
else if (character >= 'a' && character <= 'z')
return GetCharInfo(character, defaultTextStyleMappings[(int)TexCharKind.Small], style);
else
return GetCharInfo(character, defaultTextStyleMappings[(int)TexCharKind.Capitals], style);
TexCharKind GetCharKind()
{
if (character >= '0' && character <= '9')
return TexCharKind.Numbers;
else if (character >= 'a' && character <= 'z')
return TexCharKind.Small;
else
return TexCharKind.Capitals;
}

return defaultTextStyleMappings[(int)GetCharKind()];
}

private CharInfo GetCharInfo(char character, CharFont[] charFont, TexStyle style)
public CharInfo GetDefaultCharInfo(char character, TexStyle style, bool assert = true) =>
this.GetCharInfo(character, GetDefaultTextStyleMapping(character), style, assert);

private CharInfo GetCharInfo(char character, CharFont[] charFont, TexStyle style, bool assert)
{
TexCharKind charKind;
int charIndexOffset;
Expand All @@ -132,28 +156,47 @@ private CharInfo GetCharInfo(char character, CharFont[] charFont, TexStyle style
charIndexOffset = character - 'A';
}

if (charFont[(int)charKind] == null)
return GetDefaultCharInfo(character, style);
else
return GetCharInfo(new CharFont((char)(charFont[(int)charKind].Character + charIndexOffset),
charFont[(int)charKind].FontId), style);
return charFont[(int)charKind] == null
? this.GetDefaultCharInfo(character, style, assert)
: this.GetCharInfo(
new CharFont(
(char)(charFont[(int)charKind].Character + charIndexOffset),
charFont[(int)charKind].FontId),
style,
assert);
}

public CharInfo GetCharInfo(char character, string textStyle, TexStyle style) =>
textStyleMappings.TryGetValue(textStyle, out var mapping)
? this.GetCharInfo(character, mapping, style)
: throw new TextStyleMappingNotFoundException(textStyle);
public CharInfo GetCharInfo(char character, string textStyle, TexStyle style, bool assert = true)
{
if (textStyleMappings.TryGetValue(textStyle, out var mapping))
{
return this.GetCharInfo(character, mapping, style, assert);
}

return assert ? throw new TextStyleMappingNotFoundException(textStyle) : (CharInfo)null;
}

public CharInfo GetCharInfo(string symbolName, TexStyle style) =>
symbolMappings.TryGetValue(symbolName, out var mapping)
? this.GetCharInfo(mapping, style)
: throw new SymbolMappingNotFoundException(symbolName);

public CharInfo GetCharInfo(CharFont charFont, TexStyle style)
public CharInfo GetCharInfo(CharFont charFont, TexStyle style, bool assert = true)
{
var size = GetSizeFactor(style);
var fontInfo = fontInfoList[charFont.FontId];
return new CharInfo(charFont.Character, fontInfo.Font, size, charFont.FontId, GetMetrics(charFont, size));
var metrics = GetMetrics(charFont, size, assert);
if (metrics == null)
{
return null;
}

return new CharInfo(
charFont.Character,
fontInfo.Font,
size,
charFont.FontId,
metrics);
}

public double GetKern(CharFont leftCharFont, CharFont rightCharFont, TexStyle style)
Expand Down Expand Up @@ -312,12 +355,23 @@ public double GetDefaultLineThickness(TexStyle style)
return GetParameter("defaultrulethickness") * GetSizeFactor(style) * TexFontUtilities.PixelsPerPoint;
}

private TexFontMetrics GetMetrics(CharFont charFont, double size)
private static TexFontMetrics GetMetrics(CharFont charFont, double size, bool assert)
{
var fontInfo = fontInfoList[charFont.FontId];
var metrics = fontInfo.GetMetrics(charFont.Character);
return new TexFontMetrics(metrics[TexFontUtilities.MetricsWidth], metrics[TexFontUtilities.MetricsHeight],
metrics[TexFontUtilities.MetricsDepth], metrics[TexFontUtilities.MetricsItalic],
if (metrics == null)
{
if (assert)
throw new TexCharacterMappingNotFoundException(
$"Cannot determine metrics for '{charFont.Character}' character in font {charFont.FontId}");
return null;
}

return new TexFontMetrics(
metrics[TexFontUtilities.MetricsWidth],
metrics[TexFontUtilities.MetricsHeight],
metrics[TexFontUtilities.MetricsDepth],
metrics[TexFontUtilities.MetricsItalic],
size * TexFontUtilities.PixelsPerPoint);
}
}
Expand Down
5 changes: 0 additions & 5 deletions src/WpfMath/DummyAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ public DummyAtom WithType(TexAtomType type) =>
public DummyAtom AsTextSymbol() =>
this.IsTextSymbol ? this : new DummyAtom(this.Type, this.Atom, true);

public bool IsCharSymbol
{
get { return this.Atom is CharSymbol; }
}

public bool IsKern
{
get { return this.Atom is SpaceAtom; }
Expand Down
4 changes: 4 additions & 0 deletions src/WpfMath/FixedCharAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public FixedCharAtom(SourceSpan source, CharFont charFont)

public CharFont CharFont { get; }

public override bool IsSupportedByFont(ITeXFont font) =>
// Always "supported" because it ignores the font.
true;

public override CharFont GetCharFont(ITeXFont texFont)
{
return this.CharFont;
Expand Down
15 changes: 12 additions & 3 deletions src/WpfMath/ITeXFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ internal interface ITeXFont
/// <summary>Whether the font supports <see cref="CharInfo"/>.</summary>
bool SupportsMetrics { get; }

/// <summary>Whether the font supports the named symbol.</summary>
bool SupportsSymbol(string name);

/// <summary>Whether the font supports the character with default size.</summary>
bool SupportsDefaultCharacter(char character, TexStyle style);

/// <summary>Whether the font supports the character with the passed style.</summary>
bool SupportsCharacter(char character, string textStyle, TexStyle style);

double Size { get; }

ITeXFont DeriveFont(double newSize);
Expand All @@ -16,11 +25,11 @@ internal interface ITeXFont

CharInfo GetNextLargerCharInfo(CharInfo charInfo, TexStyle style);

CharInfo GetDefaultCharInfo(char character, TexStyle style);
CharInfo GetDefaultCharInfo(char character, TexStyle style, bool assert = true);

CharInfo GetCharInfo(char character, string textStyle, TexStyle style);
CharInfo GetCharInfo(char character, string textStyle, TexStyle style, bool assert = true);

CharInfo GetCharInfo(CharFont charFont, TexStyle style);
CharInfo GetCharInfo(CharFont charFont, TexStyle style, bool assert = true);

CharInfo GetCharInfo(string name, TexStyle style);

Expand Down
11 changes: 5 additions & 6 deletions src/WpfMath/RowAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,16 @@ protected override Box CreateBoxCore(TexEnvironment environment)

// Check if atom is part of ligature or should be kerned.
var kern = 0d;
if ((hasNextAtom && curAtom.GetRightType() == TexAtomType.Ordinary && curAtom.IsCharSymbol) &&
!(this.Elements[i].GetType() == typeof(CharAtom) && ((CharAtom)this.Elements[i]).TextStyle == "text"))
if (hasNextAtom && curAtom.GetRightType() == TexAtomType.Ordinary && curAtom.Atom is CharSymbol cs)
{
if (nextAtom is CharSymbol cs && ligatureKernChangeSet[(int)nextAtom.GetLeftType()])
if (nextAtom is CharSymbol ns && ligatureKernChangeSet[(int)nextAtom.GetLeftType()])
{
var font = cs.GetStyledFont(environment);
var font = ns.GetStyledFont(environment);
curAtom = curAtom.AsTextSymbol();
if (font.SupportsMetrics)
if (font.SupportsMetrics && cs.IsSupportedByFont(font))
{
var leftAtomCharFont = curAtom.GetCharFont(font);
var rightAtomCharFont = cs.GetCharFont(font);
var rightAtomCharFont = ns.GetCharFont(font);
var ligatureCharFont = font.GetLigature(leftAtomCharFont, rightAtomCharFont);
if (ligatureCharFont == null)
{
Expand Down
2 changes: 2 additions & 0 deletions src/WpfMath/SymbolAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public SymbolAtom(SourceSpan source, string name, TexAtomType type, bool isDelim
protected override Box CreateBoxCore(TexEnvironment environment) =>
new CharBox(environment, environment.MathFont.GetCharInfo(this.Name, environment.Style));

public override bool IsSupportedByFont(ITeXFont font) => font.SupportsSymbol(this.Name);

public override CharFont GetCharFont(ITeXFont texFont)
{
// Style is irrelevant here.
Expand Down
31 changes: 21 additions & 10 deletions src/WpfMath/SystemFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,24 @@ namespace WpfMath
{
internal class SystemFont : ITeXFont
{
private readonly FontFamily _fontFamily;
private readonly FontFamily fontFamily;

public SystemFont(double size, FontFamily fontFamily)
{
_fontFamily = fontFamily;
this.fontFamily = fontFamily;
Size = size;
}

public bool SupportsMetrics => false;

public bool SupportsSymbol(string name) => false;

public bool SupportsDefaultCharacter(char character, TexStyle style) =>
// System font implicitly supports any characters (so it seems).
true;

public bool SupportsCharacter(char character, string textStyle, TexStyle style) => false;

public double Size { get; }

public ITeXFont DeriveFont(double newSize) => throw MethodNotSupported(nameof(DeriveFont));
Expand All @@ -28,23 +36,26 @@ public ExtensionChar GetExtension(CharInfo charInfo, TexStyle style) =>
public CharInfo GetNextLargerCharInfo(CharInfo charInfo, TexStyle style) =>
throw MethodNotSupported(nameof(GetNextLargerCharInfo));

public CharInfo GetDefaultCharInfo(char character, TexStyle style) =>
throw MethodNotSupported(nameof(GetDefaultCharInfo));
public CharInfo GetDefaultCharInfo(char character, TexStyle style, bool assert = true) =>
assert ? throw MethodNotSupported(nameof(this.GetDefaultCharInfo)) : (CharInfo)null;

public CharInfo GetCharInfo(char character, string textStyle, TexStyle style)
public CharInfo GetCharInfo(char character, string textStyle, TexStyle style, bool assert = true)
{
var typeface = GetTypeface();
var typeface = this.GetTypeface();
if (!typeface.TryGetGlyphTypeface(out var glyphTypeface))
{
throw new TypeFaceNotFoundException($"Glyph typeface for font {_fontFamily.BaseUri} was not found");
if (assert)
throw new TypeFaceNotFoundException(
$"Glyph typeface for font {this.fontFamily.BaseUri} was not found");
return null;
}

var metrics = GetFontMetrics(character, typeface);
return new CharInfo(character, glyphTypeface, 1.0, TexFontUtilities.NoFontId, metrics);
}

public CharInfo GetCharInfo(CharFont charFont, TexStyle style) =>
throw MethodNotSupported(nameof(GetCharInfo));
public CharInfo GetCharInfo(CharFont charFont, TexStyle style, bool assert = true) =>
assert ? throw MethodNotSupported(nameof(this.GetCharInfo)) : (CharInfo)null;

public CharInfo GetCharInfo(string name, TexStyle style) => throw MethodNotSupported(nameof(GetCharInfo));

Expand Down Expand Up @@ -121,6 +132,6 @@ private TexFontMetrics GetFontMetrics(char c, Typeface typeface)
return new TexFontMetrics(formattedText.Width, formattedText.Height, 0.0, formattedText.Width, 1.0);
}

private Typeface GetTypeface() => new Typeface(_fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); // TODO[F]: Put into lazy field
private Typeface GetTypeface() => new Typeface(this.fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); // TODO[F]: Put into lazy field
}
}
5 changes: 2 additions & 3 deletions src/WpfMath/TexFontInfo.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Windows.Media;
using WpfMath.Exceptions;

namespace WpfMath
{
Expand Down Expand Up @@ -139,12 +138,12 @@ public double GetXHeight(double factor)
return this.XHeight * factor;
}

/// <summary>Return the character metrics or <c>null</c> if the metrics weren't found.</summary>
public double[] GetMetrics(char character)
{
if (metrics.Length <= character || metrics[character] == null)
{
throw new TexCharacterMappingNotFoundException(
$"Cannot determine metrics for '{character}' character in font {FontId}");
return null;
}

return this.metrics[character];
Expand Down

0 comments on commit ab17032

Please sign in to comment.