aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/ttLib/tables/_h_h_e_a.py
blob: 9b8baaadf034d1949eeb5cbfd092d9adbff67ecc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
from fontTools.misc import sstruct
from fontTools.misc.textTools import safeEval
from fontTools.misc.fixedTools import (
	ensureVersionIsLong as fi2ve, versionToFixed as ve2fi)
from . import DefaultTable
import math


hheaFormat = """
		>  # big endian
		tableVersion:           L
		ascent:                 h
		descent:                h
		lineGap:                h
		advanceWidthMax:        H
		minLeftSideBearing:     h
		minRightSideBearing:    h
		xMaxExtent:             h
		caretSlopeRise:         h
		caretSlopeRun:          h
		caretOffset:            h
		reserved0:              h
		reserved1:              h
		reserved2:              h
		reserved3:              h
		metricDataFormat:       h
		numberOfHMetrics:       H
"""


class table__h_h_e_a(DefaultTable.DefaultTable):

	# Note: Keep in sync with table__v_h_e_a

	dependencies = ['hmtx', 'glyf', 'CFF ', 'CFF2']

	# OpenType spec renamed these, add aliases for compatibility
	@property
	def ascender(self): return self.ascent

	@ascender.setter
	def ascender(self,value): self.ascent = value

	@property
	def descender(self): return self.descent

	@descender.setter
	def descender(self,value): self.descent = value

	def decompile(self, data, ttFont):
		sstruct.unpack(hheaFormat, data, self)

	def compile(self, ttFont):
		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ') or ttFont.isLoaded('CFF2')):
			self.recalc(ttFont)
		self.tableVersion = fi2ve(self.tableVersion)
		return sstruct.pack(hheaFormat, self)

	def recalc(self, ttFont):
		if 'hmtx' in ttFont:
			hmtxTable = ttFont['hmtx']
			self.advanceWidthMax = max(adv for adv, _ in hmtxTable.metrics.values())

		boundsWidthDict = {}
		if 'glyf' in ttFont:
			glyfTable = ttFont['glyf']
			for name in ttFont.getGlyphOrder():
				g = glyfTable[name]
				if g.numberOfContours == 0:
					continue
				if g.numberOfContours < 0 and not hasattr(g, "xMax"):
					# Composite glyph without extents set.
					# Calculate those.
					g.recalcBounds(glyfTable)
				boundsWidthDict[name] = g.xMax - g.xMin
		elif 'CFF ' in ttFont or 'CFF2' in ttFont:
			if 'CFF ' in ttFont:
				topDict = ttFont['CFF '].cff.topDictIndex[0]
			else:
				topDict = ttFont['CFF2'].cff.topDictIndex[0]
			charStrings = topDict.CharStrings
			for name in ttFont.getGlyphOrder():
				cs = charStrings[name]
				bounds = cs.calcBounds(charStrings)
				if bounds is not None:
					boundsWidthDict[name] = int(
						math.ceil(bounds[2]) - math.floor(bounds[0]))

		if boundsWidthDict:
			minLeftSideBearing = float('inf')
			minRightSideBearing = float('inf')
			xMaxExtent = -float('inf')
			for name, boundsWidth in boundsWidthDict.items():
				advanceWidth, lsb = hmtxTable[name]
				rsb = advanceWidth - lsb - boundsWidth
				extent = lsb + boundsWidth
				minLeftSideBearing = min(minLeftSideBearing, lsb)
				minRightSideBearing = min(minRightSideBearing, rsb)
				xMaxExtent = max(xMaxExtent, extent)
			self.minLeftSideBearing = minLeftSideBearing
			self.minRightSideBearing = minRightSideBearing
			self.xMaxExtent = xMaxExtent

		else:  # No glyph has outlines.
			self.minLeftSideBearing = 0
			self.minRightSideBearing = 0
			self.xMaxExtent = 0

	def toXML(self, writer, ttFont):
		formatstring, names, fixes = sstruct.getformat(hheaFormat)
		for name in names:
			value = getattr(self, name)
			if name == "tableVersion":
				value = fi2ve(value)
				value = "0x%08x" % value
			writer.simpletag(name, value=value)
			writer.newline()

	def fromXML(self, name, attrs, content, ttFont):
		if name == "tableVersion":
			setattr(self, name, ve2fi(attrs["value"]))
			return
		setattr(self, name, safeEval(attrs["value"]))