truetype.go 19.2 KB
Newer Older
1 2
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
3 4
// FreeType License or the GNU General Public License version 2 (or
// 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 8
// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/
// and http://www.microsoft.com/typography/otspec/
9
//
10 11
// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font
// metrics and control points. All these methods take a scale parameter, which
12 13 14
// is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For
// example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to
// fixed.Int26_6(10 << 6).
15 16 17
//
// To measure a TrueType font in ideal FUnit space, use scale equal to
// font.FUnitsPerEm().
N
Nigel Tao 已提交
18
package truetype // import "github.com/golang/freetype/truetype"
19 20 21

import (
	"fmt"
22 23

	"golang.org/x/image/math/fixed"
24 25
)

N
Nigel Tao 已提交
26
// An Index is a Font's index of a rune.
27 28
type Index uint16

N
Nigel Tao 已提交
29 30 31
// A NameID identifies a name table entry.
//
// See https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
S
Stephen Edwards 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
type NameID uint16

const (
	NameIDCopyright          NameID = 0
	NameIDFontFamily                = 1
	NameIDFontSubfamily             = 2
	NameIDUniqueSubfamilyID         = 3
	NameIDFontFullName              = 4
	NameIDNameTableVersion          = 5
	NameIDPostscriptName            = 6
	NameIDTrademarkNotice           = 7
	NameIDManufacturerName          = 8
	NameIDDesignerName              = 9
	NameIDFontDescription           = 10
	NameIDFontVendorURL             = 11
	NameIDFontDesignerURL           = 12
	NameIDFontLicense               = 13
	NameIDFontLicenseURL            = 14
	NameIDPreferredFamily           = 16
	NameIDPreferredSubfamily        = 17
	NameIDCompatibleName            = 18
	NameIDSampleText                = 19
)

const (
	// A 32-bit encoding consists of a most-significant 16-bit Platform ID and a
	// least-significant 16-bit Platform Specific ID. The magic numbers are
	// specified at https://www.microsoft.com/typography/otspec/name.htm
	unicodeEncoding         = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0)
	microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol)
	microsoftUCS2Encoding   = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2)
	microsoftUCS4Encoding   = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4)
)

66 67
// An HMetric holds the horizontal metrics of a single glyph.
type HMetric struct {
68
	AdvanceWidth, LeftSideBearing fixed.Int26_6
69 70 71 72
}

// A VMetric holds the vertical metrics of a single glyph.
type VMetric struct {
73
	AdvanceHeight, TopSideBearing fixed.Int26_6
74 75 76 77 78
}

// A FormatError reports that the input is not a valid TrueType font.
type FormatError string

N
Nigel Tao 已提交
79
func (e FormatError) Error() string {
80 81 82 83 84 85 86
	return "freetype: invalid TrueType format: " + string(e)
}

// An UnsupportedError reports that the input uses a valid but unimplemented
// TrueType feature.
type UnsupportedError string

N
Nigel Tao 已提交
87
func (e UnsupportedError) Error() string {
88 89 90
	return "freetype: unsupported TrueType feature: " + string(e)
}

91 92 93
// u32 returns the big-endian uint32 at b[i:].
func u32(b []byte, i int) uint32 {
	return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
94 95
}

96 97 98
// u16 returns the big-endian uint16 at b[i:].
func u16(b []byte, i int) uint16 {
	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.
N
Nigel Tao 已提交
102
func readTable(ttf []byte, offsetLength []byte) ([]byte, error) {
103
	offset := int(u32(offsetLength, 0))
104 105
	if offset < 0 {
		return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset)))
106
	}
107
	length := int(u32(offsetLength, 4))
108 109
	if length < 0 {
		return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length)))
110
	}
111 112 113 114 115
	end := offset + length
	if end < 0 || end > len(ttf) {
		return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length)))
	}
	return ttf[offset:end], nil
116 117
}

N
Nigel Tao 已提交
118 119 120 121 122 123 124 125 126 127 128
// parseSubtables returns the offset and platformID of the best subtable in
// table, where best favors a Unicode cmap encoding, and failing that, a
// Microsoft cmap encoding. offset is the offset of the first subtable in
// table, and size is the size of each subtable.
//
// If pred is non-nil, then only subtables that satisfy that predicate will be
// considered.
func parseSubtables(table []byte, name string, offset, size int, pred func([]byte) bool) (
	bestOffset int, bestPID uint32, retErr error) {

	if len(table) < 4 {
S
Stephen Edwards 已提交
129 130
		return 0, 0, FormatError(name + " too short")
	}
N
Nigel Tao 已提交
131 132
	nSubtables := int(u16(table, 2))
	if len(table) < size*nSubtables+offset {
S
Stephen Edwards 已提交
133 134
		return 0, 0, FormatError(name + " too short")
	}
N
Nigel Tao 已提交
135 136 137
	ok := false
	for i := 0; i < nSubtables; i, offset = i+1, offset+size {
		if pred != nil && !pred(table[offset:]) {
S
Stephen Edwards 已提交
138 139 140 141
			continue
		}
		// We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32.
		// All values are big-endian.
N
Nigel Tao 已提交
142
		pidPsid := u32(table, offset)
S
Stephen Edwards 已提交
143 144 145
		// We prefer the Unicode cmap encoding. Failing to find that, we fall
		// back onto the Microsoft cmap encoding.
		if pidPsid == unicodeEncoding {
N
Nigel Tao 已提交
146
			bestOffset, bestPID, ok = offset, pidPsid>>16, true
S
Stephen Edwards 已提交
147 148 149 150 151 152
			break

		} else if pidPsid == microsoftSymbolEncoding ||
			pidPsid == microsoftUCS2Encoding ||
			pidPsid == microsoftUCS4Encoding {

N
Nigel Tao 已提交
153
			bestOffset, bestPID, ok = offset, pidPsid>>16, true
S
Stephen Edwards 已提交
154 155 156
			// We don't break out of the for loop, so that Unicode can override Microsoft.
		}
	}
N
Nigel Tao 已提交
157 158 159 160
	if !ok {
		return 0, 0, UnsupportedError(name + " encoding")
	}
	return bestOffset, bestPID, nil
S
Stephen Edwards 已提交
161 162
}

163 164 165 166 167 168 169 170
const (
	locaOffsetFormatUnknown int = iota
	locaOffsetFormatShort
	locaOffsetFormatLong
)

// A cm holds a parsed cmap entry.
type cm struct {
171
	start, end, delta, offset uint32
172 173 174 175 176 177
}

// A Font represents a Truetype font.
type Font struct {
	// Tables sliced from the TTF data. The different tables are documented
	// at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
S
Stephen Edwards 已提交
178
	cmap, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, name, os2, prep, vmtx []byte
179 180

	cmapIndexes []byte
181 182 183 184 185

	// Cached values derived from the raw ttf data.
	cm                      []cm
	locaOffsetFormat        int
	nGlyph, nHMetric, nKern int
186
	fUnitsPerEm             int32
187 188 189
	ascent                  int32               // In FUnits.
	descent                 int32               // In FUnits; typically negative.
	bounds                  fixed.Rectangle26_6 // In FUnits.
190 191
	// Values from the maxp section.
	maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16
192 193
}

N
Nigel Tao 已提交
194
func (f *Font) parseCmap() error {
195 196
	const (
		cmapFormat4         = 4
197
		cmapFormat12        = 12
198 199 200
		languageIndependent = 0
	)

N
Nigel Tao 已提交
201
	offset, _, err := parseSubtables(f.cmap, "cmap", 4, 8, nil)
S
Stephen Edwards 已提交
202 203
	if err != nil {
		return err
204
	}
N
Nigel Tao 已提交
205
	offset = int(u32(f.cmap, offset+4))
206 207 208 209
	if offset <= 0 || offset > len(f.cmap) {
		return FormatError("bad cmap offset")
	}

210
	cmapFormat := u16(f.cmap, offset)
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	switch cmapFormat {
	case cmapFormat4:
		language := u16(f.cmap, offset+4)
		if language != languageIndependent {
			return UnsupportedError(fmt.Sprintf("language: %d", language))
		}
		segCountX2 := int(u16(f.cmap, offset+6))
		if segCountX2%2 == 1 {
			return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2))
		}
		segCount := segCountX2 / 2
		offset += 14
		f.cm = make([]cm, segCount)
		for i := 0; i < segCount; i++ {
			f.cm[i].end = uint32(u16(f.cmap, offset))
			offset += 2
		}
228
		offset += 2
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
		for i := 0; i < segCount; i++ {
			f.cm[i].start = uint32(u16(f.cmap, offset))
			offset += 2
		}
		for i := 0; i < segCount; i++ {
			f.cm[i].delta = uint32(u16(f.cmap, offset))
			offset += 2
		}
		for i := 0; i < segCount; i++ {
			f.cm[i].offset = uint32(u16(f.cmap, offset))
			offset += 2
		}
		f.cmapIndexes = f.cmap[offset:]
		return nil

	case cmapFormat12:
		if u16(f.cmap, offset+2) != 0 {
			return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4]))
		}
		length := u32(f.cmap, offset+4)
		language := u32(f.cmap, offset+8)
		if language != languageIndependent {
			return UnsupportedError(fmt.Sprintf("language: %d", language))
		}
		nGroups := u32(f.cmap, offset+12)
		if length != 12*nGroups+16 {
			return FormatError("inconsistent cmap length")
		}
		offset += 16
		f.cm = make([]cm, nGroups)
		for i := uint32(0); i < nGroups; i++ {
			f.cm[i].start = u32(f.cmap, offset+0)
			f.cm[i].end = u32(f.cmap, offset+4)
			f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start
			offset += 12
		}
		return nil
266
	}
267
	return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat))
268 269
}

N
Nigel Tao 已提交
270
func (f *Font) parseHead() error {
271 272 273
	if len(f.head) != 54 {
		return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
	}
274
	f.fUnitsPerEm = int32(u16(f.head, 18))
275 276 277 278
	f.bounds.Min.X = fixed.Int26_6(int16(u16(f.head, 36)))
	f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38)))
	f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40)))
	f.bounds.Max.Y = fixed.Int26_6(int16(u16(f.head, 42)))
279
	switch i := u16(f.head, 50); i {
280 281 282 283 284 285 286 287 288 289
	case 0:
		f.locaOffsetFormat = locaOffsetFormatShort
	case 1:
		f.locaOffsetFormat = locaOffsetFormatLong
	default:
		return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i))
	}
	return nil
}

N
Nigel Tao 已提交
290
func (f *Font) parseHhea() error {
291 292 293
	if len(f.hhea) != 36 {
		return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea)))
	}
294 295
	f.ascent = int32(int16(u16(f.hhea, 4)))
	f.descent = int32(int16(u16(f.hhea, 6)))
296
	f.nHMetric = int(u16(f.hhea, 34))
297 298 299 300 301 302
	if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) {
		return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx)))
	}
	return nil
}

N
Nigel Tao 已提交
303
func (f *Font) parseKern() error {
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	// Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says:
	// "Previous versions of the 'kern' table defined both the version and nTables fields in the header
	// as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged
	// (although AAT can sense an old kerning table and still make correct use of it). Microsoft
	// Windows still uses the older format for the 'kern' table and will not recognize the newer one.
	// Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS
	// and Windows should use the old format."
	// Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format,
	// just like the C Freetype implementation.
	if len(f.kern) == 0 {
		if f.nKern != 0 {
			return FormatError("bad kern table length")
		}
		return nil
	}
	if len(f.kern) < 18 {
		return FormatError("kern data too short")
	}
322
	version, offset := u16(f.kern, 0), 2
323 324 325
	if version != 0 {
		return UnsupportedError(fmt.Sprintf("kern version: %d", version))
	}
326
	n, offset := u16(f.kern, offset), offset+2
327 328 329
	if n != 1 {
		return UnsupportedError(fmt.Sprintf("kern nTables: %d", n))
	}
330 331 332
	offset += 2
	length, offset := int(u16(f.kern, offset)), offset+2
	coverage, offset := u16(f.kern, offset), offset+2
333 334 335 336
	if coverage != 0x0001 {
		// We only support horizontal kerning.
		return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage))
	}
337
	f.nKern, offset = int(u16(f.kern, offset)), offset+2
338 339 340 341 342 343
	if 6*f.nKern != length-14 {
		return FormatError("bad kern table length")
	}
	return nil
}

N
Nigel Tao 已提交
344
func (f *Font) parseMaxp() error {
345 346 347
	if len(f.maxp) != 32 {
		return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp)))
	}
348
	f.nGlyph = int(u16(f.maxp, 4))
349 350 351 352
	f.maxTwilightPoints = u16(f.maxp, 16)
	f.maxStorage = u16(f.maxp, 18)
	f.maxFunctionDefs = u16(f.maxp, 20)
	f.maxStackElements = u16(f.maxp, 24)
353 354 355
	return nil
}

356
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
357
func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 {
358
	if x >= 0 {
359
		x += fixed.Int26_6(f.fUnitsPerEm) / 2
360
	} else {
361
		x -= fixed.Int26_6(f.fUnitsPerEm) / 2
362
	}
363
	return x / fixed.Int26_6(f.fUnitsPerEm)
364 365
}

366
// Bounds returns the union of a Font's glyphs' bounds.
367
func (f *Font) Bounds(scale fixed.Int26_6) fixed.Rectangle26_6 {
368
	b := f.bounds
369 370 371 372
	b.Min.X = f.scale(scale * b.Min.X)
	b.Min.Y = f.scale(scale * b.Min.Y)
	b.Max.X = f.scale(scale * b.Max.X)
	b.Max.Y = f.scale(scale * b.Max.Y)
373
	return b
374 375
}

376 377 378
// FUnitsPerEm returns the number of FUnits in a Font's em-square's side.
func (f *Font) FUnitsPerEm() int32 {
	return f.fUnitsPerEm
379 380
}

N
Nigel Tao 已提交
381 382
// Index returns a Font's index for the given rune.
func (f *Font) Index(x rune) Index {
383
	c := uint32(x)
384 385 386 387 388 389 390 391 392 393 394
	for i, j := 0, len(f.cm); i < j; {
		h := i + (j-i)/2
		cm := &f.cm[h]
		if c < cm.start {
			j = h
		} else if cm.end < c {
			i = h + 1
		} else if cm.offset == 0 {
			return Index(c + cm.delta)
		} else {
			offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start))
395
			return Index(u16(f.cmapIndexes, offset))
396 397
		}
	}
398
	return 0
399 400
}

N
Nigel Tao 已提交
401 402
// Name returns the Font's name value for the given NameID. It returns "" if
// there was an error, or if that name was not found.
S
Stephen Edwards 已提交
403 404 405 406 407 408 409
func (f *Font) Name(id NameID) string {
	x, platformID, err := parseSubtables(f.name, "name", 6, 12, func(b []byte) bool {
		return NameID(u16(b, 6)) == id
	})
	if err != nil {
		return ""
	}
N
Nigel Tao 已提交
410
	offset, length := u16(f.name, 4)+u16(f.name, x+10), u16(f.name, x+8)
S
Stephen Edwards 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
	// Return the ASCII value of the encoded string.
	// The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1.
	src := f.name[offset : offset+length]
	var dst []byte
	if platformID != 1 { // UTF-16.
		if len(src)&1 != 0 {
			return ""
		}
		dst = make([]byte, len(src)/2)
		for i := range dst {
			dst[i] = printable(u16(src, 2*i))
		}
	} else { // ASCII.
		dst = make([]byte, len(src))
		for i, c := range src {
			dst[i] = printable(uint16(c))
		}
	}
	return string(dst)
}

func printable(r uint16) byte {
N
Nigel Tao 已提交
433
	if 0x20 <= r && r < 0x7f {
S
Stephen Edwards 已提交
434 435 436 437 438
		return byte(r)
	}
	return '?'
}

439 440 441
// unscaledHMetric returns the unscaled horizontal metrics for the glyph with
// the given index.
func (f *Font) unscaledHMetric(i Index) (h HMetric) {
442
	j := int(i)
443
	if j < 0 || f.nGlyph <= j {
444 445 446 447
		return HMetric{}
	}
	if j >= f.nHMetric {
		p := 4 * (f.nHMetric - 1)
448
		return HMetric{
449 450
			AdvanceWidth:    fixed.Int26_6(u16(f.hmtx, p)),
			LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
451 452 453
		}
	}
	return HMetric{
454 455
		AdvanceWidth:    fixed.Int26_6(u16(f.hmtx, 4*j)),
		LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))),
456
	}
457 458 459
}

// HMetric returns the horizontal metrics for the glyph with the given index.
460
func (f *Font) HMetric(scale fixed.Int26_6, i Index) HMetric {
461
	h := f.unscaledHMetric(i)
462 463 464
	h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
	h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
	return h
465 466
}

467
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
468
// the given index. yMax is the top of the glyph's bounding box.
469
func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) {
470 471 472 473 474 475
	j := int(i)
	if j < 0 || f.nGlyph <= j {
		return VMetric{}
	}
	if 4*j+4 <= len(f.vmtx) {
		return VMetric{
476 477
			AdvanceHeight:  fixed.Int26_6(u16(f.vmtx, 4*j)),
			TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))),
478 479
		}
	}
480 481 482 483 484 485
	// The OS/2 table has grown over time.
	// https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html
	// says that it was originally 68 bytes. Optional fields, including
	// the ascender and descender, are described at
	// http://www.microsoft.com/typography/otspec/os2.htm
	if len(f.os2) >= 72 {
486 487
		sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68)))
		sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70)))
488 489 490 491 492
		return VMetric{
			AdvanceHeight:  sTypoAscender - sTypoDescender,
			TopSideBearing: sTypoAscender - yMax,
		}
	}
493
	return VMetric{
494
		AdvanceHeight:  fixed.Int26_6(f.fUnitsPerEm),
495 496 497 498 499
		TopSideBearing: 0,
	}
}

// VMetric returns the vertical metrics for the glyph with the given index.
500
func (f *Font) VMetric(scale fixed.Int26_6, i Index) VMetric {
501 502
	// TODO: should 0 be bounds.YMax?
	v := f.unscaledVMetric(i, 0)
503 504 505 506 507
	v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
	v.TopSideBearing = f.scale(scale * v.TopSideBearing)
	return v
}

N
Nigel Tao 已提交
508 509 510
// Kern returns the horizontal adjustment for the given glyph pair. A positive
// kern means to move the glyphs further apart.
func (f *Font) Kern(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 {
511 512 513 514 515 516 517
	if f.nKern == 0 {
		return 0
	}
	g := uint32(i0)<<16 | uint32(i1)
	lo, hi := 0, f.nKern
	for lo < hi {
		i := (lo + hi) / 2
518
		ig := u32(f.kern, 18+6*i)
519 520 521 522 523
		if ig < g {
			lo = i + 1
		} else if ig > g {
			hi = i
		} else {
524
			return f.scale(scale * fixed.Int26_6(int16(u16(f.kern, 22+6*i))))
525 526 527 528 529
		}
	}
	return 0
}

530 531 532
// Parse returns a new Font for the given TTF or TTC data.
//
// For TrueType Collections, the first font in the collection is parsed.
N
Nigel Tao 已提交
533
func Parse(ttf []byte) (font *Font, err error) {
534 535 536 537 538
	return parse(ttf, 0)
}

func parse(ttf []byte, offset int) (font *Font, err error) {
	if len(ttf)-offset < 12 {
539 540 541
		err = FormatError("TTF data is too short")
		return
	}
542 543 544
	originalOffset := offset
	magic, offset := u32(ttf, offset), offset+4
	switch magic {
545 546 547
	case 0x00010000:
		// No-op.
	case 0x74746366: // "ttcf" as a big-endian uint32.
548
		if originalOffset != 0 {
549 550 551
			err = FormatError("recursive TTC")
			return
		}
552
		ttcVersion, offset := u32(ttf, offset), offset+4
Y
Yasuhiro Matsumoto 已提交
553
		if ttcVersion != 0x00010000 && ttcVersion != 0x00020000 {
554 555 556
			err = FormatError("bad TTC version")
			return
		}
557
		numFonts, offset := int(u32(ttf, offset)), offset+4
558 559 560 561
		if numFonts <= 0 {
			err = FormatError("bad number of TTC fonts")
			return
		}
562
		if len(ttf[offset:])/4 < numFonts {
563 564 565 566 567 568
			err = FormatError("TTC offset table is too short")
			return
		}
		// TODO: provide an API to select which font in a TrueType collection to return,
		// not just the first one. This may require an API to parse a TTC's name tables,
		// so users of this package can select the font in a TTC by name.
569
		offset = int(u32(ttf, offset))
570 571 572 573 574 575 576
		if offset <= 0 || offset > len(ttf) {
			err = FormatError("bad TTC offset")
			return
		}
		return parse(ttf, offset)
	default:
		err = FormatError("bad TTF version")
577 578
		return
	}
579
	n, offset := int(u16(ttf, offset)), offset+2
Y
Yasuhiro Matsumoto 已提交
580 581
	offset += 6 // Skip the searchRange, entrySelector and rangeShift.
	if len(ttf) < 16*n+offset {
582 583 584 585 586 587
		err = FormatError("TTF data is too short")
		return
	}
	f := new(Font)
	// Assign the table slices.
	for i := 0; i < n; i++ {
Y
Yasuhiro Matsumoto 已提交
588
		x := 16*i + offset
589 590 591
		switch string(ttf[x : x+4]) {
		case "cmap":
			f.cmap, err = readTable(ttf, ttf[x+8:x+16])
592 593 594 595
		case "cvt ":
			f.cvt, err = readTable(ttf, ttf[x+8:x+16])
		case "fpgm":
			f.fpgm, err = readTable(ttf, ttf[x+8:x+16])
596 597
		case "glyf":
			f.glyf, err = readTable(ttf, ttf[x+8:x+16])
598 599
		case "hdmx":
			f.hdmx, err = readTable(ttf, ttf[x+8:x+16])
600 601 602 603 604 605 606 607 608 609 610 611
		case "head":
			f.head, err = readTable(ttf, ttf[x+8:x+16])
		case "hhea":
			f.hhea, err = readTable(ttf, ttf[x+8:x+16])
		case "hmtx":
			f.hmtx, err = readTable(ttf, ttf[x+8:x+16])
		case "kern":
			f.kern, err = readTable(ttf, ttf[x+8:x+16])
		case "loca":
			f.loca, err = readTable(ttf, ttf[x+8:x+16])
		case "maxp":
			f.maxp, err = readTable(ttf, ttf[x+8:x+16])
S
Stephen Edwards 已提交
612 613
		case "name":
			f.name, err = readTable(ttf, ttf[x+8:x+16])
614 615
		case "OS/2":
			f.os2, err = readTable(ttf, ttf[x+8:x+16])
616 617
		case "prep":
			f.prep, err = readTable(ttf, ttf[x+8:x+16])
618 619
		case "vmtx":
			f.vmtx, err = readTable(ttf, ttf[x+8:x+16])
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
		}
		if err != nil {
			return
		}
	}
	// Parse and sanity-check the TTF data.
	if err = f.parseHead(); err != nil {
		return
	}
	if err = f.parseMaxp(); err != nil {
		return
	}
	if err = f.parseCmap(); err != nil {
		return
	}
	if err = f.parseKern(); err != nil {
		return
	}
	if err = f.parseHhea(); err != nil {
		return
	}
	font = f
	return
}