1
2
3
4
5 package sfnt
6
7 import (
8 "sort"
9 )
10
11 const (
12 hexScriptLatn = uint32(0x6c61746e)
13 hexScriptDFLT = uint32(0x44464c54)
14 hexFeatureKern = uint32(0x6b65726e)
15 )
16
17
18
19 type kernFunc func(a, b GlyphIndex) (int16, error)
20
21 func (f *Font) parseGPOSKern(buf []byte) ([]byte, []kernFunc, error) {
22
23
24 if f.gpos.length == 0 {
25 return buf, nil, nil
26 }
27 const headerSize = 10
28 if f.gpos.length < headerSize {
29 return buf, nil, errInvalidGPOSTable
30 }
31
32 buf, err := f.src.view(buf, int(f.gpos.offset), headerSize)
33 if err != nil {
34 return buf, nil, err
35 }
36
37
38 if u16(buf) != 1 || u16(buf[2:]) > 1 {
39 return buf, nil, errUnsupportedGPOSTable
40 }
41 scriptListOffset := u16(buf[4:])
42 featureListOffset := u16(buf[6:])
43 lookupListOffset := u16(buf[8:])
44
45
46 buf, featureIdxs, err := f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptLatn)
47 if err != nil {
48 return buf, nil, err
49 }
50 if len(featureIdxs) == 0 {
51
52 buf, featureIdxs, err = f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptDFLT)
53 if err != nil {
54 return buf, nil, err
55 }
56 if len(featureIdxs) == 0 {
57 return buf, nil, nil
58 }
59 }
60
61
62 buf, lookupIdx, err := f.parseGPOSFeaturesLookup(buf, int(f.gpos.offset)+int(featureListOffset), featureIdxs, hexFeatureKern)
63 if err != nil {
64 return buf, nil, err
65 }
66
67
68 buf, numLookupTables, err := f.src.varLenView(buf, int(f.gpos.offset)+int(lookupListOffset), 2, 0, 2)
69 if err != nil {
70 return buf, nil, err
71 }
72
73 var kernFuncs []kernFunc
74
75 lookupTables:
76 for _, n := range lookupIdx {
77 if n > numLookupTables {
78 return buf, nil, errInvalidGPOSTable
79 }
80 tableOffset := int(f.gpos.offset) + int(lookupListOffset) + int(u16(buf[2+n*2:]))
81
82
83 buf, numSubTables, err := f.src.varLenView(buf, tableOffset, 8, 4, 2)
84 if err != nil {
85 return buf, nil, err
86 }
87
88 flags := u16(buf[2:])
89
90 subTableOffsets := make([]int, numSubTables)
91 for i := 0; i < int(numSubTables); i++ {
92 subTableOffsets[i] = int(tableOffset) + int(u16(buf[6+i*2:]))
93 }
94
95 switch lookupType := u16(buf); lookupType {
96 case 2:
97 case 9:
98
99
100 for i := range subTableOffsets {
101 buf, err = f.src.view(buf, subTableOffsets[i], 8)
102 if err != nil {
103 return buf, nil, err
104 }
105 if format := u16(buf); format != 1 {
106 return buf, nil, errUnsupportedExtensionPosFormat
107 }
108 if lookupType := u16(buf[2:]); lookupType != 2 {
109 continue lookupTables
110 }
111 subTableOffsets[i] += int(u32(buf[4:]))
112 }
113 default:
114 continue
115 }
116
117 if flags&0x0010 > 0 {
118
119 continue
120 }
121
122 for _, subTableOffset := range subTableOffsets {
123 buf, err = f.src.view(buf, int(subTableOffset), 4)
124 if err != nil {
125 return buf, nil, err
126 }
127 format := u16(buf)
128
129 var lookupIndex indexLookupFunc
130 buf, lookupIndex, err = f.makeCachedCoverageLookup(buf, subTableOffset+int(u16(buf[2:])))
131 if err != nil {
132 return buf, nil, err
133 }
134
135 switch format {
136 case 1:
137 buf, kern, err := f.parsePairPosFormat1(buf, subTableOffset, lookupIndex)
138 if err != nil {
139 return buf, nil, err
140 }
141 if kern != nil {
142 kernFuncs = append(kernFuncs, kern)
143 }
144 case 2:
145 buf, kern, err := f.parsePairPosFormat2(buf, subTableOffset, lookupIndex)
146 if err != nil {
147 return buf, nil, err
148 }
149 if kern != nil {
150 kernFuncs = append(kernFuncs, kern)
151 }
152 }
153 }
154 }
155
156 return buf, kernFuncs, nil
157 }
158
159 func (f *Font) parsePairPosFormat1(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
160
161
162 var err error
163 var nPairs int
164 buf, nPairs, err = f.src.varLenView(buf, offset, 10, 8, 2)
165 if err != nil {
166 return buf, nil, err
167 }
168
169 if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
170
171 return buf, nil, nil
172 }
173
174
175
176
177
178
179
180 var lastPairSetOffset int
181 for n := 0; n < nPairs; n++ {
182 pairOffset := int(u16(buf[10+n*2:]))
183 if pairOffset > lastPairSetOffset {
184 lastPairSetOffset = pairOffset
185 }
186 }
187 buf, err = f.src.view(buf, offset+lastPairSetOffset, 2)
188 if err != nil {
189 return buf, nil, err
190 }
191
192 pairValueCount := int(u16(buf))
193
194
195 lastPairSetLength := 2 + pairValueCount*4
196
197 length := lastPairSetOffset + lastPairSetLength
198 buf, err = f.src.view(buf, offset, length)
199 if err != nil {
200 return buf, nil, err
201 }
202
203 kern := makeCachedPairPosGlyph(lookupIndex, nPairs, buf)
204 return buf, kern, nil
205 }
206
207 func (f *Font) parsePairPosFormat2(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
208
209
210
211
212 var err error
213 buf, err = f.src.view(buf, offset, 16)
214 if err != nil {
215 return buf, nil, err
216 }
217
218 if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
219
220 return buf, nil, nil
221 }
222 numClass1 := int(u16(buf[12:]))
223 numClass2 := int(u16(buf[14:]))
224 cdef1Offset := offset + int(u16(buf[8:]))
225 cdef2Offset := offset + int(u16(buf[10:]))
226 var cdef1, cdef2 classLookupFunc
227 buf, cdef1, err = f.makeCachedClassLookup(buf, cdef1Offset)
228 if err != nil {
229 return buf, nil, err
230 }
231 buf, cdef2, err = f.makeCachedClassLookup(buf, cdef2Offset)
232 if err != nil {
233 return buf, nil, err
234 }
235
236 buf, err = f.src.view(buf, offset+16, numClass1*numClass2*2)
237 if err != nil {
238 return buf, nil, err
239 }
240 kern := makeCachedPairPosClass(
241 lookupIndex,
242 numClass1,
243 numClass2,
244 cdef1,
245 cdef2,
246 buf,
247 )
248
249 return buf, kern, nil
250 }
251
252
253
254
255
256
257 func (f *Font) parseGPOSScriptFeatures(buf []byte, offset int, script uint32) ([]byte, []int, error) {
258
259 buf, numScriptTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
260 if err != nil {
261 return buf, nil, err
262 }
263
264
265 var scriptTableOffset uint16
266 for i := 0; i < numScriptTables; i++ {
267 scriptTag := u32(buf[2+i*6:])
268 if scriptTag == script {
269 scriptTableOffset = u16(buf[2+i*6+4:])
270 break
271 }
272 }
273 if scriptTableOffset == 0 {
274 return buf, nil, nil
275 }
276
277
278 buf, err = f.src.view(buf, offset+int(scriptTableOffset), 2)
279 if err != nil {
280 return buf, nil, err
281 }
282 defaultLangSysOffset := u16(buf)
283
284 if defaultLangSysOffset == 0 {
285 return buf, nil, nil
286 }
287
288
289 buf, numFeatures, err := f.src.varLenView(buf, offset+int(scriptTableOffset)+int(defaultLangSysOffset), 6, 4, 2)
290 if err != nil {
291 return buf, nil, err
292 }
293
294 featureIdxs := make([]int, numFeatures)
295 for i := range featureIdxs {
296 featureIdxs[i] = int(u16(buf[6+i*2:]))
297 }
298 return buf, featureIdxs, nil
299 }
300
301 func (f *Font) parseGPOSFeaturesLookup(buf []byte, offset int, featureIdxs []int, feature uint32) ([]byte, []int, error) {
302
303 buf, numFeatureTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
304 if err != nil {
305 return buf, nil, err
306 }
307
308 lookupIdx := make([]int, 0, 4)
309
310 for _, fidx := range featureIdxs {
311 if fidx > numFeatureTables {
312 return buf, nil, errInvalidGPOSTable
313 }
314 featureTag := u32(buf[2+fidx*6:])
315 if featureTag != feature {
316 continue
317 }
318 featureOffset := u16(buf[2+fidx*6+4:])
319
320 buf, numLookups, err := f.src.varLenView(nil, offset+int(featureOffset), 4, 2, 2)
321 if err != nil {
322 return buf, nil, err
323 }
324
325 for i := 0; i < numLookups; i++ {
326 lookupIdx = append(lookupIdx, int(u16(buf[4+i*2:])))
327 }
328 }
329
330 return buf, lookupIdx, nil
331 }
332
333 func makeCachedPairPosGlyph(cov indexLookupFunc, num int, buf []byte) kernFunc {
334 glyphs := make([]byte, len(buf))
335 copy(glyphs, buf)
336 return func(a, b GlyphIndex) (int16, error) {
337 idx, found := cov(a)
338 if !found {
339 return 0, ErrNotFound
340 }
341 if idx >= num {
342 return 0, ErrNotFound
343 }
344 offset := int(u16(glyphs[10+idx*2:]))
345 if offset+1 >= len(glyphs) {
346 return 0, errInvalidGPOSTable
347 }
348
349 count := int(u16(glyphs[offset:]))
350 for i := 0; i < count; i++ {
351 secondGlyphIndex := GlyphIndex(int(u16(glyphs[offset+2+i*4:])))
352 if secondGlyphIndex == b {
353 return int16(u16(glyphs[offset+2+i*4+2:])), nil
354 }
355 if secondGlyphIndex > b {
356 return 0, ErrNotFound
357 }
358 }
359
360 return 0, ErrNotFound
361 }
362 }
363
364 func makeCachedPairPosClass(cov indexLookupFunc, num1, num2 int, cdef1, cdef2 classLookupFunc, buf []byte) kernFunc {
365 glyphs := make([]byte, len(buf))
366 copy(glyphs, buf)
367 return func(a, b GlyphIndex) (int16, error) {
368
369 _, found := cov(a)
370 if !found {
371 return 0, ErrNotFound
372 }
373 idxa := cdef1(a)
374 idxb := cdef2(b)
375 return int16(u16(glyphs[(idxb+idxa*num2)*2:])), nil
376 }
377 }
378
379
380
381 type indexLookupFunc func(GlyphIndex) (int, bool)
382
383 func (f *Font) makeCachedCoverageLookup(buf []byte, offset int) ([]byte, indexLookupFunc, error) {
384 var err error
385 buf, err = f.src.view(buf, offset, 2)
386 if err != nil {
387 return buf, nil, err
388 }
389 switch u16(buf) {
390 case 1:
391
392 buf, _, err = f.src.varLenView(buf, offset, 4, 2, 2)
393 if err != nil {
394 return buf, nil, err
395 }
396 return buf, makeCachedCoverageList(buf[2:]), nil
397 case 2:
398
399 buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
400 if err != nil {
401 return buf, nil, err
402 }
403 return buf, makeCachedCoverageRange(buf[2:]), nil
404 default:
405 return buf, nil, errUnsupportedCoverageFormat
406 }
407 }
408
409 func makeCachedCoverageList(buf []byte) indexLookupFunc {
410 num := int(u16(buf))
411 list := make([]byte, len(buf)-2)
412 copy(list, buf[2:])
413 return func(gi GlyphIndex) (int, bool) {
414 idx := sort.Search(num, func(i int) bool {
415 return gi <= GlyphIndex(u16(list[i*2:]))
416 })
417 if idx < num && GlyphIndex(u16(list[idx*2:])) == gi {
418 return idx, true
419 }
420
421 return 0, false
422 }
423 }
424
425 func makeCachedCoverageRange(buf []byte) indexLookupFunc {
426 num := int(u16(buf))
427 ranges := make([]byte, len(buf)-2)
428 copy(ranges, buf[2:])
429 return func(gi GlyphIndex) (int, bool) {
430 if num == 0 {
431 return 0, false
432 }
433
434
435
436
437
438
439
440
441
442 idx := sort.Search(num, func(i int) bool {
443 return gi <= GlyphIndex(u16(ranges[i*6:]))
444 })
445
446
447
448
449 if idx < num {
450 if start := u16(ranges[idx*6:]); gi == GlyphIndex(start) {
451 return int(u16(ranges[idx*6+4:])), true
452 }
453 }
454
455 if idx > 0 {
456 idx--
457 start, end := u16(ranges[idx*6:]), u16(ranges[idx*6+2:])
458 if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
459 return int(u16(ranges[idx*6+4:]) + uint16(gi) - start), true
460 }
461 }
462
463 return 0, false
464 }
465 }
466
467
468
469 type classLookupFunc func(GlyphIndex) int
470
471 func (f *Font) makeCachedClassLookup(buf []byte, offset int) ([]byte, classLookupFunc, error) {
472 var err error
473 buf, err = f.src.view(buf, offset, 2)
474 if err != nil {
475 return buf, nil, err
476 }
477 switch u16(buf) {
478 case 1:
479
480 buf, _, err = f.src.varLenView(buf, offset, 6, 4, 2)
481 if err != nil {
482 return buf, nil, err
483 }
484 return buf, makeCachedClassLookupFormat1(buf), nil
485 case 2:
486
487 buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
488 if err != nil {
489 return buf, nil, err
490 }
491 return buf, makeCachedClassLookupFormat2(buf), nil
492 default:
493 return buf, nil, errUnsupportedClassDefFormat
494 }
495 }
496
497 func makeCachedClassLookupFormat1(buf []byte) classLookupFunc {
498 startGI := u16(buf[2:])
499 num := u16(buf[4:])
500 classIDs := make([]byte, len(buf)-4)
501 copy(classIDs, buf[6:])
502
503 return func(gi GlyphIndex) int {
504
505 if gi < GlyphIndex(startGI) || gi >= GlyphIndex(startGI+num) {
506
507 return 0
508 }
509 return int(u16(classIDs[(int(gi)-int(startGI))*2:]))
510 }
511 }
512
513 func makeCachedClassLookupFormat2(buf []byte) classLookupFunc {
514 num := int(u16(buf[2:]))
515 classRanges := make([]byte, len(buf)-2)
516 copy(classRanges, buf[4:])
517
518 return func(gi GlyphIndex) int {
519 if num == 0 {
520 return 0
521 }
522
523
524
525
526
527 idx := sort.Search(num, func(i int) bool {
528 return gi <= GlyphIndex(u16(classRanges[i*6:]))
529 })
530
531
532
533
534 if idx < num {
535 if start := u16(classRanges[idx*6:]); gi == GlyphIndex(start) {
536 return int(u16(classRanges[idx*6+4:]))
537 }
538 }
539
540 if idx > 0 {
541 idx--
542 start, end := u16(classRanges[idx*6:]), u16(classRanges[idx*6+2:])
543 if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
544 return int(u16(classRanges[idx*6+4:]))
545 }
546 }
547
548 return 0
549 }
550 }
551
View as plain text