github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/freetype/truetype/truetype.go (about) 1 // Copyright 2010 The Freetype-Go Authors. All rights reserved. 2 // Use of this source code is governed by your choice of either the 3 // FreeType License or the GNU General Public License version 2 (or 4 // any later version), both of which can be found in the LICENSE file. 5 6 // Package truetype provides a parser for the TTF and TTC file formats. 7 // Those formats are documented at http://developer.apple.com/fonts/TTRefMan/ 8 // and http://www.microsoft.com/typography/otspec/ 9 // 10 // Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font 11 // metrics and control points. All these methods take a scale parameter, which 12 // is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For 13 // example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to 14 // fixed.Int26_6(10 << 6). 15 // 16 // To measure a TrueType font in ideal FUnit space, use scale equal to 17 // font.FUnitsPerEm(). 18 package truetype // import "github.com/insionng/yougam/libraries/golang/freetype/truetype" 19 20 import ( 21 "fmt" 22 23 "github.com/insionng/yougam/libraries/x/image/math/fixed" 24 ) 25 26 // An Index is a Font's index of a rune. 27 type Index uint16 28 29 // A NameID identifies a name table entry. 30 // 31 // See https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html 32 type NameID uint16 33 34 const ( 35 NameIDCopyright NameID = 0 36 NameIDFontFamily = 1 37 NameIDFontSubfamily = 2 38 NameIDUniqueSubfamilyID = 3 39 NameIDFontFullName = 4 40 NameIDNameTableVersion = 5 41 NameIDPostscriptName = 6 42 NameIDTrademarkNotice = 7 43 NameIDManufacturerName = 8 44 NameIDDesignerName = 9 45 NameIDFontDescription = 10 46 NameIDFontVendorURL = 11 47 NameIDFontDesignerURL = 12 48 NameIDFontLicense = 13 49 NameIDFontLicenseURL = 14 50 NameIDPreferredFamily = 16 51 NameIDPreferredSubfamily = 17 52 NameIDCompatibleName = 18 53 NameIDSampleText = 19 54 ) 55 56 const ( 57 // A 32-bit encoding consists of a most-significant 16-bit Platform ID and a 58 // least-significant 16-bit Platform Specific ID. The magic numbers are 59 // specified at https://www.microsoft.com/typography/otspec/name.htm 60 unicodeEncoding = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0) 61 microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol) 62 microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2) 63 microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4) 64 ) 65 66 // An HMetric holds the horizontal metrics of a single glyph. 67 type HMetric struct { 68 AdvanceWidth, LeftSideBearing fixed.Int26_6 69 } 70 71 // A VMetric holds the vertical metrics of a single glyph. 72 type VMetric struct { 73 AdvanceHeight, TopSideBearing fixed.Int26_6 74 } 75 76 // A FormatError reports that the input is not a valid TrueType font. 77 type FormatError string 78 79 func (e FormatError) Error() string { 80 return "freetype: invalid TrueType format: " + string(e) 81 } 82 83 // An UnsupportedError reports that the input uses a valid but unimplemented 84 // TrueType feature. 85 type UnsupportedError string 86 87 func (e UnsupportedError) Error() string { 88 return "freetype: unsupported TrueType feature: " + string(e) 89 } 90 91 // u32 returns the big-endian uint32 at b[i:]. 92 func u32(b []byte, i int) uint32 { 93 return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3]) 94 } 95 96 // u16 returns the big-endian uint16 at b[i:]. 97 func u16(b []byte, i int) uint16 { 98 return uint16(b[i])<<8 | uint16(b[i+1]) 99 } 100 101 // readTable returns a slice of the TTF data given by a table's directory entry. 102 func readTable(ttf []byte, offsetLength []byte) ([]byte, error) { 103 offset := int(u32(offsetLength, 0)) 104 if offset < 0 { 105 return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset))) 106 } 107 length := int(u32(offsetLength, 4)) 108 if length < 0 { 109 return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length))) 110 } 111 end := offset + length 112 if end < 0 || end > len(ttf) { 113 return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length))) 114 } 115 return ttf[offset:end], nil 116 } 117 118 // parseSubtables returns the offset and platformID of the best subtable in 119 // table, where best favors a Unicode cmap encoding, and failing that, a 120 // Microsoft cmap encoding. offset is the offset of the first subtable in 121 // table, and size is the size of each subtable. 122 // 123 // If pred is non-nil, then only subtables that satisfy that predicate will be 124 // considered. 125 func parseSubtables(table []byte, name string, offset, size int, pred func([]byte) bool) ( 126 bestOffset int, bestPID uint32, retErr error) { 127 128 if len(table) < 4 { 129 return 0, 0, FormatError(name + " too short") 130 } 131 nSubtables := int(u16(table, 2)) 132 if len(table) < size*nSubtables+offset { 133 return 0, 0, FormatError(name + " too short") 134 } 135 ok := false 136 for i := 0; i < nSubtables; i, offset = i+1, offset+size { 137 if pred != nil && !pred(table[offset:]) { 138 continue 139 } 140 // We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32. 141 // All values are big-endian. 142 pidPsid := u32(table, offset) 143 // We prefer the Unicode cmap encoding. Failing to find that, we fall 144 // back onto the Microsoft cmap encoding. 145 if pidPsid == unicodeEncoding { 146 bestOffset, bestPID, ok = offset, pidPsid>>16, true 147 break 148 149 } else if pidPsid == microsoftSymbolEncoding || 150 pidPsid == microsoftUCS2Encoding || 151 pidPsid == microsoftUCS4Encoding { 152 153 bestOffset, bestPID, ok = offset, pidPsid>>16, true 154 // We don't break out of the for loop, so that Unicode can override Microsoft. 155 } 156 } 157 if !ok { 158 return 0, 0, UnsupportedError(name + " encoding") 159 } 160 return bestOffset, bestPID, nil 161 } 162 163 const ( 164 locaOffsetFormatUnknown int = iota 165 locaOffsetFormatShort 166 locaOffsetFormatLong 167 ) 168 169 // A cm holds a parsed cmap entry. 170 type cm struct { 171 start, end, delta, offset uint32 172 } 173 174 // A Font represents a Truetype font. 175 type Font struct { 176 // Tables sliced from the TTF data. The different tables are documented 177 // at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html 178 cmap, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, name, os2, prep, vmtx []byte 179 180 cmapIndexes []byte 181 182 // Cached values derived from the raw ttf data. 183 cm []cm 184 locaOffsetFormat int 185 nGlyph, nHMetric, nKern int 186 fUnitsPerEm int32 187 bounds fixed.Rectangle26_6 188 // Values from the maxp section. 189 maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16 190 } 191 192 func (f *Font) parseCmap() error { 193 const ( 194 cmapFormat4 = 4 195 cmapFormat12 = 12 196 languageIndependent = 0 197 ) 198 199 offset, _, err := parseSubtables(f.cmap, "cmap", 4, 8, nil) 200 if err != nil { 201 return err 202 } 203 offset = int(u32(f.cmap, offset+4)) 204 if offset <= 0 || offset > len(f.cmap) { 205 return FormatError("bad cmap offset") 206 } 207 208 cmapFormat := u16(f.cmap, offset) 209 switch cmapFormat { 210 case cmapFormat4: 211 language := u16(f.cmap, offset+4) 212 if language != languageIndependent { 213 return UnsupportedError(fmt.Sprintf("language: %d", language)) 214 } 215 segCountX2 := int(u16(f.cmap, offset+6)) 216 if segCountX2%2 == 1 { 217 return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2)) 218 } 219 segCount := segCountX2 / 2 220 offset += 14 221 f.cm = make([]cm, segCount) 222 for i := 0; i < segCount; i++ { 223 f.cm[i].end = uint32(u16(f.cmap, offset)) 224 offset += 2 225 } 226 offset += 2 227 for i := 0; i < segCount; i++ { 228 f.cm[i].start = uint32(u16(f.cmap, offset)) 229 offset += 2 230 } 231 for i := 0; i < segCount; i++ { 232 f.cm[i].delta = uint32(u16(f.cmap, offset)) 233 offset += 2 234 } 235 for i := 0; i < segCount; i++ { 236 f.cm[i].offset = uint32(u16(f.cmap, offset)) 237 offset += 2 238 } 239 f.cmapIndexes = f.cmap[offset:] 240 return nil 241 242 case cmapFormat12: 243 if u16(f.cmap, offset+2) != 0 { 244 return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4])) 245 } 246 length := u32(f.cmap, offset+4) 247 language := u32(f.cmap, offset+8) 248 if language != languageIndependent { 249 return UnsupportedError(fmt.Sprintf("language: %d", language)) 250 } 251 nGroups := u32(f.cmap, offset+12) 252 if length != 12*nGroups+16 { 253 return FormatError("inconsistent cmap length") 254 } 255 offset += 16 256 f.cm = make([]cm, nGroups) 257 for i := uint32(0); i < nGroups; i++ { 258 f.cm[i].start = u32(f.cmap, offset+0) 259 f.cm[i].end = u32(f.cmap, offset+4) 260 f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start 261 offset += 12 262 } 263 return nil 264 } 265 return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat)) 266 } 267 268 func (f *Font) parseHead() error { 269 if len(f.head) != 54 { 270 return FormatError(fmt.Sprintf("bad head length: %d", len(f.head))) 271 } 272 f.fUnitsPerEm = int32(u16(f.head, 18)) 273 f.bounds.Min.X = fixed.Int26_6(int16(u16(f.head, 36))) 274 f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38))) 275 f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40))) 276 f.bounds.Max.Y = fixed.Int26_6(int16(u16(f.head, 42))) 277 switch i := u16(f.head, 50); i { 278 case 0: 279 f.locaOffsetFormat = locaOffsetFormatShort 280 case 1: 281 f.locaOffsetFormat = locaOffsetFormatLong 282 default: 283 return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i)) 284 } 285 return nil 286 } 287 288 func (f *Font) parseHhea() error { 289 if len(f.hhea) != 36 { 290 return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea))) 291 } 292 f.nHMetric = int(u16(f.hhea, 34)) 293 if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) { 294 return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx))) 295 } 296 return nil 297 } 298 299 func (f *Font) parseKern() error { 300 // Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says: 301 // "Previous versions of the 'kern' table defined both the version and nTables fields in the header 302 // as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged 303 // (although AAT can sense an old kerning table and still make correct use of it). Microsoft 304 // Windows still uses the older format for the 'kern' table and will not recognize the newer one. 305 // Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS 306 // and Windows should use the old format." 307 // Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format, 308 // just like the C Freetype implementation. 309 if len(f.kern) == 0 { 310 if f.nKern != 0 { 311 return FormatError("bad kern table length") 312 } 313 return nil 314 } 315 if len(f.kern) < 18 { 316 return FormatError("kern data too short") 317 } 318 version, offset := u16(f.kern, 0), 2 319 if version != 0 { 320 return UnsupportedError(fmt.Sprintf("kern version: %d", version)) 321 } 322 n, offset := u16(f.kern, offset), offset+2 323 if n != 1 { 324 return UnsupportedError(fmt.Sprintf("kern nTables: %d", n)) 325 } 326 offset += 2 327 length, offset := int(u16(f.kern, offset)), offset+2 328 coverage, offset := u16(f.kern, offset), offset+2 329 if coverage != 0x0001 { 330 // We only support horizontal kerning. 331 return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage)) 332 } 333 f.nKern, offset = int(u16(f.kern, offset)), offset+2 334 if 6*f.nKern != length-14 { 335 return FormatError("bad kern table length") 336 } 337 return nil 338 } 339 340 func (f *Font) parseMaxp() error { 341 if len(f.maxp) != 32 { 342 return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp))) 343 } 344 f.nGlyph = int(u16(f.maxp, 4)) 345 f.maxTwilightPoints = u16(f.maxp, 16) 346 f.maxStorage = u16(f.maxp, 18) 347 f.maxFunctionDefs = u16(f.maxp, 20) 348 f.maxStackElements = u16(f.maxp, 24) 349 return nil 350 } 351 352 // scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer. 353 func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 { 354 if x >= 0 { 355 x += fixed.Int26_6(f.fUnitsPerEm) / 2 356 } else { 357 x -= fixed.Int26_6(f.fUnitsPerEm) / 2 358 } 359 return x / fixed.Int26_6(f.fUnitsPerEm) 360 } 361 362 // Bounds returns the union of a Font's glyphs' bounds. 363 func (f *Font) Bounds(scale fixed.Int26_6) fixed.Rectangle26_6 { 364 b := f.bounds 365 b.Min.X = f.scale(scale * b.Min.X) 366 b.Min.Y = f.scale(scale * b.Min.Y) 367 b.Max.X = f.scale(scale * b.Max.X) 368 b.Max.Y = f.scale(scale * b.Max.Y) 369 return b 370 } 371 372 // FUnitsPerEm returns the number of FUnits in a Font's em-square's side. 373 func (f *Font) FUnitsPerEm() int32 { 374 return f.fUnitsPerEm 375 } 376 377 // Index returns a Font's index for the given rune. 378 func (f *Font) Index(x rune) Index { 379 c := uint32(x) 380 for i, j := 0, len(f.cm); i < j; { 381 h := i + (j-i)/2 382 cm := &f.cm[h] 383 if c < cm.start { 384 j = h 385 } else if cm.end < c { 386 i = h + 1 387 } else if cm.offset == 0 { 388 return Index(c + cm.delta) 389 } else { 390 offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start)) 391 return Index(u16(f.cmapIndexes, offset)) 392 } 393 } 394 return 0 395 } 396 397 // Name returns the Font's name value for the given NameID. It returns "" if 398 // there was an error, or if that name was not found. 399 func (f *Font) Name(id NameID) string { 400 x, platformID, err := parseSubtables(f.name, "name", 6, 12, func(b []byte) bool { 401 return NameID(u16(b, 6)) == id 402 }) 403 if err != nil { 404 return "" 405 } 406 offset, length := u16(f.name, 4)+u16(f.name, x+10), u16(f.name, x+8) 407 // Return the ASCII value of the encoded string. 408 // The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1. 409 src := f.name[offset : offset+length] 410 var dst []byte 411 if platformID != 1 { // UTF-16. 412 if len(src)&1 != 0 { 413 return "" 414 } 415 dst = make([]byte, len(src)/2) 416 for i := range dst { 417 dst[i] = printable(u16(src, 2*i)) 418 } 419 } else { // ASCII. 420 dst = make([]byte, len(src)) 421 for i, c := range src { 422 dst[i] = printable(uint16(c)) 423 } 424 } 425 return string(dst) 426 } 427 428 func printable(r uint16) byte { 429 if 0x20 <= r && r < 0x7f { 430 return byte(r) 431 } 432 return '?' 433 } 434 435 // unscaledHMetric returns the unscaled horizontal metrics for the glyph with 436 // the given index. 437 func (f *Font) unscaledHMetric(i Index) (h HMetric) { 438 j := int(i) 439 if j < 0 || f.nGlyph <= j { 440 return HMetric{} 441 } 442 if j >= f.nHMetric { 443 p := 4 * (f.nHMetric - 1) 444 return HMetric{ 445 AdvanceWidth: fixed.Int26_6(u16(f.hmtx, p)), 446 LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))), 447 } 448 } 449 return HMetric{ 450 AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)), 451 LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))), 452 } 453 } 454 455 // HMetric returns the horizontal metrics for the glyph with the given index. 456 func (f *Font) HMetric(scale fixed.Int26_6, i Index) HMetric { 457 h := f.unscaledHMetric(i) 458 h.AdvanceWidth = f.scale(scale * h.AdvanceWidth) 459 h.LeftSideBearing = f.scale(scale * h.LeftSideBearing) 460 return h 461 } 462 463 // unscaledVMetric returns the unscaled vertical metrics for the glyph with 464 // the given index. yMax is the top of the glyph's bounding box. 465 func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) { 466 j := int(i) 467 if j < 0 || f.nGlyph <= j { 468 return VMetric{} 469 } 470 if 4*j+4 <= len(f.vmtx) { 471 return VMetric{ 472 AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)), 473 TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))), 474 } 475 } 476 // The OS/2 table has grown over time. 477 // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html 478 // says that it was originally 68 bytes. Optional fields, including 479 // the ascender and descender, are described at 480 // http://www.microsoft.com/typography/otspec/os2.htm 481 if len(f.os2) >= 72 { 482 sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68))) 483 sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70))) 484 return VMetric{ 485 AdvanceHeight: sTypoAscender - sTypoDescender, 486 TopSideBearing: sTypoAscender - yMax, 487 } 488 } 489 return VMetric{ 490 AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm), 491 TopSideBearing: 0, 492 } 493 } 494 495 // VMetric returns the vertical metrics for the glyph with the given index. 496 func (f *Font) VMetric(scale fixed.Int26_6, i Index) VMetric { 497 // TODO: should 0 be bounds.YMax? 498 v := f.unscaledVMetric(i, 0) 499 v.AdvanceHeight = f.scale(scale * v.AdvanceHeight) 500 v.TopSideBearing = f.scale(scale * v.TopSideBearing) 501 return v 502 } 503 504 // Kern returns the horizontal adjustment for the given glyph pair. A positive 505 // kern means to move the glyphs further apart. 506 func (f *Font) Kern(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 { 507 if f.nKern == 0 { 508 return 0 509 } 510 g := uint32(i0)<<16 | uint32(i1) 511 lo, hi := 0, f.nKern 512 for lo < hi { 513 i := (lo + hi) / 2 514 ig := u32(f.kern, 18+6*i) 515 if ig < g { 516 lo = i + 1 517 } else if ig > g { 518 hi = i 519 } else { 520 return f.scale(scale * fixed.Int26_6(int16(u16(f.kern, 22+6*i)))) 521 } 522 } 523 return 0 524 } 525 526 // Parse returns a new Font for the given TTF or TTC data. 527 // 528 // For TrueType Collections, the first font in the collection is parsed. 529 func Parse(ttf []byte) (font *Font, err error) { 530 return parse(ttf, 0) 531 } 532 533 func parse(ttf []byte, offset int) (font *Font, err error) { 534 if len(ttf)-offset < 12 { 535 err = FormatError("TTF data is too short") 536 return 537 } 538 originalOffset := offset 539 magic, offset := u32(ttf, offset), offset+4 540 switch magic { 541 case 0x00010000: 542 // No-op. 543 case 0x74746366: // "ttcf" as a big-endian uint32. 544 if originalOffset != 0 { 545 err = FormatError("recursive TTC") 546 return 547 } 548 ttcVersion, offset := u32(ttf, offset), offset+4 549 if ttcVersion != 0x00010000 { 550 // TODO: support TTC version 2.0, once I have such a .ttc file to test with. 551 err = FormatError("bad TTC version") 552 return 553 } 554 numFonts, offset := int(u32(ttf, offset)), offset+4 555 if numFonts <= 0 { 556 err = FormatError("bad number of TTC fonts") 557 return 558 } 559 if len(ttf[offset:])/4 < numFonts { 560 err = FormatError("TTC offset table is too short") 561 return 562 } 563 // TODO: provide an API to select which font in a TrueType collection to return, 564 // not just the first one. This may require an API to parse a TTC's name tables, 565 // so users of this package can select the font in a TTC by name. 566 offset = int(u32(ttf, offset)) 567 if offset <= 0 || offset > len(ttf) { 568 err = FormatError("bad TTC offset") 569 return 570 } 571 return parse(ttf, offset) 572 default: 573 err = FormatError("bad TTF version") 574 return 575 } 576 n, offset := int(u16(ttf, offset)), offset+2 577 if len(ttf) < 16*n+12 { 578 err = FormatError("TTF data is too short") 579 return 580 } 581 f := new(Font) 582 // Assign the table slices. 583 for i := 0; i < n; i++ { 584 x := 16*i + 12 585 switch string(ttf[x : x+4]) { 586 case "cmap": 587 f.cmap, err = readTable(ttf, ttf[x+8:x+16]) 588 case "cvt ": 589 f.cvt, err = readTable(ttf, ttf[x+8:x+16]) 590 case "fpgm": 591 f.fpgm, err = readTable(ttf, ttf[x+8:x+16]) 592 case "glyf": 593 f.glyf, err = readTable(ttf, ttf[x+8:x+16]) 594 case "hdmx": 595 f.hdmx, err = readTable(ttf, ttf[x+8:x+16]) 596 case "head": 597 f.head, err = readTable(ttf, ttf[x+8:x+16]) 598 case "hhea": 599 f.hhea, err = readTable(ttf, ttf[x+8:x+16]) 600 case "hmtx": 601 f.hmtx, err = readTable(ttf, ttf[x+8:x+16]) 602 case "kern": 603 f.kern, err = readTable(ttf, ttf[x+8:x+16]) 604 case "loca": 605 f.loca, err = readTable(ttf, ttf[x+8:x+16]) 606 case "maxp": 607 f.maxp, err = readTable(ttf, ttf[x+8:x+16]) 608 case "name": 609 f.name, err = readTable(ttf, ttf[x+8:x+16]) 610 case "OS/2": 611 f.os2, err = readTable(ttf, ttf[x+8:x+16]) 612 case "prep": 613 f.prep, err = readTable(ttf, ttf[x+8:x+16]) 614 case "vmtx": 615 f.vmtx, err = readTable(ttf, ttf[x+8:x+16]) 616 } 617 if err != nil { 618 return 619 } 620 } 621 // Parse and sanity-check the TTF data. 622 if err = f.parseHead(); err != nil { 623 return 624 } 625 if err = f.parseMaxp(); err != nil { 626 return 627 } 628 if err = f.parseCmap(); err != nil { 629 return 630 } 631 if err = f.parseKern(); err != nil { 632 return 633 } 634 if err = f.parseHhea(); err != nil { 635 return 636 } 637 font = f 638 return 639 }