Skip to content

Commit

Permalink
[opentype] support cff2 tables, closes #118
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitkugler committed Dec 4, 2023
1 parent b77a9b9 commit eec08f4
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 59 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ module github.com/go-text/typesetting
go 1.17

require (
github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22
github.com/go-text/typesetting-utils v0.0.0-20231204162240-fa4dc564ba79
golang.org/x/image v0.3.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22 h1:LBQTFxP2MfsyEDqSKmUBZaDuDHN1vpqDyOZjcqS7MYI=
github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/go-text/typesetting-utils v0.0.0-20231204162240-fa4dc564ba79 h1:3yBOzx29wog0i7TnUBMcp90EwIb+A5kqmr5vny1UOm8=
github.com/go-text/typesetting-utils v0.0.0-20231204162240-fa4dc564ba79/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
Expand Down
56 changes: 0 additions & 56 deletions opentype/api/font/cff/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ package cff
import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"reflect"
"sort"
"strconv"
"strings"
"testing"

td "github.com/go-text/typesetting-utils/opentype"
Expand Down Expand Up @@ -141,54 +136,3 @@ func TestParseCFF2(t *testing.T) {
tu.AssertNoErr(t, err)
}
}

func TestExec(t *testing.T) {
t.Skip()

text := []rune("a sample text あのイーハトーヴォの すきとおった風、夏でも底に冷たさを もつ青いそら… 不,那不是杂志。那是字典 史密斯是王明的朋友。")

type extent struct {
GID int
Extents [4]int
}

for _, coord := range []int{
100, 200, 301, 400, 450, 710, 800, 900,
} {
cmd := exec.Command("./hb-shape", "/home/benoit/go/src/github.com/go-text/typesetting-utils/opentype/common/NotoSansCJKjp-VF.otf", "--variations", fmt.Sprintf(`wght=%d`, coord), "--show-extents", "--no-glyph-names", "--text", string(text))
cmd.Dir = "/home/benoit/Téléchargements/harfbuzz/build/util"
b, err := cmd.Output()
tu.AssertNoErr(t, err)
s := string(b[1 : len(b)-2])
glyphs := strings.Split(s, "|")
expected := map[int][4]int{}
for _, glyph := range glyphs {
gidS, val, _ := strings.Cut(glyph, "=")
gid, _ := strconv.Atoi(gidS)
_, extents, _ := strings.Cut(val, "<")
extents = extents[:len(extents)-1]
extS := strings.Split(extents, ",")
var exts [4]int
for i, e := range extS {
exts[i], _ = strconv.Atoi(e)
}
expected[gid] = exts
}
var extents []extent
for gid, ext := range expected {
extents = append(extents, extent{gid, ext})
}
sort.Slice(extents, func(i, j int) bool { return extents[i].GID < extents[j].GID })

chunks := make([]string, len(extents))
for i, ext := range extents {
chunks[i] = fmt.Sprintf("{%d, [4]int{%d, %d, %d, %d}},", ext.GID, ext.Extents[0], ext.Extents[1], ext.Extents[2], ext.Extents[3])
}
fmt.Printf(`{
Coord: %d,
Extents: []extent{%s
},
},
`, coord, strings.Join(chunks, "\n"))
}
}
15 changes: 15 additions & 0 deletions opentype/api/font/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,17 @@ func (f *Font) getExtentsFromCff1(glyph gID) (api.GlyphExtents, bool) {
return bounds.ToExtents(), true
}

func (f *Face) getExtentsFromCff2(glyph gID) (api.GlyphExtents, bool) {
if f.cff2 == nil {
return api.GlyphExtents{}, false
}
_, bounds, err := f.cff2.LoadGlyph(glyph, f.Coords)
if err != nil {
return api.GlyphExtents{}, false
}
return bounds.ToExtents(), true
}

func (f *Face) GlyphExtents(glyph GID) (api.GlyphExtents, bool) {
out, ok := f.getExtentsFromSbix(gID(glyph), f.XPpem, f.YPpem)
if ok {
Expand All @@ -400,6 +411,10 @@ func (f *Face) GlyphExtents(glyph GID) (api.GlyphExtents, bool) {
if ok {
return out, ok
}
out, ok = f.getExtentsFromCff2(gID(glyph))
if ok {
return out, ok
}
out, ok = f.getExtentsFromBitmap(gID(glyph), f.XPpem, f.YPpem)
return out, ok
}
23 changes: 21 additions & 2 deletions opentype/api/font/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,18 @@ func (bt bitmap) glyphData(gid gID, xPpem, yPpem uint16) (api.GlyphBitmap, error
return out, nil
}

// look for data in 'glyf' and 'cff' tables
// look for data in 'glyf', 'CFF ' and 'CFF2' tables
func (f *Face) outlineGlyphData(gid gID) (api.GlyphOutline, bool) {
out, err := f.glyphDataFromCFF1(gid)
if err == nil {
return out, true
}

out, err = f.glyphDataFromCFF2(gid)
if err == nil {
return out, true
}

out, err = f.glyphDataFromGlyf(gid)
if err == nil {
return out, true
Expand Down Expand Up @@ -288,7 +293,10 @@ func (f *Face) glyphDataFromGlyf(glyph gID) (api.GlyphOutline, error) {
return api.GlyphOutline{Segments: segments}, nil
}

var errNoCFFTable error = errors.New("no CFF table")
var (
errNoCFFTable error = errors.New("no CFF table")
errNoCFF2Table error = errors.New("no CFF2 table")
)

func (f *Font) glyphDataFromCFF1(glyph gID) (api.GlyphOutline, error) {
if f.cff == nil {
Expand All @@ -301,6 +309,17 @@ func (f *Font) glyphDataFromCFF1(glyph gID) (api.GlyphOutline, error) {
return api.GlyphOutline{Segments: segments}, nil
}

func (f *Face) glyphDataFromCFF2(glyph gID) (api.GlyphOutline, error) {
if f.cff2 == nil {
return api.GlyphOutline{}, errNoCFF2Table
}
segments, _, err := f.cff2.LoadGlyph(glyph, f.Coords)
if err != nil {
return api.GlyphOutline{}, err
}
return api.GlyphOutline{Segments: segments}, nil
}

// BitmapSizes returns the size of bitmap glyphs present in the font.
func (font *Font) BitmapSizes() []api.BitmapSize {
upem := font.head.UnitsPerEm
Expand Down
25 changes: 25 additions & 0 deletions shaping/shaping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
tu "github.com/go-text/typesetting/opentype/testutils"
"golang.org/x/image/font/gofont/gomono"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/math/fixed"
)

func TestShape(t *testing.T) {
Expand Down Expand Up @@ -488,3 +489,27 @@ func TestFeatures(t *testing.T) {
out = shaper.Shape(input)
tu.Assert(t, len(out.Glyphs) == 1)
}

func TestCFF2(t *testing.T) {
// regression test for https://github.com/go-text/typesetting/issues/118
b, err := td.Files.ReadFile("common/NotoSansCJKjp-VF.otf")
tu.AssertNoErr(t, err)

face, err := font.ParseTTF(bytes.NewReader(b))
tu.AssertNoErr(t, err)

str := []rune("abcあいう")
input := Input{
Text: str,
RunStart: 0,
RunEnd: len(str),
Direction: di.DirectionLTR,
Face: face,
Size: fixed.I(10),
}
out := (&HarfbuzzShaper{}).Shape(input)
for _, g := range out.Glyphs {
tu.Assert(t, g.Width > 0 && g.Height < 0)
}
tu.Assert(t, out.Advance > 0)
}

0 comments on commit eec08f4

Please sign in to comment.