@@ -18,27 +18,18 @@ package cff
18
18
19
19
import (
20
20
"fmt"
21
- "iter"
22
21
"math"
23
- "math/bits"
24
- "slices"
25
- "strings"
26
-
27
- "golang.org/x/exp/maps"
28
22
29
23
"seehuhn.de/go/geom/matrix"
30
24
31
- "seehuhn.de/go/postscript/cid"
32
- "seehuhn.de/go/postscript/type1/names"
33
-
34
25
"seehuhn.de/go/sfnt/cff"
35
26
"seehuhn.de/go/sfnt/glyph"
36
27
"seehuhn.de/go/sfnt/os2"
37
28
38
29
"seehuhn.de/go/pdf"
39
30
"seehuhn.de/go/pdf/font"
40
31
"seehuhn.de/go/pdf/font/dict"
41
- "seehuhn.de/go/pdf/font/encoding"
32
+ "seehuhn.de/go/pdf/font/encoding/simpleenc "
42
33
"seehuhn.de/go/pdf/font/glyphdata"
43
34
"seehuhn.de/go/pdf/font/glyphdata/cffglyphs"
44
35
"seehuhn.de/go/pdf/font/pdfenc"
@@ -69,183 +60,16 @@ type embeddedSimple struct {
69
60
CapHeight float64 // PDF glyph space units
70
61
XHeight float64 // PDF glyph space units
71
62
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
91
64
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
243
66
}
244
67
245
68
func newEmbeddedSimple (ref pdf.Reference , f * Instance ) * embeddedSimple {
246
69
e := & embeddedSimple {
247
- Ref : ref ,
248
- Font : f .Font ,
70
+ Ref : ref ,
71
+ Font : f .Font ,
72
+
249
73
Stretch : f .Stretch ,
250
74
Weight : f .Weight ,
251
75
IsSerif : f .IsSerif ,
@@ -255,44 +79,33 @@ func newEmbeddedSimple(ref pdf.Reference, f *Instance) *embeddedSimple {
255
79
Leading : f .Leading ,
256
80
CapHeight : f .CapHeight ,
257
81
XHeight : f .XHeight ,
258
- gd : newGlyphData (
82
+
83
+ Simple : simpleenc .NewSimple (
259
84
math .Round (f .Font .GlyphWidthPDF (0 )),
260
- f .Font .FontName == "ZapfDingbats" ,
85
+ f .Font .FontName ,
261
86
& pdfenc .WinAnsi ,
262
87
),
263
88
}
264
-
265
89
return e
266
90
}
267
91
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
-
285
92
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 )
287
94
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
291
105
}
292
- e .gd .SetCode (gid , text , c )
293
106
}
294
107
295
- _ , w , _ := e .gd . GetData (c )
108
+ w := e .Simple . Width (c )
296
109
return append (s , c ), w / 1000
297
110
}
298
111
@@ -302,16 +115,17 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
302
115
}
303
116
e .finished = true
304
117
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 )
307
120
}
308
121
309
122
fontInfo := e .Font .FontInfo
310
123
outlines := e .Font .Outlines
311
124
312
125
// subset the font, if needed
313
- glyphs := e .gd . Subset ()
126
+ glyphs := e .Simple . Glyphs ()
314
127
subsetTag := subset .Tag (glyphs , outlines .NumGlyphs ())
128
+
315
129
var subsetOutlines * cff.Outlines
316
130
if subsetTag != "" {
317
131
subsetOutlines = outlines .Subset (glyphs )
@@ -332,7 +146,7 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
332
146
subsetOutlines .FontMatrices = nil
333
147
for gid , origGID := range glyphs { // fill in the glyph names
334
148
g := subsetOutlines .Glyphs [gid ]
335
- glyphName := e .gd .GlyphName [ origGID ]
149
+ glyphName := e .Simple .GlyphName ( origGID )
336
150
if g .Name == glyphName {
337
151
continue
338
152
}
@@ -357,7 +171,7 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
357
171
if gid == 0 {
358
172
continue
359
173
}
360
- if ! pdfenc .StandardLatin .Has [e .gd .GlyphName [ gid ] ] {
174
+ if ! pdfenc .StandardLatin .Has [e .Simple .GlyphName ( gid ) ] {
361
175
isSymbolic = true
362
176
break
363
177
}
@@ -386,18 +200,19 @@ func (e *embeddedSimple) Finish(rm *pdf.ResourceManager) error {
386
200
XHeight : e .XHeight ,
387
201
StemV : math .Round (subsetCFF .Private [0 ].StdVW * qh ),
388
202
StemH : math .Round (subsetCFF .Private [0 ].StdHW * qv ),
389
- MissingWidth : e .gd . MissingWidth (),
203
+ MissingWidth : e .Simple . DefaultWidth (),
390
204
}
391
205
dict := dict.Type1 {
392
206
PostScriptName : e .Font .FontName ,
393
207
SubsetTag : subsetTag ,
394
208
Descriptor : fd ,
395
- Encoding : e .gd .Encoding (),
209
+ Encoding : e .Simple .Encoding (),
396
210
FontType : glyphdata .CFFSimple ,
397
211
FontRef : rm .Out .Alloc (),
398
212
}
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
401
216
}
402
217
403
218
err := dict .WriteToPDF (rm , e .Ref )
0 commit comments