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