Skip to content

Commit 77a349a

Browse files
Fix #470 , cover #468
1 parent 09ca137 commit 77a349a

File tree

10 files changed

+134
-34
lines changed

10 files changed

+134
-34
lines changed

src/SixLabors.Fonts/Tables/AdvancedTypographic/CoverageTable.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using static SixLabors.Fonts.Tables.AdvancedTypographic.CoverageFormat2Table;
5+
46
namespace SixLabors.Fonts.Tables.AdvancedTypographic;
57

68
/// <summary>
@@ -23,7 +25,10 @@ public static CoverageTable Load(BigEndianBinaryReader reader, long offset)
2325
{
2426
1 => CoverageFormat1Table.Load(reader),
2527
2 => CoverageFormat2Table.Load(reader),
26-
_ => throw new InvalidFontFileException($"Invalid value for 'coverageFormat' {coverageFormat}. Should be '1' or '2'.")
28+
29+
// Harfbuzz (Coverage.hh) treats this as an empty table and does not throw.
30+
// SofiaSans Condensed can trigger this. See https://github.com/SixLabors/Fonts/issues/470
31+
_ => new EmptyCoverageTable()
2732
};
2833
}
2934

@@ -124,4 +129,9 @@ public static CoverageFormat2Table Load(BigEndianBinaryReader reader)
124129

125130
return new CoverageFormat2Table(records);
126131
}
132+
133+
internal sealed class EmptyCoverageTable : CoverageTable
134+
{
135+
public override int CoverageIndexOf(ushort glyphId) => -1;
136+
}
127137
}

src/SixLabors.Fonts/Tables/AdvancedTypographic/GPos/AnchorTable.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace SixLabors.Fonts.Tables.AdvancedTypographic.GPos;
1111
[DebuggerDisplay("X: {XCoordinate}, Y: {YCoordinate}")]
1212
internal abstract class AnchorTable
1313
{
14-
private static readonly AnchorTable Empty = new EmptyAnchor();
14+
private static readonly AnchorTable EmptyAnchorTable = new EmptyAnchor();
1515

1616
/// <summary>
1717
/// Initializes a new instance of the <see cref="AnchorTable"/> class.
@@ -53,9 +53,9 @@ public static AnchorTable Load(BigEndianBinaryReader reader, long offset)
5353
2 => AnchorFormat2.Load(reader),
5454
3 => AnchorFormat3.Load(reader),
5555

56-
// Harfbuzz (Anchor.hh) and FontKit appear to treat this as a default anchor and do not throw.
56+
// Harfbuzz (Anchor.hh) treats this as an empty table and does not throw..
5757
// NotoSans Regular can trigger this. See https://github.com/SixLabors/Fonts/issues/417
58-
_ => Empty,
58+
_ => EmptyAnchorTable,
5959
};
6060
}
6161

Lines changed: 3 additions & 0 deletions
Loading
190 KB
Binary file not shown.
Binary file not shown.
448 KB
Binary file not shown.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Text;
5+
6+
namespace SixLabors.Fonts.Tests.Issues;
7+
8+
public class Issues_468
9+
{
10+
[Fact]
11+
public void TestIssue_468()
12+
{
13+
StringBuilder stringBuilder = new();
14+
stringBuilder
15+
.AppendLine("Latin: The quick brown fox jumps over the lazy dog.")
16+
.AppendLine("Arabic (RTL & Shaping): نص حكيم له سر قاطع وذو شأن عظيم");
17+
18+
string text = stringBuilder.ToString();
19+
FontCollection fontCollection = new();
20+
21+
string consola = fontCollection.Add(TestFonts.Consola).Name;
22+
string arabic = fontCollection.Add(TestFonts.NotoSansArabicRegular).Name;
23+
24+
FontFamily mainFontFamily = fontCollection.Get(consola);
25+
Font mainFont = mainFontFamily.CreateFont(50, FontStyle.Regular);
26+
27+
TextOptions options = new(mainFont)
28+
{
29+
FallbackFontFamilies =
30+
[
31+
fontCollection.Get(arabic),
32+
],
33+
};
34+
35+
// There are too many metrics to validate here so we just ensure no exceptions are thrown
36+
// and the rendering looks correct by inspecting the snapshot.
37+
TextLayoutTestUtilities.TestLayout(
38+
text,
39+
options,
40+
includeGeometry: false);
41+
}
42+
}

tests/SixLabors.Fonts.Tests/Issues/Issues_469.cs

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,6 @@ public class Issues_469
1010
[Fact]
1111
public void Test_Issue_469()
1212
{
13-
const string arialFontName = "Arial";
14-
const string inconsolataFontName = "Inconsolata";
15-
const string nanumGothicCodingFontName = "NanumGothicCoding";
16-
const string cousineFontName = "Cousine";
17-
const string notoSansScThinFontName = "Noto Sans SC Thin";
18-
const string notoSansJpThinFontName = "Noto Sans JP Thin";
19-
const string notoNaskhArabicFontName = "Noto Naskh Arabic";
20-
const string sarabunFontName = "Sarabun";
21-
const string hindFontName = "Hind";
22-
2313
StringBuilder stringBuilder = new();
2414
stringBuilder.AppendLine("Latin: The quick brown fox jumps over the lazy dog.")
2515
.AppendLine("Cyrillic: Съешь же ещё этих мягких французских булок.")
@@ -33,33 +23,33 @@ public void Test_Issue_469()
3323
.AppendLine("Devanagari (Conjuncts): ऋषियों को सताने वाले राक्षसों का अंत हो गया");
3424

3525
string text = stringBuilder.ToString();
36-
FontCollection fontCollection = new();
37-
fontCollection.Add(TestFonts.Arial);
38-
fontCollection.Add(TestFonts.CousineRegular);
39-
fontCollection.Add(TestFonts.HindRegular);
40-
fontCollection.Add(TestFonts.NanumGothicCodingRegular);
41-
fontCollection.Add(TestFonts.InconsolataRegular);
42-
fontCollection.Add(TestFonts.NotoNaskhArabicRegular);
43-
fontCollection.Add(TestFonts.NotoSansHKVariableFontWght);
44-
fontCollection.Add(TestFonts.NotoSansJPRegular);
45-
fontCollection.Add(TestFonts.NotoSansSCRegular);
46-
fontCollection.Add(TestFonts.SarabunRegular);
4726

48-
FontFamily mainFontFamily = fontCollection.Get(arialFontName);
27+
FontCollection fontCollection = new();
28+
string arial = fontCollection.Add(TestFonts.Arial).Name;
29+
string cousine = fontCollection.Add(TestFonts.CousineRegular).Name;
30+
string hind = fontCollection.Add(TestFonts.HindRegular).Name;
31+
string nanumGothicCoding = fontCollection.Add(TestFonts.NanumGothicCodingRegular).Name;
32+
string inconsolata = fontCollection.Add(TestFonts.InconsolataRegular).Name;
33+
string notoNaskhArabic = fontCollection.Add(TestFonts.NotoNaskhArabicRegular).Name;
34+
string notoSansJpThin = fontCollection.Add(TestFonts.NotoSansJPRegular).Name;
35+
string notoSansScThin = fontCollection.Add(TestFonts.NotoSansSCRegular).Name;
36+
string sarabun = fontCollection.Add(TestFonts.SarabunRegular).Name;
37+
38+
FontFamily mainFontFamily = fontCollection.Get(arial);
4939
Font mainFont = mainFontFamily.CreateFont(30, FontStyle.Regular);
5040

5141
TextOptions options = new(mainFont)
5242
{
5343
FallbackFontFamilies =
5444
[
55-
fontCollection.Get(inconsolataFontName),
56-
fontCollection.Get(nanumGothicCodingFontName),
57-
fontCollection.Get(cousineFontName),
58-
fontCollection.Get(notoSansScThinFontName),
59-
fontCollection.Get(notoSansJpThinFontName),
60-
fontCollection.Get(notoNaskhArabicFontName),
61-
fontCollection.Get(sarabunFontName),
62-
fontCollection.Get(hindFontName),
45+
fontCollection.Get(inconsolata),
46+
fontCollection.Get(nanumGothicCoding),
47+
fontCollection.Get(cousine),
48+
fontCollection.Get(notoSansScThin),
49+
fontCollection.Get(notoSansJpThin),
50+
fontCollection.Get(notoNaskhArabic),
51+
fontCollection.Get(sarabun),
52+
fontCollection.Get(hind),
6353
],
6454
};
6555

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Text;
5+
6+
namespace SixLabors.Fonts.Tests.Issues;
7+
8+
public class Issues_470
9+
{
10+
[Fact]
11+
public void Test_Issue_470()
12+
{
13+
StringBuilder stringBuilder = new();
14+
stringBuilder.AppendLine("Latin: The quick brown fox jumps over the lazy dog.")
15+
.AppendLine("Cyrillic: Съешь же ещё этих мягких французских булок.")
16+
.AppendLine("Greek: Ζαφείρι δέξου πάγκαλο, βαθῶν ψυχῆς τὸ σῆμα.")
17+
.AppendLine("Chinese: 敏捷的棕色狐狸跳过了懒狗")
18+
.AppendLine("Japanese: いろはにほへと ちりぬるを")
19+
.AppendLine("Korean: 다람쥐 헌 쳇바퀴에 타고파")
20+
.AppendLine("Arabic (RTL & Shaping): نص حكيم له سر قاطع وذو شأن عظيم")
21+
.AppendLine("Hebrew (RTL): דג סקרן שט בים מאוכזב ולפתע מצא חברה")
22+
.AppendLine("Thai (Complex): เป็นมนุษย์สุดประเสริฐเลิศคุณค่า")
23+
.AppendLine("Devanagari (Conjuncts): ऋषियों को सताने वाले राक्षसों का अंत हो गया");
24+
25+
string text = stringBuilder.ToString();
26+
27+
FontCollection fontCollection = new();
28+
string arial = fontCollection.Add(TestFonts.Arial).Name;
29+
string sofia = fontCollection.Add(TestFonts.SofiaSansCondensedLight).Name;
30+
31+
FontFamily mainFontFamily = fontCollection.Get(arial);
32+
Font mainFont = mainFontFamily.CreateFont(30, FontStyle.Regular);
33+
34+
TextOptions options = new(mainFont)
35+
{
36+
FallbackFontFamilies =
37+
[
38+
fontCollection.Get(sofia),
39+
],
40+
};
41+
42+
// There are too many metrics to validate here so we just ensure no exceptions are thrown
43+
// and the rendering looks correct by inspecting the snapshot.
44+
TextLayoutTestUtilities.TestLayout(
45+
text,
46+
options,
47+
includeGeometry: false);
48+
}
49+
}

tests/SixLabors.Fonts.Tests/TestFonts.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ public static class TestFonts
285285

286286
public static string SarabunRegular => GetFullPath("Sarabun-Regular.ttf");
287287

288+
public static string NotoSansArabicRegular => GetFullPath("NotoSansArabic-Regular.ttf");
289+
290+
public static string Consola => GetFullPath("consola.ttf");
291+
292+
public static string SofiaSansCondensedLight => GetFullPath("SofiaSansCondensed-ExtraLight-Regular.ttf");
293+
288294
public static Stream TwemojiMozillaData() => OpenStream(TwemojiMozillaFile);
289295

290296
public static Stream SegoeuiEmojiData() => OpenStream(SegoeuiEmojiFile);

0 commit comments

Comments
 (0)