Skip to content

Commit 2ae4747

Browse files
committed
[shaping] do not use .notdef for non supported spaces
1 parent c41d02a commit 2ae4747

5 files changed

Lines changed: 49 additions & 2 deletions

File tree

font/renderer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ func TestAppleBitmapGlyph(t *testing.T) {
610610

611611
func TestMixedGlyphs(t *testing.T) {
612612
for _, filename := range tu.Filenames(t, "common") {
613-
if strings.HasPrefix(filename, "common/SourceSans") {
613+
if strings.HasPrefix(filename, "common/SourceSans") || strings.HasSuffix(filename, "Subsetted.ttf") {
614614
continue
615615
}
616616
font := loadFont(t, filename)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/go-text/typesetting
33
go 1.19
44

55
require (
6-
github.com/go-text/typesetting-utils v0.0.0-20260327125527-fbf04b32d9ad
6+
github.com/go-text/typesetting-utils v0.0.0-20260419141703-4ffe8874dabc
77
golang.org/x/image v0.23.0
88
golang.org/x/text v0.21.0
99
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/go-text/typesetting-utils v0.0.0-20260327125527-fbf04b32d9ad h1:J6fi06yzug4KkyQo0hK7UZVFBIlCh7iaG38sGq7THaY=
22
github.com/go-text/typesetting-utils v0.0.0-20260327125527-fbf04b32d9ad/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o=
3+
github.com/go-text/typesetting-utils v0.0.0-20260419141703-4ffe8874dabc h1:8FGo2It5K75XkavhTiCKExUfVaVDS1feBnLCru5qeoY=
4+
github.com/go-text/typesetting-utils v0.0.0-20260419141703-4ffe8874dabc/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o=
35
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
46
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
57
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

shaping/shaping.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ package shaping
44

55
import (
66
"github.com/go-text/typesetting/di"
7+
ft "github.com/go-text/typesetting/font"
78
"github.com/go-text/typesetting/harfbuzz"
9+
ucd "github.com/go-text/typesetting/internal/unicodedata"
810
"golang.org/x/image/math/fixed"
911
)
1012

@@ -166,6 +168,9 @@ func (t *HarfbuzzShaper) Shape(input Input) Output {
166168
Gap: fixed.I(int(fontExtents.LineGap)) >> scaleShift,
167169
}
168170
out.RecalculateAll()
171+
172+
replaceNotSupportedSpaces(input.Text, out.Glyphs)
173+
169174
return out
170175
}
171176

@@ -209,3 +214,21 @@ func countClusters(glyphs []Glyph, textLen int, dir di.Progression) {
209214
glyphs[i].RuneCount = runesInCluster
210215
}
211216
}
217+
218+
// special handling of non supported white space :
219+
// our face selection process assumes all fonts contains the ASCII space,
220+
// but it turns out to be sometimes incorrect, for instance for the
221+
// NotoSansSymbols-Regular-Subsetted.ttf (found on Android)
222+
func replaceNotSupportedSpaces(text []rune, glyphs []Glyph) {
223+
for i, g := range glyphs {
224+
const NotFound ft.GID = 0 // this is the default value used by Harfbuzz
225+
if !(g.GlyphID == NotFound && g.GlyphsCount() == 1 && g.RunesCount() == 1) {
226+
continue
227+
}
228+
// only replace glyph corresponding to a space
229+
if r := text[g.TextIndex()]; ucd.LookupGeneralCategory(r) == ucd.Zs {
230+
glyphs[i].GlyphID = ft.EmptyGlyph
231+
glyphs[i].Width, glyphs[i].Height = 0, 0
232+
}
233+
}
234+
}

shaping/shaping_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,3 +725,25 @@ func TestShapingLanguage(t *testing.T) {
725725
// without the language information, regular space are used
726726
tu.Assert(t, output.Glyphs[3].GlyphID == regularSpace)
727727
}
728+
729+
func TestSpaceReplacement(t *testing.T) {
730+
b, err := td.Files.ReadFile("common/NotoSansSymbols-Regular-Subsetted.ttf")
731+
tu.AssertNoErr(t, err)
732+
face, err := font.ParseTTF(bytes.NewReader(b))
733+
tu.AssertNoErr(t, err)
734+
735+
text := []rune("✘ ✘")
736+
out := (&HarfbuzzShaper{}).Shape(Input{
737+
Text: text,
738+
RunEnd: len(text),
739+
Face: face,
740+
Size: fixed.I(10),
741+
})
742+
tu.Assert(t, len(out.Glyphs) == 4)
743+
tu.Assert(t, out.Glyphs[1].Advance.Round() == 6)
744+
tu.Assert(t, out.Glyphs[1].Width.Round() == 0)
745+
tu.Assert(t, out.Glyphs[1].GlyphID == font.EmptyGlyph)
746+
tu.Assert(t, out.Glyphs[2].Advance.Round() == 6)
747+
tu.Assert(t, out.Glyphs[2].Width.Round() == 0)
748+
tu.Assert(t, out.Glyphs[2].GlyphID == font.EmptyGlyph)
749+
}

0 commit comments

Comments
 (0)