Skip to content

Commit

Permalink
(#63) CharInfo: decouple from WPF and move into Shared assembly
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Dec 31, 2022
1 parent 4cef929 commit baddf7a
Show file tree
Hide file tree
Showing 18 changed files with 87 additions and 71 deletions.
4 changes: 2 additions & 2 deletions src/WpfMath.Shared/CharFont.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace WpfMath
{
// Single character together with specific font.
internal class CharFont
/// <summary>Single character together with specific font.</summary>
public class CharFont
{
public CharFont(char character, int fontId)
{
Expand Down
13 changes: 6 additions & 7 deletions src/WpfMath/CharInfo.cs → src/WpfMath.Shared/CharInfo.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System.Windows.Media;
using WpfMath.Fonts;

namespace WpfMath
{
// Single character togeter with information about font and metrics.
internal class CharInfo
/// <summary>Single character together with information about font and metrics.</summary>
public class CharInfo
{
public CharInfo(char character, GlyphTypeface font, double size, int fontId, TexFontMetrics metrics)
public CharInfo(char character, IFontTypeface font, double size, int fontId, TexFontMetrics metrics)
{
this.Character = character;
this.Font = font;
Font = font;
this.Size = size;
FontId = fontId;
this.Metrics = metrics;
Expand All @@ -20,10 +20,9 @@ public char Character
set;
}

public GlyphTypeface Font
public IFontTypeface Font
{
get;
set;
}

public double Size
Expand Down
File renamed without changes.
5 changes: 5 additions & 0 deletions src/WpfMath.Shared/Fonts/IFontTypeface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace WpfMath.Fonts;

public interface IFontTypeface
{
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/WpfMath.Shared/TexFontMetrics.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace WpfMath
{
// Specifies font metrics for single character.
internal class TexFontMetrics
public class TexFontMetrics
{
public TexFontMetrics(double width, double height, double depth, double italicWidth, double scale)
{
Expand Down
4 changes: 4 additions & 0 deletions src/WpfMath.Shared/WpfMath.Shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@
<InternalsVisibleTo Include="WpfMath.Tests" />
</ItemGroup>

<ItemGroup>
<Folder Include="Atoms" />
</ItemGroup>

</Project>
12 changes: 6 additions & 6 deletions src/WpfMath.Tests/CharBoxTests.fs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
namespace WpfMath.Tests

open System.Windows
open System
open System.Windows.Media

open Foq
open Xunit

open WpfMath
open WpfMath.Boxes
open WpfMath.Fonts
open WpfMath.Rendering
open WpfMath.Exceptions
open System

type CharBoxTests() =
static do Utils.initializeFontResourceLoading()
Expand All @@ -26,25 +26,25 @@ type CharBoxTests() =
TexEnvironment(TexStyle.Display, mathFont, textFont)

[<Fact>]
member _.``CharBox rendering calls to RenderGlyphRun``() =
member _.``CharBox rendering calls to RenderCharacter``() =
let char = environment.MathFont.GetDefaultCharInfo('x', TexStyle.Display).Value
let x = 0.5
let y = 1.0

let mockedRenderer = Mock.Of<IElementRenderer>()
let charBox = CharBox(environment, char)
charBox.RenderTo(mockedRenderer, x, y)
Mock.Verify(<@ mockedRenderer.RenderGlyphRun(any(), x, y, Brushes.Black) @>, once)
Mock.Verify(<@ mockedRenderer.RenderCharacter(any(), x, y, Brushes.Black) @>, once)

[<Fact>]
member _.``Currently unsupporteded characters like "Å" should result in TexCharacterMappingNotFoundException``() =
member _.``Currently unsupported characters like "Å" should result in TexCharacterMappingNotFoundException``() =
Assert.IsType<TexCharacterMappingNotFoundException>(
environment.MathFont.GetDefaultCharInfo('Å', TexStyle.Display).Error)

[<Fact>]
member _.``CharBox GetGlyphRun for \text{} should throw the TexCharacterMappingNotFoundException``() =
let atom = parse @"\text{∅}"
let charBox : CharBox = downcast atom.CreateBox(environment)
let action = Func<obj>(fun () -> upcast charBox.GetGlyphRun(20.0, 0.5, 1.0))
let action = Func<obj>(fun () -> upcast WpfCharInfoEx.GetGlyphRun(charBox.Character, 20.0, 0.5, 1.0))
let exc = Assert.Throws<TexCharacterMappingNotFoundException>(action)
Assert.Equal("The Arial font does not support '∅' (U+2205) character.", exc.Message)
8 changes: 2 additions & 6 deletions src/WpfMath.Tests/GeometryElementRendererTests.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace WpfMath.Tests

open System
open System.Windows
open System.Windows.Media

Expand All @@ -25,14 +24,11 @@ type GeometryElementRendererTests() =
Mock.Verify(<@ box.RenderTo(renderer, 1.0, 2.0) @>, once)

[<Fact>]
member _.``GeometryElementRenderer.RenderGlyphRun adds a PathGeometry group``() : unit =
member _.``GeometryElementRenderer.RenderCharacter adds a PathGeometry group``() : unit =
let font = DefaultTexFont 20.0
let environment = TexEnvironment(TexStyle.Display, font, font)
let char = environment.MathFont.GetDefaultCharInfo('x', TexStyle.Display).Value
let charBox = CharBox(environment, char)
let glyphRun = charBox.GetGlyphRun(1.0, 0.0, 0.0)
let factory = Func<double, GlyphRun>(fun s -> glyphRun)
renderer.RenderGlyphRun(factory, 0.0, 0.0, Brushes.Black)
renderer.RenderCharacter(char, 0.0, 0.0, Brushes.Black)

let group = Seq.exactlyOne geometry.Children :?> GeometryGroup
Assert.IsType<PathGeometry>(Seq.exactlyOne group.Children) |> ignore
Expand Down
34 changes: 1 addition & 33 deletions src/WpfMath/Boxes/CharBox.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using WpfMath.Exceptions;
using WpfMath.Rendering;

namespace WpfMath.Boxes
Expand All @@ -26,38 +22,10 @@ public CharInfo Character
private set;
}

internal GlyphRun GetGlyphRun(double scale, double x, double y)
{
var typeface = this.Character.Font;
var characterInt = (int)this.Character.Character;
if (!typeface.CharacterToGlyphMap.TryGetValue(characterInt, out var glyphIndex))
{
var fontName = typeface.FamilyNames.Values.First();
var characterHex = characterInt.ToString("X4");
throw new TexCharacterMappingNotFoundException(
$"The {fontName} font does not support '{this.Character.Character}' (U+{characterHex}) character.");
}
#if NET452
var glyphRun = new GlyphRun(typeface, 0, false, this.Character.Size * scale,
new ushort[] { glyphIndex }, new Point(x * scale, y * scale),
new double[] { typeface.AdvanceWidths[glyphIndex] }, null, null, null, null, null, null);
#else
var glyphRun = new GlyphRun((float)scale);
((ISupportInitialize)glyphRun).BeginInit();
glyphRun.GlyphTypeface = typeface;
glyphRun.FontRenderingEmSize = this.Character.Size * scale;
glyphRun.GlyphIndices = new[] { glyphIndex };
glyphRun.BaselineOrigin = new Point(x * scale, y * scale);
glyphRun.AdvanceWidths = new[] { typeface.AdvanceWidths[glyphIndex] };
((ISupportInitialize)glyphRun).EndInit();
#endif
return glyphRun;
}

public override void RenderTo(IElementRenderer renderer, double x, double y)
{
var color = this.Foreground ?? Brushes.Black;
renderer.RenderGlyphRun(scale => this.GetGlyphRun(scale, x, y), x, y, color);
renderer.RenderCharacter(Character, x, y, color);
}

public override int GetLastFontId()
Expand Down
5 changes: 3 additions & 2 deletions src/WpfMath/DefaultTexFont.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using WpfMath.Exceptions;
using WpfMath.Fonts;
using WpfMath.Utils;

namespace WpfMath
Expand Down Expand Up @@ -108,7 +109,7 @@ public CharInfo GetNextLargerCharInfo(CharInfo charInfo, TexStyle style)
var newFontInfo = fontInfoList[charFont.FontId];
return new CharInfo(
charFont.Character,
newFontInfo.Font,
new WpfGlyphTypeface(newFontInfo.Font),
GetSizeFactor(style),
charFont.FontId,
GetMetrics(charFont, GetSizeFactor(style)).Value);
Expand Down Expand Up @@ -176,7 +177,7 @@ public Result<CharInfo> GetCharInfo(CharFont charFont, TexStyle style)
var size = GetSizeFactor(style);
var fontInfo = fontInfoList[charFont.FontId];
var metrics = GetMetrics(charFont, size);
return metrics.Map(m => new CharInfo(charFont.Character, fontInfo.Font, size, charFont.FontId, m));
return metrics.Map(m => new CharInfo(charFont.Character, new WpfGlyphTypeface(fontInfo.Font), size, charFont.FontId, m));
}

public double GetKern(CharFont leftCharFont, CharFont rightCharFont, TexStyle style)
Expand Down
37 changes: 37 additions & 0 deletions src/WpfMath/Fonts/WpfCharInfoEx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Linq;
using System.Windows;
using System.Windows.Media;
using WpfMath.Exceptions;

namespace WpfMath.Fonts;

internal static class WpfCharInfoEx
{
public static GlyphRun GetGlyphRun(this CharInfo info, double x, double y, double scale)
{
var typeface = ((WpfGlyphTypeface)info.Font).Typeface;
var characterInt = (int)info.Character;
if (!typeface.CharacterToGlyphMap.TryGetValue(characterInt, out var glyphIndex))
{
var fontName = typeface.FamilyNames.Values.First();
var characterHex = characterInt.ToString("X4");
throw new TexCharacterMappingNotFoundException(
$"The {fontName} font does not support '{info.Character}' (U+{characterHex}) character.");
}
#if NET452
var glyphRun = new GlyphRun(typeface, 0, false, info.Size * scale,
new ushort[] { glyphIndex }, new Point(x * scale, y * scale),
new double[] { typeface.AdvanceWidths[glyphIndex] }, null, null, null, null, null, null);
#else
var glyphRun = new GlyphRun((float)scale);
((ISupportInitialize)glyphRun).BeginInit();
glyphRun.GlyphTypeface = typeface;
glyphRun.FontRenderingEmSize = info.Size * scale;
glyphRun.GlyphIndices = new[] { glyphIndex };
glyphRun.BaselineOrigin = new Point(x * scale, y * scale);
glyphRun.AdvanceWidths = new[] { typeface.AdvanceWidths[glyphIndex] };
((ISupportInitialize)glyphRun).EndInit();
#endif
return glyphRun;
}
}
5 changes: 5 additions & 0 deletions src/WpfMath/Fonts/WpfGlyphTypeface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using System.Windows.Media;

namespace WpfMath.Fonts;

internal record WpfGlyphTypeface(GlyphTypeface Typeface) : IFontTypeface;
5 changes: 3 additions & 2 deletions src/WpfMath/Rendering/GeometryElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Windows;
using System.Windows.Media;
using WpfMath.Boxes;
using WpfMath.Fonts;
using WpfMath.Rendering.Transformations;

namespace WpfMath.Rendering
Expand All @@ -22,9 +23,9 @@ public GeometryElementRenderer(GeometryGroup geometry, double scale)

public void RenderElement(Box box, double x, double y) => box.RenderTo(this, x, y);

public void RenderGlyphRun(Func<double, GlyphRun> scaledGlyphFactory, double x, double y, Brush foreground)
public void RenderCharacter(CharInfo info, double x, double y, Brush foreground)
{
var glyph = scaledGlyphFactory(_scale);
var glyph = info.GetGlyphRun(x, y, _scale);
var glyphGeometry = glyph.BuildGeometry();
_geometry.Children.Add(glyphGeometry);
}
Expand Down
13 changes: 5 additions & 8 deletions src/WpfMath/Rendering/IElementRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Windows;
using System.Windows.Media;
using WpfMath.Boxes;
Expand All @@ -19,13 +18,11 @@ public interface IElementRenderer
/// </remarks>
void RenderElement(Box box, double x, double y);

/// <summary>Renders a glyph run (e.g. a character).</summary>
/// <param name="scaledGlyphFactory">Function to generate a glyph run for the chosen scale.</param>
/// <param name="x">An X coordinate of the top left corner.</param>
/// <param name="y">An Y coordinate of the top left corner.</param>
/// <param name="foreground">Glyph foreground color.</param>
// TODO[F]: Scale the GlyphRun in the implementations, replace the factory with the initial (unscaled) GlyphRun
void RenderGlyphRun(Func<double, GlyphRun> scaledGlyphFactory, double x, double y, Brush foreground);
/// <summary>
/// Renders a character denoted by <paramref name="info"/> at the chosen coordinates, using the color
/// <paramref name="foreground"/>.
/// </summary>
void RenderCharacter(CharInfo info, double x, double y, Brush foreground); // TODO[#63]: Get rid of Brush type.

/// <summary>Renders a rectangle.</summary>
/// <param name="rectangle">Rectangle to render.</param>
Expand Down
5 changes: 3 additions & 2 deletions src/WpfMath/Rendering/WpfElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Windows;
using System.Windows.Media;
using WpfMath.Boxes;
using WpfMath.Fonts;
using WpfMath.Rendering.Transformations;

namespace WpfMath.Rendering
Expand Down Expand Up @@ -42,9 +43,9 @@ public void RenderElement(Box box, double x, double y)
_foregroundContext.Pop();
}

public void RenderGlyphRun(Func<double, GlyphRun> scaledGlyphFactory, double x, double y, Brush foreground)
public void RenderCharacter(CharInfo info, double x, double y, Brush foreground)
{
var glyphRun = scaledGlyphFactory(_scale);
var glyphRun = info.GetGlyphRun(x, y, _scale);
_foregroundContext.DrawGlyphRun(foreground, glyphRun);
}

Expand Down
4 changes: 3 additions & 1 deletion src/WpfMath/SystemFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Windows;
using System.Windows.Media;
using WpfMath.Exceptions;
using WpfMath.Fonts;
using WpfMath.Utils;

namespace WpfMath
Expand Down Expand Up @@ -42,7 +43,8 @@ public Result<CharInfo> GetCharInfo(char character, string textStyle, TexStyle s
}

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

public Result<CharInfo> GetCharInfo(CharFont charFont, TexStyle style) =>
Expand Down
2 changes: 1 addition & 1 deletion src/WpfMath/TexFormula.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ internal Box CreateBox(TexEnvironment environment)

internal static SystemFont GetSystemFont(string fontName, double size)
{
var fontFamily = Fonts.SystemFontFamilies.First(
var fontFamily = System.Windows.Media.Fonts.SystemFontFamilies.First(
ff => ff.ToString() == fontName || ff.FamilyNames.Values?.Contains(fontName) == true);
return new SystemFont(size, fontFamily);
}
Expand Down

0 comments on commit baddf7a

Please sign in to comment.