git clone https://git.lucas.co/go_mono.git
font/sfnt/sfnt.go (62.6K)
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 //go:generate go run gen.go
6
7 // Package sfnt implements a decoder for TTF (TrueType Fonts) and OTF (OpenType
8 // Fonts). Such fonts are also known as SFNT fonts.
9 //
10 // This package provides a low-level API and does not depend on vector
11 // rasterization packages. Glyphs are represented as vectors, not pixels.
12 //
13 // The sibling golang.org/x/image/font/opentype package provides a high-level
14 // API, including glyph rasterization.
15 //
16 // This package provides a decoder in that it produces a TTF's glyphs (and
17 // other metadata such as advance width and kerning pairs): give me the 'A'
18 // from times_new_roman.ttf.
19 //
20 // Unlike the image.Image decoder functions (gif.Decode, jpeg.Decode and
21 // png.Decode) in Go's standard library, an sfnt.Font needs ongoing access to
22 // the TTF data (as a []byte or io.ReaderAt) after the sfnt.ParseXxx functions
23 // return. If parsing a []byte, its elements are assumed immutable while the
24 // sfnt.Font remains in use. If parsing an *os.File, you should not close the
25 // file until after you're done with the sfnt.Font.
26 //
27 // The []byte or io.ReaderAt data given to ParseXxx can be re-written to
28 // another io.Writer, copying the underlying TTF file, but this package does
29 // not provide an encoder. Specifically, there is no API to build a different
30 // TTF file, whether 'from scratch' or by modifying an existing one.
31 package sfnt // import "golang.org/x/image/font/sfnt"
32
33 // This implementation was written primarily to the
34 // https://www.microsoft.com/en-us/Typography/OpenTypeSpecification.aspx
35 // specification. Additional documentation is at
36 // http://developer.apple.com/fonts/TTRefMan/
37 //
38 // The pyftinspect tool from https://github.com/fonttools/fonttools is useful
39 // for inspecting SFNT fonts.
40 //
41 // The ttfdump tool is also useful. For example:
42 // ttfdump -t cmap ../testdata/CFFTest.otf dump.txt
43
44 import (
45 "errors"
46 "image"
47 "io"
48
49 "golang.org/x/image/font"
50 "golang.org/x/image/math/fixed"
51 "golang.org/x/text/encoding/charmap"
52 )
53
54 // These constants are not part of the specifications, but are limitations used
55 // by this implementation.
56 const (
57 // This value is arbitrary, but defends against parsing malicious font
58 // files causing excessive memory allocations. For reference, Adobe's
59 // SourceHanSansSC-Regular.otf has 65535 glyphs and:
60 // - its format-4 cmap table has 1581 segments.
61 // - its format-12 cmap table has 16498 segments.
62 //
63 // TODO: eliminate this constraint? If the cmap table is very large, load
64 // some or all of it lazily (at the time Font.GlyphIndex is called) instead
65 // of all of it eagerly (at the time Font.initialize is called), while
66 // keeping an upper bound on the memory used? This will make the code in
67 // cmap.go more complicated, considering that all of the Font methods are
68 // safe to call concurrently, as long as each call has a different *Buffer.
69 maxCmapSegments = 20000
70
71 // TODO: similarly, load subroutine locations lazily. Adobe's
72 // SourceHanSansSC-Regular.otf has up to 30000 subroutines.
73 maxNumSubroutines = 40000
74
75 maxCompoundRecursionDepth = 8
76 maxCompoundStackSize = 64
77 maxGlyphDataLength = 64 * 1024
78 maxHintBits = 256
79 maxNumFontDicts = 256
80 maxNumFonts = 256
81 maxNumTables = 256
82 maxRealNumberStrLen = 64 // Maximum length in bytes of the "-123.456E-7" representation.
83
84 // (maxTableOffset + maxTableLength) will not overflow an int32.
85 maxTableLength = 1 << 29
86 maxTableOffset = 1 << 29
87 )
88
89 var (
90 // ErrColoredGlyph indicates that the requested glyph is not a monochrome
91 // vector glyph, such as a colored (bitmap or vector) emoji glyph.
92 ErrColoredGlyph = errors.New("sfnt: colored glyph")
93 // ErrNotFound indicates that the requested value was not found.
94 ErrNotFound = errors.New("sfnt: not found")
95
96 errInvalidBounds = errors.New("sfnt: invalid bounds")
97 errInvalidCFFTable = errors.New("sfnt: invalid CFF table")
98 errInvalidCmapTable = errors.New("sfnt: invalid cmap table")
99 errInvalidDfont = errors.New("sfnt: invalid dfont")
100 errInvalidFont = errors.New("sfnt: invalid font")
101 errInvalidFontCollection = errors.New("sfnt: invalid font collection")
102 errInvalidGPOSTable = errors.New("sfnt: invalid GPOS table")
103 errInvalidGlyphData = errors.New("sfnt: invalid glyph data")
104 errInvalidGlyphDataLength = errors.New("sfnt: invalid glyph data length")
105 errInvalidHeadTable = errors.New("sfnt: invalid head table")
106 errInvalidHheaTable = errors.New("sfnt: invalid hhea table")
107 errInvalidHmtxTable = errors.New("sfnt: invalid hmtx table")
108 errInvalidKernTable = errors.New("sfnt: invalid kern table")
109 errInvalidLocaTable = errors.New("sfnt: invalid loca table")
110 errInvalidLocationData = errors.New("sfnt: invalid location data")
111 errInvalidMaxpTable = errors.New("sfnt: invalid maxp table")
112 errInvalidNameTable = errors.New("sfnt: invalid name table")
113 errInvalidOS2Table = errors.New("sfnt: invalid OS/2 table")
114 errInvalidPostTable = errors.New("sfnt: invalid post table")
115 errInvalidSingleFont = errors.New("sfnt: invalid single font (data is a font collection)")
116 errInvalidSourceData = errors.New("sfnt: invalid source data")
117 errInvalidTableOffset = errors.New("sfnt: invalid table offset")
118 errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order")
119 errInvalidUCS2String = errors.New("sfnt: invalid UCS-2 string")
120
121 errUnsupportedCFFFDSelectTable = errors.New("sfnt: unsupported CFF FDSelect table")
122 errUnsupportedCFFVersion = errors.New("sfnt: unsupported CFF version")
123 errUnsupportedClassDefFormat = errors.New("sfnt: unsupported class definition format")
124 errUnsupportedCmapEncodings = errors.New("sfnt: unsupported cmap encodings")
125 errUnsupportedCollection = errors.New("sfnt: unsupported collection")
126 errUnsupportedCompoundGlyph = errors.New("sfnt: unsupported compound glyph")
127 errUnsupportedCoverageFormat = errors.New("sfnt: unsupported coverage format")
128 errUnsupportedExtensionPosFormat = errors.New("sfnt: unsupported extension positioning format")
129 errUnsupportedGPOSTable = errors.New("sfnt: unsupported GPOS table")
130 errUnsupportedGlyphDataLength = errors.New("sfnt: unsupported glyph data length")
131 errUnsupportedKernTable = errors.New("sfnt: unsupported kern table")
132 errUnsupportedNumberOfCmapSegments = errors.New("sfnt: unsupported number of cmap segments")
133 errUnsupportedNumberOfFontDicts = errors.New("sfnt: unsupported number of font dicts")
134 errUnsupportedNumberOfFonts = errors.New("sfnt: unsupported number of fonts")
135 errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
136 errUnsupportedNumberOfSubroutines = errors.New("sfnt: unsupported number of subroutines")
137 errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
138 errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
139 errUnsupportedPostTable = errors.New("sfnt: unsupported post table")
140 errUnsupportedRealNumberEncoding = errors.New("sfnt: unsupported real number encoding")
141 errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
142 errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring")
143 )
144
145 // GlyphIndex is a glyph index in a Font.
146 type GlyphIndex uint16
147
148 // NameID identifies a name table entry.
149 //
150 // See the "Name IDs" section of
151 // https://www.microsoft.com/typography/otspec/name.htm
152 type NameID uint16
153
154 const (
155 NameIDCopyright NameID = 0
156 NameIDFamily NameID = 1
157 NameIDSubfamily NameID = 2
158 NameIDUniqueIdentifier NameID = 3
159 NameIDFull NameID = 4
160 NameIDVersion NameID = 5
161 NameIDPostScript NameID = 6
162 NameIDTrademark NameID = 7
163 NameIDManufacturer NameID = 8
164 NameIDDesigner NameID = 9
165 NameIDDescription NameID = 10
166 NameIDVendorURL NameID = 11
167 NameIDDesignerURL NameID = 12
168 NameIDLicense NameID = 13
169 NameIDLicenseURL NameID = 14
170 NameIDTypographicFamily NameID = 16
171 NameIDTypographicSubfamily NameID = 17
172 NameIDCompatibleFull NameID = 18
173 NameIDSampleText NameID = 19
174 NameIDPostScriptCID NameID = 20
175 NameIDWWSFamily NameID = 21
176 NameIDWWSSubfamily NameID = 22
177 NameIDLightBackgroundPalette NameID = 23
178 NameIDDarkBackgroundPalette NameID = 24
179 NameIDVariationsPostScriptPrefix NameID = 25
180 )
181
182 // Units are an integral number of abstract, scalable "font units". The em
183 // square is typically 1000 or 2048 "font units". This would map to a certain
184 // number (e.g. 30 pixels) of physical pixels, depending on things like the
185 // display resolution (DPI) and font size (e.g. a 12 point font).
186 type Units int32
187
188 // scale returns x divided by unitsPerEm, rounded to the nearest fixed.Int26_6
189 // value (1/64th of a pixel).
190 func scale(x fixed.Int26_6, unitsPerEm Units) fixed.Int26_6 {
191 if x >= 0 {
192 x += fixed.Int26_6(unitsPerEm) / 2
193 } else {
194 x -= fixed.Int26_6(unitsPerEm) / 2
195 }
196 return x / fixed.Int26_6(unitsPerEm)
197 }
198
199 func u16(b []byte) uint16 {
200 _ = b[1] // Bounds check hint to compiler.
201 return uint16(b[0])<<8 | uint16(b[1])<<0
202 }
203
204 func u32(b []byte) uint32 {
205 _ = b[3] // Bounds check hint to compiler.
206 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])<<0
207 }
208
209 // source is a source of byte data. Conceptually, it is like an io.ReaderAt,
210 // except that a common source of SFNT font data is in-memory instead of
211 // on-disk: a []byte containing the entire data, either as a global variable
212 // (e.g. "goregular.TTF") or the result of an ioutil.ReadFile call. In such
213 // cases, as an optimization, we skip the io.Reader / io.ReaderAt model of
214 // copying from the source to a caller-supplied buffer, and instead provide
215 // direct access to the underlying []byte data.
216 type source struct {
217 b []byte
218 r io.ReaderAt
219
220 // TODO: add a caching layer, if we're using the io.ReaderAt? Note that
221 // this might make a source no longer safe to use concurrently.
222 }
223
224 // valid returns whether exactly one of s.b and s.r is nil.
225 func (s *source) valid() bool {
226 return (s.b == nil) != (s.r == nil)
227 }
228
229 // viewBufferWritable returns whether the []byte returned by source.view can be
230 // written to by the caller, including by passing it to the same method
231 // (source.view) on other receivers (i.e. different sources).
232 //
233 // In other words, it returns whether the source's underlying data is an
234 // io.ReaderAt, not a []byte.
235 func (s *source) viewBufferWritable() bool {
236 return s.b == nil
237 }
238
239 // view returns the length bytes at the given offset. buf is an optional
240 // scratch buffer to reduce allocations when calling view multiple times. A nil
241 // buf is valid. The []byte returned may be a sub-slice of buf[:cap(buf)], or
242 // it may be an unrelated slice. In any case, the caller should not modify the
243 // contents of the returned []byte, other than passing that []byte back to this
244 // method on the same source s.
245 func (s *source) view(buf []byte, offset, length int) ([]byte, error) {
246 if 0 > offset || offset > offset+length {
247 return nil, errInvalidBounds
248 }
249
250 // Try reading from the []byte.
251 if s.b != nil {
252 if offset+length > len(s.b) {
253 return nil, errInvalidBounds
254 }
255 return s.b[offset : offset+length], nil
256 }
257
258 // Read from the io.ReaderAt.
259 if length <= cap(buf) {
260 buf = buf[:length]
261 } else {
262 // Round length up to the nearest KiB. The slack can lead to fewer
263 // allocations if the buffer is re-used for multiple source.view calls.
264 n := length
265 n += 1023
266 n &^= 1023
267 buf = make([]byte, length, n)
268 }
269 if n, err := s.r.ReadAt(buf, int64(offset)); n != length {
270 return nil, err
271 }
272 return buf, nil
273 }
274
275 // varLenView returns bytes from the given offset for sub-tables with varying
276 // length. The length of bytes is determined by staticLength plus n*itemLength,
277 // where n is read as uint16 from countOffset (relative to offset). buf is an
278 // optional scratch buffer (see source.view())
279 func (s *source) varLenView(buf []byte, offset, staticLength, countOffset, itemLength int) ([]byte, int, error) {
280 if 0 > offset || offset > offset+staticLength {
281 return nil, 0, errInvalidBounds
282 }
283 if 0 > countOffset || countOffset+1 >= staticLength {
284 return nil, 0, errInvalidBounds
285 }
286
287 // read static part which contains our count
288 buf, err := s.view(buf, offset, staticLength)
289 if err != nil {
290 return nil, 0, err
291 }
292
293 count := int(u16(buf[countOffset:]))
294 buf, err = s.view(buf, offset, staticLength+count*itemLength)
295 if err != nil {
296 return nil, 0, err
297 }
298
299 return buf, count, nil
300 }
301
302 // u16 returns the uint16 in the table t at the relative offset i.
303 //
304 // buf is an optional scratch buffer as per the source.view method.
305 func (s *source) u16(buf []byte, t table, i int) (uint16, error) {
306 if i < 0 || uint(t.length) < uint(i+2) {
307 return 0, errInvalidBounds
308 }
309 buf, err := s.view(buf, int(t.offset)+i, 2)
310 if err != nil {
311 return 0, err
312 }
313 return u16(buf), nil
314 }
315
316 // u32 returns the uint32 in the table t at the relative offset i.
317 //
318 // buf is an optional scratch buffer as per the source.view method.
319 func (s *source) u32(buf []byte, t table, i int) (uint32, error) {
320 if i < 0 || uint(t.length) < uint(i+4) {
321 return 0, errInvalidBounds
322 }
323 buf, err := s.view(buf, int(t.offset)+i, 4)
324 if err != nil {
325 return 0, err
326 }
327 return u32(buf), nil
328 }
329
330 // table is a section of the font data.
331 type table struct {
332 offset, length uint32
333 }
334
335 // ParseCollection parses an SFNT font collection, such as TTC or OTC data,
336 // from a []byte data source.
337 //
338 // If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it
339 // will return a collection containing 1 font.
340 //
341 // The caller should not modify src while the Collection or its Fonts remain in
342 // use. See the package documentation for details.
343 func ParseCollection(src []byte) (*Collection, error) {
344 c := &Collection{src: source{b: src}}
345 if err := c.initialize(); err != nil {
346 return nil, err
347 }
348 return c, nil
349 }
350
351 // ParseCollectionReaderAt parses an SFNT collection, such as TTC or OTC data,
352 // from an io.ReaderAt data source.
353 //
354 // If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it
355 // will return a collection containing 1 font.
356 //
357 // The caller should not modify or close src while the Collection or its Fonts
358 // remain in use. See the package documentation for details.
359 func ParseCollectionReaderAt(src io.ReaderAt) (*Collection, error) {
360 c := &Collection{src: source{r: src}}
361 if err := c.initialize(); err != nil {
362 return nil, err
363 }
364 return c, nil
365 }
366
367 // Collection is a collection of one or more fonts.
368 //
369 // All of the Collection methods are safe to call concurrently.
370 type Collection struct {
371 src source
372 offsets []uint32
373 isDfont bool
374 }
375
376 // NumFonts returns the number of fonts in the collection.
377 func (c *Collection) NumFonts() int { return len(c.offsets) }
378
379 func (c *Collection) initialize() error {
380 // The https://www.microsoft.com/typography/otspec/otff.htm "Font
381 // Collections" section describes the TTC header.
382 //
383 // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
384 // describes the dfont header.
385 //
386 // 16 is the maximum of sizeof(TTCHeader) and sizeof(DfontHeader).
387 buf, err := c.src.view(nil, 0, 16)
388 if err != nil {
389 return err
390 }
391 // These cases match the switch statement in Font.initializeTables.
392 switch u32(buf) {
393 default:
394 return errInvalidFontCollection
395 case dfontResourceDataOffset:
396 return c.parseDfont(buf, u32(buf[4:]), u32(buf[12:]))
397 case 0x00010000, 0x4f54544f, 0x74727565: // 0x10000, "OTTO", "true"
398 // Try parsing it as a single font instead of a collection.
399 c.offsets = []uint32{0}
400 case 0x74746366: // "ttcf".
401 numFonts := u32(buf[8:])
402 if numFonts == 0 || numFonts > maxNumFonts {
403 return errUnsupportedNumberOfFonts
404 }
405 buf, err = c.src.view(nil, 12, int(4*numFonts))
406 if err != nil {
407 return err
408 }
409 c.offsets = make([]uint32, numFonts)
410 for i := range c.offsets {
411 o := u32(buf[4*i:])
412 if o > maxTableOffset {
413 return errUnsupportedTableOffsetLength
414 }
415 c.offsets[i] = o
416 }
417 }
418 return nil
419 }
420
421 // dfontResourceDataOffset is the assumed value of a dfont file's resource data
422 // offset.
423 //
424 // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
425 // says that "A Mac OS resource file... [starts with an] offset from start of
426 // file to start of resource data section... [usually] 0x0100". In theory,
427 // 0x00000100 isn't always a magic number for identifying dfont files. In
428 // practice, it seems to work.
429 const dfontResourceDataOffset = 0x00000100
430
431 // parseDfont parses a dfont resource map, as per
432 // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
433 //
434 // That unofficial wiki page lists all of its fields as *signed* integers,
435 // which looks unusual. The actual file format might use *unsigned* integers in
436 // various places, but until we have either an official specification or an
437 // actual dfont file where this matters, we'll use signed integers and treat
438 // negative values as invalid.
439 func (c *Collection) parseDfont(buf []byte, resourceMapOffset, resourceMapLength uint32) error {
440 if resourceMapOffset > maxTableOffset || resourceMapLength > maxTableLength {
441 return errUnsupportedTableOffsetLength
442 }
443
444 const headerSize = 28
445 if resourceMapLength < headerSize {
446 return errInvalidDfont
447 }
448 buf, err := c.src.view(buf, int(resourceMapOffset+24), 2)
449 if err != nil {
450 return err
451 }
452 typeListOffset := int(int16(u16(buf)))
453
454 if typeListOffset < headerSize || resourceMapLength < uint32(typeListOffset)+2 {
455 return errInvalidDfont
456 }
457 buf, err = c.src.view(buf, int(resourceMapOffset)+typeListOffset, 2)
458 if err != nil {
459 return err
460 }
461 typeCount := int(int16(u16(buf)))
462
463 const tSize = 8
464 if typeCount < 0 || tSize*uint32(typeCount) > resourceMapLength-uint32(typeListOffset)-2 {
465 return errInvalidDfont
466 }
467 buf, err = c.src.view(buf, int(resourceMapOffset)+typeListOffset+2, tSize*typeCount)
468 if err != nil {
469 return err
470 }
471 resourceCount, resourceListOffset := 0, 0
472 for i := 0; i < typeCount; i++ {
473 if u32(buf[tSize*i:]) != 0x73666e74 { // "sfnt".
474 continue
475 }
476
477 resourceCount = int(int16(u16(buf[tSize*i+4:])))
478 if resourceCount < 0 {
479 return errInvalidDfont
480 }
481 // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
482 // says that the value in the wire format is "the number of
483 // resources of this type, minus one."
484 resourceCount++
485
486 resourceListOffset = int(int16(u16(buf[tSize*i+6:])))
487 if resourceListOffset < 0 {
488 return errInvalidDfont
489 }
490 break
491 }
492 if resourceCount == 0 {
493 return errInvalidDfont
494 }
495 if resourceCount > maxNumFonts {
496 return errUnsupportedNumberOfFonts
497 }
498
499 const rSize = 12
500 if o, n := uint32(typeListOffset+resourceListOffset), rSize*uint32(resourceCount); o > resourceMapLength || n > resourceMapLength-o {
501 return errInvalidDfont
502 } else {
503 buf, err = c.src.view(buf, int(resourceMapOffset+o), int(n))
504 if err != nil {
505 return err
506 }
507 }
508 c.offsets = make([]uint32, resourceCount)
509 for i := range c.offsets {
510 o := 0xffffff & u32(buf[rSize*i+4:])
511 // Offsets are relative to the resource data start, not the file start.
512 // A particular resource's data also starts with a 4-byte length, which
513 // we skip.
514 o += dfontResourceDataOffset + 4
515 if o > maxTableOffset {
516 return errUnsupportedTableOffsetLength
517 }
518 c.offsets[i] = o
519 }
520 c.isDfont = true
521 return nil
522 }
523
524 // Font returns the i'th font in the collection.
525 func (c *Collection) Font(i int) (*Font, error) {
526 if i < 0 || len(c.offsets) <= i {
527 return nil, ErrNotFound
528 }
529 f := &Font{src: c.src}
530 if err := f.initialize(int(c.offsets[i]), c.isDfont); err != nil {
531 return nil, err
532 }
533 return f, nil
534 }
535
536 // Parse parses an SFNT font, such as TTF or OTF data, from a []byte data
537 // source.
538 //
539 // The caller should not modify src while the Font remains in use. See the
540 // package documentation for details.
541 func Parse(src []byte) (*Font, error) {
542 f := &Font{src: source{b: src}}
543 if err := f.initialize(0, false); err != nil {
544 return nil, err
545 }
546 return f, nil
547 }
548
549 // ParseReaderAt parses an SFNT font, such as TTF or OTF data, from an
550 // io.ReaderAt data source.
551 //
552 // The caller should not modify or close src while the Font remains in use. See
553 // the package documentation for details.
554 func ParseReaderAt(src io.ReaderAt) (*Font, error) {
555 f := &Font{src: source{r: src}}
556 if err := f.initialize(0, false); err != nil {
557 return nil, err
558 }
559 return f, nil
560 }
561
562 // Font is an SFNT font.
563 //
564 // Many of its methods take a *Buffer argument, as re-using buffers can reduce
565 // the total memory allocation of repeated Font method calls, such as measuring
566 // and rasterizing every unique glyph in a string of text. If efficiency is not
567 // a concern, passing a nil *Buffer is valid, and implies using a temporary
568 // buffer for a single call.
569 //
570 // It is valid to re-use a *Buffer with multiple Font method calls, even with
571 // different *Font receivers, as long as they are not concurrent calls.
572 //
573 // All of the Font methods are safe to call concurrently, as long as each call
574 // has a different *Buffer (or nil).
575 //
576 // The Font methods that don't take a *Buffer argument are always safe to call
577 // concurrently.
578 //
579 // Some methods provide lengths or coordinates, e.g. bounds, font metrics and
580 // control points. All of these methods take a ppem parameter, which is the
581 // number of pixels in 1 em, expressed as a 26.6 fixed point value. For
582 // example, if 1 em is 10 pixels then ppem is fixed.I(10), which equals
583 // fixed.Int26_6(10 << 6).
584 //
585 // To get those lengths or coordinates in terms of font units instead of
586 // pixels, use ppem = fixed.Int26_6(f.UnitsPerEm()) and if those methods take a
587 // font.Hinting parameter, use font.HintingNone. The return values will have
588 // type fixed.Int26_6, but those numbers can be converted back to Units with no
589 // further scaling necessary.
590 type Font struct {
591 src source
592
593 // initialOffset is the file offset of the start of the font. This may be
594 // non-zero for fonts within a font collection.
595 initialOffset int32
596
597 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
598 // "Required Tables".
599 cmap table
600 head table
601 hhea table
602 hmtx table
603 maxp table
604 name table
605 os2 table
606 post table
607
608 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
609 // "Tables Related to TrueType Outlines".
610 //
611 // This implementation does not support hinting, so it does not read the
612 // cvt, fpgm gasp or prep tables.
613 glyf table
614 loca table
615
616 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
617 // "Tables Related to PostScript Outlines".
618 //
619 // TODO: cff2, vorg?
620 cff table
621
622 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
623 // "Tables Related to Bitmap Glyphs".
624 //
625 // TODO: Others?
626 cblc table
627
628 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
629 // "Advanced Typographic Tables".
630 //
631 // TODO: base, gdef, gsub, jstf, math?
632 gpos table
633
634 // https://www.microsoft.com/typography/otspec/otff.htm#otttables
635 // "Other OpenType Tables".
636 //
637 // TODO: hdmx, vmtx? Others?
638 kern table
639
640 cached struct {
641 ascent int32
642 capHeight int32
643 finalTableOffset int32
644 glyphData glyphData
645 glyphIndex glyphIndexFunc
646 bounds [4]int16
647 descent int32
648 indexToLocFormat bool // false means short, true means long.
649 isColorBitmap bool
650 isPostScript bool
651 kernNumPairs int32
652 kernOffset int32
653 kernFuncs []kernFunc
654 lineGap int32
655 numHMetrics int32
656 post *PostTable
657 slope [2]int32
658 unitsPerEm Units
659 xHeight int32
660 }
661 }
662
663 // NumGlyphs returns the number of glyphs in f.
664 func (f *Font) NumGlyphs() int { return len(f.cached.glyphData.locations) - 1 }
665
666 // UnitsPerEm returns the number of units per em for f.
667 func (f *Font) UnitsPerEm() Units { return f.cached.unitsPerEm }
668
669 func (f *Font) initialize(offset int, isDfont bool) error {
670 if !f.src.valid() {
671 return errInvalidSourceData
672 }
673 buf, finalTableOffset, isPostScript, err := f.initializeTables(offset, isDfont)
674 if err != nil {
675 return err
676 }
677
678 // The order of these parseXxx calls matters. Later calls may depend on
679 // information parsed by earlier calls, such as the maxp table's numGlyphs.
680 // To enforce these dependencies, such information is passed and returned
681 // explicitly, and the f.cached fields are only set afterwards.
682 //
683 // When implementing new parseXxx methods, take care not to call methods
684 // such as Font.NumGlyphs that implicitly depend on f.cached fields.
685
686 buf, bounds, indexToLocFormat, unitsPerEm, err := f.parseHead(buf)
687 if err != nil {
688 return err
689 }
690 buf, numGlyphs, err := f.parseMaxp(buf, isPostScript)
691 if err != nil {
692 return err
693 }
694 buf, glyphData, isColorBitmap, err := f.parseGlyphData(buf, numGlyphs, indexToLocFormat, isPostScript)
695 if err != nil {
696 return err
697 }
698 buf, glyphIndex, err := f.parseCmap(buf)
699 if err != nil {
700 return err
701 }
702 buf, kernNumPairs, kernOffset, err := f.parseKern(buf)
703 if err != nil {
704 return err
705 }
706 buf, kernFuncs, err := f.parseGPOSKern(buf)
707 if err != nil {
708 return err
709 }
710 buf, ascent, descent, lineGap, run, rise, numHMetrics, err := f.parseHhea(buf, numGlyphs)
711 if err != nil {
712 return err
713 }
714 buf, err = f.parseHmtx(buf, numGlyphs, numHMetrics)
715 if err != nil {
716 return err
717 }
718 buf, hasXHeightCapHeight, xHeight, capHeight, err := f.parseOS2(buf)
719 if err != nil {
720 return err
721 }
722 buf, post, err := f.parsePost(buf, numGlyphs)
723 if err != nil {
724 return err
725 }
726
727 f.cached.ascent = ascent
728 f.cached.capHeight = capHeight
729 f.cached.finalTableOffset = finalTableOffset
730 f.cached.glyphData = glyphData
731 f.cached.glyphIndex = glyphIndex
732 f.cached.bounds = bounds
733 f.cached.descent = descent
734 f.cached.indexToLocFormat = indexToLocFormat
735 f.cached.isColorBitmap = isColorBitmap
736 f.cached.isPostScript = isPostScript
737 f.cached.kernNumPairs = kernNumPairs
738 f.cached.kernOffset = kernOffset
739 f.cached.kernFuncs = kernFuncs
740 f.cached.lineGap = lineGap
741 f.cached.numHMetrics = numHMetrics
742 f.cached.post = post
743 f.cached.slope = [2]int32{run, rise}
744 f.cached.unitsPerEm = unitsPerEm
745 f.cached.xHeight = xHeight
746
747 if !hasXHeightCapHeight {
748 xh, ch, err := f.initOS2VersionBelow2()
749 if err != nil {
750 return err
751 }
752 f.cached.xHeight = xh
753 f.cached.capHeight = ch
754 }
755
756 return nil
757 }
758
759 func (f *Font) initializeTables(offset int, isDfont bool) (buf1 []byte, finalTableOffset int32, isPostScript bool, err error) {
760 f.initialOffset = int32(offset)
761 if int(f.initialOffset) != offset {
762 return nil, 0, false, errUnsupportedTableOffsetLength
763 }
764 // https://www.microsoft.com/typography/otspec/otff.htm "Organization of an
765 // OpenType Font" says that "The OpenType font starts with the Offset
766 // Table", which is 12 bytes.
767 buf, err := f.src.view(nil, offset, 12)
768 if err != nil {
769 return nil, 0, false, err
770 }
771 // When updating the cases in this switch statement, also update the
772 // Collection.initialize method.
773 switch u32(buf) {
774 default:
775 return nil, 0, false, errInvalidFont
776 case dfontResourceDataOffset:
777 return nil, 0, false, errInvalidSingleFont
778 case 0x00010000:
779 // No-op.
780 case 0x4f54544f: // "OTTO".
781 isPostScript = true
782 case 0x74727565: // "true"
783 // No-op.
784 case 0x74746366: // "ttcf".
785 return nil, 0, false, errInvalidSingleFont
786 }
787 numTables := int(u16(buf[4:]))
788 if numTables > maxNumTables {
789 return nil, 0, false, errUnsupportedNumberOfTables
790 }
791
792 // "The Offset Table is followed immediately by the Table Record entries...
793 // sorted in ascending order by tag", 16 bytes each.
794 buf, err = f.src.view(buf, offset+12, 16*numTables)
795 if err != nil {
796 return nil, 0, false, err
797 }
798 for b, first, prevTag := buf, true, uint32(0); len(b) > 0; b = b[16:] {
799 tag := u32(b)
800 if first {
801 first = false
802 } else if tag <= prevTag {
803 return nil, 0, false, errInvalidTableTagOrder
804 }
805 prevTag = tag
806
807 o, n := u32(b[8:12]), u32(b[12:16])
808 // For dfont files, the offset is relative to the resource, not the
809 // file.
810 if isDfont {
811 origO := o
812 o += uint32(offset)
813 if o < origO {
814 return nil, 0, false, errUnsupportedTableOffsetLength
815 }
816 }
817 if o > maxTableOffset || n > maxTableLength {
818 return nil, 0, false, errUnsupportedTableOffsetLength
819 }
820 // We ignore the checksums, but "all tables must begin on four byte
821 // boundries [sic]".
822 if o&3 != 0 {
823 return nil, 0, false, errInvalidTableOffset
824 }
825 if finalTableOffset < int32(o+n) {
826 finalTableOffset = int32(o + n)
827 }
828
829 // Match the 4-byte tag as a uint32. For example, "OS/2" is 0x4f532f32.
830 switch tag {
831 case 0x43424c43:
832 f.cblc = table{o, n}
833 case 0x43464620:
834 f.cff = table{o, n}
835 case 0x4f532f32:
836 f.os2 = table{o, n}
837 case 0x636d6170:
838 f.cmap = table{o, n}
839 case 0x676c7966:
840 f.glyf = table{o, n}
841 case 0x47504f53:
842 f.gpos = table{o, n}
843 case 0x68656164:
844 f.head = table{o, n}
845 case 0x68686561:
846 f.hhea = table{o, n}
847 case 0x686d7478:
848 f.hmtx = table{o, n}
849 case 0x6b65726e:
850 f.kern = table{o, n}
851 case 0x6c6f6361:
852 f.loca = table{o, n}
853 case 0x6d617870:
854 f.maxp = table{o, n}
855 case 0x6e616d65:
856 f.name = table{o, n}
857 case 0x706f7374:
858 f.post = table{o, n}
859 }
860 }
861
862 if (f.src.b != nil) && (int(finalTableOffset) > len(f.src.b)) {
863 return nil, 0, false, errInvalidSourceData
864 }
865 return buf, finalTableOffset, isPostScript, nil
866 }
867
868 func (f *Font) parseCmap(buf []byte) (buf1 []byte, glyphIndex glyphIndexFunc, err error) {
869 // https://www.microsoft.com/typography/OTSPEC/cmap.htm
870
871 const headerSize, entrySize = 4, 8
872 if f.cmap.length < headerSize {
873 return nil, nil, errInvalidCmapTable
874 }
875 u, err := f.src.u16(buf, f.cmap, 2)
876 if err != nil {
877 return nil, nil, err
878 }
879 numSubtables := int(u)
880 if f.cmap.length < headerSize+entrySize*uint32(numSubtables) {
881 return nil, nil, errInvalidCmapTable
882 }
883
884 var (
885 bestWidth int
886 bestOffset uint32
887 bestLength uint32
888 bestFormat uint16
889 )
890
891 // Scan all of the subtables, picking the widest supported one. See the
892 // platformEncodingWidth comment for more discussion of width.
893 for i := 0; i < numSubtables; i++ {
894 buf, err = f.src.view(buf, int(f.cmap.offset)+headerSize+entrySize*i, entrySize)
895 if err != nil {
896 return nil, nil, err
897 }
898 pid := u16(buf)
899 psid := u16(buf[2:])
900 width := platformEncodingWidth(pid, psid)
901 if width <= bestWidth {
902 continue
903 }
904 offset := u32(buf[4:])
905
906 if offset > f.cmap.length-4 {
907 return nil, nil, errInvalidCmapTable
908 }
909 buf, err = f.src.view(buf, int(f.cmap.offset+offset), 4)
910 if err != nil {
911 return nil, nil, err
912 }
913 format := u16(buf)
914 if !supportedCmapFormat(format, pid, psid) {
915 continue
916 }
917 length := uint32(u16(buf[2:]))
918
919 bestWidth = width
920 bestOffset = offset
921 bestLength = length
922 bestFormat = format
923 }
924
925 if bestWidth == 0 {
926 return nil, nil, errUnsupportedCmapEncodings
927 }
928 return f.makeCachedGlyphIndex(buf, bestOffset, bestLength, bestFormat)
929 }
930
931 func (f *Font) parseHead(buf []byte) (buf1 []byte, bounds [4]int16, indexToLocFormat bool, unitsPerEm Units, err error) {
932 // https://www.microsoft.com/typography/otspec/head.htm
933
934 if f.head.length != 54 {
935 return nil, [4]int16{}, false, 0, errInvalidHeadTable
936 }
937
938 u, err := f.src.u16(buf, f.head, 18)
939 if err != nil {
940 return nil, [4]int16{}, false, 0, err
941 }
942 if u == 0 {
943 return nil, [4]int16{}, false, 0, errInvalidHeadTable
944 }
945 unitsPerEm = Units(u)
946
947 for i := range bounds {
948 u, err := f.src.u16(buf, f.head, 36+2*i)
949 if err != nil {
950 return nil, [4]int16{}, false, 0, err
951 }
952 bounds[i] = int16(u)
953 }
954
955 u, err = f.src.u16(buf, f.head, 50)
956 if err != nil {
957 return nil, [4]int16{}, false, 0, err
958 }
959 indexToLocFormat = u != 0
960 return buf, bounds, indexToLocFormat, unitsPerEm, nil
961 }
962
963 func (f *Font) parseHhea(buf []byte, numGlyphs int32) (buf1 []byte, ascent, descent, lineGap, run, rise, numHMetrics int32, err error) {
964 // https://www.microsoft.com/typography/OTSPEC/hhea.htm
965
966 if f.hhea.length != 36 {
967 return nil, 0, 0, 0, 0, 0, 0, errInvalidHheaTable
968 }
969 u, err := f.src.u16(buf, f.hhea, 34)
970 if err != nil {
971 return nil, 0, 0, 0, 0, 0, 0, err
972 }
973 if int32(u) > numGlyphs || u == 0 {
974 return nil, 0, 0, 0, 0, 0, 0, errInvalidHheaTable
975 }
976 a, err := f.src.u16(buf, f.hhea, 4)
977 if err != nil {
978 return nil, 0, 0, 0, 0, 0, 0, err
979 }
980 d, err := f.src.u16(buf, f.hhea, 6)
981 if err != nil {
982 return nil, 0, 0, 0, 0, 0, 0, err
983 }
984 l, err := f.src.u16(buf, f.hhea, 8)
985 if err != nil {
986 return nil, 0, 0, 0, 0, 0, 0, err
987 }
988 ru, err := f.src.u16(buf, f.hhea, 20)
989 if err != nil {
990 return nil, 0, 0, 0, 0, 0, 0, err
991 }
992 ri, err := f.src.u16(buf, f.hhea, 18)
993 if err != nil {
994 return nil, 0, 0, 0, 0, 0, 0, err
995 }
996 return buf, int32(int16(a)), int32(int16(d)), int32(int16(l)), int32(int16(ru)), int32(int16(ri)), int32(u), nil
997 }
998
999 func (f *Font) parseHmtx(buf []byte, numGlyphs, numHMetrics int32) (buf1 []byte, err error) {
1000 // https://www.microsoft.com/typography/OTSPEC/hmtx.htm
1001
1002 // The spec says that the hmtx table's length should be
1003 // "4*numHMetrics+2*(numGlyphs-numHMetrics)". However, some fonts seen in the
1004 // wild omit the "2*(nG-nHM)". See https://github.com/golang/go/issues/28379
1005 if f.hmtx.length != uint32(4*numHMetrics) && f.hmtx.length != uint32(4*numHMetrics+2*(numGlyphs-numHMetrics)) {
1006 return nil, errInvalidHmtxTable
1007 }
1008 return buf, nil
1009 }
1010
1011 func (f *Font) parseKern(buf []byte) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
1012 // https://www.microsoft.com/typography/otspec/kern.htm
1013
1014 if f.kern.length == 0 {
1015 return buf, 0, 0, nil
1016 }
1017 const headerSize = 4
1018 if f.kern.length < headerSize {
1019 return nil, 0, 0, errInvalidKernTable
1020 }
1021 buf, err = f.src.view(buf, int(f.kern.offset), headerSize)
1022 if err != nil {
1023 return nil, 0, 0, err
1024 }
1025 offset := int(f.kern.offset) + headerSize
1026 length := int(f.kern.length) - headerSize
1027
1028 switch version := u16(buf); version {
1029 case 0:
1030 if numTables := int(u16(buf[2:])); numTables == 0 {
1031 return buf, 0, 0, nil
1032 } else if numTables > 1 {
1033 // TODO: support multiple subtables. For now, fall through and use
1034 // only the first one.
1035 }
1036 return f.parseKernVersion0(buf, offset, length)
1037 case 1:
1038 if buf[2] != 0 || buf[3] != 0 {
1039 return nil, 0, 0, errUnsupportedKernTable
1040 }
1041 // Microsoft's https://www.microsoft.com/typography/otspec/kern.htm
1042 // says that "Apple has extended the definition of the 'kern' table to
1043 // provide additional functionality. The Apple extensions are not
1044 // supported on Windows."
1045 //
1046 // The format is relatively complicated, including encoding a state
1047 // machine, but rarely seen. We follow Microsoft's and FreeType's
1048 // behavior and simply ignore it. Theoretically, we could follow
1049 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
1050 // but it doesn't seem worth the effort.
1051 return buf, 0, 0, nil
1052 }
1053 return nil, 0, 0, errUnsupportedKernTable
1054 }
1055
1056 func (f *Font) parseKernVersion0(buf []byte, offset, length int) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
1057 const headerSize = 6
1058 if length < headerSize {
1059 return nil, 0, 0, errInvalidKernTable
1060 }
1061 buf, err = f.src.view(buf, offset, headerSize)
1062 if err != nil {
1063 return nil, 0, 0, err
1064 }
1065 if version := u16(buf); version != 0 {
1066 return nil, 0, 0, errUnsupportedKernTable
1067 }
1068 subtableLengthU16 := u16(buf[2:])
1069 if int(subtableLengthU16) < headerSize || length < int(subtableLengthU16) {
1070 return nil, 0, 0, errInvalidKernTable
1071 }
1072 if coverageBits := buf[5]; coverageBits != 0x01 {
1073 // We only support horizontal kerning.
1074 return nil, 0, 0, errUnsupportedKernTable
1075 }
1076 offset += headerSize
1077 length -= headerSize
1078 subtableLengthU16 -= headerSize
1079
1080 switch format := buf[4]; format {
1081 case 0:
1082 return f.parseKernFormat0(buf, offset, length, subtableLengthU16)
1083 case 2:
1084 // If we could find such a font, we could write code to support it, but
1085 // a comment in the equivalent FreeType code (sfnt/ttkern.c) says that
1086 // they've never seen such a font.
1087 }
1088 return nil, 0, 0, errUnsupportedKernTable
1089 }
1090
1091 func (f *Font) parseKernFormat0(buf []byte, offset, length int, subtableLengthU16 uint16) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
1092 const headerSize, entrySize = 8, 6
1093 if length < headerSize {
1094 return nil, 0, 0, errInvalidKernTable
1095 }
1096 buf, err = f.src.view(buf, offset, headerSize)
1097 if err != nil {
1098 return nil, 0, 0, err
1099 }
1100 kernNumPairs = int32(u16(buf))
1101
1102 // The subtable length from the kern table is only uint16. Fonts like
1103 // Cambria, Calibri or Corbel have more then 10k kerning pairs and the
1104 // actual subtable size is truncated to uint16. Compare size with KERN
1105 // length and truncated size with subtable length.
1106 n := headerSize + entrySize*int(kernNumPairs)
1107 if (length < n) || (subtableLengthU16 != uint16(n)) {
1108 return nil, 0, 0, errInvalidKernTable
1109 }
1110 return buf, kernNumPairs, int32(offset) + headerSize, nil
1111 }
1112
1113 func (f *Font) parseMaxp(buf []byte, isPostScript bool) (buf1 []byte, numGlyphs int32, err error) {
1114 // https://www.microsoft.com/typography/otspec/maxp.htm
1115
1116 if isPostScript {
1117 if f.maxp.length != 6 {
1118 return nil, 0, errInvalidMaxpTable
1119 }
1120 } else {
1121 if f.maxp.length != 32 {
1122 return nil, 0, errInvalidMaxpTable
1123 }
1124 }
1125 u, err := f.src.u16(buf, f.maxp, 4)
1126 if err != nil {
1127 return nil, 0, err
1128 }
1129 return buf, int32(u), nil
1130 }
1131
1132 type glyphData struct {
1133 // The glyph data for the i'th glyph index is in
1134 // src[locations[i+0]:locations[i+1]].
1135 //
1136 // The slice length equals 1 plus the number of glyphs.
1137 locations []uint32
1138
1139 // For PostScript fonts, the bytecode for the i'th global or local
1140 // subroutine is in src[x[i+0]:x[i+1]].
1141 //
1142 // The []uint32 slice length equals 1 plus the number of subroutines
1143 gsubrs []uint32
1144 singleSubrs []uint32
1145 multiSubrs [][]uint32
1146
1147 fdSelect fdSelect
1148 }
1149
1150 func (f *Font) parseGlyphData(buf []byte, numGlyphs int32, indexToLocFormat, isPostScript bool) (buf1 []byte, ret glyphData, isColorBitmap bool, err error) {
1151 if isPostScript {
1152 p := cffParser{
1153 src: &f.src,
1154 base: int(f.cff.offset),
1155 offset: int(f.cff.offset),
1156 end: int(f.cff.offset + f.cff.length),
1157 }
1158 ret, err = p.parse(numGlyphs)
1159 if err != nil {
1160 return nil, glyphData{}, false, err
1161 }
1162 } else if f.loca.length != 0 {
1163 ret.locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs)
1164 if err != nil {
1165 return nil, glyphData{}, false, err
1166 }
1167 } else if f.cblc.length != 0 {
1168 isColorBitmap = true
1169 // TODO: parse the CBLC (and CBDT) tables. For now, we return a font
1170 // with empty glyphs.
1171 ret.locations = make([]uint32, numGlyphs+1)
1172 }
1173
1174 if len(ret.locations) != int(numGlyphs+1) {
1175 return nil, glyphData{}, false, errInvalidLocationData
1176 }
1177
1178 return buf, ret, isColorBitmap, nil
1179 }
1180
1181 func (f *Font) glyphTopOS2(b *Buffer, ppem fixed.Int26_6, r rune) (int32, error) {
1182 ind, err := f.GlyphIndex(b, r)
1183 if err != nil && err != ErrNotFound {
1184 return 0, err
1185 } else if ind == 0 {
1186 return 0, nil
1187 }
1188 // Y axis points down
1189 var min fixed.Int26_6
1190 seg, err := f.LoadGlyph(b, ind, ppem, nil)
1191 if err != nil {
1192 return 0, err
1193 }
1194 for _, s := range seg {
1195 for _, p := range s.Args {
1196 if p.Y < min {
1197 min = p.Y
1198 }
1199 }
1200 }
1201 return int32(min), nil
1202 }
1203
1204 func (f *Font) initOS2VersionBelow2() (xHeight, capHeight int32, err error) {
1205 ppem := fixed.Int26_6(f.UnitsPerEm())
1206 var b Buffer
1207
1208 // sxHeight equal to the top of the unscaled and unhinted glyph bounding box
1209 // of the glyph encoded at U+0078 (LATIN SMALL LETTER X).
1210 xh, err := f.glyphTopOS2(&b, ppem, 'x')
1211 if err != nil {
1212 return 0, 0, err
1213 }
1214
1215 // sCapHeight may be set equal to the top of the unscaled and unhinted glyph
1216 // bounding box of the glyph encoded at U+0048 (LATIN CAPITAL LETTER H).
1217 ch, err := f.glyphTopOS2(&b, ppem, 'H')
1218 if err != nil {
1219 return 0, 0, err
1220 }
1221
1222 return int32(xh), int32(ch), nil
1223 }
1224
1225 func (f *Font) parseOS2(buf []byte) (buf1 []byte, hasXHeightCapHeight bool, xHeight, capHeight int32, err error) {
1226 // https://docs.microsoft.com/da-dk/typography/opentype/spec/os2
1227
1228 if f.os2.length == 0 {
1229 // Apple TrueType fonts might omit the OS/2 table.
1230 return buf, false, 0, 0, nil
1231 } else if f.os2.length < 2 {
1232 return nil, false, 0, 0, errInvalidOS2Table
1233 }
1234 vers, err := f.src.u16(buf, f.os2, 0)
1235 if err != nil {
1236 return nil, false, 0, 0, err
1237 }
1238 if vers < 2 {
1239 // "The original TrueType specification had this table at 68 bytes long."
1240 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html
1241 const headerSize = 68
1242 if f.os2.length < headerSize {
1243 return nil, false, 0, 0, errInvalidOS2Table
1244 }
1245 // Will resolve xHeight and capHeight later, see initOS2VersionBelow2.
1246 return buf, false, 0, 0, nil
1247 }
1248 const headerSize = 96
1249 if f.os2.length < headerSize {
1250 return nil, false, 0, 0, errInvalidOS2Table
1251 }
1252 xh, err := f.src.u16(buf, f.os2, 86)
1253 if err != nil {
1254 return nil, false, 0, 0, err
1255 }
1256 ch, err := f.src.u16(buf, f.os2, 88)
1257 if err != nil {
1258 return nil, false, 0, 0, err
1259 }
1260 return buf, true, int32(int16(xh)), int32(int16(ch)), nil
1261 }
1262
1263 // PostTable represents an information stored in the PostScript font section.
1264 type PostTable struct {
1265 // Version of the version tag of the "post" table.
1266 Version uint32
1267 // ItalicAngle in counter-clockwise degrees from the vertical. Zero for
1268 // upright text, negative for text that leans to the right (forward).
1269 ItalicAngle float64
1270 // UnderlinePosition is the suggested distance of the top of the
1271 // underline from the baseline (negative values indicate below baseline).
1272 UnderlinePosition int16
1273 // Suggested values for the underline thickness.
1274 UnderlineThickness int16
1275 // IsFixedPitch indicates that the font is not proportionally spaced
1276 // (i.e. monospaced).
1277 IsFixedPitch bool
1278 }
1279
1280 // PostTable returns the information from the font's "post" table. It can
1281 // return nil, if the font doesn't have such a table.
1282 //
1283 // See https://docs.microsoft.com/en-us/typography/opentype/spec/post
1284 func (f *Font) PostTable() *PostTable {
1285 return f.cached.post
1286 }
1287
1288 func (f *Font) parsePost(buf []byte, numGlyphs int32) (buf1 []byte, post *PostTable, err error) {
1289 // https://www.microsoft.com/typography/otspec/post.htm
1290
1291 const headerSize = 32
1292 if f.post.length < headerSize {
1293 return nil, nil, errInvalidPostTable
1294 }
1295 u, err := f.src.u32(buf, f.post, 0)
1296 if err != nil {
1297 return nil, nil, err
1298 }
1299
1300 switch u {
1301 case 0x10000:
1302 // No-op.
1303 case 0x20000:
1304 if f.post.length < headerSize+2+2*uint32(numGlyphs) {
1305 return nil, nil, errInvalidPostTable
1306 }
1307 case 0x30000:
1308 // No-op.
1309 default:
1310 return nil, nil, errUnsupportedPostTable
1311 }
1312
1313 ang, err := f.src.u32(buf, f.post, 4)
1314 if err != nil {
1315 return nil, nil, err
1316 }
1317 up, err := f.src.u16(buf, f.post, 8)
1318 if err != nil {
1319 return nil, nil, err
1320 }
1321 ut, err := f.src.u16(buf, f.post, 10)
1322 if err != nil {
1323 return nil, nil, err
1324 }
1325 fp, err := f.src.u32(buf, f.post, 12)
1326 if err != nil {
1327 return nil, nil, err
1328 }
1329 post = &PostTable{
1330 Version: u,
1331 ItalicAngle: float64(int32(ang)) / 0x10000,
1332 UnderlinePosition: int16(up),
1333 UnderlineThickness: int16(ut),
1334 IsFixedPitch: fp != 0,
1335 }
1336 return buf, post, nil
1337 }
1338
1339 // Bounds returns the union of a Font's glyphs' bounds.
1340 //
1341 // In the returned Rectangle26_6's (x, y) coordinates, the Y axis increases
1342 // down.
1343 func (f *Font) Bounds(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (fixed.Rectangle26_6, error) {
1344 // The 0, 3, 2, 1 indices are to flip the Y coordinates. OpenType's Y axis
1345 // increases up. Go's standard graphics libraries' Y axis increases down.
1346 r := fixed.Rectangle26_6{
1347 Min: fixed.Point26_6{
1348 X: +scale(fixed.Int26_6(f.cached.bounds[0])*ppem, f.cached.unitsPerEm),
1349 Y: -scale(fixed.Int26_6(f.cached.bounds[3])*ppem, f.cached.unitsPerEm),
1350 },
1351 Max: fixed.Point26_6{
1352 X: +scale(fixed.Int26_6(f.cached.bounds[2])*ppem, f.cached.unitsPerEm),
1353 Y: -scale(fixed.Int26_6(f.cached.bounds[1])*ppem, f.cached.unitsPerEm),
1354 },
1355 }
1356 if h == font.HintingFull {
1357 // Quantize the Min down and Max up to a whole pixel.
1358 r.Min.X = (r.Min.X + 0) &^ 63
1359 r.Min.Y = (r.Min.Y + 0) &^ 63
1360 r.Max.X = (r.Max.X + 63) &^ 63
1361 r.Max.Y = (r.Max.Y + 63) &^ 63
1362 }
1363 return r, nil
1364 }
1365
1366 // TODO: API for looking up glyph variants?? For example, some fonts may
1367 // provide both slashed and dotted zero glyphs ('0'), or regular and 'old
1368 // style' numerals, and users can direct software to choose a variant.
1369
1370 type glyphIndexFunc func(f *Font, b *Buffer, r rune) (GlyphIndex, error)
1371
1372 // GlyphIndex returns the glyph index for the given rune.
1373 //
1374 // It returns (0, nil) if there is no glyph for r.
1375 // https://www.microsoft.com/typography/OTSPEC/cmap.htm says that "Character
1376 // codes that do not correspond to any glyph in the font should be mapped to
1377 // glyph index 0. The glyph at this location must be a special glyph
1378 // representing a missing character, commonly known as .notdef."
1379 func (f *Font) GlyphIndex(b *Buffer, r rune) (GlyphIndex, error) {
1380 return f.cached.glyphIndex(f, b, r)
1381 }
1382
1383 func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) (buf []byte, offset, length uint32, err error) {
1384 xx := int(x)
1385 if f.NumGlyphs() <= xx {
1386 return nil, 0, 0, ErrNotFound
1387 }
1388 i := f.cached.glyphData.locations[xx+0]
1389 j := f.cached.glyphData.locations[xx+1]
1390 if j < i {
1391 return nil, 0, 0, errInvalidGlyphDataLength
1392 }
1393 if j-i > maxGlyphDataLength {
1394 return nil, 0, 0, errUnsupportedGlyphDataLength
1395 }
1396 buf, err = b.view(&f.src, int(i), int(j-i))
1397 return buf, i, j - i, err
1398 }
1399
1400 // LoadGlyphOptions are the options to the Font.LoadGlyph method.
1401 type LoadGlyphOptions struct {
1402 // TODO: transform / hinting.
1403 }
1404
1405 // LoadGlyph returns the vector segments for the x'th glyph. ppem is the number
1406 // of pixels in 1 em.
1407 //
1408 // If b is non-nil, the segments become invalid to use once b is re-used.
1409 //
1410 // In the returned Segments' (x, y) coordinates, the Y axis increases down.
1411 //
1412 // It returns ErrNotFound if the glyph index is out of range. It returns
1413 // ErrColoredGlyph if the glyph is not a monochrome vector glyph, such as a
1414 // colored (bitmap or vector) emoji glyph.
1415 func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) (Segments, error) {
1416 if b == nil {
1417 b = &Buffer{}
1418 }
1419
1420 b.segments = b.segments[:0]
1421 if f.cached.isColorBitmap {
1422 return nil, ErrColoredGlyph
1423 }
1424 if f.cached.isPostScript {
1425 buf, offset, length, err := f.viewGlyphData(b, x)
1426 if err != nil {
1427 return nil, err
1428 }
1429 b.psi.type2Charstrings.initialize(f, b, x)
1430 if err := b.psi.run(psContextType2Charstring, buf, offset, length); err != nil {
1431 return nil, err
1432 }
1433 if !b.psi.type2Charstrings.ended {
1434 return nil, errInvalidCFFTable
1435 }
1436 } else if err := loadGlyf(f, b, x, 0, 0); err != nil {
1437 return nil, err
1438 }
1439
1440 // Scale the segments. If we want to support hinting, we'll have to push
1441 // the scaling computation into the PostScript / TrueType specific glyph
1442 // loading code, such as the appendGlyfSegments body, since TrueType
1443 // hinting bytecode works on the scaled glyph vectors. For now, though,
1444 // it's simpler to scale as a post-processing step.
1445 //
1446 // We also flip the Y coordinates. OpenType's Y axis increases up. Go's
1447 // standard graphics libraries' Y axis increases down.
1448 for i := range b.segments {
1449 a := &b.segments[i].Args
1450 for j := range a {
1451 a[j].X = +scale(a[j].X*ppem, f.cached.unitsPerEm)
1452 a[j].Y = -scale(a[j].Y*ppem, f.cached.unitsPerEm)
1453 }
1454 }
1455
1456 // TODO: look at opts to transform / hint the Buffer.segments.
1457
1458 return b.segments, nil
1459 }
1460
1461 func (f *Font) glyphNameFormat10(x GlyphIndex) (string, error) {
1462 if x >= numBuiltInPostNames {
1463 return "", ErrNotFound
1464 }
1465 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
1466 i := builtInPostNamesOffsets[x+0]
1467 j := builtInPostNamesOffsets[x+1]
1468 return builtInPostNamesData[i:j], nil
1469 }
1470
1471 func (f *Font) glyphNameFormat20(b *Buffer, x GlyphIndex) (string, error) {
1472 if b == nil {
1473 b = &Buffer{}
1474 }
1475 // The wire format for a Version 2 post table is documented at:
1476 // https://www.microsoft.com/typography/otspec/post.htm
1477 const glyphNameIndexOffset = 34
1478
1479 buf, err := b.view(&f.src, int(f.post.offset)+glyphNameIndexOffset+2*int(x), 2)
1480 if err != nil {
1481 return "", err
1482 }
1483 u := u16(buf)
1484 if u < numBuiltInPostNames {
1485 i := builtInPostNamesOffsets[u+0]
1486 j := builtInPostNamesOffsets[u+1]
1487 return builtInPostNamesData[i:j], nil
1488 }
1489 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
1490 // says that "32768 through 65535 are reserved for future use".
1491 if u > 32767 {
1492 return "", errUnsupportedPostTable
1493 }
1494 u -= numBuiltInPostNames
1495
1496 // Iterate through the list of Pascal-formatted strings. A linear scan is
1497 // clearly O(u), which isn't great (as the obvious loop, calling
1498 // Font.GlyphName, to get all of the glyph names in a font has quadratic
1499 // complexity), but the wire format doesn't suggest a better alternative.
1500
1501 offset := glyphNameIndexOffset + 2*f.NumGlyphs()
1502 buf, err = b.view(&f.src, int(f.post.offset)+offset, int(f.post.length)-offset)
1503 if err != nil {
1504 return "", err
1505 }
1506
1507 for {
1508 if len(buf) == 0 {
1509 return "", errInvalidPostTable
1510 }
1511 n := 1 + int(buf[0])
1512 if len(buf) < n {
1513 return "", errInvalidPostTable
1514 }
1515 if u == 0 {
1516 return string(buf[1:n]), nil
1517 }
1518 buf = buf[n:]
1519 u--
1520 }
1521 }
1522
1523 // GlyphName returns the name of the x'th glyph.
1524 //
1525 // Not every font contains glyph names. If not present, GlyphName will return
1526 // ("", nil).
1527 //
1528 // If present, the glyph name, provided by the font, is assumed to follow the
1529 // Adobe Glyph List Specification:
1530 // https://github.com/adobe-type-tools/agl-specification/blob/master/README.md
1531 //
1532 // This is also known as the "Adobe Glyph Naming convention", the "Adobe
1533 // document [for] Unicode and Glyph Names" or "PostScript glyph names".
1534 //
1535 // It returns ErrNotFound if the glyph index is out of range.
1536 func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error) {
1537 if int(x) >= f.NumGlyphs() {
1538 return "", ErrNotFound
1539 }
1540 if f.cached.post == nil {
1541 return "", nil
1542 }
1543 switch f.cached.post.Version {
1544 case 0x10000:
1545 return f.glyphNameFormat10(x)
1546 case 0x20000:
1547 return f.glyphNameFormat20(b, x)
1548 default:
1549 return "", nil
1550 }
1551 }
1552
1553 // GlyphBounds returns the bounding box of the x'th glyph, drawn at a dot equal
1554 // to the origin, and that glyph's advance width. ppem is the number of pixels
1555 // in 1 em.
1556 //
1557 // It returns ErrNotFound if the glyph index is out of range.
1558 //
1559 // The glyph's ascent and descent are equal to -bounds.Min.Y and +bounds.Max.Y.
1560 // The glyph's left-side and right-side bearings are equal to bounds.Min.X and
1561 // advance-bounds.Max.X. A visual depiction of what these metrics are is at
1562 // https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png
1563 func (f *Font) GlyphBounds(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, err error) {
1564 if int(x) >= f.NumGlyphs() {
1565 return fixed.Rectangle26_6{}, 0, ErrNotFound
1566 }
1567 if b == nil {
1568 b = &Buffer{}
1569 }
1570
1571 // https://www.microsoft.com/typography/OTSPEC/hmtx.htm says that "As an
1572 // optimization, the number of records can be less than the number of
1573 // glyphs, in which case the advance width value of the last record applies
1574 // to all remaining glyph IDs."
1575 metricIndex := x
1576 if n := GlyphIndex(f.cached.numHMetrics - 1); x > n {
1577 metricIndex = n
1578 }
1579
1580 buf, err := b.view(&f.src, int(f.hmtx.offset)+4*int(metricIndex), 2)
1581 if err != nil {
1582 return fixed.Rectangle26_6{}, 0, err
1583 }
1584 advance = fixed.Int26_6(u16(buf))
1585 advance = scale(advance*ppem, f.cached.unitsPerEm)
1586 if h == font.HintingFull {
1587 // Quantize the fixed.Int26_6 value to the nearest pixel.
1588 advance = (advance + 32) &^ 63
1589 }
1590
1591 // Ignore the hmtx LSB entries and the glyf bounding boxes. Instead, always
1592 // calculate bounds from the segments. OpenType does contain the bounds for
1593 // each glyph in the glyf table, but the bounds are not available for
1594 // compound glyphs. CFF/PostScript also have no explicit bounds and must be
1595 // obtained from the segments.
1596
1597 segments, err := f.LoadGlyph(b, x, ppem, &LoadGlyphOptions{
1598 // TODO: pass h, the font.Hinting.
1599 })
1600 if err != nil {
1601 return fixed.Rectangle26_6{}, 0, err
1602 }
1603 return segments.Bounds(), advance, nil
1604 }
1605
1606 // GlyphAdvance returns the advance width for the x'th glyph. ppem is the
1607 // number of pixels in 1 em.
1608 //
1609 // It returns ErrNotFound if the glyph index is out of range.
1610 func (f *Font) GlyphAdvance(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error) {
1611 if int(x) >= f.NumGlyphs() {
1612 return 0, ErrNotFound
1613 }
1614 if b == nil {
1615 b = &Buffer{}
1616 }
1617
1618 // https://www.microsoft.com/typography/OTSPEC/hmtx.htm says that "As an
1619 // optimization, the number of records can be less than the number of
1620 // glyphs, in which case the advance width value of the last record applies
1621 // to all remaining glyph IDs."
1622 if n := GlyphIndex(f.cached.numHMetrics - 1); x > n {
1623 x = n
1624 }
1625
1626 buf, err := b.view(&f.src, int(f.hmtx.offset)+4*int(x), 2)
1627 if err != nil {
1628 return 0, err
1629 }
1630 adv := fixed.Int26_6(u16(buf))
1631 adv = scale(adv*ppem, f.cached.unitsPerEm)
1632 if h == font.HintingFull {
1633 // Quantize the fixed.Int26_6 value to the nearest pixel.
1634 adv = (adv + 32) &^ 63
1635 }
1636 return adv, nil
1637 }
1638
1639 // Kern returns the horizontal adjustment for the kerning pair (x0, x1). A
1640 // positive kern means to move the glyphs further apart. ppem is the number of
1641 // pixels in 1 em.
1642 //
1643 // It returns ErrNotFound if either glyph index is out of range.
1644 func (f *Font) Kern(b *Buffer, x0, x1 GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error) {
1645
1646 // Use GPOS kern tables if available.
1647 if f.cached.kernFuncs != nil {
1648 for _, kf := range f.cached.kernFuncs {
1649 adv, err := kf(x0, x1)
1650 if err == ErrNotFound {
1651 continue
1652 }
1653 if err != nil {
1654 return 0, err
1655 }
1656 kern := fixed.Int26_6(adv)
1657 kern = scale(kern*ppem, f.cached.unitsPerEm)
1658 if h == font.HintingFull {
1659 // Quantize the fixed.Int26_6 value to the nearest pixel.
1660 kern = (kern + 32) &^ 63
1661 }
1662 return kern, nil
1663 }
1664 return 0, ErrNotFound
1665 }
1666
1667 // Fallback to kern table.
1668
1669 // TODO: Convert kern table handling into kernFunc and decide in Parse if
1670 // GPOS or kern should be used.
1671
1672 if n := f.NumGlyphs(); int(x0) >= n || int(x1) >= n {
1673 return 0, ErrNotFound
1674 }
1675 // Not every font has a kern table. If it doesn't, or if that table is
1676 // ignored, there's no need to allocate a Buffer.
1677 if f.cached.kernNumPairs == 0 {
1678 return 0, nil
1679 }
1680 if b == nil {
1681 b = &Buffer{}
1682 }
1683
1684 key := uint32(x0)<<16 | uint32(x1)
1685 lo, hi := int32(0), f.cached.kernNumPairs
1686 for lo < hi {
1687 i := (lo + hi) / 2
1688
1689 // TODO: this view call inside the inner loop can lead to many small
1690 // reads instead of fewer larger reads, which can be expensive. We
1691 // should be able to do better, although we don't want to make (one)
1692 // arbitrarily large read. Perhaps we should round up reads to 4K or 8K
1693 // chunks. For reference, Arial.ttf's kern table is 5472 bytes.
1694 // Times_New_Roman.ttf's kern table is 5220 bytes.
1695 const entrySize = 6
1696 buf, err := b.view(&f.src, int(f.cached.kernOffset+i*entrySize), entrySize)
1697 if err != nil {
1698 return 0, err
1699 }
1700
1701 k := u32(buf)
1702 if k < key {
1703 lo = i + 1
1704 } else if k > key {
1705 hi = i
1706 } else {
1707 kern := fixed.Int26_6(int16(u16(buf[4:])))
1708 kern = scale(kern*ppem, f.cached.unitsPerEm)
1709 if h == font.HintingFull {
1710 // Quantize the fixed.Int26_6 value to the nearest pixel.
1711 kern = (kern + 32) &^ 63
1712 }
1713 return kern, nil
1714 }
1715 }
1716 return 0, nil
1717 }
1718
1719 // Metrics returns the metrics of this font.
1720 func (f *Font) Metrics(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (font.Metrics, error) {
1721 m := font.Metrics{
1722 Height: scale(fixed.Int26_6(f.cached.ascent-f.cached.descent+f.cached.lineGap)*ppem, f.cached.unitsPerEm),
1723 Ascent: +scale(fixed.Int26_6(f.cached.ascent)*ppem, f.cached.unitsPerEm),
1724 Descent: -scale(fixed.Int26_6(f.cached.descent)*ppem, f.cached.unitsPerEm),
1725 XHeight: scale(fixed.Int26_6(f.cached.xHeight)*ppem, f.cached.unitsPerEm),
1726 CapHeight: scale(fixed.Int26_6(f.cached.capHeight)*ppem, f.cached.unitsPerEm),
1727 CaretSlope: image.Point{X: int(f.cached.slope[0]), Y: int(f.cached.slope[1])},
1728 }
1729 if h == font.HintingFull {
1730 // Quantize up to a whole pixel.
1731 m.Height = (m.Height + 63) &^ 63
1732 m.Ascent = (m.Ascent + 63) &^ 63
1733 m.Descent = (m.Descent + 63) &^ 63
1734 m.XHeight = (m.XHeight + 63) &^ 63
1735 m.CapHeight = (m.CapHeight + 63) &^ 63
1736 }
1737 return m, nil
1738 }
1739
1740 // WriteSourceTo writes the source data (the []byte or io.ReaderAt passed to
1741 // Parse or ParseReaderAt) to w.
1742 //
1743 // It returns the number of bytes written. On success, this is the final offset
1744 // of the furthest SFNT table in the source. This may be less than the length
1745 // of the []byte or io.ReaderAt originally passed.
1746 func (f *Font) WriteSourceTo(b *Buffer, w io.Writer) (int64, error) {
1747 if f.initialOffset != 0 {
1748 // TODO: when extracting a single font (i.e. TTF) out of a font
1749 // collection (i.e. TTC), write only the i'th font and not the (i-1)
1750 // previous fonts. Subtly, in the file format, table offsets may be
1751 // relative to the start of the resource (for dfont collections) or the
1752 // start of the file (otherwise). If we were to extract a single font
1753 // here, we might need to dynamically patch the table offsets, bearing
1754 // in mind that f.src.b is conceptually a 'read-only' slice of bytes.
1755 return 0, errUnsupportedCollection
1756 }
1757
1758 if f.src.b != nil {
1759 n, err := w.Write(f.src.b[:f.cached.finalTableOffset])
1760 return int64(n), err
1761 }
1762
1763 // We have an io.ReaderAt source, not a []byte. It is tempting to see if
1764 // the io.ReaderAt optionally implements the io.WriterTo interface, but we
1765 // don't for two reasons:
1766 // - We want to write exactly f.cached.finalTableOffset bytes, even if the
1767 // underlying 'file' is larger, to be consistent with the []byte flavor.
1768 // - We document that "Font methods are safe to call concurrently" and
1769 // while io.ReaderAt is stateless (the offset is an argument), the
1770 // io.Reader / io.Writer abstractions are stateful (the current position
1771 // is a field) and mutable state generally isn't concurrent-safe.
1772
1773 if b == nil {
1774 b = &Buffer{}
1775 }
1776 finalTableOffset := int(f.cached.finalTableOffset)
1777 numBytesWritten := int64(0)
1778 for offset := 0; offset < finalTableOffset; {
1779 length := finalTableOffset - offset
1780 if length > 4096 {
1781 length = 4096
1782 }
1783 view, err := b.view(&f.src, offset, length)
1784 if err != nil {
1785 return numBytesWritten, err
1786 }
1787 n, err := w.Write(view)
1788 numBytesWritten += int64(n)
1789 if err != nil {
1790 return numBytesWritten, err
1791 }
1792 offset += length
1793 }
1794 return numBytesWritten, nil
1795 }
1796
1797 // Name returns the name value keyed by the given NameID.
1798 //
1799 // It returns ErrNotFound if there is no value for that key.
1800 func (f *Font) Name(b *Buffer, id NameID) (string, error) {
1801 if b == nil {
1802 b = &Buffer{}
1803 }
1804
1805 const headerSize, entrySize = 6, 12
1806 if f.name.length < headerSize {
1807 return "", errInvalidNameTable
1808 }
1809 buf, err := b.view(&f.src, int(f.name.offset), headerSize)
1810 if err != nil {
1811 return "", err
1812 }
1813 numSubtables := u16(buf[2:])
1814 if f.name.length < headerSize+entrySize*uint32(numSubtables) {
1815 return "", errInvalidNameTable
1816 }
1817 stringOffset := u16(buf[4:])
1818
1819 seen := false
1820 for i, n := 0, int(numSubtables); i < n; i++ {
1821 buf, err := b.view(&f.src, int(f.name.offset)+headerSize+entrySize*i, entrySize)
1822 if err != nil {
1823 return "", err
1824 }
1825 if u16(buf[6:]) != uint16(id) {
1826 continue
1827 }
1828 seen = true
1829
1830 var stringify func([]byte) (string, error)
1831 switch u32(buf) {
1832 default:
1833 continue
1834 case pidMacintosh<<16 | psidMacintoshRoman:
1835 stringify = stringifyMacintosh
1836 case pidWindows<<16 | psidWindowsUCS2:
1837 stringify = stringifyUCS2
1838 }
1839
1840 nameLength := u16(buf[8:])
1841 nameOffset := u16(buf[10:])
1842 buf, err = b.view(&f.src, int(f.name.offset)+int(nameOffset)+int(stringOffset), int(nameLength))
1843 if err != nil {
1844 return "", err
1845 }
1846 return stringify(buf)
1847 }
1848
1849 if seen {
1850 return "", errUnsupportedPlatformEncoding
1851 }
1852 return "", ErrNotFound
1853 }
1854
1855 func stringifyMacintosh(b []byte) (string, error) {
1856 for _, c := range b {
1857 if c >= 0x80 {
1858 // b contains some non-ASCII bytes.
1859 s, _ := charmap.Macintosh.NewDecoder().Bytes(b)
1860 return string(s), nil
1861 }
1862 }
1863 // b contains only ASCII bytes.
1864 return string(b), nil
1865 }
1866
1867 func stringifyUCS2(b []byte) (string, error) {
1868 if len(b)&1 != 0 {
1869 return "", errInvalidUCS2String
1870 }
1871 r := make([]rune, len(b)/2)
1872 for i := range r {
1873 r[i] = rune(u16(b))
1874 b = b[2:]
1875 }
1876 return string(r), nil
1877 }
1878
1879 // Buffer holds re-usable buffers that can reduce the total memory allocation
1880 // of repeated Font method calls.
1881 //
1882 // See the Font type's documentation comment for more details.
1883 type Buffer struct {
1884 // buf is a byte buffer for when a Font's source is an io.ReaderAt.
1885 buf []byte
1886 // segments holds glyph vector path segments.
1887 segments Segments
1888 // compoundStack holds the components of a TrueType compound glyph.
1889 compoundStack [maxCompoundStackSize]struct {
1890 glyphIndex GlyphIndex
1891 dx, dy int16
1892 hasTransform bool
1893 transformXX int16
1894 transformXY int16
1895 transformYX int16
1896 transformYY int16
1897 }
1898 // psi is a PostScript interpreter for when the Font is an OpenType/CFF
1899 // font.
1900 psi psInterpreter
1901 }
1902
1903 func (b *Buffer) view(src *source, offset, length int) ([]byte, error) {
1904 buf, err := src.view(b.buf, offset, length)
1905 if err != nil {
1906 return nil, err
1907 }
1908 // Only update b.buf if it is safe to re-use buf.
1909 if src.viewBufferWritable() {
1910 b.buf = buf
1911 }
1912 return buf, nil
1913 }
1914
1915 // Segment is a segment of a vector path.
1916 type Segment struct {
1917 // Op is the operator.
1918 Op SegmentOp
1919 // Args is up to three (x, y) coordinates. The Y axis increases down.
1920 Args [3]fixed.Point26_6
1921 }
1922
1923 // SegmentOp is a vector path segment's operator.
1924 type SegmentOp uint32
1925
1926 const (
1927 SegmentOpMoveTo SegmentOp = iota
1928 SegmentOpLineTo
1929 SegmentOpQuadTo
1930 SegmentOpCubeTo
1931 )
1932
1933 // Segments is a slice of Segment.
1934 type Segments []Segment
1935
1936 // Bounds returns s' bounding box. It returns an empty rectangle if s is empty.
1937 func (s Segments) Bounds() (bounds fixed.Rectangle26_6) {
1938 if len(s) == 0 {
1939 return fixed.Rectangle26_6{}
1940 }
1941
1942 bounds.Min.X = fixed.Int26_6(+(1 << 31) - 1)
1943 bounds.Min.Y = fixed.Int26_6(+(1 << 31) - 1)
1944 bounds.Max.X = fixed.Int26_6(-(1 << 31) + 0)
1945 bounds.Max.Y = fixed.Int26_6(-(1 << 31) + 0)
1946
1947 for _, seg := range s {
1948 n := 1
1949 switch seg.Op {
1950 case SegmentOpQuadTo:
1951 n = 2
1952 case SegmentOpCubeTo:
1953 n = 3
1954 }
1955 for i := 0; i < n; i++ {
1956 if bounds.Max.X < seg.Args[i].X {
1957 bounds.Max.X = seg.Args[i].X
1958 }
1959 if bounds.Min.X > seg.Args[i].X {
1960 bounds.Min.X = seg.Args[i].X
1961 }
1962 if bounds.Max.Y < seg.Args[i].Y {
1963 bounds.Max.Y = seg.Args[i].Y
1964 }
1965 if bounds.Min.Y > seg.Args[i].Y {
1966 bounds.Min.Y = seg.Args[i].Y
1967 }
1968 }
1969 }
1970
1971 return bounds
1972 }
1973
1974 // translateArgs applies a translation to args.
1975 func translateArgs(args *[3]fixed.Point26_6, dx, dy fixed.Int26_6) {
1976 args[0].X += dx
1977 args[0].Y += dy
1978 args[1].X += dx
1979 args[1].Y += dy
1980 args[2].X += dx
1981 args[2].Y += dy
1982 }
1983
1984 // transformArgs applies an affine transformation to args. The t?? arguments
1985 // are 2.14 fixed point values.
1986 func transformArgs(args *[3]fixed.Point26_6, txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6) {
1987 args[0] = tform(txx, txy, tyx, tyy, dx, dy, args[0])
1988 args[1] = tform(txx, txy, tyx, tyy, dx, dy, args[1])
1989 args[2] = tform(txx, txy, tyx, tyy, dx, dy, args[2])
1990 }
1991
1992 func tform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, p fixed.Point26_6) fixed.Point26_6 {
1993 const half = 1 << 13
1994 return fixed.Point26_6{
1995 X: dx +
1996 fixed.Int26_6((int64(p.X)*int64(txx)+half)>>14) +
1997 fixed.Int26_6((int64(p.Y)*int64(tyx)+half)>>14),
1998 Y: dy +
1999 fixed.Int26_6((int64(p.X)*int64(txy)+half)>>14) +
2000 fixed.Int26_6((int64(p.Y)*int64(tyy)+half)>>14),
2001 }
2002 }