diff --git a/src/WpfMath/CharAtom.cs b/src/WpfMath/CharAtom.cs
index c59563bd..b02a4265 100644
--- a/src/WpfMath/CharAtom.cs
+++ b/src/WpfMath/CharAtom.cs
@@ -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);
@@ -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)
{
diff --git a/src/WpfMath/CharSymbol.cs b/src/WpfMath/CharSymbol.cs
index bc14d6ef..a5ef76ea 100644
--- a/src/WpfMath/CharSymbol.cs
+++ b/src/WpfMath/CharSymbol.cs
@@ -14,6 +14,13 @@ protected CharSymbol(SourceSpan source, TexAtomType type = TexAtomType.Ordinary)
/// Returns the preferred font to render this character.
public virtual ITeXFont GetStyledFont(TexEnvironment environment) => environment.MathFont;
+ /// Checks if the symbol can be rendered by font.
+ public abstract bool IsSupportedByFont(ITeXFont font);
+
+ ///
+ /// Returns the symbol rendered by font. Throws an exception if the symbol is not supported by font. Always
+ /// succeed if .
+ ///
public abstract CharFont GetCharFont(ITeXFont texFont);
}
}
diff --git a/src/WpfMath/DefaultTexFont.cs b/src/WpfMath/DefaultTexFont.cs
index 720c5bff..5c8dffae 100644
--- a/src/WpfMath/DefaultTexFont.cs
+++ b/src/WpfMath/DefaultTexFont.cs
@@ -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;
@@ -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],
@@ -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;
@@ -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)
@@ -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);
}
}
diff --git a/src/WpfMath/DummyAtom.cs b/src/WpfMath/DummyAtom.cs
index 65935b2d..c16f9a1b 100644
--- a/src/WpfMath/DummyAtom.cs
+++ b/src/WpfMath/DummyAtom.cs
@@ -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; }
diff --git a/src/WpfMath/FixedCharAtom.cs b/src/WpfMath/FixedCharAtom.cs
index 1eb8c7b0..3f4f1ed2 100644
--- a/src/WpfMath/FixedCharAtom.cs
+++ b/src/WpfMath/FixedCharAtom.cs
@@ -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;
diff --git a/src/WpfMath/ITeXFont.cs b/src/WpfMath/ITeXFont.cs
index 6a06175a..f51d2403 100644
--- a/src/WpfMath/ITeXFont.cs
+++ b/src/WpfMath/ITeXFont.cs
@@ -6,6 +6,15 @@ internal interface ITeXFont
/// Whether the font supports .
bool SupportsMetrics { get; }
+ /// Whether the font supports the named symbol.
+ bool SupportsSymbol(string name);
+
+ /// Whether the font supports the character with default size.
+ bool SupportsDefaultCharacter(char character, TexStyle style);
+
+ /// Whether the font supports the character with the passed style.
+ bool SupportsCharacter(char character, string textStyle, TexStyle style);
+
double Size { get; }
ITeXFont DeriveFont(double newSize);
@@ -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);
diff --git a/src/WpfMath/RowAtom.cs b/src/WpfMath/RowAtom.cs
index f5141bb2..3525ed77 100644
--- a/src/WpfMath/RowAtom.cs
+++ b/src/WpfMath/RowAtom.cs
@@ -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)
{
diff --git a/src/WpfMath/SymbolAtom.cs b/src/WpfMath/SymbolAtom.cs
index d548b766..7ff04e39 100644
--- a/src/WpfMath/SymbolAtom.cs
+++ b/src/WpfMath/SymbolAtom.cs
@@ -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.
diff --git a/src/WpfMath/SystemFont.cs b/src/WpfMath/SystemFont.cs
index f14228fc..26c2729c 100644
--- a/src/WpfMath/SystemFont.cs
+++ b/src/WpfMath/SystemFont.cs
@@ -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));
@@ -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));
@@ -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
}
}
diff --git a/src/WpfMath/TexFontInfo.cs b/src/WpfMath/TexFontInfo.cs
index ffe6a5bc..e62a9e17 100644
--- a/src/WpfMath/TexFontInfo.cs
+++ b/src/WpfMath/TexFontInfo.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Windows.Media;
-using WpfMath.Exceptions;
namespace WpfMath
{
@@ -139,12 +138,12 @@ public double GetXHeight(double factor)
return this.XHeight * factor;
}
+ /// Return the character metrics or null if the metrics weren't found.
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];