git clone https://git.lucas.co/go_mono.git
font/sfnt/postscript.go (37.8K)
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package sfnt
6
7 // Compact Font Format (CFF) fonts are written in PostScript, a stack-based
8 // programming language.
9 //
10 // A fundamental concept is a DICT, or a key-value map, expressed in reverse
11 // Polish notation. For example, this sequence of operations:
12 // - push the number 379
13 // - version operator
14 // - push the number 392
15 // - Notice operator
16 // - etc
17 // - push the number 100
18 // - push the number 0
19 // - push the number 500
20 // - push the number 800
21 // - FontBBox operator
22 // - etc
23 // defines a DICT that maps "version" to the String ID (SID) 379, "Notice" to
24 // the SID 392, "FontBBox" to the four numbers [100, 0, 500, 800], etc.
25 //
26 // The first 391 String IDs (starting at 0) are predefined as per the CFF spec
27 // Appendix A, in 5176.CFF.pdf referenced below. For example, 379 means
28 // "001.000". String ID 392 is not predefined, and is mapped by a separate
29 // structure, the "String INDEX", inside the CFF data. (String ID 391 is also
30 // not predefined. Specifically for ../testdata/CFFTest.otf, 391 means
31 // "uni4E2D", as this font contains a glyph for U+4E2D).
32 //
33 // The actual glyph vectors are similarly encoded (in PostScript), in a format
34 // called Type 2 Charstrings. The wire encoding is similar to but not exactly
35 // the same as CFF's. For example, the byte 0x05 means FontBBox for CFF DICTs,
36 // but means rlineto (relative line-to) for Type 2 Charstrings. See
37 // 5176.CFF.pdf Appendix H and 5177.Type2.pdf Appendix A in the PDF files
38 // referenced below.
39 //
40 // CFF is a stand-alone format, but CFF as used in SFNT fonts have further
41 // restrictions. For example, a stand-alone CFF can contain multiple fonts, but
42 // https://www.microsoft.com/typography/OTSPEC/cff.htm says that "The Name
43 // INDEX in the CFF must contain only one entry; that is, there must be only
44 // one font in the CFF FontSet".
45 //
46 // The relevant specifications are:
47 // - http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
48 // - http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf
49
50 import (
51 "fmt"
52 "math"
53 "strconv"
54
55 "golang.org/x/image/math/fixed"
56 )
57
58 const (
59 // psArgStackSize is the argument stack size for a PostScript interpreter.
60 // 5176.CFF.pdf section 4 "DICT Data" says that "An operator may be
61 // preceded by up to a maximum of 48 operands". 5177.Type2.pdf Appendix B
62 // "Type 2 Charstring Implementation Limits" says that "Argument stack 48".
63 psArgStackSize = 48
64
65 // Similarly, Appendix B says "Subr nesting, stack limit 10".
66 psCallStackSize = 10
67 )
68
69 func bigEndian(b []byte) uint32 {
70 switch len(b) {
71 case 1:
72 return uint32(b[0])
73 case 2:
74 return uint32(b[0])<<8 | uint32(b[1])
75 case 3:
76 return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
77 case 4:
78 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
79 }
80 panic("unreachable")
81 }
82
83 // fdSelect holds a CFF font's Font Dict Select data.
84 type fdSelect struct {
85 format uint8
86 numRanges uint16
87 offset int32
88 }
89
90 func (t *fdSelect) lookup(f *Font, b *Buffer, x GlyphIndex) (int, error) {
91 switch t.format {
92 case 0:
93 buf, err := b.view(&f.src, int(t.offset)+int(x), 1)
94 if err != nil {
95 return 0, err
96 }
97 return int(buf[0]), nil
98 case 3:
99 lo, hi := 0, int(t.numRanges)
100 for lo < hi {
101 i := (lo + hi) / 2
102 buf, err := b.view(&f.src, int(t.offset)+3*i, 3+2)
103 if err != nil {
104 return 0, err
105 }
106 // buf holds the range [xlo, xhi).
107 if xlo := GlyphIndex(u16(buf[0:])); x < xlo {
108 hi = i
109 continue
110 }
111 if xhi := GlyphIndex(u16(buf[3:])); xhi <= x {
112 lo = i + 1
113 continue
114 }
115 return int(buf[2]), nil
116 }
117 }
118 return 0, ErrNotFound
119 }
120
121 // cffParser parses the CFF table from an SFNT font.
122 type cffParser struct {
123 src *source
124 base int
125 offset int
126 end int
127 err error
128
129 buf []byte
130 locBuf [2]uint32
131
132 psi psInterpreter
133 }
134
135 func (p *cffParser) parse(numGlyphs int32) (ret glyphData, err error) {
136 // Parse the header.
137 {
138 if !p.read(4) {
139 return glyphData{}, p.err
140 }
141 if p.buf[0] != 1 || p.buf[1] != 0 || p.buf[2] != 4 {
142 return glyphData{}, errUnsupportedCFFVersion
143 }
144 }
145
146 // Parse the Name INDEX.
147 {
148 count, offSize, ok := p.parseIndexHeader()
149 if !ok {
150 return glyphData{}, p.err
151 }
152 // https://www.microsoft.com/typography/OTSPEC/cff.htm says that "The
153 // Name INDEX in the CFF must contain only one entry".
154 if count != 1 {
155 return glyphData{}, errInvalidCFFTable
156 }
157 if !p.parseIndexLocations(p.locBuf[:2], count, offSize) {
158 return glyphData{}, p.err
159 }
160 p.offset = int(p.locBuf[1])
161 }
162
163 // Parse the Top DICT INDEX.
164 p.psi.topDict.initialize()
165 {
166 count, offSize, ok := p.parseIndexHeader()
167 if !ok {
168 return glyphData{}, p.err
169 }
170 // 5176.CFF.pdf section 8 "Top DICT INDEX" says that the count here
171 // should match the count of the Name INDEX, which is 1.
172 if count != 1 {
173 return glyphData{}, errInvalidCFFTable
174 }
175 if !p.parseIndexLocations(p.locBuf[:2], count, offSize) {
176 return glyphData{}, p.err
177 }
178 if !p.read(int(p.locBuf[1] - p.locBuf[0])) {
179 return glyphData{}, p.err
180 }
181 if p.err = p.psi.run(psContextTopDict, p.buf, 0, 0); p.err != nil {
182 return glyphData{}, p.err
183 }
184 }
185
186 // Skip the String INDEX.
187 {
188 count, offSize, ok := p.parseIndexHeader()
189 if !ok {
190 return glyphData{}, p.err
191 }
192 if count != 0 {
193 // Read the last location. Locations are off by 1 byte. See the
194 // comment in parseIndexLocations.
195 if !p.skip(int(count * offSize)) {
196 return glyphData{}, p.err
197 }
198 if !p.read(int(offSize)) {
199 return glyphData{}, p.err
200 }
201 loc := bigEndian(p.buf) - 1
202 // Check that locations are in bounds.
203 if uint32(p.end-p.offset) < loc {
204 return glyphData{}, errInvalidCFFTable
205 }
206 // Skip the index data.
207 if !p.skip(int(loc)) {
208 return glyphData{}, p.err
209 }
210 }
211 }
212
213 // Parse the Global Subrs [Subroutines] INDEX.
214 {
215 count, offSize, ok := p.parseIndexHeader()
216 if !ok {
217 return glyphData{}, p.err
218 }
219 if count != 0 {
220 if count > maxNumSubroutines {
221 return glyphData{}, errUnsupportedNumberOfSubroutines
222 }
223 ret.gsubrs = make([]uint32, count+1)
224 if !p.parseIndexLocations(ret.gsubrs, count, offSize) {
225 return glyphData{}, p.err
226 }
227 }
228 }
229
230 // Parse the CharStrings INDEX, whose location was found in the Top DICT.
231 {
232 if !p.seekFromBase(p.psi.topDict.charStringsOffset) {
233 return glyphData{}, errInvalidCFFTable
234 }
235 count, offSize, ok := p.parseIndexHeader()
236 if !ok {
237 return glyphData{}, p.err
238 }
239 if count == 0 || int32(count) != numGlyphs {
240 return glyphData{}, errInvalidCFFTable
241 }
242 ret.locations = make([]uint32, count+1)
243 if !p.parseIndexLocations(ret.locations, count, offSize) {
244 return glyphData{}, p.err
245 }
246 }
247
248 if !p.psi.topDict.isCIDFont {
249 // Parse the Private DICT, whose location was found in the Top DICT.
250 ret.singleSubrs, err = p.parsePrivateDICT(
251 p.psi.topDict.privateDictOffset,
252 p.psi.topDict.privateDictLength,
253 )
254 if err != nil {
255 return glyphData{}, err
256 }
257
258 } else {
259 // Parse the Font Dict Select data, whose location was found in the Top
260 // DICT.
261 ret.fdSelect, err = p.parseFDSelect(p.psi.topDict.fdSelect, numGlyphs)
262 if err != nil {
263 return glyphData{}, err
264 }
265
266 // Parse the Font Dicts. Each one contains its own Private DICT.
267 if !p.seekFromBase(p.psi.topDict.fdArray) {
268 return glyphData{}, errInvalidCFFTable
269 }
270
271 count, offSize, ok := p.parseIndexHeader()
272 if !ok {
273 return glyphData{}, p.err
274 }
275 if count > maxNumFontDicts {
276 return glyphData{}, errUnsupportedNumberOfFontDicts
277 }
278
279 fdLocations := make([]uint32, count+1)
280 if !p.parseIndexLocations(fdLocations, count, offSize) {
281 return glyphData{}, p.err
282 }
283
284 privateDicts := make([]struct {
285 offset, length int32
286 }, count)
287
288 for i := range privateDicts {
289 length := fdLocations[i+1] - fdLocations[i]
290 if !p.read(int(length)) {
291 return glyphData{}, errInvalidCFFTable
292 }
293 p.psi.topDict.initialize()
294 if p.err = p.psi.run(psContextTopDict, p.buf, 0, 0); p.err != nil {
295 return glyphData{}, p.err
296 }
297 privateDicts[i].offset = p.psi.topDict.privateDictOffset
298 privateDicts[i].length = p.psi.topDict.privateDictLength
299 }
300
301 ret.multiSubrs = make([][]uint32, count)
302 for i, pd := range privateDicts {
303 ret.multiSubrs[i], err = p.parsePrivateDICT(pd.offset, pd.length)
304 if err != nil {
305 return glyphData{}, err
306 }
307 }
308 }
309
310 return ret, err
311 }
312
313 // parseFDSelect parses the Font Dict Select data as per 5176.CFF.pdf section
314 // 19 "FDSelect".
315 func (p *cffParser) parseFDSelect(offset int32, numGlyphs int32) (ret fdSelect, err error) {
316 if !p.seekFromBase(p.psi.topDict.fdSelect) {
317 return fdSelect{}, errInvalidCFFTable
318 }
319 if !p.read(1) {
320 return fdSelect{}, p.err
321 }
322 ret.format = p.buf[0]
323 switch ret.format {
324 case 0:
325 if p.end-p.offset < int(numGlyphs) {
326 return fdSelect{}, errInvalidCFFTable
327 }
328 ret.offset = int32(p.offset)
329 return ret, nil
330 case 3:
331 if !p.read(2) {
332 return fdSelect{}, p.err
333 }
334 ret.numRanges = u16(p.buf)
335 if p.end-p.offset < 3*int(ret.numRanges)+2 {
336 return fdSelect{}, errInvalidCFFTable
337 }
338 ret.offset = int32(p.offset)
339 return ret, nil
340 }
341 return fdSelect{}, errUnsupportedCFFFDSelectTable
342 }
343
344 func (p *cffParser) parsePrivateDICT(offset, length int32) (subrs []uint32, err error) {
345 p.psi.privateDict.initialize()
346 if length != 0 {
347 fullLength := int32(p.end - p.base)
348 if offset <= 0 || fullLength < offset || fullLength-offset < length || length < 0 {
349 return nil, errInvalidCFFTable
350 }
351 p.offset = p.base + int(offset)
352 if !p.read(int(length)) {
353 return nil, p.err
354 }
355 if p.err = p.psi.run(psContextPrivateDict, p.buf, 0, 0); p.err != nil {
356 return nil, p.err
357 }
358 }
359
360 // Parse the Local Subrs [Subroutines] INDEX, whose location was found in
361 // the Private DICT.
362 if p.psi.privateDict.subrsOffset != 0 {
363 if !p.seekFromBase(offset + p.psi.privateDict.subrsOffset) {
364 return nil, errInvalidCFFTable
365 }
366 count, offSize, ok := p.parseIndexHeader()
367 if !ok {
368 return nil, p.err
369 }
370 if count != 0 {
371 if count > maxNumSubroutines {
372 return nil, errUnsupportedNumberOfSubroutines
373 }
374 subrs = make([]uint32, count+1)
375 if !p.parseIndexLocations(subrs, count, offSize) {
376 return nil, p.err
377 }
378 }
379 }
380
381 return subrs, err
382 }
383
384 // read sets p.buf to view the n bytes from p.offset to p.offset+n. It also
385 // advances p.offset by n.
386 //
387 // As per the source.view method, the caller should not modify the contents of
388 // p.buf after read returns, other than by calling read again.
389 //
390 // The caller should also avoid modifying the pointer / length / capacity of
391 // the p.buf slice, not just avoid modifying the slice's contents, in order to
392 // maximize the opportunity to re-use p.buf's allocated memory when viewing the
393 // underlying source data for subsequent read calls.
394 func (p *cffParser) read(n int) (ok bool) {
395 if n < 0 || p.end-p.offset < n {
396 p.err = errInvalidCFFTable
397 return false
398 }
399 p.buf, p.err = p.src.view(p.buf, p.offset, n)
400 // TODO: if p.err == io.EOF, change that to a different error??
401 p.offset += n
402 return p.err == nil
403 }
404
405 func (p *cffParser) skip(n int) (ok bool) {
406 if p.end-p.offset < n {
407 p.err = errInvalidCFFTable
408 return false
409 }
410 p.offset += n
411 return true
412 }
413
414 func (p *cffParser) seekFromBase(offset int32) (ok bool) {
415 if offset < 0 || int32(p.end-p.base) < offset {
416 return false
417 }
418 p.offset = p.base + int(offset)
419 return true
420 }
421
422 func (p *cffParser) parseIndexHeader() (count, offSize int32, ok bool) {
423 if !p.read(2) {
424 return 0, 0, false
425 }
426 count = int32(u16(p.buf[:2]))
427 // 5176.CFF.pdf section 5 "INDEX Data" says that "An empty INDEX is
428 // represented by a count field with a 0 value and no additional fields.
429 // Thus, the total size of an empty INDEX is 2 bytes".
430 if count == 0 {
431 return count, 0, true
432 }
433 if !p.read(1) {
434 return 0, 0, false
435 }
436 offSize = int32(p.buf[0])
437 if offSize < 1 || 4 < offSize {
438 p.err = errInvalidCFFTable
439 return 0, 0, false
440 }
441 return count, offSize, true
442 }
443
444 func (p *cffParser) parseIndexLocations(dst []uint32, count, offSize int32) (ok bool) {
445 if count == 0 {
446 return true
447 }
448 if len(dst) != int(count+1) {
449 panic("unreachable")
450 }
451 if !p.read(len(dst) * int(offSize)) {
452 return false
453 }
454
455 buf, prev := p.buf, uint32(0)
456 for i := range dst {
457 loc := bigEndian(buf[:offSize])
458 buf = buf[offSize:]
459
460 // Locations are off by 1 byte. 5176.CFF.pdf section 5 "INDEX Data"
461 // says that "Offsets in the offset array are relative to the byte that
462 // precedes the object data... This ensures that every object has a
463 // corresponding offset which is always nonzero".
464 if loc == 0 {
465 p.err = errInvalidCFFTable
466 return false
467 }
468 loc--
469
470 // In the same paragraph, "Therefore the first element of the offset
471 // array is always 1" before correcting for the off-by-1.
472 if i == 0 {
473 if loc != 0 {
474 p.err = errInvalidCFFTable
475 break
476 }
477 } else if loc <= prev { // Check that locations are increasing.
478 p.err = errInvalidCFFTable
479 break
480 }
481
482 // Check that locations are in bounds.
483 if uint32(p.end-p.offset) < loc {
484 p.err = errInvalidCFFTable
485 break
486 }
487
488 dst[i] = uint32(p.offset) + loc
489 prev = loc
490 }
491 return p.err == nil
492 }
493
494 type psCallStackEntry struct {
495 offset, length uint32
496 }
497
498 type psContext uint32
499
500 const (
501 psContextTopDict psContext = iota
502 psContextPrivateDict
503 psContextType2Charstring
504 )
505
506 // psTopDictData contains fields specific to the Top DICT context.
507 type psTopDictData struct {
508 charStringsOffset int32
509 fdArray int32
510 fdSelect int32
511 isCIDFont bool
512 privateDictOffset int32
513 privateDictLength int32
514 }
515
516 func (d *psTopDictData) initialize() {
517 *d = psTopDictData{}
518 }
519
520 // psPrivateDictData contains fields specific to the Private DICT context.
521 type psPrivateDictData struct {
522 subrsOffset int32
523 }
524
525 func (d *psPrivateDictData) initialize() {
526 *d = psPrivateDictData{}
527 }
528
529 // psType2CharstringsData contains fields specific to the Type 2 Charstrings
530 // context.
531 type psType2CharstringsData struct {
532 f *Font
533 b *Buffer
534 x int32
535 y int32
536 firstX int32
537 firstY int32
538 hintBits int32
539 seenWidth bool
540 ended bool
541 glyphIndex GlyphIndex
542 // fdSelectIndexPlusOne is the result of the Font Dict Select lookup, plus
543 // one. That plus one lets us use the zero value to denote either unused
544 // (for CFF fonts with a single Font Dict) or lazily evaluated.
545 fdSelectIndexPlusOne int32
546 }
547
548 func (d *psType2CharstringsData) initialize(f *Font, b *Buffer, glyphIndex GlyphIndex) {
549 *d = psType2CharstringsData{
550 f: f,
551 b: b,
552 glyphIndex: glyphIndex,
553 }
554 }
555
556 func (d *psType2CharstringsData) closePath() {
557 if d.x != d.firstX || d.y != d.firstY {
558 d.b.segments = append(d.b.segments, Segment{
559 Op: SegmentOpLineTo,
560 Args: [3]fixed.Point26_6{{
561 X: fixed.Int26_6(d.firstX),
562 Y: fixed.Int26_6(d.firstY),
563 }},
564 })
565 }
566 }
567
568 func (d *psType2CharstringsData) moveTo(dx, dy int32) {
569 d.closePath()
570 d.x += dx
571 d.y += dy
572 d.b.segments = append(d.b.segments, Segment{
573 Op: SegmentOpMoveTo,
574 Args: [3]fixed.Point26_6{{
575 X: fixed.Int26_6(d.x),
576 Y: fixed.Int26_6(d.y),
577 }},
578 })
579 d.firstX = d.x
580 d.firstY = d.y
581 }
582
583 func (d *psType2CharstringsData) lineTo(dx, dy int32) {
584 d.x += dx
585 d.y += dy
586 d.b.segments = append(d.b.segments, Segment{
587 Op: SegmentOpLineTo,
588 Args: [3]fixed.Point26_6{{
589 X: fixed.Int26_6(d.x),
590 Y: fixed.Int26_6(d.y),
591 }},
592 })
593 }
594
595 func (d *psType2CharstringsData) cubeTo(dxa, dya, dxb, dyb, dxc, dyc int32) {
596 d.x += dxa
597 d.y += dya
598 xa := fixed.Int26_6(d.x)
599 ya := fixed.Int26_6(d.y)
600 d.x += dxb
601 d.y += dyb
602 xb := fixed.Int26_6(d.x)
603 yb := fixed.Int26_6(d.y)
604 d.x += dxc
605 d.y += dyc
606 xc := fixed.Int26_6(d.x)
607 yc := fixed.Int26_6(d.y)
608 d.b.segments = append(d.b.segments, Segment{
609 Op: SegmentOpCubeTo,
610 Args: [3]fixed.Point26_6{{X: xa, Y: ya}, {X: xb, Y: yb}, {X: xc, Y: yc}},
611 })
612 }
613
614 // psInterpreter is a PostScript interpreter.
615 type psInterpreter struct {
616 ctx psContext
617 instructions []byte
618 instrOffset uint32
619 instrLength uint32
620 argStack struct {
621 a [psArgStackSize]int32
622 top int32
623 }
624 callStack struct {
625 a [psCallStackSize]psCallStackEntry
626 top int32
627 }
628 parseNumberBuf [maxRealNumberStrLen]byte
629
630 topDict psTopDictData
631 privateDict psPrivateDictData
632 type2Charstrings psType2CharstringsData
633 }
634
635 func (p *psInterpreter) hasMoreInstructions() bool {
636 if len(p.instructions) != 0 {
637 return true
638 }
639 for i := int32(0); i < p.callStack.top; i++ {
640 if p.callStack.a[i].length != 0 {
641 return true
642 }
643 }
644 return false
645 }
646
647 // run runs the instructions in the given PostScript context. For the
648 // psContextType2Charstring context, offset and length give the location of the
649 // instructions in p.type2Charstrings.f.src.
650 func (p *psInterpreter) run(ctx psContext, instructions []byte, offset, length uint32) error {
651 p.ctx = ctx
652 p.instructions = instructions
653 p.instrOffset = offset
654 p.instrLength = length
655 p.argStack.top = 0
656 p.callStack.top = 0
657
658 loop:
659 for len(p.instructions) > 0 {
660 // Push a numeric operand on the stack, if applicable.
661 if hasResult, err := p.parseNumber(); hasResult {
662 if err != nil {
663 return err
664 }
665 continue
666 }
667
668 // Otherwise, execute an operator.
669 b := p.instructions[0]
670 p.instructions = p.instructions[1:]
671
672 for escaped, ops := false, psOperators[ctx][0]; ; {
673 if b == escapeByte && !escaped {
674 if len(p.instructions) <= 0 {
675 return errInvalidCFFTable
676 }
677 b = p.instructions[0]
678 p.instructions = p.instructions[1:]
679 escaped = true
680 ops = psOperators[ctx][1]
681 continue
682 }
683
684 if int(b) < len(ops) {
685 if op := ops[b]; op.name != "" {
686 if p.argStack.top < op.numPop {
687 return errInvalidCFFTable
688 }
689 if op.run != nil {
690 if err := op.run(p); err != nil {
691 return err
692 }
693 }
694 if op.numPop < 0 {
695 p.argStack.top = 0
696 } else {
697 p.argStack.top -= op.numPop
698 }
699 continue loop
700 }
701 }
702
703 if escaped {
704 return fmt.Errorf("sfnt: unrecognized CFF 2-byte operator (12 %d)", b)
705 } else {
706 return fmt.Errorf("sfnt: unrecognized CFF 1-byte operator (%d)", b)
707 }
708 }
709 }
710 return nil
711 }
712
713 // See 5176.CFF.pdf section 4 "DICT Data".
714 func (p *psInterpreter) parseNumber() (hasResult bool, err error) {
715 number := int32(0)
716 switch b := p.instructions[0]; {
717 case b == 28:
718 if len(p.instructions) < 3 {
719 return true, errInvalidCFFTable
720 }
721 number, hasResult = int32(int16(u16(p.instructions[1:]))), true
722 p.instructions = p.instructions[3:]
723
724 case b == 29 && p.ctx != psContextType2Charstring:
725 if len(p.instructions) < 5 {
726 return true, errInvalidCFFTable
727 }
728 number, hasResult = int32(u32(p.instructions[1:])), true
729 p.instructions = p.instructions[5:]
730
731 case b == 30 && p.ctx != psContextType2Charstring:
732 // Parse a real number. This isn't listed in 5176.CFF.pdf Table 3
733 // "Operand Encoding" but that table lists integer encodings. Further
734 // down the page it says "A real number operand is provided in addition
735 // to integer operands. This operand begins with a byte value of 30
736 // followed by a variable-length sequence of bytes."
737
738 s := p.parseNumberBuf[:0]
739 p.instructions = p.instructions[1:]
740 loop:
741 for {
742 if len(p.instructions) == 0 {
743 return true, errInvalidCFFTable
744 }
745 b := p.instructions[0]
746 p.instructions = p.instructions[1:]
747 // Process b's two nibbles, high then low.
748 for i := 0; i < 2; i++ {
749 nib := b >> 4
750 b = b << 4
751 if nib == 0x0f {
752 f, err := strconv.ParseFloat(string(s), 32)
753 if err != nil {
754 return true, errInvalidCFFTable
755 }
756 number, hasResult = int32(math.Float32bits(float32(f))), true
757 break loop
758 }
759 if nib == 0x0d {
760 return true, errInvalidCFFTable
761 }
762 if len(s)+maxNibbleDefsLength > len(p.parseNumberBuf) {
763 return true, errUnsupportedRealNumberEncoding
764 }
765 s = append(s, nibbleDefs[nib]...)
766 }
767 }
768
769 case b < 32:
770 // No-op.
771
772 case b < 247:
773 p.instructions = p.instructions[1:]
774 number, hasResult = int32(b)-139, true
775
776 case b < 251:
777 if len(p.instructions) < 2 {
778 return true, errInvalidCFFTable
779 }
780 b1 := p.instructions[1]
781 p.instructions = p.instructions[2:]
782 number, hasResult = +int32(b-247)*256+int32(b1)+108, true
783
784 case b < 255:
785 if len(p.instructions) < 2 {
786 return true, errInvalidCFFTable
787 }
788 b1 := p.instructions[1]
789 p.instructions = p.instructions[2:]
790 number, hasResult = -int32(b-251)*256-int32(b1)-108, true
791
792 case b == 255 && p.ctx == psContextType2Charstring:
793 if len(p.instructions) < 5 {
794 return true, errInvalidCFFTable
795 }
796 number, hasResult = int32(u32(p.instructions[1:])), true
797 p.instructions = p.instructions[5:]
798 // 5177.Type2.pdf section 3.2 "Charstring Number Encoding" says "If the
799 // charstring byte contains the value 255... [this] number is
800 // interpreted as a Fixed; that is, a signed number with 16 bits of
801 // fraction".
802 //
803 // TODO: change the psType2CharstringsData.b.segments and
804 // psInterpreter.argStack data structures to optionally hold fixed
805 // point values, not just integer values. That's a substantial
806 // re-design, though. Until then, just round the 16.16 fixed point
807 // number to the closest integer value. This isn't just "number =
808 // ((number + 0x8000) >> 16)" because of potential overflow.
809 number = (number >> 16) + (1 & (number >> 15))
810 }
811
812 if hasResult {
813 if p.argStack.top == psArgStackSize {
814 return true, errInvalidCFFTable
815 }
816 p.argStack.a[p.argStack.top] = number
817 p.argStack.top++
818 }
819 return hasResult, nil
820 }
821
822 const maxNibbleDefsLength = len("E-")
823
824 // nibbleDefs encodes 5176.CFF.pdf Table 5 "Nibble Definitions".
825 var nibbleDefs = [16]string{
826 0x00: "0",
827 0x01: "1",
828 0x02: "2",
829 0x03: "3",
830 0x04: "4",
831 0x05: "5",
832 0x06: "6",
833 0x07: "7",
834 0x08: "8",
835 0x09: "9",
836 0x0a: ".",
837 0x0b: "E",
838 0x0c: "E-",
839 0x0d: "",
840 0x0e: "-",
841 0x0f: "",
842 }
843
844 type psOperator struct {
845 // numPop is the number of stack values to pop. -1 means "array" and -2
846 // means "delta" as per 5176.CFF.pdf Table 6 "Operand Types".
847 numPop int32
848 // name is the operator name. An empty name (i.e. the zero value for the
849 // struct overall) means an unrecognized 1-byte operator.
850 name string
851 // run is the function that implements the operator. Nil means that we
852 // ignore the operator, other than popping its arguments off the stack.
853 run func(*psInterpreter) error
854 }
855
856 // psOperators holds the 1-byte and 2-byte operators for PostScript interpreter
857 // contexts.
858 var psOperators = [...][2][]psOperator{
859 // The Top DICT operators are defined by 5176.CFF.pdf Table 9 "Top DICT
860 // Operator Entries" and Table 10 "CIDFont Operator Extensions".
861 psContextTopDict: {{
862 // 1-byte operators.
863 0: {+1, "version", nil},
864 1: {+1, "Notice", nil},
865 2: {+1, "FullName", nil},
866 3: {+1, "FamilyName", nil},
867 4: {+1, "Weight", nil},
868 5: {-1, "FontBBox", nil},
869 13: {+1, "UniqueID", nil},
870 14: {-1, "XUID", nil},
871 15: {+1, "charset", nil},
872 16: {+1, "Encoding", nil},
873 17: {+1, "CharStrings", func(p *psInterpreter) error {
874 p.topDict.charStringsOffset = p.argStack.a[p.argStack.top-1]
875 return nil
876 }},
877 18: {+2, "Private", func(p *psInterpreter) error {
878 p.topDict.privateDictLength = p.argStack.a[p.argStack.top-2]
879 p.topDict.privateDictOffset = p.argStack.a[p.argStack.top-1]
880 return nil
881 }},
882 }, {
883 // 2-byte operators. The first byte is the escape byte.
884 0: {+1, "Copyright", nil},
885 1: {+1, "isFixedPitch", nil},
886 2: {+1, "ItalicAngle", nil},
887 3: {+1, "UnderlinePosition", nil},
888 4: {+1, "UnderlineThickness", nil},
889 5: {+1, "PaintType", nil},
890 6: {+1, "CharstringType", nil},
891 7: {-1, "FontMatrix", nil},
892 8: {+1, "StrokeWidth", nil},
893 20: {+1, "SyntheticBase", nil},
894 21: {+1, "PostScript", nil},
895 22: {+1, "BaseFontName", nil},
896 23: {-2, "BaseFontBlend", nil},
897 30: {+3, "ROS", func(p *psInterpreter) error {
898 p.topDict.isCIDFont = true
899 return nil
900 }},
901 31: {+1, "CIDFontVersion", nil},
902 32: {+1, "CIDFontRevision", nil},
903 33: {+1, "CIDFontType", nil},
904 34: {+1, "CIDCount", nil},
905 35: {+1, "UIDBase", nil},
906 36: {+1, "FDArray", func(p *psInterpreter) error {
907 p.topDict.fdArray = p.argStack.a[p.argStack.top-1]
908 return nil
909 }},
910 37: {+1, "FDSelect", func(p *psInterpreter) error {
911 p.topDict.fdSelect = p.argStack.a[p.argStack.top-1]
912 return nil
913 }},
914 38: {+1, "FontName", nil},
915 }},
916
917 // The Private DICT operators are defined by 5176.CFF.pdf Table 23 "Private
918 // DICT Operators".
919 psContextPrivateDict: {{
920 // 1-byte operators.
921 6: {-2, "BlueValues", nil},
922 7: {-2, "OtherBlues", nil},
923 8: {-2, "FamilyBlues", nil},
924 9: {-2, "FamilyOtherBlues", nil},
925 10: {+1, "StdHW", nil},
926 11: {+1, "StdVW", nil},
927 19: {+1, "Subrs", func(p *psInterpreter) error {
928 p.privateDict.subrsOffset = p.argStack.a[p.argStack.top-1]
929 return nil
930 }},
931 20: {+1, "defaultWidthX", nil},
932 21: {+1, "nominalWidthX", nil},
933 }, {
934 // 2-byte operators. The first byte is the escape byte.
935 9: {+1, "BlueScale", nil},
936 10: {+1, "BlueShift", nil},
937 11: {+1, "BlueFuzz", nil},
938 12: {-2, "StemSnapH", nil},
939 13: {-2, "StemSnapV", nil},
940 14: {+1, "ForceBold", nil},
941 17: {+1, "LanguageGroup", nil},
942 18: {+1, "ExpansionFactor", nil},
943 19: {+1, "initialRandomSeed", nil},
944 }},
945
946 // The Type 2 Charstring operators are defined by 5177.Type2.pdf Appendix A
947 // "Type 2 Charstring Command Codes".
948 psContextType2Charstring: {{
949 // 1-byte operators.
950 0: {}, // Reserved.
951 1: {-1, "hstem", t2CStem},
952 2: {}, // Reserved.
953 3: {-1, "vstem", t2CStem},
954 4: {-1, "vmoveto", t2CVmoveto},
955 5: {-1, "rlineto", t2CRlineto},
956 6: {-1, "hlineto", t2CHlineto},
957 7: {-1, "vlineto", t2CVlineto},
958 8: {-1, "rrcurveto", t2CRrcurveto},
959 9: {}, // Reserved.
960 10: {+1, "callsubr", t2CCallsubr},
961 11: {+0, "return", t2CReturn},
962 12: {}, // escape.
963 13: {}, // Reserved.
964 14: {-1, "endchar", t2CEndchar},
965 15: {}, // Reserved.
966 16: {}, // Reserved.
967 17: {}, // Reserved.
968 18: {-1, "hstemhm", t2CStem},
969 19: {-1, "hintmask", t2CMask},
970 20: {-1, "cntrmask", t2CMask},
971 21: {-1, "rmoveto", t2CRmoveto},
972 22: {-1, "hmoveto", t2CHmoveto},
973 23: {-1, "vstemhm", t2CStem},
974 24: {-1, "rcurveline", t2CRcurveline},
975 25: {-1, "rlinecurve", t2CRlinecurve},
976 26: {-1, "vvcurveto", t2CVvcurveto},
977 27: {-1, "hhcurveto", t2CHhcurveto},
978 28: {}, // shortint.
979 29: {+1, "callgsubr", t2CCallgsubr},
980 30: {-1, "vhcurveto", t2CVhcurveto},
981 31: {-1, "hvcurveto", t2CHvcurveto},
982 }, {
983 // 2-byte operators. The first byte is the escape byte.
984 34: {+7, "hflex", t2CHflex},
985 36: {+9, "hflex1", t2CHflex1},
986 // TODO: more operators.
987 }},
988 }
989
990 // 5176.CFF.pdf section 4 "DICT Data" says that "Two-byte operators have an
991 // initial escape byte of 12".
992 const escapeByte = 12
993
994 // t2CReadWidth reads the optional width adjustment. If present, it is on the
995 // bottom of the arg stack. nArgs is the expected number of arguments on the
996 // stack. A negative nArgs means a multiple of 2.
997 //
998 // 5177.Type2.pdf page 16 Note 4 says: "The first stack-clearing operator,
999 // which must be one of hstem, hstemhm, vstem, vstemhm, cntrmask, hintmask,
1000 // hmoveto, vmoveto, rmoveto, or endchar, takes an additional argument — the
1001 // width... which may be expressed as zero or one numeric argument."
1002 func t2CReadWidth(p *psInterpreter, nArgs int32) {
1003 if p.type2Charstrings.seenWidth {
1004 return
1005 }
1006 p.type2Charstrings.seenWidth = true
1007 if nArgs >= 0 {
1008 if p.argStack.top != nArgs+1 {
1009 return
1010 }
1011 } else if p.argStack.top&1 == 0 {
1012 return
1013 }
1014 // When parsing a standalone CFF, we'd save the value of p.argStack.a[0]
1015 // here as it defines the glyph's width (horizontal advance). Specifically,
1016 // if present, it is a delta to the font-global nominalWidthX value found
1017 // in the Private DICT. If absent, the glyph's width is the defaultWidthX
1018 // value in that dict. See 5176.CFF.pdf section 15 "Private DICT Data".
1019 //
1020 // For a CFF embedded in an SFNT font (i.e. an OpenType font), glyph widths
1021 // are already stored in the hmtx table, separate to the CFF table, and it
1022 // is simpler to parse that table for all OpenType fonts (PostScript and
1023 // TrueType). We therefore ignore the width value here, and just remove it
1024 // from the bottom of the argStack.
1025 copy(p.argStack.a[:p.argStack.top-1], p.argStack.a[1:p.argStack.top])
1026 p.argStack.top--
1027 }
1028
1029 func t2CStem(p *psInterpreter) error {
1030 t2CReadWidth(p, -1)
1031 if p.argStack.top%2 != 0 {
1032 return errInvalidCFFTable
1033 }
1034 // We update the number of hintBits need to parse hintmask and cntrmask
1035 // instructions, but this Type 2 Charstring implementation otherwise
1036 // ignores the stem hints.
1037 p.type2Charstrings.hintBits += p.argStack.top / 2
1038 if p.type2Charstrings.hintBits > maxHintBits {
1039 return errUnsupportedNumberOfHints
1040 }
1041 return nil
1042 }
1043
1044 func t2CMask(p *psInterpreter) error {
1045 // 5176.CFF.pdf section 4.3 "Hint Operators" says that "If hstem and vstem
1046 // hints are both declared at the beginning of a charstring, and this
1047 // sequence is followed directly by the hintmask or cntrmask operators, the
1048 // vstem hint operator need not be included."
1049 //
1050 // What we implement here is more permissive (but the same as what the
1051 // FreeType implementation does, and simpler than tracking the previous
1052 // operator and other hinting state): if a hintmask is given any arguments
1053 // (i.e. the argStack is non-empty), we run an implicit vstem operator.
1054 //
1055 // Note that the vstem operator consumes from p.argStack, but the hintmask
1056 // or cntrmask operators consume from p.instructions.
1057 if p.argStack.top != 0 {
1058 if err := t2CStem(p); err != nil {
1059 return err
1060 }
1061 } else if !p.type2Charstrings.seenWidth {
1062 p.type2Charstrings.seenWidth = true
1063 }
1064
1065 hintBytes := (p.type2Charstrings.hintBits + 7) / 8
1066 if len(p.instructions) < int(hintBytes) {
1067 return errInvalidCFFTable
1068 }
1069 p.instructions = p.instructions[hintBytes:]
1070 return nil
1071 }
1072
1073 func t2CHmoveto(p *psInterpreter) error {
1074 t2CReadWidth(p, 1)
1075 if p.argStack.top != 1 {
1076 return errInvalidCFFTable
1077 }
1078 p.type2Charstrings.moveTo(p.argStack.a[0], 0)
1079 return nil
1080 }
1081
1082 func t2CVmoveto(p *psInterpreter) error {
1083 t2CReadWidth(p, 1)
1084 if p.argStack.top != 1 {
1085 return errInvalidCFFTable
1086 }
1087 p.type2Charstrings.moveTo(0, p.argStack.a[0])
1088 return nil
1089 }
1090
1091 func t2CRmoveto(p *psInterpreter) error {
1092 t2CReadWidth(p, 2)
1093 if p.argStack.top != 2 {
1094 return errInvalidCFFTable
1095 }
1096 p.type2Charstrings.moveTo(p.argStack.a[0], p.argStack.a[1])
1097 return nil
1098 }
1099
1100 func t2CHlineto(p *psInterpreter) error { return t2CLineto(p, false) }
1101 func t2CVlineto(p *psInterpreter) error { return t2CLineto(p, true) }
1102
1103 func t2CLineto(p *psInterpreter, vertical bool) error {
1104 if !p.type2Charstrings.seenWidth || p.argStack.top < 1 {
1105 return errInvalidCFFTable
1106 }
1107 for i := int32(0); i < p.argStack.top; i, vertical = i+1, !vertical {
1108 dx, dy := p.argStack.a[i], int32(0)
1109 if vertical {
1110 dx, dy = dy, dx
1111 }
1112 p.type2Charstrings.lineTo(dx, dy)
1113 }
1114 return nil
1115 }
1116
1117 func t2CRlineto(p *psInterpreter) error {
1118 if !p.type2Charstrings.seenWidth || p.argStack.top < 2 || p.argStack.top%2 != 0 {
1119 return errInvalidCFFTable
1120 }
1121 for i := int32(0); i < p.argStack.top; i += 2 {
1122 p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1])
1123 }
1124 return nil
1125 }
1126
1127 // As per 5177.Type2.pdf section 4.1 "Path Construction Operators",
1128 //
1129 // rcurveline is:
1130 // - {dxa dya dxb dyb dxc dyc}+ dxd dyd
1131 //
1132 // rlinecurve is:
1133 // - {dxa dya}+ dxb dyb dxc dyc dxd dyd
1134
1135 func t2CRcurveline(p *psInterpreter) error {
1136 if !p.type2Charstrings.seenWidth || p.argStack.top < 8 || p.argStack.top%6 != 2 {
1137 return errInvalidCFFTable
1138 }
1139 i := int32(0)
1140 for iMax := p.argStack.top - 2; i < iMax; i += 6 {
1141 p.type2Charstrings.cubeTo(
1142 p.argStack.a[i+0],
1143 p.argStack.a[i+1],
1144 p.argStack.a[i+2],
1145 p.argStack.a[i+3],
1146 p.argStack.a[i+4],
1147 p.argStack.a[i+5],
1148 )
1149 }
1150 p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1])
1151 return nil
1152 }
1153
1154 func t2CRlinecurve(p *psInterpreter) error {
1155 if !p.type2Charstrings.seenWidth || p.argStack.top < 8 || p.argStack.top%2 != 0 {
1156 return errInvalidCFFTable
1157 }
1158 i := int32(0)
1159 for iMax := p.argStack.top - 6; i < iMax; i += 2 {
1160 p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1])
1161 }
1162 p.type2Charstrings.cubeTo(
1163 p.argStack.a[i+0],
1164 p.argStack.a[i+1],
1165 p.argStack.a[i+2],
1166 p.argStack.a[i+3],
1167 p.argStack.a[i+4],
1168 p.argStack.a[i+5],
1169 )
1170 return nil
1171 }
1172
1173 // As per 5177.Type2.pdf section 4.1 "Path Construction Operators",
1174 //
1175 // hhcurveto is:
1176 // - dy1 {dxa dxb dyb dxc}+
1177 //
1178 // vvcurveto is:
1179 // - dx1 {dya dxb dyb dyc}+
1180 //
1181 // hvcurveto is one of:
1182 // - dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
1183 // - {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
1184 //
1185 // vhcurveto is one of:
1186 // - dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf?
1187 // - {dya dxb dyb dxc dxd dxe dye dyf}+ dxf?
1188
1189 func t2CHhcurveto(p *psInterpreter) error { return t2CCurveto(p, false, false) }
1190 func t2CVvcurveto(p *psInterpreter) error { return t2CCurveto(p, false, true) }
1191 func t2CHvcurveto(p *psInterpreter) error { return t2CCurveto(p, true, false) }
1192 func t2CVhcurveto(p *psInterpreter) error { return t2CCurveto(p, true, true) }
1193
1194 // t2CCurveto implements the hh / vv / hv / vh xxcurveto operators. N relative
1195 // cubic curve requires 6*N control points, but only 4*N+0 or 4*N+1 are used
1196 // here: all (or all but one) of the piecewise cubic curve's tangents are
1197 // implicitly horizontal or vertical.
1198 //
1199 // swap is whether that implicit horizontal / vertical constraint swaps as you
1200 // move along the piecewise cubic curve. If swap is false, the constraints are
1201 // either all horizontal or all vertical. If swap is true, it alternates.
1202 //
1203 // vertical is whether the first implicit constraint is vertical.
1204 func t2CCurveto(p *psInterpreter, swap, vertical bool) error {
1205 if !p.type2Charstrings.seenWidth || p.argStack.top < 4 {
1206 return errInvalidCFFTable
1207 }
1208
1209 i := int32(0)
1210 switch p.argStack.top & 3 {
1211 case 0:
1212 // No-op.
1213 case 1:
1214 if swap {
1215 break
1216 }
1217 i = 1
1218 if vertical {
1219 p.type2Charstrings.x += p.argStack.a[0]
1220 } else {
1221 p.type2Charstrings.y += p.argStack.a[0]
1222 }
1223 default:
1224 return errInvalidCFFTable
1225 }
1226
1227 for i != p.argStack.top {
1228 i = t2CCurveto4(p, swap, vertical, i)
1229 if i < 0 {
1230 return errInvalidCFFTable
1231 }
1232 if swap {
1233 vertical = !vertical
1234 }
1235 }
1236 return nil
1237 }
1238
1239 func t2CCurveto4(p *psInterpreter, swap bool, vertical bool, i int32) (j int32) {
1240 if i+4 > p.argStack.top {
1241 return -1
1242 }
1243 dxa := p.argStack.a[i+0]
1244 dya := int32(0)
1245 dxb := p.argStack.a[i+1]
1246 dyb := p.argStack.a[i+2]
1247 dxc := p.argStack.a[i+3]
1248 dyc := int32(0)
1249 i += 4
1250
1251 if vertical {
1252 dxa, dya = dya, dxa
1253 }
1254
1255 if swap {
1256 if i+1 == p.argStack.top {
1257 dyc = p.argStack.a[i]
1258 i++
1259 }
1260 }
1261
1262 if swap != vertical {
1263 dxc, dyc = dyc, dxc
1264 }
1265
1266 p.type2Charstrings.cubeTo(dxa, dya, dxb, dyb, dxc, dyc)
1267 return i
1268 }
1269
1270 func t2CRrcurveto(p *psInterpreter) error {
1271 if !p.type2Charstrings.seenWidth || p.argStack.top < 6 || p.argStack.top%6 != 0 {
1272 return errInvalidCFFTable
1273 }
1274 for i := int32(0); i != p.argStack.top; i += 6 {
1275 p.type2Charstrings.cubeTo(
1276 p.argStack.a[i+0],
1277 p.argStack.a[i+1],
1278 p.argStack.a[i+2],
1279 p.argStack.a[i+3],
1280 p.argStack.a[i+4],
1281 p.argStack.a[i+5],
1282 )
1283 }
1284 return nil
1285 }
1286
1287 // For the flex operators, we ignore the flex depth and always produce cubic
1288 // segments, not linear segments. It's not obvious why the Type 2 Charstring
1289 // format cares about switching behavior based on a metric in pixels, not in
1290 // ideal font units. The Go vector rasterizer has no problems with almost
1291 // linear cubic segments.
1292
1293 func t2CHflex(p *psInterpreter) error {
1294 p.type2Charstrings.cubeTo(
1295 p.argStack.a[0], 0,
1296 p.argStack.a[1], +p.argStack.a[2],
1297 p.argStack.a[3], 0,
1298 )
1299 p.type2Charstrings.cubeTo(
1300 p.argStack.a[4], 0,
1301 p.argStack.a[5], -p.argStack.a[2],
1302 p.argStack.a[6], 0,
1303 )
1304 return nil
1305 }
1306
1307 func t2CHflex1(p *psInterpreter) error {
1308 dy1 := p.argStack.a[1]
1309 dy2 := p.argStack.a[3]
1310 dy5 := p.argStack.a[7]
1311 dy6 := -dy1 - dy2 - dy5
1312 p.type2Charstrings.cubeTo(
1313 p.argStack.a[0], dy1,
1314 p.argStack.a[2], dy2,
1315 p.argStack.a[4], 0,
1316 )
1317 p.type2Charstrings.cubeTo(
1318 p.argStack.a[5], 0,
1319 p.argStack.a[6], dy5,
1320 p.argStack.a[8], dy6,
1321 )
1322 return nil
1323 }
1324
1325 // subrBias returns the subroutine index bias as per 5177.Type2.pdf section 4.7
1326 // "Subroutine Operators".
1327 func subrBias(numSubroutines int) int32 {
1328 if numSubroutines < 1240 {
1329 return 107
1330 }
1331 if numSubroutines < 33900 {
1332 return 1131
1333 }
1334 return 32768
1335 }
1336
1337 func t2CCallgsubr(p *psInterpreter) error {
1338 return t2CCall(p, p.type2Charstrings.f.cached.glyphData.gsubrs)
1339 }
1340
1341 func t2CCallsubr(p *psInterpreter) error {
1342 t := &p.type2Charstrings
1343 d := &t.f.cached.glyphData
1344 subrs := d.singleSubrs
1345 if d.multiSubrs != nil {
1346 if t.fdSelectIndexPlusOne == 0 {
1347 index, err := d.fdSelect.lookup(t.f, t.b, t.glyphIndex)
1348 if err != nil {
1349 return err
1350 }
1351 if index < 0 || len(d.multiSubrs) <= index {
1352 return errInvalidCFFTable
1353 }
1354 t.fdSelectIndexPlusOne = int32(index + 1)
1355 }
1356 subrs = d.multiSubrs[t.fdSelectIndexPlusOne-1]
1357 }
1358 return t2CCall(p, subrs)
1359 }
1360
1361 func t2CCall(p *psInterpreter, subrs []uint32) error {
1362 if p.callStack.top == psCallStackSize || len(subrs) == 0 {
1363 return errInvalidCFFTable
1364 }
1365 length := uint32(len(p.instructions))
1366 p.callStack.a[p.callStack.top] = psCallStackEntry{
1367 offset: p.instrOffset + p.instrLength - length,
1368 length: length,
1369 }
1370 p.callStack.top++
1371
1372 subrIndex := p.argStack.a[p.argStack.top-1] + subrBias(len(subrs)-1)
1373 if subrIndex < 0 || int32(len(subrs)-1) <= subrIndex {
1374 return errInvalidCFFTable
1375 }
1376 i := subrs[subrIndex+0]
1377 j := subrs[subrIndex+1]
1378 if j < i {
1379 return errInvalidCFFTable
1380 }
1381 if j-i > maxGlyphDataLength {
1382 return errUnsupportedGlyphDataLength
1383 }
1384 buf, err := p.type2Charstrings.b.view(&p.type2Charstrings.f.src, int(i), int(j-i))
1385 if err != nil {
1386 return err
1387 }
1388
1389 p.instructions = buf
1390 p.instrOffset = i
1391 p.instrLength = j - i
1392 return nil
1393 }
1394
1395 func t2CReturn(p *psInterpreter) error {
1396 if p.callStack.top <= 0 {
1397 return errInvalidCFFTable
1398 }
1399 p.callStack.top--
1400 o := p.callStack.a[p.callStack.top].offset
1401 n := p.callStack.a[p.callStack.top].length
1402 buf, err := p.type2Charstrings.b.view(&p.type2Charstrings.f.src, int(o), int(n))
1403 if err != nil {
1404 return err
1405 }
1406
1407 p.instructions = buf
1408 p.instrOffset = o
1409 p.instrLength = n
1410 return nil
1411 }
1412
1413 func t2CEndchar(p *psInterpreter) error {
1414 t2CReadWidth(p, 0)
1415 if p.argStack.top != 0 || p.hasMoreInstructions() {
1416 if p.argStack.top == 4 {
1417 // TODO: process the implicit "seac" command as per 5177.Type2.pdf
1418 // Appendix C "Compatibility and Deprecated Operators".
1419 return errUnsupportedType2Charstring
1420 }
1421 return errInvalidCFFTable
1422 }
1423 p.type2Charstrings.closePath()
1424 p.type2Charstrings.ended = true
1425 return nil
1426 }