Skip to content

Commit 09ca137

Browse files
Merge pull request #471 from SixLabors/js/fix-469
Ensure glyphs are not overwritten by fallbacks.
2 parents 9aa2a5c + 1bde281 commit 09ca137

21 files changed

+146
-17
lines changed

SixLabors.Fonts.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnicodeTestData", "UnicodeT
7373
EndProject
7474
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SixLabors.Fonts.Benchmarks", "tests\SixLabors.Fonts.Benchmarks\SixLabors.Fonts.Benchmarks\SixLabors.Fonts.Benchmarks.csproj", "{FB8FDC5F-7FEB-4132-9133-C25E05C0B3D9}"
7575
EndProject
76+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrawWithImageSharp", "samples\DrawWithImageSharp\DrawWithImageSharp.csproj", "{01863664-6C7E-61F2-F74B-7D451FFDC3C2}"
77+
EndProject
7678
Global
7779
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7880
Debug|Any CPU = Debug|Any CPU
@@ -99,6 +101,10 @@ Global
99101
{FB8FDC5F-7FEB-4132-9133-C25E05C0B3D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
100102
{FB8FDC5F-7FEB-4132-9133-C25E05C0B3D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
101103
{FB8FDC5F-7FEB-4132-9133-C25E05C0B3D9}.Release|Any CPU.Build.0 = Release|Any CPU
104+
{01863664-6C7E-61F2-F74B-7D451FFDC3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
105+
{01863664-6C7E-61F2-F74B-7D451FFDC3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
106+
{01863664-6C7E-61F2-F74B-7D451FFDC3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
107+
{01863664-6C7E-61F2-F74B-7D451FFDC3C2}.Release|Any CPU.Build.0 = Release|Any CPU
102108
EndGlobalSection
103109
GlobalSection(SolutionProperties) = preSolution
104110
HideSolutionNode = FALSE
@@ -113,6 +119,7 @@ Global
113119
{ABB6E111-672F-4846-88D6-C49C6CD01606} = {249327CF-1415-428B-8EEA-8C7705B1DE8F}
114120
{654DD381-B93D-4459-B669-296F5D9172ED} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
115121
{FB8FDC5F-7FEB-4132-9133-C25E05C0B3D9} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
122+
{01863664-6C7E-61F2-F74B-7D451FFDC3C2} = {71A3911C-D6B9-4EBE-9691-2FE28BDF462E}
116123
EndGlobalSection
117124
GlobalSection(ExtensibilityGlobals) = postSolution
118125
SolutionGuid = {38F4B47F-4F74-40F5-8707-C0EF1D0BDF92}

samples/DrawWithImageSharp/DrawWithImageSharp.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@
4646
</ItemGroup>
4747

4848
<ItemGroup>
49-
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" />
50-
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
49+
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="3.0.0-alpha.0.6" />
5150
</ItemGroup>
5251

5352
</Project>

samples/DrawWithImageSharp/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using SixLabors.ImageSharp.Drawing;
1010
using SixLabors.ImageSharp.Drawing.Processing;
1111
using SixLabors.ImageSharp.Drawing.Processing.Processors.Text;
12+
using SixLabors.ImageSharp.Drawing.Text;
1213
using SixLabors.ImageSharp.PixelFormats;
1314
using SixLabors.ImageSharp.Processing;
1415
using IOPath = System.IO.Path;
@@ -218,7 +219,7 @@ public static void RenderText(Font font, string text, int width, int height)
218219
using var img = new Image<Rgba32>(width, height);
219220
img.Mutate(x => x.Fill(Color.White));
220221

221-
IPathCollection shapes = TextBuilder.GenerateGlyphs(text, new RichTextOptions(font) { Origin = new Vector2(50f, 4f) });
222+
IPathCollection shapes = TextBuilder.GeneratePaths(text, new RichTextOptions(font) { Origin = new Vector2(50f, 4f) });
222223
img.Mutate(x => x.Fill(Color.Black, shapes));
223224

224225
Directory.CreateDirectory(IOPath.GetDirectoryName(fullPath));

src/SixLabors.Fonts/GlyphPositioningCollection.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal sealed class GlyphPositioningCollection : IGlyphShapingCollection
1717
/// <summary>
1818
/// Contains a map the index of a map within the collection, non-sequential codepoint offsets, and their glyph ids, point size, and mtrics.
1919
/// </summary>
20-
private readonly List<GlyphPositioningData> glyphs = new();
20+
private readonly List<GlyphPositioningData> glyphs = [];
2121

2222
/// <summary>
2323
/// Initializes a new instance of the <see cref="GlyphPositioningCollection"/> class.
@@ -149,6 +149,11 @@ public bool TryUpdate(Font font, GlyphSubstitutionCollection collection)
149149
ColorFontSupport colorFontSupport = this.TextOptions.ColorFontSupport;
150150
bool hasFallBacks = false;
151151
List<int> orphans = [];
152+
153+
Tag vert = FeatureTags.VerticalAlternates;
154+
Tag vrt2 = FeatureTags.VerticalAlternatesAndRotation;
155+
Tag vrtr = FeatureTags.VerticalAlternatesForRotation;
156+
152157
for (int i = 0; i < this.glyphs.Count; i++)
153158
{
154159
GlyphPositioningData current = this.glyphs[i];
@@ -173,6 +178,15 @@ public bool TryUpdate(Font font, GlyphSubstitutionCollection collection)
173178
// cache the original in the font metrics and only update our collection.
174179
TextAttributes textAttributes = shape.TextRun.TextAttributes;
175180
TextDecorations textDecorations = shape.TextRun.TextDecorations;
181+
182+
bool isVertical = AdvancedTypographicUtils.IsVerticalGlyph(codePoint, layoutMode);
183+
foreach (Tag feature in shape.AppliedFeatures)
184+
{
185+
isVertical |= feature == vert;
186+
isVertical |= feature == vrt2;
187+
isVertical |= feature == vrtr;
188+
}
189+
176190
GlyphMetrics metrics = fontMetrics.GetGlyphMetrics(codePoint, id, textAttributes, textDecorations, layoutMode, colorFontSupport);
177191
{
178192
// If the glyphs are fallbacks we don't want them as
@@ -183,16 +197,20 @@ public bool TryUpdate(Font font, GlyphSubstitutionCollection collection)
183197
}
184198
}
185199

186-
if (!hasFallBacks)
200+
if (metrics.GlyphType != GlyphType.Fallback)
187201
{
188202
if (j == 0)
189203
{
190204
// There should only be a single fallback glyph at this position from the previous collection.
191205
this.glyphs.RemoveAt(i);
192206
}
193207

208+
// We only want a single dimensional advance for positioning.
209+
GlyphShapingBounds bounds = isVertical
210+
? new(0, 0, 0, metrics.AdvanceHeight)
211+
: new(0, 0, metrics.AdvanceWidth, 0);
212+
194213
// Track the number of inserted glyphs at the offset so we can correctly increment our position.
195-
GlyphShapingBounds bounds = new(0, 0, metrics.AdvanceWidth, metrics.AdvanceHeight);
196214
this.glyphs.Insert(i += replacementCount, new(offset, new(shape, true) { Bounds = bounds }, pointSize, metrics.CloneForRendering(shape.TextRun)));
197215
replacementCount++;
198216
}
@@ -259,6 +277,7 @@ public bool TryAdd(Font font, GlyphSubstitutionCollection collection)
259277
hasFallBacks = true;
260278
}
261279

280+
// We only want a single dimensional advance for positioning.
262281
GlyphShapingBounds bounds = isVertical
263282
? new(0, 0, 0, metrics.AdvanceHeight)
264283
: new(0, 0, metrics.AdvanceWidth, 0);

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,13 @@ public bool TryUpdatePositions(FontMetrics fontMetrics, GlyphPositioningCollecti
125125
// We want to assign the same feature lookups to individual sections of the text rather
126126
// than the text as a whole to ensure that different language shapers do not interfere
127127
// with each other when the text contains multiple languages.
128-
GlyphShapingData nextData = collection[i + 1];
128+
int ni = i + 1;
129+
GlyphShapingData nextData = collection[ni];
130+
if (!collection.ShouldProcess(fontMetrics, ni))
131+
{
132+
break;
133+
}
134+
129135
ScriptClass next = CodePoint.GetScriptClass(nextData.CodePoint);
130136
if (next != current &&
131137
current is not ScriptClass.Common and not ScriptClass.Unknown and not ScriptClass.Inherited &&

src/SixLabors.Fonts/Tables/General/HorizontalMetricsTable.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ public ushort GetAdvancedWidth(int glyphIndex)
1919
{
2020
if (glyphIndex >= this.advancedWidths.Length)
2121
{
22-
return this.advancedWidths[0];
22+
// Records are indexed by glyph ID. As an optimization, the number of records can
23+
// be less than the number of glyphs, in which case the advance width value of the
24+
// last record applies to all remaining glyph IDs.
25+
return this.advancedWidths[^1];
2326
}
2427

2528
return this.advancedWidths[glyphIndex];
@@ -29,7 +32,7 @@ internal short GetLeftSideBearing(int glyphIndex)
2932
{
3033
if (glyphIndex >= this.leftSideBearings.Length)
3134
{
32-
return this.leftSideBearings[0];
35+
return this.leftSideBearings[^1];
3336
}
3437

3538
return this.leftSideBearings[glyphIndex];
Lines changed: 3 additions & 0 deletions
Loading
301 KB
Binary file not shown.
293 KB
Binary file not shown.
339 KB
Binary file not shown.

0 commit comments

Comments
 (0)