Skip to content

Commit

Permalink
Merge branch 'main' into js/justified-text
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants authored Jul 2, 2022
2 parents bcd9d16 + cab42e5 commit dd419f4
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 28 deletions.
14 changes: 12 additions & 2 deletions src/SixLabors.Fonts/Tables/Cff/CffParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,17 @@ private void ReadFDSelect(BigEndianBinaryReader reader, CidFontInfo cidFontInfo)
reader.BaseStream.Position = this.offset + cidFontInfo.FDSelect;
switch (reader.ReadByte())
{
case 0:
cidFontInfo.FdSelectFormat = 0;
for (int i = 0; i < cidFontInfo.CIDFountCount; i++)
{
cidFontInfo.FdSelectMap[i] = reader.ReadByte();
}

break;

case 3:
cidFontInfo.FdSelectFormat = 3;
ushort nRanges = reader.ReadUInt16();
var ranges = new FDRange3[nRanges + 1];

Expand All @@ -448,7 +458,7 @@ private void ReadFDSelect(BigEndianBinaryReader reader, CidFontInfo cidFontInfo)
break;

default:
throw new NotSupportedException();
throw new NotSupportedException("Only FD Select format 0 and 3 are supported");
}
}

Expand Down Expand Up @@ -574,7 +584,7 @@ private CffGlyphData[] ReadCharStringsIndex(
byte[][]? localSubBuffer = privateDictionary?.LocalSubrRawBuffers;

// Is the font a CID font?
FDRangeProvider fdRangeProvider = new(topDictionary.CidFontInfo.FdRanges);
FDRangeProvider fdRangeProvider = new(topDictionary.CidFontInfo);
bool isCidFont = topDictionary.CidFontInfo.FdRanges.Length > 0;

for (int i = 0; i < glyphCount; ++i)
Expand Down
6 changes: 6 additions & 0 deletions src/SixLabors.Fonts/Tables/Cff/CidFontInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;

namespace SixLabors.Fonts.Tables.Cff
{
Expand All @@ -24,5 +25,10 @@ internal class CidFontInfo
public int FdSelectFormat { get; set; }

public FDRange3[] FdRanges { get; set; } = Array.Empty<FDRange3>();

/// <summary>
/// Gets or sets the fd select map, which maps glyph # to font #.
/// </summary>
public Dictionary<int, byte> FdSelectMap { get; set; } = new();
}
}
68 changes: 43 additions & 25 deletions src/SixLabors.Fonts/Tables/Cff/FDRangeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,33 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;

namespace SixLabors.Fonts.Tables.Cff
{
internal struct FDRangeProvider
{
// helper class
private readonly int format;
private readonly FDRange3[] ranges;
private readonly Dictionary<int, byte> fdSelectMap;
private ushort currentGlyphIndex;
private ushort endGlyphIndexMax;
private FDRange3 currentRange;
private int currentSelectedRangeIndex;

public FDRangeProvider(FDRange3[] ranges)
public FDRangeProvider(CidFontInfo cidFontInfo)
{
this.ranges = ranges;
this.format = cidFontInfo.FdSelectFormat;
this.ranges = cidFontInfo.FdRanges;
this.fdSelectMap = cidFontInfo.FdSelectMap;
this.currentGlyphIndex = 0;
this.currentSelectedRangeIndex = 0;

if (ranges != null)
if (this.ranges.Length is not 0)
{
this.currentRange = ranges[0];
this.endGlyphIndexMax = ranges[1].First;
this.currentRange = this.ranges[0];
this.endGlyphIndexMax = this.ranges[1].First;
}
else
{
Expand All @@ -39,30 +44,43 @@ public FDRangeProvider(FDRange3[] ranges)

public void SetCurrentGlyphIndex(ushort index)
{
// find proper range for selected index
if (index >= this.currentRange.First && index < this.endGlyphIndexMax)
switch (this.format)
{
// ok, in current range
this.SelectedFDArray = this.currentRange.FontDictionary;
}
else
{
// move to next range
this.currentSelectedRangeIndex++;
this.currentRange = this.ranges[this.currentSelectedRangeIndex];
case 0:
this.currentGlyphIndex = this.fdSelectMap[index];
break;

case 3:
// Find proper range for selected index.
if (index >= this.currentRange.First && index < this.endGlyphIndexMax)
{
// Ok, in current range.
this.SelectedFDArray = this.currentRange.FontDictionary;
}
else
{
// Move to next range.
this.currentSelectedRangeIndex++;
this.currentRange = this.ranges[this.currentSelectedRangeIndex];

this.endGlyphIndexMax = this.ranges[this.currentSelectedRangeIndex + 1].First;
if (index >= this.currentRange.First && index < this.endGlyphIndexMax)
{
this.SelectedFDArray = this.currentRange.FontDictionary;
}
else
{
this.endGlyphIndexMax = this.ranges[this.currentSelectedRangeIndex + 1].First;
if (index >= this.currentRange.First && index < this.endGlyphIndexMax)
{
this.SelectedFDArray = this.currentRange.FontDictionary;
}
else
{
throw new NotSupportedException();
}
}

this.currentGlyphIndex = index;

break;

default:
throw new NotSupportedException();
}
}

this.currentGlyphIndex = index;
}
}
}
29 changes: 29 additions & 0 deletions tests/SixLabors.Fonts.Tests/CompactFontFormatTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using Xunit;

namespace SixLabors.Fonts.Tests
{
public class CompactFontFormatTests
{
// https://github.com/adobe-fonts/fdarray-test/
[Theory]
[InlineData("\u0041", 66)]
[InlineData("\u211D", 30)]
[InlineData("\u24EA", 235)]
public void FDSelectFormat0_Works(string testStr, int expectedGlyphIndex)
{
// arrange
Font font = new FontCollection().Add(TestFonts.FDArrayTest257File).CreateFont(8);
var renderer = new ColorGlyphRenderer();

// act
TextRenderer.RenderTextTo(renderer, testStr, new TextOptions(font));

// assert
GlyphRendererParameters glyphKey = Assert.Single(renderer.GlyphKeys);
Assert.Equal(expectedGlyphIndex, glyphKey.GlyphIndex);
}
}
}
Binary file not shown.
7 changes: 6 additions & 1 deletion tests/SixLabors.Fonts.Tests/GlyphTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ public void RenderToPointAndSingleDPI()
TrueTypeGlyphMetrics glyphMetrics = new(
(StreamFontMetrics)metrics,
codePoint,
new GlyphVector(new Vector2[0], new bool[0], new ushort[0], new Bounds(0, metrics.UnitsPerEm, 0, metrics.UnitsPerEm), Array.Empty<byte>()),
new GlyphVector(
Array.Empty<Vector2>(),
Array.Empty<bool>(),
Array.Empty<ushort>(),
new Bounds(0, metrics.UnitsPerEm, 0, metrics.UnitsPerEm),
Array.Empty<byte>()),
0,
0,
0,
Expand Down
3 changes: 3 additions & 0 deletions tests/SixLabors.Fonts.Tests/TestFonts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public static class TestFonts

public static string TimesNewRomanFile => GetFullPath("TimesNewRoman.ttf");

// FdSelect format 0: https://github.com/adobe-fonts/fdarray-test/
public static string FDArrayTest257File => GetFullPath("FDArrayTest257.otf");

/// <summary>
/// Gets a gsub test font file which has the following substitution for unit tests:
/// - Single Substitution: A -> B
Expand Down

0 comments on commit dd419f4

Please sign in to comment.