1from __future__ import print_function, division, absolute_import 2from fontTools.misc.py23 import * 3from fontTools.misc.textTools import safeEval 4from . import DefaultTable 5import sys 6import array 7import warnings 8 9 10class table__h_m_t_x(DefaultTable.DefaultTable): 11 12 headerTag = 'hhea' 13 advanceName = 'width' 14 sideBearingName = 'lsb' 15 numberOfMetricsName = 'numberOfHMetrics' 16 17 def decompile(self, data, ttFont): 18 numGlyphs = ttFont['maxp'].numGlyphs 19 numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName)) 20 if numberOfMetrics > numGlyphs: 21 numberOfMetrics = numGlyphs # We warn later. 22 # Note: advanceWidth is unsigned, but we read/write as signed. 23 metrics = array.array("h", data[:4 * numberOfMetrics]) 24 if sys.byteorder != "big": 25 metrics.byteswap() 26 data = data[4 * numberOfMetrics:] 27 numberOfSideBearings = numGlyphs - numberOfMetrics 28 sideBearings = array.array("h", data[:2 * numberOfSideBearings]) 29 data = data[2 * numberOfSideBearings:] 30 31 if sys.byteorder != "big": 32 sideBearings.byteswap() 33 if data: 34 warnings.warn("too much 'hmtx'/'vmtx' table data") 35 self.metrics = {} 36 glyphOrder = ttFont.getGlyphOrder() 37 for i in range(numberOfMetrics): 38 glyphName = glyphOrder[i] 39 self.metrics[glyphName] = list(metrics[i*2:i*2+2]) 40 lastAdvance = metrics[-2] 41 for i in range(numberOfSideBearings): 42 glyphName = glyphOrder[i + numberOfMetrics] 43 self.metrics[glyphName] = [lastAdvance, sideBearings[i]] 44 45 def compile(self, ttFont): 46 metrics = [] 47 for glyphName in ttFont.getGlyphOrder(): 48 metrics.append(self.metrics[glyphName]) 49 lastAdvance = metrics[-1][0] 50 lastIndex = len(metrics) 51 while metrics[lastIndex-2][0] == lastAdvance: 52 lastIndex -= 1 53 if lastIndex <= 1: 54 # all advances are equal 55 lastIndex = 1 56 break 57 additionalMetrics = metrics[lastIndex:] 58 additionalMetrics = [sb for advance, sb in additionalMetrics] 59 metrics = metrics[:lastIndex] 60 setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics)) 61 62 allMetrics = [] 63 for item in metrics: 64 allMetrics.extend(item) 65 allMetrics = array.array("h", allMetrics) 66 if sys.byteorder != "big": 67 allMetrics.byteswap() 68 data = allMetrics.tostring() 69 70 additionalMetrics = array.array("h", additionalMetrics) 71 if sys.byteorder != "big": 72 additionalMetrics.byteswap() 73 data = data + additionalMetrics.tostring() 74 return data 75 76 def toXML(self, writer, ttFont): 77 names = sorted(self.metrics.keys()) 78 for glyphName in names: 79 advance, sb = self.metrics[glyphName] 80 writer.simpletag("mtx", [ 81 ("name", glyphName), 82 (self.advanceName, advance), 83 (self.sideBearingName, sb), 84 ]) 85 writer.newline() 86 87 def fromXML(self, name, attrs, content, ttFont): 88 if not hasattr(self, "metrics"): 89 self.metrics = {} 90 if name == "mtx": 91 self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), 92 safeEval(attrs[self.sideBearingName])] 93 94 def __delitem__(self, glyphName): 95 del self.metrics[glyphName] 96 97 def __getitem__(self, glyphName): 98 return self.metrics[glyphName] 99 100 def __setitem__(self, glyphName, advance_sb_pair): 101 self.metrics[glyphName] = tuple(advance_sb_pair) 102 103