Skip to content

Commit 12ee510

Browse files
committed
updates
1 parent e51676a commit 12ee510

File tree

25 files changed

+152
-316
lines changed

25 files changed

+152
-316
lines changed

examples/font/cff-glyphs/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ func (ctx *illustrator) Show(fnt *cff.Font, pageSize *pdf.Rectangle) error {
222222
page.TextFirstLine(ctx.pageSize.LLx+22, ctx.pageSize.URy-30)
223223
page.TextShow(strings.Join(label, ", "))
224224
if g.Name != "" {
225-
rr := names.ToUnicode(g.Name, false)
225+
rr := []rune(names.ToUnicode(g.Name, ""))
226226
if len(rr) == 1 {
227227
runeName := runenames.Name(rr[0])
228228
page.TextSecondLine(0, -15)

examples/viewer-tests/ttf-encoding/font.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func (fb *fontBuilder) BuildFont(enc *encInfo) (font.Font, error) {
208208
for i := range 3 {
209209
code := markerString[i]
210210
name := pdfenc.WinAnsi.Encoding[code]
211-
uni := names.ToUnicode(name, false)
211+
uni := names.ToUnicode(name, "")
212212
if len(uni) != 1 {
213213
panic(fmt.Sprintf("expected 1 rune for %s, got %d", name, len(uni)))
214214
}

font/cff/composite.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ func (e *embeddedComposite) Finish(rm *pdf.ResourceManager) error {
172172
m[code] = val.Text
173173
}
174174
}
175-
toUnicode := cmap.NewToUnicodeFile(e.CIDEncoder.Codec(), m)
175+
toUnicode, err := cmap.NewToUnicodeFile(e.CIDEncoder.Codec().CodeSpaceRange(), m)
176+
if err != nil {
177+
return err
178+
}
176179

177180
// Simple CFF fonts can only have one private dict, and ...
178181
canUseSimple := len(subsetOutlines.Private) == 1
@@ -230,13 +233,8 @@ func (e *embeddedComposite) Finish(rm *pdf.ResourceManager) error {
230233

231234
isSymbolic := false
232235
for _, info := range e.CIDEncoder.MappedCodes() {
233-
// TODO(voss): if the font is simple, use the existing glyph names
234-
rr := []rune(info.Text)
235-
if len(rr) != 1 {
236-
isSymbolic = true
237-
break
238-
}
239-
glyphName := names.FromUnicode(rr[0])
236+
// TODO(voss): if the font is simple, use the existing glyph names?
237+
glyphName := names.FromUnicode(info.Text)
240238
if !pdfenc.StandardLatin.Has[glyphName] {
241239
isSymbolic = true
242240
break
@@ -284,7 +282,7 @@ func (e *embeddedComposite) Finish(rm *pdf.ResourceManager) error {
284282
FontRef: rm.Out.Alloc(),
285283
}
286284

287-
err := dict.WriteToPDF(rm, e.Ref)
285+
err = dict.WriteToPDF(rm, e.Ref)
288286
if err != nil {
289287
return err
290288
}

font/cff/simple.go

Lines changed: 32 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,18 @@ package cff
1818

1919
import (
2020
"fmt"
21-
"iter"
2221
"math"
23-
"math/bits"
24-
"slices"
25-
"strings"
26-
27-
"golang.org/x/exp/maps"
2822

2923
"seehuhn.de/go/geom/matrix"
3024

31-
"seehuhn.de/go/postscript/cid"
32-
"seehuhn.de/go/postscript/type1/names"
33-
3425
"seehuhn.de/go/sfnt/cff"
3526
"seehuhn.de/go/sfnt/glyph"
3627
"seehuhn.de/go/sfnt/os2"
3728

3829
"seehuhn.de/go/pdf"
3930
"seehuhn.de/go/pdf/font"
4031
"seehuhn.de/go/pdf/font/dict"
41-
"seehuhn.de/go/pdf/font/encoding"
32+
"seehuhn.de/go/pdf/font/encoding/simpleenc"
4233
"seehuhn.de/go/pdf/font/glyphdata"
4334
"seehuhn.de/go/pdf/font/glyphdata/cffglyphs"
4435
"seehuhn.de/go/pdf/font/pdfenc"
@@ -69,183 +60,16 @@ type embeddedSimple struct {
6960
CapHeight float64 // PDF glyph space units
7061
XHeight float64 // PDF glyph space units
7162

72-
gd *GlyphData
73-
finished bool
74-
}
75-
76-
type codeInfo struct {
77-
Width float64
78-
Text string
79-
}
80-
81-
type GlyphData struct {
82-
code map[glyphKey]byte
83-
info map[byte]*codeInfo
84-
notdef *codeInfo
85-
GlyphName map[glyph.ID]string
86-
glyphNameUsed map[string]bool
87-
88-
isZapfDingbats bool
89-
encoding *pdfenc.Encoding
90-
}
63+
*simpleenc.Simple
9164

92-
type glyphKey struct {
93-
gid glyph.ID
94-
text string
95-
}
96-
97-
// newGlyphData creates a glyphData and registers the .notdef glyph.
98-
func newGlyphData(notdefWidth float64, isZapfDingbats bool, base *pdfenc.Encoding) *GlyphData {
99-
gd := &GlyphData{
100-
code: make(map[glyphKey]byte),
101-
info: make(map[byte]*codeInfo),
102-
notdef: &codeInfo{Width: notdefWidth},
103-
GlyphName: make(map[glyph.ID]string),
104-
glyphNameUsed: make(map[string]bool),
105-
isZapfDingbats: isZapfDingbats,
106-
encoding: base,
107-
}
108-
gd.GlyphName[0] = ".notdef"
109-
gd.glyphNameUsed[".notdef"] = true
110-
return gd
111-
}
112-
113-
// GetCode looks up the code for a (gid,text) pair, returning the code byte
114-
// and whether it already exists.
115-
func (gd *GlyphData) GetCode(gid glyph.ID, text string) (byte, bool) {
116-
k := glyphKey{gid: gid, text: text}
117-
c, ok := gd.code[k]
118-
return c, ok
119-
}
120-
121-
// new method added to GlyphData
122-
func (gd *GlyphData) SetCode(gid glyph.ID, text string, c byte) {
123-
gd.code[glyphKey{gid: gid, text: text}] = c
124-
}
125-
126-
// GetData returns the CID, width and text for the given code,
127-
// substituting .notdef if it doesn't exist.
128-
func (gd *GlyphData) GetData(c byte) (cid.CID, float64, string) {
129-
info, ok := gd.info[c]
130-
if !ok {
131-
info = gd.notdef
132-
return 0, info.Width, info.Text
133-
}
134-
return cid.CID(c) + 1, info.Width, info.Text
135-
}
136-
137-
// AllocateCode finds a free code slot (0–255) for the glyph, then stores the
138-
// corresponding codeInfo in gd.info.
139-
func (gd *GlyphData) AllocateCode(gid glyph.ID, defaultGlyphName, text string, width float64) byte {
140-
if len(gd.code) >= 256 {
141-
return 0
142-
}
143-
144-
glyphName := gd.makeGlyphName(gid, defaultGlyphName, text)
145-
146-
var r rune
147-
rr := names.ToUnicode(glyphName, gd.isZapfDingbats)
148-
if len(rr) > 0 {
149-
r = rr[0]
150-
}
151-
bestScore := -1
152-
bestCode := byte(0)
153-
for codeInt := 0; codeInt < 256; codeInt++ {
154-
code := byte(codeInt)
155-
if _, used := gd.info[code]; used {
156-
continue
157-
}
158-
score := 0
159-
stdName := gd.encoding.Encoding[code]
160-
if stdName == glyphName {
161-
bestCode = code
162-
break
163-
} else if stdName == ".notdef" || stdName == "" {
164-
score += 100
165-
} else if !(code == 32 && glyphName != "space") {
166-
score += 10
167-
}
168-
score += bits.TrailingZeros16(uint16(r) ^ uint16(code))
169-
if score > bestScore {
170-
bestScore = score
171-
bestCode = code
172-
}
173-
}
174-
gd.info[bestCode] = &codeInfo{Width: width, Text: text}
175-
return bestCode
176-
}
177-
178-
// makeGlyphName returns a name for the given glyph, adding any needed suffix.
179-
func (gd *GlyphData) makeGlyphName(gid glyph.ID, defaultGlyphName, text string) string {
180-
if name, ok := gd.GlyphName[gid]; ok {
181-
return name
182-
}
183-
name := defaultGlyphName
184-
if name == "" {
185-
var parts []string
186-
for _, r := range text {
187-
parts = append(parts, names.FromUnicode(r))
188-
}
189-
if len(parts) > 0 {
190-
name = strings.Join(parts, "_")
191-
}
192-
}
193-
alt := 0
194-
base := name
195-
nameLoop:
196-
for {
197-
if len(name) <= 31 && !gd.glyphNameUsed[name] {
198-
break
199-
}
200-
if len(name) > 31 {
201-
for idx := len(gd.glyphNameUsed); idx >= 0; idx-- {
202-
name = fmt.Sprintf("orn%03d", idx)
203-
if !gd.glyphNameUsed[name] {
204-
break nameLoop
205-
}
206-
}
207-
}
208-
alt++
209-
name = fmt.Sprintf("%s.alt%d", base, alt)
210-
}
211-
gd.GlyphName[gid] = name
212-
gd.glyphNameUsed[name] = true
213-
return name
214-
}
215-
216-
// Overflow checks if more than 256 codes have been allocated.
217-
func (gd *GlyphData) Overflow() bool {
218-
return len(gd.code) > 256
219-
}
220-
221-
// Subset returns a sorted list of the glyphs used in this encoding.
222-
func (gd *GlyphData) Subset() []glyph.ID {
223-
gidIsUsed := make(map[glyph.ID]struct{})
224-
gidIsUsed[0] = struct{}{} // always include .notdef
225-
for k := range gd.code {
226-
gidIsUsed[k.gid] = struct{}{}
227-
}
228-
glyphs := maps.Keys(gidIsUsed)
229-
slices.Sort(glyphs)
230-
return glyphs
231-
}
232-
233-
func (gd *GlyphData) Encoding() encoding.Simple {
234-
enc := make(map[byte]string)
235-
for k, c := range gd.code {
236-
enc[c] = gd.GlyphName[k.gid]
237-
}
238-
return func(c byte) string { return enc[c] }
239-
}
240-
241-
func (gd *GlyphData) MissingWidth() float64 {
242-
return gd.notdef.Width
65+
finished bool
24366
}
24467

24568
func newEmbeddedSimple(ref pdf.Reference, f *Instance) *embeddedSimple {
24669
e := &embeddedSimple{
247-
Ref: ref,
248-
Font: f.Font,
70+
Ref: ref,
71+
Font: f.Font,
72+
24973
Stretch: f.Stretch,
25074
Weight: f.Weight,
25175
IsSerif: f.IsSerif,
@@ -255,44 +79,33 @@ func newEmbeddedSimple(ref pdf.Reference, f *Instance) *embeddedSimple {
25579
Leading: f.Leading,
25680
CapHeight: f.CapHeight,
25781
XHeight: f.XHeight,
258-
gd: newGlyphData(
82+
83+
Simple: simpleenc.NewSimple(
25984
math.Round(f.Font.GlyphWidthPDF(0)),
260-
f.Font.FontName == "ZapfDingbats",
85+
f.Font.FontName,
26186
&pdfenc.WinAnsi,
26287
),
26388
}
264-
26589
return e
26690
}
26791

268-
func (*embeddedSimple) WritingMode() font.WritingMode {
269-
return font.Horizontal
270-
}
271-
272-
func (e *embeddedSimple) Codes(s pdf.String) iter.Seq[*font.Code] {
273-
return func(yield func(*font.Code) bool) {
274-
var code font.Code
275-
for _, c := range s {
276-
code.CID, code.Width, code.Text = e.gd.GetData(c)
277-
code.UseWordSpacing = (c == 0x20)
278-
if !yield(&code) {
279-
return
280-
}
281-
}
282-
}
283-
}
284-
28592
func (e *embeddedSimple) AppendEncoded(s pdf.String, gid glyph.ID, text string) (pdf.String, float64) {
286-
c, ok := e.gd.GetCode(gid, text)
93+
c, ok := e.Simple.GetCode(gid, text)
28794
if !ok {
288-
if !e.finished {
289-
width := math.Round(e.Font.GlyphWidthPDF(gid))
290-
c = e.gd.AllocateCode(gid, e.Font.Outlines.Glyphs[gid].Name, text, width)
95+
if e.finished {
96+
return s, 0
97+
}
98+
99+
glyphName := e.Font.Outlines.Glyphs[gid].Name
100+
width := math.Round(e.Font.GlyphWidthPDF(gid))
101+
var err error
102+
c, err = e.Simple.AllocateCode(gid, glyphName, text, width)
103+
if err != nil {
104+
return s, 0
291105
}
292-
e.gd.SetCode(gid, text, c)
293106
}
294107

295-
_, w, _ := e.gd.GetData(c)
108+
w := e.Simple.Width(c)
296109
return append(s, c), w / 1000
297110
}
298111

@@ -302,16 +115,17 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
302115
}
303116
e.finished = true
304117

305-
if e.gd.Overflow() {
306-
return fmt.Errorf("too many distinct glyphs used in font %q", e.Font.FontName)
118+
if err := e.Simple.Error(); err != nil {
119+
return pdf.Errorf("font %q: %w", e.Font.FontName, err)
307120
}
308121

309122
fontInfo := e.Font.FontInfo
310123
outlines := e.Font.Outlines
311124

312125
// subset the font, if needed
313-
glyphs := e.gd.Subset()
126+
glyphs := e.Simple.Glyphs()
314127
subsetTag := subset.Tag(glyphs, outlines.NumGlyphs())
128+
315129
var subsetOutlines *cff.Outlines
316130
if subsetTag != "" {
317131
subsetOutlines = outlines.Subset(glyphs)
@@ -332,7 +146,7 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
332146
subsetOutlines.FontMatrices = nil
333147
for gid, origGID := range glyphs { // fill in the glyph names
334148
g := subsetOutlines.Glyphs[gid]
335-
glyphName := e.gd.GlyphName[origGID]
149+
glyphName := e.Simple.GlyphName(origGID)
336150
if g.Name == glyphName {
337151
continue
338152
}
@@ -357,7 +171,7 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
357171
if gid == 0 {
358172
continue
359173
}
360-
if !pdfenc.StandardLatin.Has[e.gd.GlyphName[gid]] {
174+
if !pdfenc.StandardLatin.Has[e.Simple.GlyphName(gid)] {
361175
isSymbolic = true
362176
break
363177
}
@@ -386,18 +200,19 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
386200
XHeight: e.XHeight,
387201
StemV: math.Round(subsetCFF.Private[0].StdVW * qh),
388202
StemH: math.Round(subsetCFF.Private[0].StdHW * qv),
389-
MissingWidth: e.gd.MissingWidth(),
203+
MissingWidth: e.Simple.DefaultWidth(),
390204
}
391205
dict := dict.Type1{
392206
PostScriptName: e.Font.FontName,
393207
SubsetTag: subsetTag,
394208
Descriptor: fd,
395-
Encoding: e.gd.Encoding(),
209+
Encoding: e.Simple.Encoding(),
396210
FontType: glyphdata.CFFSimple,
397211
FontRef: rm.Out.Alloc(),
398212
}
399-
for c := range 256 {
400-
_, dict.Width[c], dict.Text[c] = e.gd.GetData(byte(c))
213+
for c, info := range e.Simple.MappedCodes() {
214+
dict.Width[c] = info.Width
215+
dict.Text[c] = info.Text
401216
}
402217

403218
err := dict.WriteToPDF(rm, e.Ref)

0 commit comments

Comments
 (0)