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