• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import safeEval
5from fontTools.misc.fixedTools import (
6	ensureVersionIsLong as fi2ve, versionToFixed as ve2fi)
7from . import DefaultTable
8import math
9
10
11hheaFormat = """
12		>  # big endian
13		tableVersion:           L
14		ascent:                 h
15		descent:                h
16		lineGap:                h
17		advanceWidthMax:        H
18		minLeftSideBearing:     h
19		minRightSideBearing:    h
20		xMaxExtent:             h
21		caretSlopeRise:         h
22		caretSlopeRun:          h
23		caretOffset:            h
24		reserved0:              h
25		reserved1:              h
26		reserved2:              h
27		reserved3:              h
28		metricDataFormat:       h
29		numberOfHMetrics:       H
30"""
31
32
33class table__h_h_e_a(DefaultTable.DefaultTable):
34
35	# Note: Keep in sync with table__v_h_e_a
36
37	dependencies = ['hmtx', 'glyf', 'CFF ']
38
39	def decompile(self, data, ttFont):
40		sstruct.unpack(hheaFormat, data, self)
41
42	def compile(self, ttFont):
43		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ')):
44			self.recalc(ttFont)
45		self.tableVersion = fi2ve(self.tableVersion)
46		return sstruct.pack(hheaFormat, self)
47
48	def recalc(self, ttFont):
49		if 'hmtx' in ttFont:
50			hmtxTable = ttFont['hmtx']
51			self.advanceWidthMax = max(adv for adv, _ in hmtxTable.metrics.values())
52
53		boundsWidthDict = {}
54		if 'glyf' in ttFont:
55			glyfTable = ttFont['glyf']
56			for name in ttFont.getGlyphOrder():
57				g = glyfTable[name]
58				if g.numberOfContours == 0:
59					continue
60				if g.numberOfContours < 0 and not hasattr(g, "xMax"):
61					# Composite glyph without extents set.
62					# Calculate those.
63					g.recalcBounds(glyfTable)
64				boundsWidthDict[name] = g.xMax - g.xMin
65		elif 'CFF ' in ttFont:
66			topDict = ttFont['CFF '].cff.topDictIndex[0]
67			charStrings = topDict.CharStrings
68			for name in ttFont.getGlyphOrder():
69				cs = charStrings[name]
70				bounds = cs.calcBounds(charStrings)
71				if bounds is not None:
72					boundsWidthDict[name] = int(
73						math.ceil(bounds[2]) - math.floor(bounds[0]))
74
75		if boundsWidthDict:
76			minLeftSideBearing = float('inf')
77			minRightSideBearing = float('inf')
78			xMaxExtent = -float('inf')
79			for name, boundsWidth in boundsWidthDict.items():
80				advanceWidth, lsb = hmtxTable[name]
81				rsb = advanceWidth - lsb - boundsWidth
82				extent = lsb + boundsWidth
83				minLeftSideBearing = min(minLeftSideBearing, lsb)
84				minRightSideBearing = min(minRightSideBearing, rsb)
85				xMaxExtent = max(xMaxExtent, extent)
86			self.minLeftSideBearing = minLeftSideBearing
87			self.minRightSideBearing = minRightSideBearing
88			self.xMaxExtent = xMaxExtent
89
90		else:  # No glyph has outlines.
91			self.minLeftSideBearing = 0
92			self.minRightSideBearing = 0
93			self.xMaxExtent = 0
94
95	def toXML(self, writer, ttFont):
96		formatstring, names, fixes = sstruct.getformat(hheaFormat)
97		for name in names:
98			value = getattr(self, name)
99			if name == "tableVersion":
100				value = fi2ve(value)
101				value = "0x%08x" % value
102			writer.simpletag(name, value=value)
103			writer.newline()
104
105	def fromXML(self, name, attrs, content, ttFont):
106		if name == "tableVersion":
107			setattr(self, name, ve2fi(attrs["value"]))
108			return
109		setattr(self, name, safeEval(attrs["value"]))
110