from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * 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 vheaFormat = """ > # big endian tableVersion: L ascent: h descent: h lineGap: h advanceHeightMax: H minTopSideBearing: h minBottomSideBearing: h yMaxExtent: h caretSlopeRise: h caretSlopeRun: h caretOffset: h reserved1: h reserved2: h reserved3: h reserved4: h metricDataFormat: h numberOfVMetrics: H """ class table__v_h_e_a(DefaultTable.DefaultTable): # Note: Keep in sync with table__h_h_e_a dependencies = ['vmtx', 'glyf'] def decompile(self, data, ttFont): sstruct.unpack(vheaFormat, data, self) def compile(self, ttFont): if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes: self.recalc(ttFont) self.tableVersion = fi2ve(self.tableVersion) return sstruct.pack(vheaFormat, self) def recalc(self, ttFont): vtmxTable = ttFont['vmtx'] if 'glyf' in ttFont: glyfTable = ttFont['glyf'] INFINITY = 100000 advanceHeightMax = 0 minTopSideBearing = +INFINITY # arbitrary big number minBottomSideBearing = +INFINITY # arbitrary big number yMaxExtent = -INFINITY # arbitrary big negative number for name in ttFont.getGlyphOrder(): height, tsb = vtmxTable[name] advanceHeightMax = max(advanceHeightMax, height) g = glyfTable[name] if g.numberOfContours == 0: continue if g.numberOfContours < 0 and not hasattr(g, "yMax"): # Composite glyph without extents set. # Calculate those. g.recalcBounds(glyfTable) minTopSideBearing = min(minTopSideBearing, tsb) bsb = height - tsb - (g.yMax - g.yMin) minBottomSideBearing = min(minBottomSideBearing, bsb) extent = tsb + (g.yMax - g.yMin) yMaxExtent = max(yMaxExtent, extent) if yMaxExtent == -INFINITY: # No glyph has outlines. minTopSideBearing = 0 minBottomSideBearing = 0 yMaxExtent = 0 self.advanceHeightMax = advanceHeightMax self.minTopSideBearing = minTopSideBearing self.minBottomSideBearing = minBottomSideBearing self.yMaxExtent = yMaxExtent else: # XXX CFF recalc... pass def toXML(self, writer, ttFont): formatstring, names, fixes = sstruct.getformat(vheaFormat) 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"])) # reserved0 is caretOffset for legacy reasons @property def reserved0(self): return self.caretOffset @reserved0.setter def reserved0(self, value): self.caretOffset = value